From 27938ef6584aa9182ca144cdc7747c5e0ab61190 Mon Sep 17 00:00:00 2001 From: Stephane Glondu Date: Wed, 10 Jul 2019 14:49:53 +0200 Subject: [PATCH] New upstream version 4.07.0 --- .depend | 561 ++-- .gitattributes | 25 +- .gitignore | 60 +- .mailmap | 4 + .merlin | 7 +- .travis-ci.sh | 154 - .travis.yml | 2 +- Changes | 579 ++++ HACKING.adoc | 29 +- INSTALL.adoc | 49 +- Makefile | 230 +- Makefile.common | 30 + README.adoc | 38 +- README.win32.adoc | 19 +- VERSION | 2 +- appveyor.yml | 6 +- appveyor_build.cmd | 113 - asmcomp/CSEgen.ml | 6 +- asmcomp/amd64/emit.mlp | 44 +- asmcomp/amd64/reload.ml | 4 +- asmcomp/arm/arch.ml | 6 +- asmcomp/arm/emit.mlp | 72 +- asmcomp/arm/proc.ml | 3 + asmcomp/arm/selection.ml | 29 +- asmcomp/arm64/emit.mlp | 26 +- asmcomp/asmgen.ml | 4 +- asmcomp/asmlink.ml | 13 +- asmcomp/build_export_info.ml | 256 +- asmcomp/build_export_info.mli | 4 +- asmcomp/clambda.ml | 6 +- asmcomp/clambda.mli | 6 +- asmcomp/closure.ml | 37 +- asmcomp/closure_offsets.ml | 49 - asmcomp/closure_offsets.mli | 17 - asmcomp/cmm.ml | 43 +- asmcomp/cmm.mli | 31 +- asmcomp/cmmgen.ml | 161 +- asmcomp/compilenv.ml | 38 +- asmcomp/compilenv.mli | 4 +- asmcomp/export_info.ml | 251 +- asmcomp/export_info.mli | 72 +- asmcomp/export_info_for_pack.ml | 42 +- asmcomp/flambda_to_clambda.ml | 189 +- asmcomp/flambda_to_clambda.mli | 2 +- asmcomp/i386/emit.mlp | 75 +- asmcomp/i386/proc.ml | 2 +- asmcomp/import_approx.ml | 252 +- asmcomp/linearize.ml | 8 +- asmcomp/mach.ml | 10 +- asmcomp/mach.mli | 10 +- asmcomp/power/emit.mlp | 31 +- asmcomp/printcmm.ml | 20 +- asmcomp/printcmm.mli | 3 +- asmcomp/printmach.ml | 11 +- asmcomp/reloadgen.ml | 2 +- asmcomp/s390x/emit.mlp | 34 +- asmcomp/selectgen.ml | 16 +- asmcomp/spill.ml | 2 +- asmcomp/split.ml | 2 +- asmcomp/traverse_for_exported_symbols.ml | 267 ++ asmcomp/traverse_for_exported_symbols.mli | 41 + asmrun/.depend | 72 +- asmrun/Makefile | 36 +- asmrun/amd64.S | 32 +- asmrun/amd64nt.asm | 51 + asmrun/spacetime.c | 58 +- asmrun/startup.c | 1 + boot/ocamlc | Bin 2250862 -> 2290614 bytes boot/ocamldep | Bin 2158089 -> 0 bytes boot/ocamllex | Bin 285700 -> 305599 bytes bytecomp/bytegen.ml | 59 +- bytecomp/bytegen.mli | 2 + bytecomp/bytelink.ml | 24 +- bytecomp/emitcode.ml | 28 +- bytecomp/instruct.ml | 5 +- bytecomp/instruct.mli | 5 +- bytecomp/lambda.ml | 310 +- bytecomp/lambda.mli | 63 +- bytecomp/matching.ml | 71 +- bytecomp/printinstr.ml | 5 +- bytecomp/printlambda.ml | 85 +- bytecomp/semantics_of_primitives.ml | 21 +- bytecomp/simplif.ml | 91 +- bytecomp/switch.ml | 28 +- bytecomp/switch.mli | 23 +- bytecomp/translattribute.ml | 23 +- bytecomp/translclass.ml | 61 +- bytecomp/translcore.ml | 663 +---- bytecomp/translcore.mli | 5 - bytecomp/translmod.ml | 143 +- bytecomp/translmod.mli | 2 +- bytecomp/translobj.ml | 6 +- bytecomp/translobj.mli | 2 +- bytecomp/translprim.ml | 757 +++++ bytecomp/translprim.mli | 49 + byterun/.depend | 44 +- byterun/Makefile | 38 +- byterun/alloc.c | 2 +- byterun/bigarray.c | 767 ++++- byterun/caml/config.h | 2 + byterun/caml/exec.h | 2 +- byterun/caml/instruct.h | 3 +- byterun/caml/intext.h | 2 +- byterun/caml/major_gc.h | 6 +- byterun/caml/minor_gc.h | 1 + byterun/caml/misc.h | 8 +- byterun/caml/osdeps.h | 9 + byterun/caml/spacetime.h | 11 +- byterun/custom.c | 16 +- byterun/debugger.c | 10 +- byterun/extern.c | 7 +- byterun/finalise.c | 2 +- byterun/fix_code.c | 1 + byterun/floats.c | 27 +- byterun/freelist.c | 8 +- byterun/intern.c | 9 +- byterun/interp.c | 11 +- byterun/ints.c | 2 +- byterun/io.c | 5 + byterun/memory.c | 11 +- byterun/minor_gc.c | 3 + byterun/signals.c | 8 +- byterun/str.c | 37 +- byterun/sys.c | 26 +- byterun/terminfo.c | 134 - byterun/unix.c | 23 +- byterun/weak.c | 46 +- byterun/win32.c | 133 +- config/Makefile-templ | 3 +- config/Makefile.mingw | 10 +- config/Makefile.mingw64 | 8 +- config/Makefile.msvc | 2 + config/Makefile.msvc64 | 2 + config/s-nt.h | 2 +- config/s-templ.h | 7 - configure | 83 +- debugger/.depend | 46 +- debugger/Makefile | 7 +- debugger/breakpoints.ml | 16 +- debugger/input_handling.ml | 2 +- debugger/loadprinter.ml | 8 +- debugger/loadprinter.mli | 2 + debugger/main.ml | 16 +- debugger/parameters.ml | 7 + debugger/parameters.mli | 5 + debugger/show_information.ml | 24 +- debugger/symbols.ml | 5 +- driver/compenv.ml | 25 +- driver/compile.ml | 2 +- driver/compmisc.ml | 28 +- driver/main.ml | 2 + driver/main_args.ml | 25 +- driver/main_args.mli | 3 + driver/makedepend.ml | 4 +- driver/optcompile.ml | 2 +- driver/optmain.ml | 3 + emacs/Makefile | 5 +- emacs/caml-font-old.el | 2 +- emacs/caml-font.el | 2 +- emacs/caml-help.el | 24 +- emacs/caml-types.el | 4 +- emacs/caml.el | 100 +- emacs/camldebug.el | 2 +- emacs/inf-caml.el | 14 +- lex/outputbis.ml | 426 ++- man/ocaml.m | 9 +- man/ocamlc.m | 14 +- man/ocamlopt.m | 20 +- manual/LICENSE-for-the-manual | 20 + manual/Makefile | 32 + manual/README.md | 252 ++ manual/manual/.gitignore | 8 + manual/manual/Makefile | 143 + manual/manual/allfiles.etex | 110 + manual/manual/biblio.etex | 240 ++ manual/manual/cmds/.gitignore | 3 + manual/manual/cmds/Makefile | 60 + manual/manual/cmds/afl-fuzz.etex | 74 + manual/manual/cmds/browser.etex | 7 + manual/manual/cmds/comp.etex | 512 ++++ manual/manual/cmds/debugger.etex | 674 +++++ manual/manual/cmds/depend.etex | 222 ++ manual/manual/cmds/flambda.etex | 1343 +++++++++ manual/manual/cmds/intf-c.etex | 2643 +++++++++++++++++ manual/manual/cmds/lexyacc.etex | 729 +++++ manual/manual/cmds/native.etex | 231 ++ manual/manual/cmds/ocamlbuild.etex | 6 + manual/manual/cmds/ocamldoc.etex | 1136 +++++++ manual/manual/cmds/plugins.etex | 88 + manual/manual/cmds/profil.etex | 176 ++ manual/manual/cmds/runtime.etex | 281 ++ manual/manual/cmds/spacetime.etex | 126 + manual/manual/cmds/top.etex | 451 +++ manual/manual/cmds/unified-options.etex | 789 +++++ manual/manual/foreword.etex | 82 + manual/manual/htmlman/.gitignore | 8 + manual/manual/htmlman/contents_motif.gif | Bin 0 -> 316 bytes .../fonts/fira-sans-v8-latin-regular.eot | Bin 0 -> 24643 bytes .../fonts/fira-sans-v8-latin-regular.svg | 330 ++ .../fonts/fira-sans-v8-latin-regular.ttf | Bin 0 -> 54032 bytes .../fonts/fira-sans-v8-latin-regular.woff | Bin 0 -> 25472 bytes .../fonts/fira-sans-v8-latin-regular.woff2 | Bin 0 -> 21016 bytes manual/manual/htmlman/libgraph.gif | Bin 0 -> 2149 bytes manual/manual/htmlman/next_motif.gif | Bin 0 -> 317 bytes manual/manual/htmlman/previous_motif.gif | Bin 0 -> 317 bytes manual/manual/index.tex | 20 + manual/manual/infoman/.gitignore | 5 + manual/manual/library/.cvsignore | 5 + manual/manual/library/.gitignore | 5 + manual/manual/library/Makefile | 86 + manual/manual/library/builtin.etex | 281 ++ manual/manual/library/compilerlibs.etex | 74 + manual/manual/library/core.etex | 36 + manual/manual/library/libbigarray.etex | 37 + manual/manual/library/libdynlink.etex | 29 + manual/manual/library/libgraph.etex | 100 + manual/manual/library/libgraph.fig | 29 + manual/manual/library/libgraph.png | Bin 0 -> 1046 bytes manual/manual/library/libnum.etex | 14 + manual/manual/library/libstr.etex | 32 + manual/manual/library/libthreads.etex | 60 + manual/manual/library/libunix.etex | 98 + manual/manual/library/stdlib.etex | 200 ++ manual/manual/macros.hva | 200 ++ manual/manual/macros.tex | 252 ++ manual/manual/manual.hva | 3 + manual/manual/manual.inf | 121 + manual/manual/manual.info.header | 4 + manual/manual/manual.tex | 42 + manual/manual/pdfmanual.tex | 31 + manual/manual/plaintext.tex | 17 + manual/manual/refman/.cvsignore | 2 + manual/manual/refman/.gitignore | 2 + manual/manual/refman/Makefile | 43 + manual/manual/refman/classes.etex | 530 ++++ manual/manual/refman/compunit.etex | 42 + manual/manual/refman/const.etex | 35 + manual/manual/refman/expr.etex | 998 +++++++ manual/manual/refman/exten.etex | 2393 +++++++++++++++ manual/manual/refman/lex.etex | 300 ++ manual/manual/refman/modtypes.etex | 303 ++ manual/manual/refman/modules.etex | 239 ++ manual/manual/refman/names.etex | 151 + manual/manual/refman/patterns.etex | 178 ++ manual/manual/refman/refman.etex | 48 + manual/manual/refman/typedecl.etex | 226 ++ manual/manual/refman/types.etex | 243 ++ manual/manual/refman/values.etex | 97 + manual/manual/style.css | 80 + manual/manual/texstuff/.cvsignore | 13 + manual/manual/texstuff/.gitignore | 13 + manual/manual/textman/.cvsignore | 5 + manual/manual/textman/.gitignore | 5 + manual/manual/tutorials/.cvsignore | 2 + manual/manual/tutorials/.gitignore | 2 + manual/manual/tutorials/Makefile | 31 + manual/manual/tutorials/advexamples.etex | 647 ++++ manual/manual/tutorials/coreexamples.etex | 761 +++++ manual/manual/tutorials/lablexamples.etex | 491 +++ manual/manual/tutorials/moduleexamples.etex | 385 +++ manual/manual/tutorials/objectexamples.etex | 1293 ++++++++ manual/manual/tutorials/polymorphism.etex | 477 +++ manual/styles/altindex.sty | 39 + manual/styles/caml-sl.sty | 61 + manual/styles/caml.sty | 31 + manual/styles/doc.tfm | Bin 0 -> 772 bytes manual/styles/docbf.tfm | Bin 0 -> 772 bytes manual/styles/docit.tfm | Bin 0 -> 772 bytes manual/styles/docmi.tfm | Bin 0 -> 772 bytes manual/styles/docrm.tfm | Bin 0 -> 772 bytes manual/styles/doctt.tfm | Bin 0 -> 772 bytes manual/styles/fullpage.sty | 2 + manual/styles/html.sty | 222 ++ manual/styles/isolatin.sty | 174 ++ manual/styles/multicols.sty | 176 ++ manual/styles/multind.sty | 65 + manual/styles/ocamldoc.hva | 20 + manual/styles/ocamldoc.sty | 75 + manual/styles/plaintext.sty | 268 ++ manual/styles/scroll.sty | 5 + manual/styles/syntaxdef.hva | 157 + manual/styles/syntaxdef.sty | 26 + manual/styles/syntaxdeftxt.sty | 22 + manual/tests/Makefile | 20 + manual/tests/README.md | 8 + manual/tests/check-stdlib-modules | 23 + manual/tests/cross_reference_checker.ml | 243 ++ manual/tools/.gitignore | 12 + manual/tools/.ignore | 11 + manual/tools/Makefile | 54 + manual/tools/caml-tex | 131 + manual/tools/caml_tex2.ml | 605 ++++ manual/tools/dvi_to_txt/Makefile | 8 + manual/tools/dvi_to_txt/dvi.h | 8 + manual/tools/dvi_to_txt/interp.c | 305 ++ manual/tools/dvi_to_txt/io.c | 43 + manual/tools/dvi_to_txt/io.h | 10 + manual/tools/dvi_to_txt/main.c | 47 + manual/tools/dvi_to_txt/output.c | 209 ++ manual/tools/dvi_to_txt/output.h | 24 + manual/tools/dvi_to_txt/print.c | 41 + manual/tools/dvi_to_txt/print_rtf.c | 80 + manual/tools/dvi_to_txt/print_styl.c | 90 + manual/tools/fix_index.sh | 52 + manual/tools/format-intf | 153 + manual/tools/htmlcut | 111 + manual/tools/htmlquote.c | 87 + manual/tools/htmltbl | 134 + manual/tools/htmlthread | 58 + manual/tools/htmltransf.mll | 117 + manual/tools/latexmacros.ml | 149 + manual/tools/latexmacros.mli | 8 + manual/tools/latexmain.ml | 4 + manual/tools/latexscan.mll | 166 ++ manual/tools/texexpand | 40 + manual/tools/texquote2.c | 167 ++ manual/tools/transf.mll | 107 + manual/tools/transfmain.ml | 8 + middle_end/allocated_const.ml | 10 +- middle_end/allocated_const.mli | 2 + middle_end/augment_specialised_args.ml | 35 +- middle_end/augment_specialised_args.mli | 2 +- middle_end/base_types/closure_origin.ml | 21 + middle_end/base_types/closure_origin.mli | 21 + middle_end/base_types/compilation_unit.ml | 6 +- middle_end/base_types/compilation_unit.mli | 1 + middle_end/base_types/mutable_variable.ml | 74 +- middle_end/base_types/mutable_variable.mli | 22 +- middle_end/base_types/symbol.ml | 91 +- middle_end/base_types/symbol.mli | 7 +- middle_end/base_types/variable.ml | 26 +- middle_end/base_types/variable.mli | 11 +- middle_end/closure_conversion.ml | 199 +- middle_end/closure_conversion_aux.ml | 18 +- middle_end/closure_conversion_aux.mli | 4 +- middle_end/flambda.ml | 95 +- middle_end/flambda.mli | 43 +- middle_end/flambda_invariants.ml | 9 +- middle_end/flambda_iterators.ml | 47 +- middle_end/flambda_utils.ml | 81 +- middle_end/flambda_utils.mli | 37 +- middle_end/freshening.ml | 17 +- .../initialize_symbol_to_let_symbol.mli | 4 + middle_end/inline_and_simplify.ml | 155 +- middle_end/inline_and_simplify.mli | 1 + middle_end/inline_and_simplify_aux.ml | 58 +- middle_end/inline_and_simplify_aux.mli | 17 +- middle_end/inlining_cost.ml | 1 - middle_end/inlining_decision.ml | 439 +-- middle_end/inlining_decision.mli | 4 +- middle_end/inlining_stats_types.ml | 13 +- middle_end/inlining_stats_types.mli | 1 + middle_end/inlining_transforms.ml | 875 +++--- middle_end/inlining_transforms.mli | 10 +- middle_end/internal_variable_names.ml | 504 ++++ middle_end/internal_variable_names.mli | 95 + middle_end/lift_code.mli | 2 +- middle_end/lift_constants.ml | 38 +- middle_end/lift_let_to_initialize_symbol.ml | 11 +- middle_end/parameter.ml | 4 +- middle_end/parameter.mli | 1 - middle_end/ref_to_variables.ml | 11 +- middle_end/remove_free_vars_equal_to_args.ml | 10 +- middle_end/remove_unused_arguments.ml | 9 +- middle_end/simple_value_approx.ml | 258 +- middle_end/simple_value_approx.mli | 81 +- middle_end/simplify_boxed_integer_ops.ml | 2 +- middle_end/simplify_common.ml | 21 +- middle_end/simplify_common.mli | 11 +- middle_end/simplify_primitives.ml | 10 +- middle_end/unbox_closures.ml | 1 - middle_end/unbox_closures.mli | 1 + middle_end/unbox_free_vars_of_closures.ml | 13 +- middle_end/unbox_specialised_args.ml | 1 - middle_end/unbox_specialised_args.mli | 1 + ocamldoc/.depend | 14 +- ocamldoc/Makefile | 121 +- ocamldoc/Makefile.unprefix | 102 + ocamldoc/odoc_analyse.ml | 31 +- ocamldoc/odoc_args.ml | 4 + ocamldoc/odoc_global.ml | 2 + ocamldoc/odoc_global.mli | 3 + ocamldoc/odoc_html.ml | 23 +- ocamldoc/odoc_index.html | 40 + ocamldoc/odoc_latex.ml | 3 +- ocamldoc/odoc_man.ml | 4 +- ocamldoc/odoc_messages.ml | 2 + ocamldoc/odoc_print.ml | 5 +- ocamldoc/odoc_sig.ml | 4 +- ocamldoc/remove_DEBUG | 3 +- ocamldoc/stdlib_non_prefixed/.depend | 185 ++ ocamldoc/stdlib_non_prefixed/Makefile | 25 + .../extract_pervasives.awk | 23 + ocamltest/.depend | 158 +- ocamltest/Makefile | 86 +- ocamltest/actions.ml | 53 +- ocamltest/actions.mli | 25 +- ocamltest/actions_helpers.ml | 291 ++ ocamltest/actions_helpers.mli | 60 + ocamltest/backends.ml | 39 - ocamltest/backends.mli | 28 - ocamltest/builtin_actions.ml | 981 +----- ocamltest/builtin_actions.mli | 40 +- ocamltest/builtin_modifiers.ml | 44 - ocamltest/builtin_modifiers.mli | 22 - ocamltest/builtin_tests.ml | 89 - ocamltest/builtin_tests.mli | 26 - ocamltest/builtin_variables.ml | 119 +- ocamltest/builtin_variables.mli | 52 +- ocamltest/environments.ml | 107 +- ocamltest/environments.mli | 30 +- ocamltest/filecompare.ml | 38 +- ocamltest/filecompare.mli | 3 +- ocamltest/filetype.ml | 69 - ocamltest/filetype.mli | 36 - ocamltest/main.ml | 160 +- ocamltest/ocaml_actions.ml | 1106 +++++++ ocamltest/ocaml_actions.mli | 52 + ocamltest/ocaml_backends.ml | 38 + ocamltest/ocaml_backends.mli | 32 + ocamltest/ocaml_commands.ml | 39 + ocamltest/ocaml_commands.mli | 32 + ocamltest/ocaml_compilers.ml | 101 + ocamltest/ocaml_compilers.mli | 40 + ocamltest/ocaml_directories.ml | 43 + ocamltest/ocaml_directories.mli | 30 + ocamltest/ocaml_files.ml | 77 + ocamltest/ocaml_files.mli | 49 + ocamltest/ocaml_filetypes.ml | 112 + ocamltest/ocaml_filetypes.mli | 43 + ocamltest/ocaml_flags.ml | 55 + ocamltest/ocaml_flags.mli | 30 + ocamltest/ocaml_modifiers.ml | 119 + ocamltest/ocaml_modifiers.mli | 28 + ocamltest/ocaml_tests.ml | 116 + ocamltest/ocaml_tests.mli | 26 + ocamltest/ocaml_tools.ml | 71 + ocamltest/ocaml_tools.mli | 40 + ocamltest/ocaml_toplevels.ml | 70 + ocamltest/ocaml_toplevels.mli | 34 + ocamltest/ocaml_variables.ml | 221 ++ ocamltest/ocaml_variables.mli | 96 + ocamltest/ocamltest_config.ml.in | 16 + ocamltest/ocamltest_config.mli | 25 +- ocamltest/ocamltest_stdlib.ml | 184 ++ ocamltest/ocamltest_stdlib.mli | 65 + ocamltest/ocamltest_stdlib_stubs.c | 113 + ocamltest/options.ml | 22 +- ocamltest/options.mli | 6 +- ocamltest/result.ml | 57 + ocamltest/result.mli | 43 + ocamltest/run.h | 2 +- ocamltest/run_command.ml | 9 +- ocamltest/run_command.mli | 2 +- ocamltest/run_stubs.c | 21 +- ocamltest/run_unix.c | 90 +- ocamltest/run_win32.c | 101 +- ocamltest/testlib.ml | 134 - ocamltest/testlib.mli | 36 - ocamltest/tests.ml | 25 +- ocamltest/tests.mli | 2 +- ocamltest/tsl_ast.ml | 3 +- ocamltest/tsl_ast.mli | 3 +- ocamltest/tsl_lexer.mll | 4 +- ocamltest/tsl_parser.mly | 11 +- ocamltest/tsl_semantics.ml | 69 +- ocamltest/variables.ml | 30 +- ocamltest/variables.mli | 14 +- otherlibs/Makefile | 28 +- otherlibs/bigarray/.depend | 10 - otherlibs/bigarray/Makefile | 13 +- otherlibs/bigarray/bigarray.ml | 313 +- otherlibs/bigarray/bigarray.mli | 931 +----- otherlibs/bigarray/bigarray_stubs.c | 820 ----- otherlibs/dynlink/Makefile | 16 +- otherlibs/dynlink/natdynlink.ml | 2 +- otherlibs/raw_spacetime_lib/.depend | 11 + otherlibs/raw_spacetime_lib/Makefile | 66 +- .../raw_spacetime_lib/raw_spacetime_lib.ml | 93 +- .../raw_spacetime_lib/raw_spacetime_lib.mli | 1 + .../raw_spacetime_lib}/spacetime_offline.c | 0 otherlibs/systhreads/Makefile | 29 +- otherlibs/systhreads/st_posix.h | 9 +- otherlibs/systhreads/thread.ml | 2 +- otherlibs/systhreads/thread.mli | 4 +- otherlibs/threads/.depend | 18 +- otherlibs/threads/Makefile | 74 +- otherlibs/threads/marshal.ml | 5 +- otherlibs/threads/pervasives.ml | 636 ---- otherlibs/threads/stdlib.ml | 695 +++++ otherlibs/threads/thread.mli | 2 +- otherlibs/threads/unix.ml | 6 +- otherlibs/unix/getgr.c | 19 +- otherlibs/unix/getpw.c | 19 +- otherlibs/unix/unix.ml | 6 +- otherlibs/unix/unix.mli | 6 +- otherlibs/unix/unixLabels.mli | 14 +- otherlibs/unix/utimes.c | 14 +- otherlibs/win32graph/open.c | 2 +- otherlibs/win32unix/Makefile | 16 +- otherlibs/win32unix/channels.c | 5 - otherlibs/win32unix/envir.c | 23 +- otherlibs/win32unix/isatty.c | 8 +- otherlibs/win32unix/stat.c | 4 +- otherlibs/win32unix/unix.ml | 6 +- otherlibs/win32unix/utimes.c | 80 + parsing/ast_invariants.ml | 2 - parsing/depend.ml | 60 +- parsing/docstrings.ml | 9 + parsing/docstrings.mli | 3 + parsing/lexer.mll | 42 +- parsing/location.ml | 57 +- parsing/location.mli | 8 + parsing/parser.mly | 31 +- parsing/parsetree.mli | 1 - parsing/pprintast.ml | 39 +- stdlib/.depend | 627 ++-- stdlib/Compflags | 16 +- stdlib/Makefile | 164 +- stdlib/StdlibModules | 97 +- stdlib/arg.ml | 22 +- stdlib/array.ml | 37 + stdlib/array.mli | 17 + stdlib/arrayLabels.mli | 14 + stdlib/bigarray.ml | 349 +++ stdlib/bigarray.mli | 961 ++++++ stdlib/buffer.ml | 28 + stdlib/buffer.mli | 21 + stdlib/bytes.ml | 40 + stdlib/bytes.mli | 15 + stdlib/bytesLabels.mli | 15 + stdlib/camlinternalBigarray.ml | 54 - stdlib/ephemeron.ml | 33 + stdlib/expand_module_aliases.awk | 27 + stdlib/float.ml | 101 + stdlib/float.mli | 267 ++ stdlib/hashtbl.ml | 50 + stdlib/hashtbl.mli | 69 + stdlib/list.ml | 29 +- stdlib/list.mli | 10 + stdlib/listLabels.mli | 10 + stdlib/map.ml | 27 + stdlib/map.mli | 17 + stdlib/marshal.ml | 5 +- stdlib/marshal.mli | 2 +- stdlib/moreLabels.mli | 42 +- stdlib/pervasives.ml | 548 ---- stdlib/pervasives.mli | 1221 -------- stdlib/queue.ml | 17 + stdlib/queue.mli | 17 + stdlib/remove_module_aliases.awk | 21 + stdlib/seq.ml | 73 + stdlib/seq.mli | 77 + stdlib/set.ml | 27 + stdlib/set.mli | 19 + stdlib/stack.ml | 12 + stdlib/stack.mli | 16 + stdlib/stdlib.ml | 607 ++++ stdlib/stdlib.mli | 1278 ++++++++ stdlib/stream.ml | 5 +- stdlib/string.ml | 23 +- stdlib/string.mli | 15 + stdlib/stringLabels.mli | 15 + stdlib/sys.mli | 14 +- stdlib/uchar.mli | 8 +- testsuite/Makefile | 67 +- testsuite/interactive/lib-graph-3/Makefile | 2 +- testsuite/lib/Makefile | 2 +- testsuite/{tests/tool-ocaml => lib}/lib.ml | 0 testsuite/makefiles/Makefile.expect | 10 +- testsuite/tests/afl-instrumentation/Makefile | 17 - .../tests/afl-instrumentation/afltest.ml | 17 + .../tests/afl-instrumentation/afltest.run | 36 + .../afl-instrumentation/has-afl-showmap.sh | 7 + .../tests/afl-instrumentation/ocamltests | 1 + testsuite/tests/afl-instrumentation/test.sh | 33 - testsuite/tests/asmcomp/Makefile | 163 - testsuite/tests/asmcomp/alpha.S | 63 - testsuite/tests/asmcomp/amd64.S | 78 - testsuite/tests/asmcomp/arm.S | 40 - testsuite/tests/asmcomp/arm64.S | 55 - testsuite/tests/asmcomp/bind_tuples.ml | 18 +- testsuite/tests/asmcomp/hppa.S | 161 - testsuite/tests/asmcomp/i386.S | 58 - testsuite/tests/asmcomp/ia64.S | 119 - testsuite/tests/asmcomp/is_static.ml | 5 + testsuite/tests/asmcomp/is_static_flambda.ml | 8 +- testsuite/tests/asmcomp/lexcmm.mll | 241 -- testsuite/tests/asmcomp/m68k.S | 57 - testsuite/tests/asmcomp/mips.s | 72 - testsuite/tests/asmcomp/ocamltests | 11 + testsuite/tests/asmcomp/optargs.ml | 6 + testsuite/tests/asmcomp/parsecmm.mly | 359 --- testsuite/tests/asmcomp/power.S | 197 -- testsuite/tests/asmcomp/register_typing.ml | 4 + .../tests/asmcomp/register_typing_switch.ml | 4 + testsuite/tests/asmcomp/s390x.S | 64 - testsuite/tests/asmcomp/sparc.S | 42 - .../asmcomp/static_float_array_flambda.ml | 7 + .../static_float_array_flambda_opaque.ml | 8 + testsuite/tests/asmcomp/staticalloc.ml | 6 + testsuite/tests/asmcomp/unrolling_flambda.ml | 4 + testsuite/tests/asmcomp/unrolling_flambda2.ml | 4 + testsuite/tests/asmgen/Makefile | 122 + testsuite/tests/asmgen/amd64.S | 83 + testsuite/tests/{asmcomp => asmgen}/arith.cmm | 0 testsuite/tests/asmgen/arm.S | 42 + testsuite/tests/asmgen/arm64.S | 58 + .../tests/{asmcomp => asmgen}/catch-rec.cmm | 0 .../tests/{asmcomp => asmgen}/catch-try.cmm | 0 .../tests/{asmcomp => asmgen}/checkbound.cmm | 0 .../{asmcomp => asmgen}/even-odd-spill.cmm | 0 .../tests/{asmcomp => asmgen}/even-odd.cmm | 0 testsuite/tests/{asmcomp => asmgen}/fib.cmm | 0 testsuite/tests/asmgen/i386.S | 59 + .../tests/{asmcomp => asmgen}/i386nt.asm | 0 .../tests/{asmcomp => asmgen}/integr.cmm | 0 .../tests/{asmcomp => asmgen}/lexcmm.mli | 0 testsuite/tests/asmgen/lexcmm.mll | 245 ++ testsuite/tests/{asmcomp => asmgen}/main.c | 0 testsuite/tests/{asmcomp => asmgen}/main.ml | 0 .../tests/{asmcomp => asmgen}/mainarith.c | 0 testsuite/tests/asmgen/parsecmm.mly | 373 +++ .../tests/{asmcomp => asmgen}/parsecmmaux.ml | 0 .../tests/{asmcomp => asmgen}/parsecmmaux.mli | 0 testsuite/tests/{asmcomp => asmgen}/pgcd.cmm | 0 testsuite/tests/asmgen/power.S | 200 ++ .../tests/{asmcomp => asmgen}/quicksort.cmm | 0 .../tests/{asmcomp => asmgen}/quicksort2.cmm | 0 testsuite/tests/asmgen/s390x.S | 67 + testsuite/tests/{asmcomp => asmgen}/soli.cmm | 0 .../tests/{asmcomp => asmgen}/tagged-fib.cmm | 0 .../{asmcomp => asmgen}/tagged-integr.cmm | 0 .../{asmcomp => asmgen}/tagged-quicksort.cmm | 0 .../tests/{asmcomp => asmgen}/tagged-tak.cmm | 0 testsuite/tests/{asmcomp => asmgen}/tak.cmm | 0 testsuite/tests/ast-invariants/Makefile | 27 - testsuite/tests/ast-invariants/ocamltests | 1 + testsuite/tests/ast-invariants/test.ml | 10 +- testsuite/tests/backtrace/Makefile | 155 - .../tests/backtrace/backtrace..byte.reference | 2 - .../backtrace/backtrace..native.reference | 2 - .../backtrace/backtrace.a.byte.reference | 1 - .../backtrace/backtrace.a.native.reference | 1 - .../backtrace/backtrace.b.byte.reference | 11 - .../backtrace/backtrace.b.native.reference | 11 - .../tests/backtrace/backtrace.byte.reference | 26 + .../backtrace/backtrace.c.byte.reference | 3 - .../backtrace/backtrace.c.native.reference | 3 - .../backtrace/backtrace.d.byte.reference | 9 - .../backtrace/backtrace.d.native.reference | 9 - testsuite/tests/backtrace/backtrace.ml | 9 + .../tests/backtrace/backtrace.opt.reference | 26 + testsuite/tests/backtrace/backtrace.run | 8 + .../tests/backtrace/backtrace2.byte.reference | 72 +- testsuite/tests/backtrace/backtrace2.ml | 9 + .../backtrace/backtrace2.native.reference | 58 - .../tests/backtrace/backtrace2.opt.reference | 58 + .../tests/backtrace/backtrace3.byte.reference | 79 +- testsuite/tests/backtrace/backtrace3.ml | 32 +- .../backtrace/backtrace3.native.reference | 27 - .../tests/backtrace/backtrace3.opt.reference | 66 + .../backtrace_deprecated.byte.reference | 40 +- .../tests/backtrace/backtrace_deprecated.ml | 9 + .../backtrace_deprecated.native.reference | 27 - .../backtrace_deprecated.opt.reference | 27 + .../backtrace/backtrace_slots.byte.reference | 40 +- testsuite/tests/backtrace/backtrace_slots.ml | 9 + .../backtrace_slots.native.reference | 27 - .../backtrace/backtrace_slots.opt.reference | 27 + .../backtrace/backtraces_and_finalizers.ml | 6 + ...ce => backtraces_and_finalizers.reference} | 0 testsuite/tests/backtrace/filter-locations.sh | 2 + .../backtrace/inline_test.byte.reference | 10 +- testsuite/tests/backtrace/inline_test.ml | 14 + .../backtrace/inline_test.native.reference | 15 - .../tests/backtrace/inline_test.opt.reference | 15 + testsuite/tests/backtrace/inline_test.run | 3 + .../inline_traversal_test.byte.reference | 8 +- .../tests/backtrace/inline_traversal_test.ml | 14 + .../inline_traversal_test.native.reference | 5 - .../inline_traversal_test.opt.reference | 5 + .../tests/backtrace/inline_traversal_test.run | 3 + testsuite/tests/backtrace/ocamltests | 11 + .../backtrace/pr6920_why_at.byte.reference | 8 +- testsuite/tests/backtrace/pr6920_why_at.ml | 12 + .../backtrace/pr6920_why_at.native.reference | 4 - .../backtrace/pr6920_why_at.opt.reference | 4 + .../pr6920_why_swallow.byte.reference | 8 +- .../tests/backtrace/pr6920_why_swallow.ml | 12 + .../pr6920_why_swallow.native.reference | 4 - .../pr6920_why_swallow.opt.reference | 4 + .../backtrace/raw_backtrace.byte.reference | 76 +- testsuite/tests/backtrace/raw_backtrace.ml | 9 + .../backtrace/raw_backtrace.native.reference | 49 - .../backtrace/raw_backtrace.opt.reference | 49 + testsuite/tests/basic-float/Makefile | 18 - testsuite/tests/basic-float/float_compare.ml | 112 +- .../tests/basic-float/float_compare.reference | 51 +- testsuite/tests/basic-float/ocamltests | 3 + testsuite/tests/basic-float/tfloat_hex.ml | 7 + .../tests/basic-float/tfloat_hex.reference | 3 + testsuite/tests/basic-float/tfloat_record.ml | 2 + .../basic-float/zero_sized_float_arrays.ml | 2 + testsuite/tests/basic-manyargs/Makefile | 22 - testsuite/tests/basic-manyargs/manyargs.ml | 4 + testsuite/tests/basic-manyargs/ocamltests | 1 + testsuite/tests/basic-modules/ocamltests | 1 + .../recursive_module_evaluation_errors.ml | 24 + testsuite/tests/basic-more/Makefile | 21 - testsuite/tests/basic-more/bounds.ml | 6 +- testsuite/tests/basic-more/div_by_zero.ml | 3 + testsuite/tests/basic-more/function_in_ref.ml | 3 + testsuite/tests/basic-more/if_in_if.ml | 3 + .../basic-more/morematch.compilers.reference | 30 + testsuite/tests/basic-more/morematch.ml | 67 +- testsuite/tests/basic-more/ocamltests | 17 + testsuite/tests/basic-more/opaque_prim.ml | 4 + testsuite/tests/basic-more/pr1271.ml | 4 + testsuite/tests/basic-more/pr2719.ml | 4 + testsuite/tests/basic-more/pr6216.ml | 5 + .../basic-more/record_evaluation_order.ml | 3 + .../tests/basic-more/sequential_and_or.ml | 4 + .../tests/basic-more/structural_constants.ml | 3 + testsuite/tests/basic-more/tbuffer.ml | 4 + testsuite/tests/basic-more/testrandom.ml | 4 + .../tests/basic-more/top_level_patterns.ml | 3 + testsuite/tests/basic-more/tprintf.ml | 4 + testsuite/tests/basic/Makefile | 10 - testsuite/tests/basic/arrays.ml | 2 + testsuite/tests/basic/bigints.ml | 2 + testsuite/tests/basic/boxedints.ml | 2 + testsuite/tests/basic/constprop.ml | 128 +- testsuite/tests/basic/constprop.mlp | 117 - testsuite/tests/basic/divint.ml | 2 + testsuite/tests/basic/equality.ml | 2 + testsuite/tests/basic/eval_order_1.ml | 2 + testsuite/tests/basic/eval_order_2.ml | 2 + testsuite/tests/basic/eval_order_3.ml | 2 + testsuite/tests/basic/eval_order_4.ml | 2 + testsuite/tests/basic/eval_order_6.ml | 2 + testsuite/tests/basic/float.ml | 2 + .../tests/basic/float_physical_equality.ml | 2 + testsuite/tests/basic/includestruct.ml | 2 + testsuite/tests/basic/localexn.ml | 2 + testsuite/tests/basic/maps.ml | 2 + testsuite/tests/basic/min_int.ml | 2 + testsuite/tests/basic/ocamltests | 29 + testsuite/tests/basic/opt_variants.ml | 2 + testsuite/tests/basic/patmatch.ml | 2 + testsuite/tests/basic/pr7253.ml | 16 + testsuite/tests/basic/pr7253.reference | 4 + testsuite/tests/basic/pr7533.ml | 2 + testsuite/tests/basic/pr7657.ml | 2 + testsuite/tests/basic/recvalues.ml | 2 + testsuite/tests/basic/sets.ml | 2 + testsuite/tests/basic/stringmatch.ml | 2 + testsuite/tests/basic/switch_opts.ml | 2 + testsuite/tests/basic/tailcalls.ml | 2 + testsuite/tests/basic/trigraph.ml | 2 + testsuite/tests/basic/zero_divided_by_n.ml | 2 + testsuite/tests/callback/Makefile | 68 - testsuite/tests/callback/ocamltests | 1 + testsuite/tests/callback/tcallback.ml | 8 + .../{reference => tcallback.reference} | 0 testsuite/tests/docstrings/Makefile | 4 - testsuite/tests/docstrings/empty.ml | 8 - testsuite/tests/docstrings/empty.ml.reference | 52 - testsuite/tests/embedded/Makefile | 44 - testsuite/tests/embedded/cmcaml.ml | 4 + .../{program.reference => cmcaml.reference} | 0 testsuite/tests/embedded/ocamltests | 1 + testsuite/tests/exotic-syntax/Makefile | 20 - testsuite/tests/exotic-syntax/exotic.ml | 3 + testsuite/tests/exotic-syntax/ocamltests | 1 + .../tests/extension-constructor/Makefile | 18 - .../tests/extension-constructor/ocamltests | 1 + testsuite/tests/extension-constructor/test.ml | 3 + testsuite/tests/flambda/Makefile | 21 - testsuite/tests/flambda/approx_meet.ml | 15 + testsuite/tests/flambda/approx_meet.reference | 1 + testsuite/tests/flambda/gpr998.ml | 4 + testsuite/tests/flambda/ocamltests | 3 + testsuite/tests/flambda/specialise.ml | 54 + .../specialise.reference} | 0 testsuite/tests/float-unboxing/Makefile | 32 - .../tests/float-unboxing/float_flambda.ml | 9 - .../float_subst_boxed_number.ml | 39 +- testsuite/tests/float-unboxing/ocamltests | 1 + testsuite/tests/formats-transition/Makefile | 3 - .../deprecated_unsigned_printers.ml | 4 + .../deprecated_unsigned_printers.ml.reference | 7 - ...precated_unsigned_printers.ocaml.reference | 6 + .../ignored_scan_counters.ml | 4 + .../ignored_scan_counters.ml.reference | 15 - .../ignored_scan_counters.ocaml.reference | 14 + .../legacy_incompatible_flags.ml | 4 + .../legacy_incompatible_flags.ml.reference | 8 - .../legacy_incompatible_flags.ocaml.reference | 7 + .../legacy_unfinished_modifiers.ml | 4 + .../legacy_unfinished_modifiers.ml.reference | 6 - ...egacy_unfinished_modifiers.ocaml.reference | 5 + testsuite/tests/formats-transition/ocamltests | 4 + testsuite/tests/formatting/Makefile | 5 - testsuite/tests/formatting/margins.ml | 4 + .../tests/formatting/margins.ml.reference | 14 - .../tests/formatting/margins.ocaml.reference | 13 + testsuite/tests/formatting/ocamltests | 1 + testsuite/tests/functors/Makefile | 4 - .../functors/functors.compilers.reference | 51 + testsuite/tests/functors/functors.ml | 7 + .../tests/functors/functors.ml.reference | 60 - testsuite/tests/functors/ocamltests | 1 + testsuite/tests/gc-roots/Makefile | 23 - testsuite/tests/gc-roots/globroots.ml | 5 + testsuite/tests/gc-roots/ocamltests | 1 + testsuite/tests/int64-unboxing/Makefile | 24 - testsuite/tests/int64-unboxing/ocamltests | 1 + testsuite/tests/int64-unboxing/test.ml | 5 + testsuite/tests/lazy/Makefile | 18 - testsuite/tests/lazy/lazy1.ml | 4 + testsuite/tests/lazy/ocamltests | 1 + testsuite/tests/letrec-disallowed/Makefile | 18 - .../tests/letrec-disallowed/disallowed.ml | 4 + .../letrec-disallowed/disallowed.ml.reference | 126 - .../disallowed.ocaml.reference | 125 + .../extension_constructor.ml | 4 + .../extension_constructor.ml.reference | 7 - .../extension_constructor.ocaml.reference | 6 + .../tests/letrec-disallowed/float_block.ml | 6 - .../float_block.ml.reference | 6 - .../letrec-disallowed/float_block_allowed.ml | 14 + .../float_block_allowed.ocaml.reference | 2 + .../float_block_disallowed.ml | 18 + .../float_block_disallowed.ocaml.reference | 5 + .../tests/letrec-disallowed/generic_arrays.ml | 4 + .../generic_arrays.ml.reference | 6 - .../generic_arrays.ocaml.reference | 5 + testsuite/tests/letrec-disallowed/labels.ml | 6 + .../letrec-disallowed/labels.ocaml.reference | 6 + testsuite/tests/letrec-disallowed/lazy_.ml | 4 + .../letrec-disallowed/lazy_.ml.reference | 8 - .../letrec-disallowed/lazy_.ocaml.reference | 7 + .../letrec-disallowed/module_constraints.ml | 4 + .../module_constraints.ml.reference | 9 - .../module_constraints.ocaml.reference | 8 + testsuite/tests/letrec-disallowed/ocamltests | 12 + testsuite/tests/letrec-disallowed/pr7215.ml | 4 + .../letrec-disallowed/pr7215.ml.reference | 8 - .../letrec-disallowed/pr7215.ocaml.reference | 7 + testsuite/tests/letrec-disallowed/pr7231.ml | 4 + .../letrec-disallowed/pr7231.ml.reference | 10 - .../letrec-disallowed/pr7231.ocaml.reference | 9 + testsuite/tests/letrec-disallowed/pr7706.ml | 8 + .../letrec-disallowed/pr7706.ocaml.reference | 9 + testsuite/tests/letrec-disallowed/unboxed.ml | 23 + .../letrec-disallowed/unboxed.ml.reference | 12 - .../letrec-disallowed/unboxed.ocaml.reference | 27 + testsuite/tests/letrec/Makefile | 19 - testsuite/tests/letrec/allowed.ml | 34 +- testsuite/tests/letrec/backreferences.ml | 2 + testsuite/tests/letrec/class_1.ml | 2 + testsuite/tests/letrec/class_2.ml | 2 + testsuite/tests/letrec/disallowed.reference | 149 - testsuite/tests/letrec/evaluation_order_1.ml | 2 + testsuite/tests/letrec/evaluation_order_2.ml | 2 + testsuite/tests/letrec/evaluation_order_3.ml | 2 + testsuite/tests/letrec/float_block_1.ml | 2 + testsuite/tests/letrec/generic_array.ml | 2 + testsuite/tests/letrec/labels.ml | 4 + .../labels.reference} | 0 testsuite/tests/letrec/lazy_.ml | 2 + testsuite/tests/letrec/lists.ml | 2 + .../tests/letrec/mixing_value_closures_1.ml | 2 + .../tests/letrec/mixing_value_closures_2.ml | 2 + testsuite/tests/letrec/mutual_functions.ml | 2 + testsuite/tests/letrec/nested.ml | 4 +- testsuite/tests/letrec/ocamltests | 19 + testsuite/tests/letrec/pr4989.ml | 2 + testsuite/tests/letrec/record_with.ml | 2 + testsuite/tests/letrec/ref.ml | 2 + testsuite/tests/lexing/Makefile | 3 - testsuite/tests/lexing/ocamltests | 1 + testsuite/tests/lexing/uchar_esc.ml | 3 + testsuite/tests/lexing/uchar_esc.ml.reference | 36 - .../tests/lexing/uchar_esc.ocaml.reference | 35 + testsuite/tests/lib-arg/Makefile | 19 - testsuite/tests/lib-arg/ocamltests | 2 + testsuite/tests/lib-arg/testarg.ml | 3 + testsuite/tests/lib-arg/testerror.ml | 3 + testsuite/tests/lib-bigarray-file/Makefile | 23 - testsuite/tests/lib-bigarray-file/mapfile.ml | 4 + testsuite/tests/lib-bigarray-file/ocamltests | 1 + testsuite/tests/lib-bigarray/Makefile | 23 - testsuite/tests/lib-bigarray/bigarrays.ml | 3 + testsuite/tests/lib-bigarray/change_layout.ml | 3 + testsuite/tests/lib-bigarray/fftba.ml | 3 + testsuite/tests/lib-bigarray/ocamltests | 5 + testsuite/tests/lib-bigarray/pr5115.ml | 3 + testsuite/tests/lib-bigarray/weak_bigarray.ml | 3 +- testsuite/tests/lib-buffer/Makefile | 18 - testsuite/tests/lib-buffer/ocamltests | 1 + testsuite/tests/lib-buffer/test.ml | 9 +- testsuite/tests/lib-bytes/Makefile | 19 - testsuite/tests/lib-bytes/ocamltests | 1 + testsuite/tests/lib-bytes/test_bytes.ml | 8 +- testsuite/tests/lib-digest/Makefile | 22 - testsuite/tests/lib-digest/md5.ml | 12 +- testsuite/tests/lib-digest/ocamltests | 1 + testsuite/tests/lib-dynlink-csharp/main.ml | 2 +- testsuite/tests/lib-dynlink-native/Makefile | 4 +- testsuite/tests/lib-filename/Makefile | 18 - testsuite/tests/lib-filename/extension.ml | 3 + testsuite/tests/lib-filename/ocamltests | 1 + testsuite/tests/lib-format/Makefile | 20 - testsuite/tests/lib-format/ocamltests | 2 + testsuite/tests/lib-format/pr6824.ml | 4 + testsuite/tests/lib-format/tformat.ml | 4 + testsuite/tests/lib-hashtbl/Makefile | 18 - testsuite/tests/lib-hashtbl/hfun.ml | 3 + testsuite/tests/lib-hashtbl/htbl.ml | 33 +- testsuite/tests/lib-hashtbl/ocamltests | 2 + testsuite/tests/lib-list/Makefile | 3 - testsuite/tests/lib-list/ocamltests | 1 + testsuite/tests/lib-list/test.ml | 3 + testsuite/tests/lib-marshal/Makefile | 22 - testsuite/tests/lib-marshal/intext.ml | 4 + testsuite/tests/lib-marshal/ocamltests | 1 + testsuite/tests/lib-obj/Makefile | 21 - testsuite/tests/lib-obj/ocamltests | 1 + testsuite/tests/lib-obj/reachable_words.ml | 11 +- testsuite/tests/lib-printf/Makefile | 20 - testsuite/tests/lib-printf/ocamltests | 3 + testsuite/tests/lib-printf/pr6534.ml | 4 + testsuite/tests/lib-printf/pr6938.ml | 4 + testsuite/tests/lib-printf/tprintf.ml | 4 + testsuite/tests/lib-queue/Makefile | 18 - testsuite/tests/lib-queue/ocamltests | 1 + testsuite/tests/lib-queue/test.ml | 3 + testsuite/tests/lib-random/Makefile | 18 - testsuite/tests/lib-random/ocamltests | 1 + testsuite/tests/lib-random/rand.ml | 3 + testsuite/tests/lib-scanf-2/Makefile | 63 - testsuite/tests/lib-scanf-2/ocamltests | 1 + testsuite/tests/lib-scanf-2/tscanf2_master.ml | 57 + testsuite/tests/lib-scanf/Makefile | 24 - testsuite/tests/lib-scanf/ocamltests | 1 + testsuite/tests/lib-scanf/tscanf.ml | 4 + testsuite/tests/lib-seq/ocamltests | 1 + testsuite/tests/lib-seq/test.ml | 18 + testsuite/tests/lib-seq/test.reference | 1 + testsuite/tests/lib-set/Makefile | 18 - testsuite/tests/lib-set/ocamltests | 2 + testsuite/tests/lib-set/testmap.ml | 20 +- testsuite/tests/lib-set/testset.ml | 20 +- testsuite/tests/lib-stack/Makefile | 18 - testsuite/tests/lib-stack/ocamltests | 1 + testsuite/tests/lib-stack/test.ml | 3 + testsuite/tests/lib-stdlabels/Makefile | 19 - testsuite/tests/lib-stdlabels/ocamltests | 1 + .../tests/lib-stdlabels/test_stdlabels.ml | 13 +- testsuite/tests/lib-str/Makefile | 22 - testsuite/tests/lib-str/ocamltests | 1 + testsuite/tests/lib-str/t01.ml | 4 + testsuite/tests/lib-stream/Makefile | 19 - .../tests/lib-stream/count_concat_bug.ml | 4 + testsuite/tests/lib-stream/mpr7769.ml | 9 + testsuite/tests/lib-stream/mpr7769.reference | 1 + testsuite/tests/lib-stream/mpr7769.txt | 1 + testsuite/tests/lib-stream/ocamltests | 2 + testsuite/tests/lib-string/Makefile | 22 - testsuite/tests/lib-string/ocamltests | 1 + testsuite/tests/lib-string/test_string.ml | 3 + testsuite/tests/lib-sys/Makefile | 21 - testsuite/tests/lib-sys/ocamltests | 1 + testsuite/tests/lib-sys/rename.ml | 3 + testsuite/tests/lib-systhreads/Makefile | 23 - testsuite/tests/lib-systhreads/ocamltests | 2 + testsuite/tests/lib-systhreads/testfork.ml | 8 + .../tests/lib-systhreads/testfork.precheck | 23 - testsuite/tests/lib-systhreads/testpreempt.ml | 35 + .../lib-systhreads/testpreempt.reference | 3 + testsuite/tests/lib-threads/Makefile | 33 - .../tests/lib-threads/backtrace_threads.ml | 5 + testsuite/tests/lib-threads/bank.ml | 6 + testsuite/tests/lib-threads/beat.ml | 6 + testsuite/tests/lib-threads/bufchan.ml | 6 + testsuite/tests/lib-threads/close.ml | 6 + testsuite/tests/lib-threads/fileio.ml | 6 + testsuite/tests/lib-threads/ocamltests | 17 + testsuite/tests/lib-threads/pr4466.ml | 10 + testsuite/tests/lib-threads/pr5325.ml | 10 + testsuite/tests/lib-threads/pr7638.ml | 6 + testsuite/tests/lib-threads/prodcons.ml | 6 + testsuite/tests/lib-threads/prodcons2.ml | 6 + testsuite/tests/lib-threads/sieve.ml | 6 + testsuite/tests/lib-threads/sigint.c | 20 +- .../lib-threads/signal.check-program-output | 6 + testsuite/tests/lib-threads/signal.checker | 16 - testsuite/tests/lib-threads/signal.ml | 68 +- testsuite/tests/lib-threads/signal.precheck | 1 - testsuite/tests/lib-threads/signal.run | 5 + testsuite/tests/lib-threads/signal.runner | 19 - testsuite/tests/lib-threads/sockets.ml | 10 + testsuite/tests/lib-threads/socketsbuf.ml | 40 - .../tests/lib-threads/socketsbuf.reference | 2 - testsuite/tests/lib-threads/swapchan.checker | 16 - testsuite/tests/lib-threads/swapchan.ml | 6 + testsuite/tests/lib-threads/swapchan.run | 1 + testsuite/tests/lib-threads/tls.checker | 16 - testsuite/tests/lib-threads/tls.ml | 6 + testsuite/tests/lib-threads/tls.run | 1 + testsuite/tests/lib-threads/token2.reference | 0 testsuite/tests/lib-threads/torture.ml | 6 + testsuite/tests/lib-uchar/Makefile | 18 - testsuite/tests/lib-uchar/ocamltests | 1 + testsuite/tests/lib-uchar/test.ml | 3 + testsuite/tests/lib-unix/common/Makefile | 37 - testsuite/tests/lib-unix/common/cloexec.ml | 69 +- .../tests/lib-unix/common/cmdline_prog.c | 10 - .../tests/lib-unix/common/cmdline_prog.ml | 4 + testsuite/tests/lib-unix/common/dup.ml | 4 + testsuite/tests/lib-unix/common/dup2.ml | 5 + testsuite/tests/lib-unix/common/fdstatus.c | 73 - .../tests/lib-unix/common/fdstatus_aux.c | 74 + .../tests/lib-unix/common/fdstatus_main.ml | 7 + testsuite/tests/lib-unix/common/ocamltests | 9 + testsuite/tests/lib-unix/common/pipe_eof.ml | 4 + .../tests/lib-unix/common/redirections.ml | 64 +- testsuite/tests/lib-unix/common/reflector.c | 74 - testsuite/tests/lib-unix/common/reflector.ml | 51 + testsuite/tests/lib-unix/common/rename.ml | 4 + .../lib-unix/common/test_unix_cmdline.ml | 32 + testsuite/tests/lib-unix/common/utimes.ml | 32 + .../tests/lib-unix/common/utimes.reference | 2 + .../common/utimes.txt} | 0 .../tests/lib-unix/common/wait_nohang.ml | 4 + testsuite/tests/lib-unix/isatty/Makefile | 9 - testsuite/tests/lib-unix/isatty/isatty_std.ml | 6 + testsuite/tests/lib-unix/isatty/isatty_tty.ml | 9 + .../tests/lib-unix/isatty/isatty_tty.precheck | 1 - testsuite/tests/lib-unix/isatty/ocamltests | 2 + .../tests/lib-unix/unix-execvpe/Makefile | 32 - testsuite/tests/lib-unix/unix-execvpe/exec.ml | 8 + .../tests/lib-unix/unix-execvpe/exec.run | 16 +- .../lib-unix/unix-execvpe/has-execvpe.sh | 11 + .../tests/lib-unix/unix-execvpe/ocamltests | 1 + testsuite/tests/lib-unix/win-env/Makefile | 18 - testsuite/tests/lib-unix/win-env/ocamltests | 1 + testsuite/tests/lib-unix/win-env/stubs.c | 2 +- testsuite/tests/lib-unix/win-env/test_env.ml | 21 +- .../tests/lib-unix/win-env/test_env.reference | 5 +- testsuite/tests/lib-unix/win-env/test_env2.ml | 17 - .../tests/lib-unix/win-env/test_env2.precheck | 4 - .../lib-unix/win-env/test_env2.reference | 1 - testsuite/tests/lib-unix/win-stat/Makefile | 20 - testsuite/tests/lib-unix/win-stat/ocamltests | 1 + testsuite/tests/lib-unix/win-stat/test.ml | 8 + testsuite/tests/lib-unix/win-stat/test.run | 4 + testsuite/tests/lib-unix/win-symlink/Makefile | 16 - .../tests/lib-unix/win-symlink/precheck.ml | 2 - testsuite/tests/lib-unix/win-symlink/test.ml | 10 + testsuite/tests/link-test/Makefile | 65 - testsuite/tests/link-test/ocamltests | 1 + testsuite/tests/link-test/test.ml | 82 + testsuite/tests/manual-intf-c/Makefile | 40 - testsuite/tests/manual-intf-c/ocamltests | 1 + testsuite/tests/manual-intf-c/prog.ml | 12 + .../tests/match-exception-warnings/Makefile | 18 - .../exhaustiveness_warnings.ml | 4 + .../exhaustiveness_warnings.ocaml.reference | 10 + .../tests/match-exception-warnings/ocamltests | 1 + testsuite/tests/match-exception/Makefile | 18 - testsuite/tests/match-exception/allocation.ml | 3 + .../match-exception/exception_propagation.ml | 3 + .../tests/match-exception/match_failure.ml | 3 + .../tests/match-exception/nested_handlers.ml | 3 + testsuite/tests/match-exception/ocamltests | 7 + .../raise_from_success_continuation.ml | 3 + testsuite/tests/match-exception/streams.ml | 3 + testsuite/tests/match-exception/tail_calls.ml | 3 + testsuite/tests/messages/Makefile | 3 - testsuite/tests/messages/ocamltests | 1 + testsuite/tests/messages/precise_locations.ml | 26 +- testsuite/tests/misc-kb/Makefile | 22 - testsuite/tests/misc-kb/kbmain.ml | 4 + testsuite/tests/misc-kb/ocamltests | 1 + testsuite/tests/misc-unsafe/Makefile | 19 - testsuite/tests/misc-unsafe/almabench.ml | 4 + testsuite/tests/misc-unsafe/fft.ml | 4 + testsuite/tests/misc-unsafe/ocamltests | 4 + testsuite/tests/misc-unsafe/quicksort.ml | 4 + testsuite/tests/misc-unsafe/soli.ml | 4 + testsuite/tests/misc/Makefile | 18 - testsuite/tests/misc/bdd.ml | 3 + testsuite/tests/misc/boyer.ml | 3 + testsuite/tests/misc/ephetest.ml | 3 + testsuite/tests/misc/ephetest2.ml | 3 + testsuite/tests/misc/ephetest3.ml | 3 + testsuite/tests/misc/fib.ml | 3 + testsuite/tests/misc/finaliser.ml | 3 +- testsuite/tests/misc/gcwords.ml | 3 + testsuite/tests/misc/gpr1370.ml | 22 + .../gpr1370.reference} | 0 testsuite/tests/misc/hamming.ml | 3 + testsuite/tests/misc/nucleic.ml | 3 + testsuite/tests/misc/ocamltests | 19 + testsuite/tests/misc/pr7168.ml | 3 + testsuite/tests/misc/sieve.ml | 3 + testsuite/tests/misc/sorts.ml | 3 + testsuite/tests/misc/takc.ml | 3 + testsuite/tests/misc/taku.ml | 3 + testsuite/tests/misc/weaklifetime.ml | 3 + testsuite/tests/misc/weaklifetime2.ml | 3 + testsuite/tests/misc/weaktest.ml | 3 + testsuite/tests/no-alias-deps/Makefile | 37 - .../tests/no-alias-deps/aliases.cmo.reference | 15 - .../no-alias-deps/aliases.compilers.reference | 5 + testsuite/tests/no-alias-deps/aliases.ml | 15 + .../tests/no-alias-deps/aliases.ml.reference | 5 - .../tests/no-alias-deps/aliases.reference | 15 + .../{b.cmi.pre => b.cmi.invalid} | 0 testsuite/tests/no-alias-deps/ocamltests | 1 + testsuite/tests/opaque/Makefile | 75 - testsuite/tests/opaque/ocamltests | 1 + testsuite/tests/opaque/test.ml | 59 + testsuite/tests/parsetree/Makefile | 23 - testsuite/tests/parsetree/ocamltests | 1 + testsuite/tests/parsetree/source.ml | 14 + testsuite/tests/parsetree/test.ml | 5 + testsuite/tests/parsing/Makefile | 19 - .../parsing/attributes.compilers.reference | 153 + testsuite/tests/parsing/attributes.ml | 7 + .../tests/parsing/attributes.ml.reference | 153 - testsuite/tests/parsing/docstrings.ml | 607 +++- .../tests/parsing/docstrings.ml.reference | 146 - ...xtended_indexoperators.compilers.reference | 327 ++ .../tests/parsing/extended_indexoperators.ml | 7 + .../extended_indexoperators.ml.reference | 327 -- .../parsing/extensions.compilers.reference | 326 ++ testsuite/tests/parsing/extensions.ml | 7 + .../tests/parsing/extensions.ml.reference | 326 -- ...nd_float_with_modifier.compilers.reference | 86 + .../parsing/int_and_float_with_modifier.ml | 8 + .../int_and_float_with_modifier.ml.reference | 86 - testsuite/tests/parsing/ocamltests | 11 + .../tests/parsing/pr6604.compilers.reference | 2 + testsuite/tests/parsing/pr6604.ml | 9 + .../parsing/pr6604_2.compilers.reference | 2 + testsuite/tests/parsing/pr6604_2.ml | 9 + .../parsing/pr6604_3.compilers.reference | 2 + testsuite/tests/parsing/pr6604_3.ml | 11 + .../tests/parsing/pr6865.compilers.reference | 52 + testsuite/tests/parsing/pr6865.ml | 8 + testsuite/tests/parsing/pr6865.ml.reference | 52 - .../tests/parsing/pr7165.compilers.reference | 2 + testsuite/tests/parsing/pr7165.ml | 10 +- testsuite/tests/parsing/pr7165.ml.reference | 2 - .../shortcut_ext_attr.compilers.reference | 978 ++++++ testsuite/tests/parsing/shortcut_ext_attr.ml | 8 +- .../parsing/shortcut_ext_attr.ml.reference | 978 ------ testsuite/tests/ppx-attributes/Makefile | 18 - testsuite/tests/ppx-attributes/ocamltests | 1 + testsuite/tests/ppx-attributes/warning.ml | 3 + testsuite/tests/ppx-contexts/Makefile | 28 - .../ppx-contexts/{program.ml => myppx.ml} | 0 testsuite/tests/ppx-contexts/ocamltests | 1 + ...est.reference => test.compilers.reference} | 0 testsuite/tests/ppx-contexts/test.ml | 16 + testsuite/tests/prim-bigstring/Makefile | 8 - .../tests/prim-bigstring/bigstring_access.ml | 2 + testsuite/tests/prim-bigstring/ocamltests | 2 + .../tests/prim-bigstring/string_access.ml | 114 +- testsuite/tests/prim-bswap/Makefile | 17 - testsuite/tests/prim-bswap/bswap.ml | 3 + testsuite/tests/prim-bswap/ocamltests | 1 + testsuite/tests/prim-revapply/Makefile | 19 - testsuite/tests/prim-revapply/apply.ml | 3 + testsuite/tests/prim-revapply/ocamltests | 2 + testsuite/tests/prim-revapply/revapply.ml | 3 + testsuite/tests/printing-types/Makefile | 3 - testsuite/tests/printing-types/ocamltests | 1 + testsuite/tests/printing-types/pr248.ml | 4 + .../tests/printing-types/pr248.ml.reference | 10 - .../printing-types/pr248.ocaml.reference | 9 + testsuite/tests/regression/gpr1623/gpr1623.ml | 15 + .../gpr1623/gpr1623.reference} | 0 testsuite/tests/regression/gpr1623/ocamltests | 1 + .../missing_set_of_closures/Makefile | 45 - .../missing_set_of_closures.ml | 22 + .../missing_set_of_closures/ocamltests | 1 + testsuite/tests/regression/pr3612/Makefile | 21 - testsuite/tests/regression/pr3612/ocamltests | 1 + testsuite/tests/regression/pr3612/pr3612.ml | 4 + .../tests/regression/pr5080-notes/Makefile | 20 - .../pr5080-notes/pr5080_notes_ok.ml | 4 - testsuite/tests/regression/pr5233/Makefile | 19 - testsuite/tests/regression/pr5233/ocamltests | 1 + testsuite/tests/regression/pr5233/pr5233.ml | 2 + testsuite/tests/regression/pr5757/Makefile | 19 - testsuite/tests/regression/pr5757/ocamltests | 1 + testsuite/tests/regression/pr5757/pr5757.ml | 2 + testsuite/tests/regression/pr6024/Makefile | 20 - testsuite/tests/regression/pr6024/ocamltests | 1 + testsuite/tests/regression/pr6024/pr6024.ml | 2 + testsuite/tests/regression/pr7042/Makefile | 20 - testsuite/tests/regression/pr7042/ocamltests | 1 + testsuite/tests/regression/pr7042/pr7042.ml | 2 + testsuite/tests/regression/pr7426/Makefile | 20 - testsuite/tests/regression/pr7426/ocamltests | 1 + testsuite/tests/regression/pr7426/pr7426.ml | 2 + testsuite/tests/required-external/Makefile | 18 - testsuite/tests/required-external/main.ml | 39 + testsuite/tests/required-external/ocamltests | 1 + testsuite/tests/runtime-C-exceptions/Makefile | 7 - .../tests/runtime-C-exceptions/ocamltests | 1 + testsuite/tests/runtime-C-exceptions/test.ml | 4 + testsuite/tests/runtime-errors/Makefile | 4 +- .../tests/self-contained-toplevel/Makefile | 34 - .../self-contained-toplevel/gen_cached_cmi.ml | 5 +- .../tests/self-contained-toplevel/main.ml | 20 + .../tests/self-contained-toplevel/ocamltests | 1 + testsuite/tests/tool-command-line/Makefile | 54 - testsuite/tests/tool-command-line/ocamltests | 1 + testsuite/tests/tool-command-line/test.ml | 26 + .../test.ocamlc.byte.reference | 130 + .../test.ocamlopt.byte.flambda.reference | 178 ++ .../test.ocamlopt.byte.reference | 178 ++ .../unknown-file.byte.reference | 1 - .../unknown-file.opt.reference | 1 - testsuite/tests/tool-debugger/basic/Makefile | 61 - .../tests/tool-debugger/basic/debuggee.ml | 12 + .../tool-debugger/basic/debuggee.reference | 3 +- .../tests/tool-debugger/basic/input_script | 0 .../tests/tool-debugger/basic/ocamltests | 1 + .../tool-debugger/find-artifacts/Makefile | 70 - .../tool-debugger/find-artifacts/debuggee.ml | 24 + .../find-artifacts/debuggee.reference | 3 +- .../tool-debugger/find-artifacts/ocamltests | 1 + .../tool-debugger/no_debug_event/Makefile | 60 - .../tool-debugger/no_debug_event/noev.ml | 27 + .../no_debug_event/noev.reference | 3 +- .../tool-debugger/no_debug_event/ocamltests | 1 + testsuite/tests/tool-lexyacc/Makefile | 25 - .../tool-lexyacc/main.compilers.reference | 1 + testsuite/tests/tool-lexyacc/main.ml | 9 + testsuite/tests/tool-lexyacc/ocamltests | 1 + testsuite/tests/tool-ocaml/Makefile | 36 - testsuite/tests/tool-ocaml/ocamltests | 157 + testsuite/tests/tool-ocaml/t000.ml | 8 + testsuite/tests/tool-ocaml/t010-const0.ml | 8 + testsuite/tests/tool-ocaml/t010-const1.ml | 8 + testsuite/tests/tool-ocaml/t010-const2.ml | 8 + testsuite/tests/tool-ocaml/t010-const3.ml | 8 + testsuite/tests/tool-ocaml/t011-constint.ml | 8 + testsuite/tests/tool-ocaml/t020.ml | 8 + testsuite/tests/tool-ocaml/t021-pushconst1.ml | 8 + testsuite/tests/tool-ocaml/t021-pushconst2.ml | 8 + testsuite/tests/tool-ocaml/t021-pushconst3.ml | 8 + .../tests/tool-ocaml/t022-pushconstint.ml | 8 + testsuite/tests/tool-ocaml/t040-makeblock1.ml | 8 + testsuite/tests/tool-ocaml/t040-makeblock2.ml | 8 + testsuite/tests/tool-ocaml/t040-makeblock3.ml | 8 + testsuite/tests/tool-ocaml/t041-makeblock.ml | 8 + testsuite/tests/tool-ocaml/t050-getglobal.ml | 8 + .../tests/tool-ocaml/t050-pushgetglobal.ml | 8 + .../tests/tool-ocaml/t051-getglobalfield.ml | 8 + .../tool-ocaml/t051-pushgetglobalfield.ml | 8 + testsuite/tests/tool-ocaml/t060-raise.ml | 9 + testsuite/tests/tool-ocaml/t070-branch.ml | 8 + testsuite/tests/tool-ocaml/t070-branchif.ml | 8 + .../tests/tool-ocaml/t070-branchifnot.ml | 8 + testsuite/tests/tool-ocaml/t071-boolnot.ml | 8 + testsuite/tests/tool-ocaml/t080-eq.ml | 8 + testsuite/tests/tool-ocaml/t080-geint.ml | 8 + testsuite/tests/tool-ocaml/t080-gtint.ml | 8 + testsuite/tests/tool-ocaml/t080-leint.ml | 8 + testsuite/tests/tool-ocaml/t080-ltint.ml | 8 + testsuite/tests/tool-ocaml/t080-neq.ml | 8 + testsuite/tests/tool-ocaml/t090-acc0.ml | 8 + testsuite/tests/tool-ocaml/t090-acc1.ml | 8 + testsuite/tests/tool-ocaml/t090-acc2.ml | 8 + testsuite/tests/tool-ocaml/t090-acc3.ml | 8 + testsuite/tests/tool-ocaml/t090-acc4.ml | 8 + testsuite/tests/tool-ocaml/t090-acc5.ml | 8 + testsuite/tests/tool-ocaml/t090-acc6.ml | 8 + testsuite/tests/tool-ocaml/t090-acc7.ml | 8 + testsuite/tests/tool-ocaml/t091-acc.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc0.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc1.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc2.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc3.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc4.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc5.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc6.ml | 8 + testsuite/tests/tool-ocaml/t092-pushacc7.ml | 8 + testsuite/tests/tool-ocaml/t093-pushacc.ml | 8 + testsuite/tests/tool-ocaml/t100-pushtrap.ml | 8 + testsuite/tests/tool-ocaml/t101-poptrap.ml | 8 + testsuite/tests/tool-ocaml/t110-addint.ml | 8 + testsuite/tests/tool-ocaml/t110-andint.ml | 8 + testsuite/tests/tool-ocaml/t110-asrint-1.ml | 8 + testsuite/tests/tool-ocaml/t110-asrint-2.ml | 8 + testsuite/tests/tool-ocaml/t110-divint-1.ml | 8 + testsuite/tests/tool-ocaml/t110-divint-2.ml | 8 + testsuite/tests/tool-ocaml/t110-divint-3.ml | 8 + testsuite/tests/tool-ocaml/t110-lslint.ml | 8 + testsuite/tests/tool-ocaml/t110-lsrint.ml | 8 + testsuite/tests/tool-ocaml/t110-modint-1.ml | 8 + testsuite/tests/tool-ocaml/t110-modint-2.ml | 8 + testsuite/tests/tool-ocaml/t110-mulint.ml | 8 + testsuite/tests/tool-ocaml/t110-negint.ml | 8 + testsuite/tests/tool-ocaml/t110-offsetint.ml | 8 + testsuite/tests/tool-ocaml/t110-orint.ml | 8 + testsuite/tests/tool-ocaml/t110-subint.ml | 8 + testsuite/tests/tool-ocaml/t110-xorint.ml | 8 + .../tests/tool-ocaml/t120-getstringchar.ml | 8 + .../tests/tool-ocaml/t121-setstringchar.ml | 8 + .../tests/tool-ocaml/t130-getvectitem.ml | 8 + testsuite/tests/tool-ocaml/t130-vectlength.ml | 8 + .../tests/tool-ocaml/t131-setvectitem.ml | 8 + testsuite/tests/tool-ocaml/t140-switch-1.ml | 8 + testsuite/tests/tool-ocaml/t140-switch-2.ml | 8 + testsuite/tests/tool-ocaml/t140-switch-3.ml | 8 + testsuite/tests/tool-ocaml/t140-switch-4.ml | 8 + testsuite/tests/tool-ocaml/t141-switch-5.ml | 8 + testsuite/tests/tool-ocaml/t141-switch-6.ml | 8 + testsuite/tests/tool-ocaml/t141-switch-7.ml | 8 + testsuite/tests/tool-ocaml/t142-switch-8.ml | 8 + testsuite/tests/tool-ocaml/t142-switch-9.ml | 8 + testsuite/tests/tool-ocaml/t142-switch-A.ml | 8 + testsuite/tests/tool-ocaml/t150-push-1.ml | 8 + testsuite/tests/tool-ocaml/t150-push-2.ml | 8 + testsuite/tests/tool-ocaml/t160-closure.ml | 8 + testsuite/tests/tool-ocaml/t161-apply1.ml | 8 + testsuite/tests/tool-ocaml/t162-return.ml | 8 + testsuite/tests/tool-ocaml/t163.ml | 8 + testsuite/tests/tool-ocaml/t164-apply2.ml | 8 + testsuite/tests/tool-ocaml/t164-apply3.ml | 8 + testsuite/tests/tool-ocaml/t165-apply.ml | 8 + testsuite/tests/tool-ocaml/t170-envacc2.ml | 8 + testsuite/tests/tool-ocaml/t170-envacc3.ml | 8 + testsuite/tests/tool-ocaml/t170-envacc4.ml | 8 + testsuite/tests/tool-ocaml/t171-envacc.ml | 8 + .../tests/tool-ocaml/t172-pushenvacc1.ml | 8 + .../tests/tool-ocaml/t172-pushenvacc2.ml | 8 + .../tests/tool-ocaml/t172-pushenvacc3.ml | 8 + .../tests/tool-ocaml/t172-pushenvacc4.ml | 8 + testsuite/tests/tool-ocaml/t173-pushenvacc.ml | 8 + testsuite/tests/tool-ocaml/t180-appterm1.ml | 8 + testsuite/tests/tool-ocaml/t180-appterm2.ml | 8 + testsuite/tests/tool-ocaml/t180-appterm3.ml | 8 + testsuite/tests/tool-ocaml/t181-appterm.ml | 8 + .../tests/tool-ocaml/t190-makefloatblock-1.ml | 8 + .../tests/tool-ocaml/t190-makefloatblock-2.ml | 8 + .../tests/tool-ocaml/t190-makefloatblock-3.ml | 8 + testsuite/tests/tool-ocaml/t191-vectlength.ml | 8 + .../tests/tool-ocaml/t192-getfloatfield-1.ml | 8 + .../tests/tool-ocaml/t192-getfloatfield-2.ml | 8 + .../tests/tool-ocaml/t193-setfloatfield-1.ml | 8 + .../tests/tool-ocaml/t193-setfloatfield-2.ml | 8 + testsuite/tests/tool-ocaml/t200-getfield0.ml | 8 + testsuite/tests/tool-ocaml/t200-getfield1.ml | 8 + testsuite/tests/tool-ocaml/t200-getfield2.ml | 8 + testsuite/tests/tool-ocaml/t200-getfield3.ml | 8 + testsuite/tests/tool-ocaml/t201-getfield.ml | 8 + testsuite/tests/tool-ocaml/t210-setfield0.ml | 8 + testsuite/tests/tool-ocaml/t210-setfield1.ml | 8 + testsuite/tests/tool-ocaml/t210-setfield2.ml | 8 + testsuite/tests/tool-ocaml/t210-setfield3.ml | 8 + testsuite/tests/tool-ocaml/t211-setfield.ml | 8 + testsuite/tests/tool-ocaml/t220-assign.ml | 8 + .../tests/tool-ocaml/t230-check_signals.ml | 8 + testsuite/tests/tool-ocaml/t240-c_call1.ml | 8 + testsuite/tests/tool-ocaml/t240-c_call2.ml | 8 + testsuite/tests/tool-ocaml/t240-c_call3.ml | 8 + testsuite/tests/tool-ocaml/t240-c_call4.ml | 8 + testsuite/tests/tool-ocaml/t240-c_call5.ml | 8 + .../tests/tool-ocaml/t250-closurerec-1.ml | 8 + .../tests/tool-ocaml/t250-closurerec-2.ml | 8 + .../tool-ocaml/t251-pushoffsetclosure0.ml | 8 + .../tool-ocaml/t251-pushoffsetclosure2.ml | 8 + .../tool-ocaml/t251-pushoffsetclosurem2.ml | 8 + .../tool-ocaml/t252-pushoffsetclosure.ml | 8 + .../tests/tool-ocaml/t253-offsetclosure0.ml | 8 + .../tests/tool-ocaml/t253-offsetclosure2.ml | 8 + .../tests/tool-ocaml/t253-offsetclosurem2.ml | 8 + .../tests/tool-ocaml/t254-offsetclosure.ml | 8 + testsuite/tests/tool-ocaml/t260-offsetref.ml | 8 + .../tests/tool-ocaml/t270-push_retaddr.ml | 8 + testsuite/tests/tool-ocaml/t300-getmethod.ml | 8 + testsuite/tests/tool-ocaml/t301-object.ml | 8 + testsuite/tests/tool-ocaml/t310-alloc-1.ml | 8 + testsuite/tests/tool-ocaml/t310-alloc-2.ml | 8 + testsuite/tests/tool-ocaml/t320-gc-1.ml | 8 + testsuite/tests/tool-ocaml/t320-gc-2.ml | 8 + testsuite/tests/tool-ocaml/t320-gc-3.ml | 8 + testsuite/tests/tool-ocaml/t330-compact-1.ml | 8 + testsuite/tests/tool-ocaml/t330-compact-2.ml | 8 + testsuite/tests/tool-ocaml/t330-compact-3.ml | 8 + testsuite/tests/tool-ocaml/t330-compact-4.ml | 8 + testsuite/tests/tool-ocaml/t340-weak.ml | 8 + testsuite/tests/tool-ocaml/t350-heapcheck.ml | 8 + testsuite/tests/tool-ocaml/t360-stacks-1.ml | 8 + testsuite/tests/tool-ocaml/t360-stacks-2.ml | 8 + testsuite/tests/tool-ocamlc-compat32/Makefile | 25 - testsuite/tests/tool-ocamlc-compat32/a.ml | 1 - .../compat32.compilers.reference | 6 + .../tests/tool-ocamlc-compat32/compat32.ml | 29 + .../tests/tool-ocamlc-compat32/ocamltests | 1 + .../tests/tool-ocamlc-compat32/test.reference | 6 - testsuite/tests/tool-ocamlc-open/Makefile | 14 - testsuite/tests/tool-ocamlc-open/ocamltests | 1 + .../tool-ocamlc-open/tool-ocamlc-open.ml | 10 + testsuite/tests/tool-ocamldoc-2/Makefile | 57 - .../tool-ocamldoc-2/extensible_variant.ml | 25 - .../tests/tool-ocamldoc-2/inline_records.mli | 48 - .../tool-ocamldoc-2/inline_records_bis.ml | 48 - testsuite/tests/tool-ocamldoc-2/level_0.mli | 15 - testsuite/tests/tool-ocamldoc-2/loop.ml | 3 - .../short_description.reference | 21 - .../tool-ocamldoc-2/short_description.txt | 4 - testsuite/tests/tool-ocamldoc-2/test.mli | 30 - testsuite/tests/tool-ocamldoc-2/variants.mli | 38 - .../tests/tool-ocamldoc-2/variants.reference | 190 -- .../tool-ocamldoc-html/Documentation_tags.mli | 19 - .../Documentation_tags.reference | 44 - .../tool-ocamldoc-html/Inline_records.mli | 45 - .../Inline_records.reference | 345 --- .../tests/tool-ocamldoc-html/Item_ids.mli | 13 - .../tool-ocamldoc-html/Item_ids.reference | 53 - .../tests/tool-ocamldoc-html/Linebreaks.mli | 68 - .../tool-ocamldoc-html/Linebreaks.reference | 135 - testsuite/tests/tool-ocamldoc-html/Loop.ml | 3 - .../tests/tool-ocamldoc-html/Loop.reference | 20 - testsuite/tests/tool-ocamldoc-html/Makefile | 62 - .../tool-ocamldoc-html/Module_whitespace.ml | 4 - .../Module_whitespace.reference | 24 - .../tests/tool-ocamldoc-html/No_preamble.mli | 5 - .../tool-ocamldoc-html/No_preamble.reference | 25 - .../tests/tool-ocamldoc-html/Paragraph.mli | 50 - .../tool-ocamldoc-html/Paragraph.reference | 75 - .../tests/tool-ocamldoc-html/Variants.mli | 43 - .../tool-ocamldoc-html/Variants.reference | 268 -- .../type_Linebreaks.reference | 27 - .../tool-ocamldoc-man/Inline_records.mli | 45 - .../Inline_records.reference | 201 -- testsuite/tests/tool-ocamldoc-man/Makefile | 54 - testsuite/tests/tool-ocamldoc-open/Makefile | 47 - .../{doc.reference => main.latex.reference} | 0 testsuite/tests/tool-ocamldoc-open/main.ml | 6 + .../main.ocamldoc.latex.reference | 3 + testsuite/tests/tool-ocamldoc-open/ocamltests | 1 + .../Documentation_tags.html.reference | 44 + .../tool-ocamldoc/Documentation_tags.mli | 23 + .../Extensible_variant.latex.reference} | 0 .../tests/tool-ocamldoc/Extensible_variant.ml | 29 + ...xtensible_variant.ocamldoc.latex.reference | 1 + .../Inline_records.html.reference | 352 +++ .../Inline_records.latex.reference} | 0 .../Inline_records.man.reference | 210 ++ .../tests/tool-ocamldoc/Inline_records.mli | 54 + .../Inline_records_bis.latex.reference} | 0 .../tests/tool-ocamldoc/Inline_records_bis.ml | 52 + .../tool-ocamldoc/Item_ids.html.reference | 53 + testsuite/tests/tool-ocamldoc/Item_ids.mli | 16 + .../Level_0.latex.reference} | 0 testsuite/tests/tool-ocamldoc/Level_0.mli | 19 + .../tool-ocamldoc/Linebreaks.html.reference | 135 + testsuite/tests/tool-ocamldoc/Linebreaks.mli | 75 + .../tests/tool-ocamldoc/Loop.html.reference | 20 + .../Loop.latex.reference} | 0 testsuite/tests/tool-ocamldoc/Loop.ml | 5 + testsuite/tests/tool-ocamldoc/Makefile | 52 - .../Module_whitespace.html.reference | 24 + .../tests/tool-ocamldoc/Module_whitespace.ml | 8 + .../Module_whitespace.ocamldoc.html.reference | 2 + .../tool-ocamldoc/No_preamble.html.reference | 25 + testsuite/tests/tool-ocamldoc/No_preamble.mli | 8 + .../tool-ocamldoc/Paragraph.html.reference | 75 + testsuite/tests/tool-ocamldoc/Paragraph.mli | 54 + .../Short_description.latex.reference | 26 + .../tests/tool-ocamldoc/Short_description.txt | 8 + .../Test.latex.reference} | 0 testsuite/tests/tool-ocamldoc/Test.mli | 33 + .../tool-ocamldoc/Variants.html.reference | 282 ++ .../tool-ocamldoc/Variants.latex.reference | 214 ++ testsuite/tests/tool-ocamldoc/Variants.mli | 51 + testsuite/tests/tool-ocamldoc/ocamltests | 19 + testsuite/tests/tool-ocamldoc/t01.ml | 6 + testsuite/tests/tool-ocamldoc/t02.ml | 6 + testsuite/tests/tool-ocamldoc/t03.ml | 6 + .../tool-ocamldoc/t03.ocamldoc.reference | 1 + testsuite/tests/tool-ocamldoc/t04.ml | 6 + testsuite/tests/tool-ocamldoc/t05.ml | 6 +- .../tool-ocamldoc/type_Linebreaks.reference | 27 + testsuite/tests/tool-ocamlobjinfo/Makefile | 38 - .../tests/tool-ocamlobjinfo/has-lib-bfd.sh | 7 + testsuite/tests/tool-ocamlobjinfo/ocamltests | 1 + testsuite/tests/tool-ocamlobjinfo/question.ml | 14 + .../tool-ocamlobjinfo/question.reference | 10 + .../tests/tool-ocamlobjinfo/test.reference | 10 - .../tests/tool-toplevel-invocation/Makefile | 36 - .../tests/tool-toplevel-invocation/ocamltests | 1 + .../tests/tool-toplevel-invocation/test.ml | 42 + .../working_arg.txt.reference | 5 +- testsuite/tests/tool-toplevel/Makefile | 19 - .../exotic_lists.compilers.reference | 14 + testsuite/tests/tool-toplevel/exotic_lists.ml | 4 + .../tool-toplevel/exotic_lists.ml.reference | 15 - testsuite/tests/tool-toplevel/ocamltests | 5 + .../tool-toplevel/pr7060.compilers.reference | 15 + testsuite/tests/tool-toplevel/pr7060.ml | 4 + .../tests/tool-toplevel/pr7060.ml.reference | 16 - .../tool-toplevel/pr7751.compilers.reference | 10 + testsuite/tests/tool-toplevel/pr7751.ml | 6 + .../tool-toplevel/strings.compilers.reference | 10 + testsuite/tests/tool-toplevel/strings.ml | 4 + .../tests/tool-toplevel/strings.ml.reference | 11 - .../tool-toplevel/tracing.compilers.reference | 29 + testsuite/tests/tool-toplevel/tracing.ml | 4 + .../tests/tool-toplevel/tracing.ml.reference | 30 - testsuite/tests/translprim/Makefile | 28 - .../array_spec.compilers.reference.flat | 65 + .../array_spec.compilers.reference.no-flat | 65 + testsuite/tests/translprim/array_spec.ml | 12 + .../translprim/array_spec.ml.reference-flat | 88 - .../translprim/array_spec.ml.reference-noflat | 88 - .../comparison_table.compilers.reference | 248 ++ .../tests/translprim/comparison_table.ml | 7 + .../translprim/comparison_table.ml.reference | 375 --- testsuite/tests/translprim/locs.ml | 44 + testsuite/tests/translprim/locs.reference | 11 + .../module_coercion.compilers.reference.flat | 87 + ...odule_coercion.compilers.reference.no-flat | 87 + testsuite/tests/translprim/module_coercion.ml | 12 + .../module_coercion.ml.reference-flat | 125 - .../module_coercion.ml.reference-noflat | 124 - testsuite/tests/translprim/ocamltests | 5 + .../translprim/ref_spec.compilers.reference | 37 + testsuite/tests/translprim/ref_spec.ml | 7 + .../tests/translprim/ref_spec.ml.reference | 50 - testsuite/tests/typing-core-bugs/ocamltests | 2 + .../type_expected_explanation.ml | 177 ++ .../tests/typing-core-bugs/unit_fun_hints.ml | 73 + testsuite/tests/typing-deprecated/Makefile | 18 - .../tests/typing-deprecated/deprecated.ml | 76 + testsuite/tests/typing-deprecated/ocamltests | 1 + .../typing-extension-constructor/Makefile | 18 - .../typing-extension-constructor/ocamltests | 1 + .../typing-extension-constructor/test.ml | 3 + .../test.ml.reference | 12 - .../test.ocaml.reference | 11 + testsuite/tests/typing-extensions/Makefile | 3 - testsuite/tests/typing-extensions/cast.ml | 4 + .../tests/typing-extensions/cast.ml.reference | 34 - .../typing-extensions/cast.ocaml.reference | 33 + .../tests/typing-extensions/extensions.ml | 4 + .../typing-extensions/extensions.ml.reference | 139 - .../extensions.ocaml.reference | 138 + testsuite/tests/typing-extensions/msg.ml | 4 + .../tests/typing-extensions/msg.ml.reference | 23 - .../typing-extensions/msg.ocaml.reference | 22 + testsuite/tests/typing-extensions/ocamltests | 4 + .../tests/typing-extensions/open_types.ml | 4 + .../typing-extensions/open_types.ml.reference | 124 - .../open_types.ocaml.reference | 123 + testsuite/tests/typing-fstclassmod/Makefile | 22 - .../tests/typing-fstclassmod/fstclassmod.ml | 4 + testsuite/tests/typing-fstclassmod/ocamltests | 1 + testsuite/tests/typing-gadts/Makefile | 18 - testsuite/tests/typing-gadts/ambiguity.ml | 198 ++ testsuite/tests/typing-gadts/didier.ml | 14 + .../tests/typing-gadts/dynamic_frisch.ml | 6 + .../tests/typing-gadts/nested_equations.ml | 8 + testsuite/tests/typing-gadts/ocamltests | 48 + testsuite/tests/typing-gadts/omega07.ml | 4 + testsuite/tests/typing-gadts/pr5332.ml | 6 + testsuite/tests/typing-gadts/pr5689.ml | 6 + testsuite/tests/typing-gadts/pr5785.ml | 7 + testsuite/tests/typing-gadts/pr5848.ml | 7 +- testsuite/tests/typing-gadts/pr5906.ml | 9 + testsuite/tests/typing-gadts/pr5948.ml | 8 + testsuite/tests/typing-gadts/pr5981.ml | 8 + testsuite/tests/typing-gadts/pr5985.ml | 26 + testsuite/tests/typing-gadts/pr5989.ml | 8 + testsuite/tests/typing-gadts/pr5997.ml | 8 + testsuite/tests/typing-gadts/pr6158.ml | 6 + testsuite/tests/typing-gadts/pr6163.ml | 6 + testsuite/tests/typing-gadts/pr6174.ml | 6 + testsuite/tests/typing-gadts/pr6241.ml | 6 + testsuite/tests/typing-gadts/pr6690.ml | 12 + testsuite/tests/typing-gadts/pr6817.ml | 4 + testsuite/tests/typing-gadts/pr6934.ml | 6 + testsuite/tests/typing-gadts/pr6980.ml | 6 + testsuite/tests/typing-gadts/pr6993_bad.ml | 6 + testsuite/tests/typing-gadts/pr7016.ml | 8 + testsuite/tests/typing-gadts/pr7160.ml | 6 + testsuite/tests/typing-gadts/pr7214.ml | 8 + testsuite/tests/typing-gadts/pr7222.ml | 8 + testsuite/tests/typing-gadts/pr7230.ml | 4 + testsuite/tests/typing-gadts/pr7234.ml | 8 + testsuite/tests/typing-gadts/pr7260.ml | 10 + testsuite/tests/typing-gadts/pr7269.ml | 10 + testsuite/tests/typing-gadts/pr7298.ml | 4 + testsuite/tests/typing-gadts/pr7374.ml | 8 + testsuite/tests/typing-gadts/pr7378.ml | 6 + testsuite/tests/typing-gadts/pr7381.ml | 4 + testsuite/tests/typing-gadts/pr7390.ml | 6 + testsuite/tests/typing-gadts/pr7391.ml | 29 +- testsuite/tests/typing-gadts/pr7397.ml | 4 + testsuite/tests/typing-gadts/pr7421.ml | 8 + testsuite/tests/typing-gadts/pr7432.ml | 6 + testsuite/tests/typing-gadts/pr7518.ml | 50 - testsuite/tests/typing-gadts/pr7618.ml | 54 + testsuite/tests/typing-gadts/pr7747.ml | 35 + testsuite/tests/typing-gadts/term-conv.ml | 4 + testsuite/tests/typing-gadts/test.ml | 160 + testsuite/tests/typing-gadts/unify_mb.ml | 4 + .../tests/typing-gadts/variables_in_mcomp.ml | 26 + testsuite/tests/typing-gadts/yallop_bugs.ml | 14 + testsuite/tests/typing-immediate/Makefile | 18 - testsuite/tests/typing-immediate/immediate.ml | 15 + testsuite/tests/typing-immediate/ocamltests | 1 + .../tests/typing-implicit_unpack/Makefile | 18 - .../typing-implicit_unpack/implicit_unpack.ml | 4 + .../implicit_unpack.ml.reference | 186 -- .../implicit_unpack.ocaml.reference | 195 ++ .../tests/typing-implicit_unpack/ocamltests | 1 + testsuite/tests/typing-labels/Makefile | 18 - testsuite/tests/typing-labels/mixin.ml | 2 + testsuite/tests/typing-labels/mixin2.ml | 2 + testsuite/tests/typing-labels/mixin3.ml | 2 + testsuite/tests/typing-labels/ocamltests | 3 + testsuite/tests/typing-misc-bugs/Makefile | 17 - .../typing-misc-bugs/core_array_reduced_ok.ml | 7 + testsuite/tests/typing-misc-bugs/ocamltests | 3 + .../pr6303_bad.compilers.reference | 4 + .../tests/typing-misc-bugs/pr6303_bad.ml | 8 + .../pr6946_bad.compilers.reference | 3 + .../tests/typing-misc-bugs/pr6946_bad.ml | 8 + testsuite/tests/typing-misc/Makefile | 36 - testsuite/tests/typing-misc/constraints.ml | 24 + .../typing-misc/disambiguate_principality.ml | 283 ++ testsuite/tests/typing-misc/empty_variant.ml | 31 + .../tests/typing-misc/enrich_typedecl.ml | 256 ++ testsuite/tests/typing-misc/inside_out.ml | 123 + testsuite/tests/typing-misc/labels.ml | 8 + testsuite/tests/typing-misc/ocamltests | 16 + testsuite/tests/typing-misc/occur_check.ml | 8 + testsuite/tests/typing-misc/polyvars.ml | 92 +- .../typing-misc/pr6939-flat-float-array.ml | 24 + .../typing-misc/pr6939-no-flat-float-array.ml | 23 + testsuite/tests/typing-misc/pr6939.ml-flat | 13 - testsuite/tests/typing-misc/pr6939.ml-noflat | 14 - testsuite/tests/typing-misc/pr7103.ml | 10 + testsuite/tests/typing-misc/pr7228.ml | 6 + testsuite/tests/typing-misc/pr7668_bad.ml | 29 + testsuite/tests/typing-misc/pr7712.ml | 20 + testsuite/tests/typing-misc/printing.ml | 6 + testsuite/tests/typing-misc/records.ml | 41 + testsuite/tests/typing-misc/variant.ml | 8 + testsuite/tests/typing-misc/wellfounded.ml | 6 + testsuite/tests/typing-missing-cmi/Makefile | 25 - testsuite/tests/typing-missing-cmi/ocamltests | 1 + .../test.compilers.reference | 5 + testsuite/tests/typing-missing-cmi/test.ml | 24 + testsuite/tests/typing-modules-bugs/Makefile | 17 - .../gatien_baron_20131019_ok.ml | 7 + .../tests/typing-modules-bugs/ocamltests | 36 + .../tests/typing-modules-bugs/pr5164_ok.ml | 7 + .../tests/typing-modules-bugs/pr51_ok.ml | 7 + .../tests/typing-modules-bugs/pr5663_ok.ml | 7 + .../tests/typing-modules-bugs/pr5914_ok.ml | 7 + .../tests/typing-modules-bugs/pr6240_ok.ml | 7 + .../pr6293_bad.compilers.reference | 10 + .../tests/typing-modules-bugs/pr6293_bad.ml | 8 + .../pr6427_bad.compilers.reference | 3 + .../tests/typing-modules-bugs/pr6427_bad.ml | 8 + .../tests/typing-modules-bugs/pr6485_ok.ml | 7 + .../tests/typing-modules-bugs/pr6513_ok.ml | 7 + .../tests/typing-modules-bugs/pr6572_ok.ml | 7 + .../tests/typing-modules-bugs/pr6651_ok.ml | 7 + .../pr6752_bad.compilers.reference | 4 + .../tests/typing-modules-bugs/pr6752_bad.ml | 8 + .../tests/typing-modules-bugs/pr6752_ok.ml | 7 + .../pr6899_first_bad.compilers.reference | 3 + .../typing-modules-bugs/pr6899_first_bad.ml | 8 + .../tests/typing-modules-bugs/pr6899_ok.ml | 7 + .../pr6899_second_bad.compilers.reference | 3 + .../typing-modules-bugs/pr6899_second_bad.ml | 8 + .../tests/typing-modules-bugs/pr6944_ok.ml | 7 + .../tests/typing-modules-bugs/pr6954_ok.ml | 7 + .../tests/typing-modules-bugs/pr6981_ok.ml | 7 + .../tests/typing-modules-bugs/pr6982_ok.ml | 7 + .../tests/typing-modules-bugs/pr6985_ok.ml | 7 + .../pr6992_bad.compilers.reference | 4 + .../tests/typing-modules-bugs/pr6992_bad.ml | 8 + .../tests/typing-modules-bugs/pr7036_ok.ml | 7 + .../tests/typing-modules-bugs/pr7082_ok.ml | 7 + .../pr7112_bad.compilers.reference | 3 + .../tests/typing-modules-bugs/pr7112_bad.ml | 8 + .../tests/typing-modules-bugs/pr7112_ok.ml | 7 + .../tests/typing-modules-bugs/pr7152_ok.ml | 7 + .../tests/typing-modules-bugs/pr7182_ok.ml | 7 + .../typing-modules-bugs/pr7305_principal.ml | 7 + .../tests/typing-modules-bugs/pr7321_ok.ml | 7 + .../pr7414_2_bad.compilers.reference | 18 + .../tests/typing-modules-bugs/pr7414_2_bad.ml | 50 + .../pr7414_bad.compilers.reference | 18 + .../tests/typing-modules-bugs/pr7414_bad.ml | 8 + .../tests/typing-modules-bugs/pr7519_ok.ml | 7 + .../tests/typing-modules-bugs/pr7601_ok.ml | 7 + .../tests/typing-modules-bugs/pr7601a_ok.ml | 7 + testsuite/tests/typing-modules/Makefile | 18 - testsuite/tests/typing-modules/Test.ml | 14 +- testsuite/tests/typing-modules/aliases.ml | 51 +- .../applicative_functor_type.ml | 83 + testsuite/tests/typing-modules/firstclass.ml | 8 + testsuite/tests/typing-modules/generative.ml | 12 + testsuite/tests/typing-modules/ocamltests | 12 + testsuite/tests/typing-modules/pr5911.ml | 4 + testsuite/tests/typing-modules/pr6394.ml | 27 + testsuite/tests/typing-modules/pr7207.ml | 6 + testsuite/tests/typing-modules/pr7348.ml | 4 + testsuite/tests/typing-modules/pr7787.ml | 45 + testsuite/tests/typing-modules/printing.ml | 4 + testsuite/tests/typing-modules/recursive.ml | 6 + testsuite/tests/typing-multifile/Makefile | 49 - testsuite/tests/typing-multifile/a.ml | 1 + testsuite/tests/typing-multifile/b.ml | 1 + testsuite/tests/typing-multifile/c.ml | 1 + testsuite/tests/typing-multifile/d.mli | 1 + testsuite/tests/typing-multifile/e.ml | 1 + testsuite/tests/typing-multifile/f.ml | 4 + testsuite/tests/typing-multifile/ocamltests | 3 + testsuite/tests/typing-multifile/pr6372.ml | 9 + testsuite/tests/typing-multifile/pr7325.ml | 13 + testsuite/tests/typing-multifile/pr7563.ml | 5 + testsuite/tests/typing-objects-bugs/Makefile | 18 - .../tests/typing-objects-bugs/ocamltests | 11 + .../pr3968_bad.compilers.reference | 39 + .../tests/typing-objects-bugs/pr3968_bad.ml | 8 + .../pr4018_bad.compilers.reference | 41 + .../tests/typing-objects-bugs/pr4018_bad.ml | 7 + .../pr4435_bad.compilers.reference | 3 + .../tests/typing-objects-bugs/pr4435_bad.ml | 8 + .../tests/typing-objects-bugs/pr4766_ok.ml | 7 + .../tests/typing-objects-bugs/pr4824_ok.ml | 7 + .../pr4824a_bad.compilers.reference | 10 + .../tests/typing-objects-bugs/pr4824a_bad.ml | 8 + .../tests/typing-objects-bugs/pr5156_ok.ml | 7 + .../pr7284_bad.compilers.reference | 4 + .../tests/typing-objects-bugs/pr7284_bad.ml | 8 + .../tests/typing-objects-bugs/pr7293_ok.ml | 7 + .../tests/typing-objects-bugs/woodyatt_ok.ml | 7 + .../typing-objects-bugs/yamagata021012_ok.ml | 7 + testsuite/tests/typing-objects/Exemples.ml | 586 +++- .../Exemples.ml.principal.reference | 358 --- .../typing-objects/Exemples.ml.reference | 360 --- testsuite/tests/typing-objects/Makefile | 18 - testsuite/tests/typing-objects/Tests.ml | 554 +++- .../Tests.ml.principal.reference | 317 -- .../tests/typing-objects/Tests.ml.reference | 317 -- testsuite/tests/typing-objects/dummy.ml | 177 ++ testsuite/tests/typing-objects/ocamltests | 10 + .../tests/typing-objects/open_in_classes.ml | 13 + .../open_in_classes.ml.reference | 5 - testsuite/tests/typing-objects/pr5545.ml | 16 + .../pr5545.ml.principal.reference | 6 - .../tests/typing-objects/pr5545.ml.reference | 6 - testsuite/tests/typing-objects/pr5619_bad.ml | 27 + .../pr5619_bad.ml.principal.reference | 18 - .../typing-objects/pr5619_bad.ml.reference | 18 - testsuite/tests/typing-objects/pr5858.ml | 14 + .../tests/typing-objects/pr5858.ml.reference | 7 - testsuite/tests/typing-objects/pr6123_bad.ml | 12 + .../pr6123_bad.ml.principal.reference | 8 - .../typing-objects/pr6123_bad.ml.reference | 8 - testsuite/tests/typing-objects/pr6383.ml | 10 + .../tests/typing-objects/pr6383.ml.reference | 6 - testsuite/tests/typing-objects/pr6907_bad.ml | 16 + .../typing-objects/pr6907_bad.ml.reference | 10 - testsuite/tests/typing-objects/pr7711_ok.ml | 15 + testsuite/tests/typing-ocamlc-i/Makefile | 15 - testsuite/tests/typing-ocamlc-i/ocamltests | 1 + .../pr7620_bad.compilers.reference | 4 + testsuite/tests/typing-ocamlc-i/pr7620_bad.ml | 8 + testsuite/tests/typing-pattern_open/Makefile | 3 - .../tests/typing-pattern_open/ocamltests | 1 + .../tests/typing-pattern_open/pattern_open.ml | 4 + .../pattern_open.ml.reference | 81 - .../pattern_open.ocaml.reference | 80 + testsuite/tests/typing-poly-bugs/Makefile | 18 - testsuite/tests/typing-poly-bugs/ocamltests | 3 + testsuite/tests/typing-poly-bugs/pr5322_ok.ml | 7 + .../pr5673_bad.compilers.reference | 11 + .../tests/typing-poly-bugs/pr5673_bad.ml | 8 + testsuite/tests/typing-poly-bugs/pr5673_ok.ml | 7 + testsuite/tests/typing-poly/Makefile | 18 - testsuite/tests/typing-poly/ocamltests | 1 + testsuite/tests/typing-poly/poly.ml | 158 +- .../tests/typing-polyvariants-bugs-2/Makefile | 26 - .../typing-polyvariants-bugs-2/ocamltests | 1 + .../pr3918c.compilers.reference | 4 + .../typing-polyvariants-bugs-2/pr3918c.ml | 15 + .../tests/typing-polyvariants-bugs/Makefile | 18 - .../tests/typing-polyvariants-bugs/ocamltests | 6 + .../typing-polyvariants-bugs/pr4775_ok.ml | 7 + .../typing-polyvariants-bugs/pr4933_ok.ml | 7 + .../typing-polyvariants-bugs/pr5057_ok.ml | 7 + .../pr5057a_bad.compilers.reference | 4 + .../typing-polyvariants-bugs/pr5057a_bad.ml | 8 + .../typing-polyvariants-bugs/pr7199_ok.ml | 7 + .../privrowsabate_ok.ml | 7 + testsuite/tests/typing-private-bugs/Makefile | 18 - .../tests/typing-private-bugs/ocamltests | 2 + .../pr5026_bad.compilers.reference | 3 + .../tests/typing-private-bugs/pr5026_bad.ml | 8 + .../tests/typing-private-bugs/pr5469_ok.ml | 7 + testsuite/tests/typing-private/Makefile | 18 - testsuite/tests/typing-private/ocamltests | 1 + .../private.compilers.principal.reference | 126 + .../private.compilers.reference | 126 + testsuite/tests/typing-private/private.ml | 5 + .../private.ml.principal.reference | 127 - .../tests/typing-private/private.ml.reference | 127 - testsuite/tests/typing-recmod/Makefile | 18 - testsuite/tests/typing-recmod/ocamltests | 22 + .../typing-recmod/t01bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t01bad.ml | 8 + .../typing-recmod/t02bad.compilers.reference | 3 + testsuite/tests/typing-recmod/t02bad.ml | 8 + testsuite/tests/typing-recmod/t03ok.ml | 7 + .../typing-recmod/t04bad.compilers.reference | 3 + testsuite/tests/typing-recmod/t04bad.ml | 8 + .../typing-recmod/t05bad.compilers.reference | 3 + testsuite/tests/typing-recmod/t05bad.ml | 8 + testsuite/tests/typing-recmod/t06ok.ml | 7 + .../typing-recmod/t07bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t07bad.ml | 8 + .../typing-recmod/t08bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t08bad.ml | 8 + .../typing-recmod/t09bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t09bad.ml | 8 + testsuite/tests/typing-recmod/t10ok.ml | 7 + .../typing-recmod/t11bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t11bad.ml | 8 + .../typing-recmod/t12bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t12bad.ml | 8 + testsuite/tests/typing-recmod/t13ok.ml | 7 + .../typing-recmod/t14bad.compilers.reference | 3 + testsuite/tests/typing-recmod/t14bad.ml | 8 + .../typing-recmod/t15bad.compilers.reference | 2 + testsuite/tests/typing-recmod/t15bad.ml | 8 + testsuite/tests/typing-recmod/t16ok.ml | 7 + testsuite/tests/typing-recmod/t17ok.ml | 7 + testsuite/tests/typing-recmod/t18ok.ml | 7 + testsuite/tests/typing-recmod/t19ok.ml | 7 + testsuite/tests/typing-recmod/t20ok.ml | 7 + testsuite/tests/typing-recmod/t21ok.ml | 7 + testsuite/tests/typing-recmod/t22ok.ml | 7 + testsuite/tests/typing-recordarg/Makefile | 18 - testsuite/tests/typing-recordarg/ocamltests | 1 + testsuite/tests/typing-recordarg/recordarg.ml | 4 + .../typing-recordarg/recordarg.ml.reference | 67 - .../recordarg.ocaml.reference | 66 + testsuite/tests/typing-rectypes-bugs/Makefile | 18 - .../tests/typing-rectypes-bugs/ocamltests | 3 + .../pr5343_bad.compilers.reference | 2 + .../tests/typing-rectypes-bugs/pr5343_bad.ml | 8 + .../pr6174_bad.compilers.reference | 3 + .../tests/typing-rectypes-bugs/pr6174_bad.ml | 8 + .../pr6870_bad.compilers.reference | 4 + .../tests/typing-rectypes-bugs/pr6870_bad.ml | 8 + testsuite/tests/typing-safe-linking/Makefile | 15 - .../b_bad.compilers.reference | 6 + testsuite/tests/typing-safe-linking/b_bad.ml | 12 + .../tests/typing-safe-linking/ocamltests | 1 + .../largeFile.ml | 1 + .../ocamltests | 1 + .../redefine_largefile.ml | 4 + .../redefine_largefile.reference | 1 + testsuite/tests/typing-short-paths/Makefile | 23 - .../gpr1223.compilers.reference | 3 + testsuite/tests/typing-short-paths/gpr1223.ml | 5 + .../typing-short-paths/gpr1223.ml.reference | 4 - testsuite/tests/typing-short-paths/ocamltests | 5 + .../pr5918.compilers.reference | 5 + testsuite/tests/typing-short-paths/pr5918.ml | 5 + .../typing-short-paths/pr5918.ml.reference | 6 - .../pr6836.compilers.reference | 6 + testsuite/tests/typing-short-paths/pr6836.ml | 5 + .../typing-short-paths/pr6836.ml.reference | 7 - .../pr7543.compilers.reference | 17 + testsuite/tests/typing-short-paths/pr7543.ml | 5 + .../typing-short-paths/pr7543.ml.reference | 18 - .../short-paths.compilers.reference | 99 + .../tests/typing-short-paths/short-paths.ml | 5 + .../short-paths.ml.reference | 96 - testsuite/tests/typing-signatures/Makefile | 18 - testsuite/tests/typing-signatures/els.ml | 4 + .../tests/typing-signatures/els.ml.reference | 95 - .../typing-signatures/els.ocaml.reference | 94 + testsuite/tests/typing-signatures/ocamltests | 3 + testsuite/tests/typing-signatures/pr6371.ml | 4 + .../typing-signatures/pr6371.ml.reference | 4 - .../typing-signatures/pr6371.ocaml.reference | 3 + testsuite/tests/typing-signatures/pr6672.ml | 4 + .../typing-signatures/pr6672.ml.reference | 10 - .../typing-signatures/pr6672.ocaml.reference | 9 + testsuite/tests/typing-sigsubst/Makefile | 18 - testsuite/tests/typing-sigsubst/ocamltests | 1 + testsuite/tests/typing-sigsubst/sigsubst.ml | 35 + testsuite/tests/typing-typeparam/Makefile | 18 - testsuite/tests/typing-typeparam/newtype.ml | 4 + .../typing-typeparam/newtype.ml.reference | 19 - .../typing-typeparam/newtype.ocaml.reference | 18 + testsuite/tests/typing-typeparam/ocamltests | 1 + testsuite/tests/typing-unboxed-types/Makefile | 21 - .../tests/typing-unboxed-types/ocamltests | 1 + testsuite/tests/typing-unboxed-types/test.ml | 18 + .../test.ml.reference-flat | 98 +- .../test.ml.reference-noflat | 98 +- testsuite/tests/typing-unboxed/Makefile | 18 - testsuite/tests/typing-unboxed/ocamltests | 1 + testsuite/tests/typing-unboxed/test.ml | 3 + .../tests/typing-unboxed/test.ml.reference | 192 -- .../tests/typing-unboxed/test.ocaml.reference | 191 ++ testsuite/tests/typing-warnings/Makefile | 19 - ...us_guarded_disjunction.compilers.reference | 163 + .../ambiguous_guarded_disjunction.ml | 83 +- ...ambiguous_guarded_disjunction.ml.reference | 140 - .../application.compilers.reference | 13 + .../tests/typing-warnings/application.ml | 5 + .../typing-warnings/application.ml.reference | 14 - .../coercions.compilers.principal.reference | 25 + .../coercions.compilers.reference | 17 + testsuite/tests/typing-warnings/coercions.ml | 6 + .../coercions.ml.principal.reference | 26 - .../typing-warnings/coercions.ml.reference | 18 - .../exhaustiveness.compilers.reference | 152 + .../tests/typing-warnings/exhaustiveness.ml | 12 + .../exhaustiveness.ml.reference | 143 - testsuite/tests/typing-warnings/ocamltests | 14 + .../pr5892.compilers.reference | 11 + testsuite/tests/typing-warnings/pr5892.ml | 5 + .../tests/typing-warnings/pr5892.ml.reference | 12 - .../pr6587.compilers.reference | 16 + testsuite/tests/typing-warnings/pr6587.ml | 5 + .../tests/typing-warnings/pr6587.ml.reference | 17 - .../pr6872.compilers.principal.reference | 38 + .../pr6872.compilers.reference | 34 + testsuite/tests/typing-warnings/pr6872.ml | 6 + .../pr6872.ml.principal.reference | 39 - .../tests/typing-warnings/pr6872.ml.reference | 35 - .../pr7085.compilers.reference | 19 + testsuite/tests/typing-warnings/pr7085.ml | 5 + .../tests/typing-warnings/pr7085.ml.reference | 20 - .../pr7115.compilers.reference | 21 + testsuite/tests/typing-warnings/pr7115.ml | 5 + .../tests/typing-warnings/pr7115.ml.reference | 22 - .../pr7261.compilers.reference | 10 + testsuite/tests/typing-warnings/pr7261.ml | 5 + .../tests/typing-warnings/pr7261.ml.reference | 11 - .../pr7297.compilers.reference | 7 + testsuite/tests/typing-warnings/pr7297.ml | 5 + .../tests/typing-warnings/pr7297.ml.reference | 8 - .../pr7553.compilers.reference | 19 + testsuite/tests/typing-warnings/pr7553.ml | 5 + .../tests/typing-warnings/pr7553.ml.reference | 20 - .../records.compilers.principal.reference | 320 ++ .../records.compilers.reference | 312 ++ testsuite/tests/typing-warnings/records.ml | 6 + .../records.ml.principal.reference | 321 -- .../typing-warnings/records.ml.reference | 313 -- .../unused_types.compilers.reference | 57 + .../tests/typing-warnings/unused_types.ml | 5 + .../typing-warnings/unused_types.ml.reference | 58 - testsuite/tests/utils/Makefile | 25 - testsuite/tests/utils/edit_distance.ml | 7 + testsuite/tests/utils/ocamltests | 3 + testsuite/tests/utils/overflow_detection.ml | 45 + .../tests/utils/overflow_detection.reference | 149 + .../test_strongly_connected_components.ml | 7 + testsuite/tests/warnings/Makefile | 62 - .../deprecated_module.compilers.reference | 4 + testsuite/tests/warnings/deprecated_module.ml | 8 + .../warnings/deprecated_module.reference | 4 - ...cated_module_assigment.compilers.reference | 72 + .../warnings/deprecated_module_assigment.ml | 10 +- .../deprecated_module_assigment.reference | 72 - .../deprecated_module_use.compilers.reference | 14 + .../tests/warnings/deprecated_module_use.ml | 17 + .../warnings/deprecated_module_use.reference | 14 - testsuite/tests/warnings/ocamltests | 22 + .../tests/warnings/w01.compilers.reference | 15 + testsuite/tests/warnings/w01.ml | 10 + testsuite/tests/warnings/w01.reference | 15 - .../tests/warnings/w04.compilers.reference | 3 + testsuite/tests/warnings/w04.ml | 11 + testsuite/tests/warnings/w04.reference | 3 - .../warnings/w04_failure.compilers.reference | 9 + testsuite/tests/warnings/w04_failure.ml | 11 + .../tests/warnings/w04_failure.reference | 9 - .../tests/warnings/w06.compilers.reference | 4 + testsuite/tests/warnings/w06.ml | 11 + testsuite/tests/warnings/w06.reference | 4 - .../tests/warnings/w32.compilers.reference | 30 + testsuite/tests/warnings/w32.ml | 20 + testsuite/tests/warnings/w32.mli | 7 + testsuite/tests/warnings/w32.reference | 26 - .../tests/warnings/w32b.compilers.reference | 2 + testsuite/tests/warnings/w32b.ml | 13 + .../tests/warnings/w33.compilers.reference | 4 + testsuite/tests/warnings/w33.ml | 11 + testsuite/tests/warnings/w33.reference | 4 - .../tests/warnings/w45.compilers.reference | 7 + testsuite/tests/warnings/w45.ml | 11 + testsuite/tests/warnings/w45.reference | 7 - .../warnings/w47_inline.compilers.reference | 15 + testsuite/tests/warnings/w47_inline.ml | 10 + testsuite/tests/warnings/w47_inline.reference | 15 - .../tests/warnings/w50.compilers.reference | 4 + testsuite/tests/warnings/w50.ml | 11 + testsuite/tests/warnings/w50.reference | 4 - .../tests/warnings/w51.compilers.reference | 2 + testsuite/tests/warnings/w51.ml | 10 + testsuite/tests/warnings/w51.reference | 2 - .../warnings/w51_bis.compilers.reference | 2 + testsuite/tests/warnings/w51_bis.ml | 11 + testsuite/tests/warnings/w51_bis.reference | 2 - .../tests/warnings/w52.compilers.reference | 12 + testsuite/tests/warnings/w52.ml | 33 + .../tests/warnings/w53.compilers.reference | 26 + testsuite/tests/warnings/w53.ml | 12 + testsuite/tests/warnings/w53.reference | 26 - .../tests/warnings/w54.compilers.reference | 8 + testsuite/tests/warnings/w54.ml | 10 + testsuite/tests/warnings/w54.reference | 8 - .../tests/warnings/w55.flambda.reference | 6 + testsuite/tests/warnings/w55.ml | 42 + testsuite/tests/warnings/w55.native.reference | 12 + .../w55.opt_backend.clambda.opt_reference | 12 - .../w55.opt_backend.flambda.opt_reference | 6 - testsuite/tests/warnings/w55.opt_backend.ml | 21 - .../tests/warnings/w55.opt_backend.reference | 0 testsuite/tests/warnings/w58.ml | 22 + ...opt.opt_reference => w58.native.reference} | 0 testsuite/tests/warnings/w58.opt.ml | 2 - testsuite/tests/warnings/w58.opt.reference | 0 .../tests/warnings/w59.flambda.reference | 20 + testsuite/tests/warnings/w59.ml | 65 + .../w59.opt_backend.clambda.opt_reference | 0 .../w59.opt_backend.flambda.opt_reference | 20 - testsuite/tests/warnings/w59.opt_backend.ml | 44 - .../tests/warnings/w59.opt_backend.reference | 0 testsuite/tests/warnings/w60.ml | 11 + testsuite/tests/warnings/w60.reference | 0 testsuite/tests/win-unicode/Makefile | 8 +- testsuite/tools/Makefile | 2 +- testsuite/tools/expect_test.ml | 111 +- tools/Makefile | 47 +- tools/ci-build | 239 -- tools/ci-build-other-configs | 21 - tools/ci/appveyor/appveyor_build.cmd | 113 + .../ci/appveyor/appveyor_build.sh | 0 tools/ci/inria/main | 240 ++ tools/ci/inria/other-configs | 29 + tools/ci/travis/travis-ci.sh | 160 + tools/dumpobj.ml | 3 +- tools/make-version-header.sh | 2 +- tools/objinfo.ml | 17 +- tools/ocamlcp.ml | 2 + tools/ocamloptp.ml | 3 + toplevel/opttoploop.ml | 4 +- toplevel/opttopmain.ml | 3 + toplevel/topdirs.ml | 2 +- toplevel/toploop.ml | 2 +- toplevel/topmain.ml | 2 + typing/btype.ml | 9 +- typing/btype.mli | 1 + typing/cmt_format.ml | 2 +- typing/ctype.ml | 287 +- typing/ctype.mli | 18 +- typing/datarepr.ml | 5 +- typing/env.ml | 324 +- typing/env.mli | 65 +- typing/envaux.ml | 5 +- typing/ident.ml | 16 +- typing/ident.mli | 4 +- typing/includeclass.ml | 2 +- typing/includecore.ml | 53 +- typing/includecore.mli | 5 +- typing/includemod.ml | 147 +- typing/includemod.mli | 28 +- typing/mtype.ml | 101 +- typing/mtype.mli | 7 +- typing/oprint.ml | 9 +- typing/parmatch.ml | 1536 +++++----- typing/parmatch.mli | 54 +- typing/predef.ml | 10 +- typing/printpat.ml | 156 + typing/printpat.mli | 22 + typing/printtyp.ml | 317 +- typing/printtyp.mli | 12 +- typing/stypes.ml | 2 +- typing/subst.ml | 5 +- typing/typeclass.ml | 99 +- typing/typeclass.mli | 1 + typing/typecore.ml | 720 +++-- typing/typecore.mli | 46 +- typing/typedecl.ml | 29 +- typing/typemod.ml | 109 +- typing/typemod.mli | 9 +- typing/typeopt.ml | 9 +- typing/typeopt.mli | 2 +- typing/types.ml | 4 +- typing/types.mli | 7 +- typing/typetexp.ml | 112 +- typing/typetexp.mli | 11 +- typing/untypeast.ml | 2 +- utils/build_path_prefix_map.ml | 104 + utils/build_path_prefix_map.mli | 24 + utils/clflags.ml | 4 +- utils/clflags.mli | 1 + utils/config.mli | 2 + utils/config.mlp | 26 +- utils/misc.ml | 4 +- utils/terminfo.ml | 37 +- utils/terminfo.mli | 13 +- utils/warnings.ml | 16 +- 2133 files changed, 71966 insertions(+), 30287 deletions(-) delete mode 100755 .travis-ci.sh create mode 100644 Makefile.common delete mode 100644 appveyor_build.cmd create mode 100644 asmcomp/traverse_for_exported_symbols.ml create mode 100644 asmcomp/traverse_for_exported_symbols.mli delete mode 100755 boot/ocamldep create mode 100644 bytecomp/translprim.ml create mode 100644 bytecomp/translprim.mli delete mode 100644 byterun/terminfo.c create mode 100644 manual/LICENSE-for-the-manual create mode 100644 manual/Makefile create mode 100644 manual/README.md create mode 100644 manual/manual/.gitignore create mode 100644 manual/manual/Makefile create mode 100644 manual/manual/allfiles.etex create mode 100644 manual/manual/biblio.etex create mode 100644 manual/manual/cmds/.gitignore create mode 100644 manual/manual/cmds/Makefile create mode 100644 manual/manual/cmds/afl-fuzz.etex create mode 100644 manual/manual/cmds/browser.etex create mode 100644 manual/manual/cmds/comp.etex create mode 100644 manual/manual/cmds/debugger.etex create mode 100644 manual/manual/cmds/depend.etex create mode 100644 manual/manual/cmds/flambda.etex create mode 100644 manual/manual/cmds/intf-c.etex create mode 100644 manual/manual/cmds/lexyacc.etex create mode 100644 manual/manual/cmds/native.etex create mode 100644 manual/manual/cmds/ocamlbuild.etex create mode 100644 manual/manual/cmds/ocamldoc.etex create mode 100644 manual/manual/cmds/plugins.etex create mode 100644 manual/manual/cmds/profil.etex create mode 100644 manual/manual/cmds/runtime.etex create mode 100644 manual/manual/cmds/spacetime.etex create mode 100644 manual/manual/cmds/top.etex create mode 100644 manual/manual/cmds/unified-options.etex create mode 100644 manual/manual/foreword.etex create mode 100644 manual/manual/htmlman/.gitignore create mode 100644 manual/manual/htmlman/contents_motif.gif create mode 100644 manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.eot create mode 100644 manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.svg create mode 100644 manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.ttf create mode 100644 manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff create mode 100644 manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff2 create mode 100644 manual/manual/htmlman/libgraph.gif create mode 100644 manual/manual/htmlman/next_motif.gif create mode 100644 manual/manual/htmlman/previous_motif.gif create mode 100644 manual/manual/index.tex create mode 100644 manual/manual/infoman/.gitignore create mode 100644 manual/manual/library/.cvsignore create mode 100644 manual/manual/library/.gitignore create mode 100644 manual/manual/library/Makefile create mode 100644 manual/manual/library/builtin.etex create mode 100644 manual/manual/library/compilerlibs.etex create mode 100644 manual/manual/library/core.etex create mode 100644 manual/manual/library/libbigarray.etex create mode 100644 manual/manual/library/libdynlink.etex create mode 100644 manual/manual/library/libgraph.etex create mode 100644 manual/manual/library/libgraph.fig create mode 100644 manual/manual/library/libgraph.png create mode 100644 manual/manual/library/libnum.etex create mode 100644 manual/manual/library/libstr.etex create mode 100644 manual/manual/library/libthreads.etex create mode 100644 manual/manual/library/libunix.etex create mode 100644 manual/manual/library/stdlib.etex create mode 100644 manual/manual/macros.hva create mode 100644 manual/manual/macros.tex create mode 100644 manual/manual/manual.hva create mode 100644 manual/manual/manual.inf create mode 100644 manual/manual/manual.info.header create mode 100644 manual/manual/manual.tex create mode 100644 manual/manual/pdfmanual.tex create mode 100644 manual/manual/plaintext.tex create mode 100644 manual/manual/refman/.cvsignore create mode 100644 manual/manual/refman/.gitignore create mode 100644 manual/manual/refman/Makefile create mode 100644 manual/manual/refman/classes.etex create mode 100644 manual/manual/refman/compunit.etex create mode 100644 manual/manual/refman/const.etex create mode 100644 manual/manual/refman/expr.etex create mode 100644 manual/manual/refman/exten.etex create mode 100644 manual/manual/refman/lex.etex create mode 100644 manual/manual/refman/modtypes.etex create mode 100644 manual/manual/refman/modules.etex create mode 100644 manual/manual/refman/names.etex create mode 100644 manual/manual/refman/patterns.etex create mode 100644 manual/manual/refman/refman.etex create mode 100644 manual/manual/refman/typedecl.etex create mode 100644 manual/manual/refman/types.etex create mode 100644 manual/manual/refman/values.etex create mode 100644 manual/manual/style.css create mode 100644 manual/manual/texstuff/.cvsignore create mode 100644 manual/manual/texstuff/.gitignore create mode 100644 manual/manual/textman/.cvsignore create mode 100644 manual/manual/textman/.gitignore create mode 100644 manual/manual/tutorials/.cvsignore create mode 100644 manual/manual/tutorials/.gitignore create mode 100644 manual/manual/tutorials/Makefile create mode 100644 manual/manual/tutorials/advexamples.etex create mode 100644 manual/manual/tutorials/coreexamples.etex create mode 100644 manual/manual/tutorials/lablexamples.etex create mode 100644 manual/manual/tutorials/moduleexamples.etex create mode 100644 manual/manual/tutorials/objectexamples.etex create mode 100644 manual/manual/tutorials/polymorphism.etex create mode 100644 manual/styles/altindex.sty create mode 100644 manual/styles/caml-sl.sty create mode 100644 manual/styles/caml.sty create mode 100644 manual/styles/doc.tfm create mode 100644 manual/styles/docbf.tfm create mode 100644 manual/styles/docit.tfm create mode 100644 manual/styles/docmi.tfm create mode 100644 manual/styles/docrm.tfm create mode 100644 manual/styles/doctt.tfm create mode 100644 manual/styles/fullpage.sty create mode 100644 manual/styles/html.sty create mode 100644 manual/styles/isolatin.sty create mode 100644 manual/styles/multicols.sty create mode 100644 manual/styles/multind.sty create mode 100644 manual/styles/ocamldoc.hva create mode 100644 manual/styles/ocamldoc.sty create mode 100644 manual/styles/plaintext.sty create mode 100644 manual/styles/scroll.sty create mode 100644 manual/styles/syntaxdef.hva create mode 100644 manual/styles/syntaxdef.sty create mode 100644 manual/styles/syntaxdeftxt.sty create mode 100644 manual/tests/Makefile create mode 100644 manual/tests/README.md create mode 100755 manual/tests/check-stdlib-modules create mode 100644 manual/tests/cross_reference_checker.ml create mode 100644 manual/tools/.gitignore create mode 100644 manual/tools/.ignore create mode 100644 manual/tools/Makefile create mode 100755 manual/tools/caml-tex create mode 100644 manual/tools/caml_tex2.ml create mode 100644 manual/tools/dvi_to_txt/Makefile create mode 100644 manual/tools/dvi_to_txt/dvi.h create mode 100644 manual/tools/dvi_to_txt/interp.c create mode 100644 manual/tools/dvi_to_txt/io.c create mode 100644 manual/tools/dvi_to_txt/io.h create mode 100644 manual/tools/dvi_to_txt/main.c create mode 100644 manual/tools/dvi_to_txt/output.c create mode 100644 manual/tools/dvi_to_txt/output.h create mode 100644 manual/tools/dvi_to_txt/print.c create mode 100644 manual/tools/dvi_to_txt/print_rtf.c create mode 100644 manual/tools/dvi_to_txt/print_styl.c create mode 100755 manual/tools/fix_index.sh create mode 100755 manual/tools/format-intf create mode 100755 manual/tools/htmlcut create mode 100644 manual/tools/htmlquote.c create mode 100755 manual/tools/htmltbl create mode 100755 manual/tools/htmlthread create mode 100644 manual/tools/htmltransf.mll create mode 100644 manual/tools/latexmacros.ml create mode 100644 manual/tools/latexmacros.mli create mode 100644 manual/tools/latexmain.ml create mode 100644 manual/tools/latexscan.mll create mode 100755 manual/tools/texexpand create mode 100644 manual/tools/texquote2.c create mode 100644 manual/tools/transf.mll create mode 100644 manual/tools/transfmain.ml create mode 100644 middle_end/base_types/closure_origin.ml create mode 100644 middle_end/base_types/closure_origin.mli create mode 100644 middle_end/internal_variable_names.ml create mode 100644 middle_end/internal_variable_names.mli create mode 100644 ocamldoc/Makefile.unprefix create mode 100644 ocamldoc/odoc_index.html create mode 100644 ocamldoc/stdlib_non_prefixed/.depend create mode 100644 ocamldoc/stdlib_non_prefixed/Makefile create mode 100644 ocamldoc/stdlib_non_prefixed/extract_pervasives.awk create mode 100644 ocamltest/actions_helpers.ml create mode 100644 ocamltest/actions_helpers.mli delete mode 100644 ocamltest/backends.ml delete mode 100644 ocamltest/backends.mli delete mode 100644 ocamltest/builtin_modifiers.ml delete mode 100644 ocamltest/builtin_modifiers.mli delete mode 100644 ocamltest/builtin_tests.ml delete mode 100644 ocamltest/builtin_tests.mli delete mode 100644 ocamltest/filetype.ml delete mode 100644 ocamltest/filetype.mli create mode 100644 ocamltest/ocaml_actions.ml create mode 100644 ocamltest/ocaml_actions.mli create mode 100644 ocamltest/ocaml_backends.ml create mode 100644 ocamltest/ocaml_backends.mli create mode 100644 ocamltest/ocaml_commands.ml create mode 100644 ocamltest/ocaml_commands.mli create mode 100644 ocamltest/ocaml_compilers.ml create mode 100644 ocamltest/ocaml_compilers.mli create mode 100644 ocamltest/ocaml_directories.ml create mode 100644 ocamltest/ocaml_directories.mli create mode 100644 ocamltest/ocaml_files.ml create mode 100644 ocamltest/ocaml_files.mli create mode 100644 ocamltest/ocaml_filetypes.ml create mode 100644 ocamltest/ocaml_filetypes.mli create mode 100644 ocamltest/ocaml_flags.ml create mode 100644 ocamltest/ocaml_flags.mli create mode 100644 ocamltest/ocaml_modifiers.ml create mode 100644 ocamltest/ocaml_modifiers.mli create mode 100644 ocamltest/ocaml_tests.ml create mode 100644 ocamltest/ocaml_tests.mli create mode 100644 ocamltest/ocaml_tools.ml create mode 100644 ocamltest/ocaml_tools.mli create mode 100644 ocamltest/ocaml_toplevels.ml create mode 100644 ocamltest/ocaml_toplevels.mli create mode 100644 ocamltest/ocaml_variables.ml create mode 100644 ocamltest/ocaml_variables.mli create mode 100644 ocamltest/ocamltest_stdlib.ml create mode 100644 ocamltest/ocamltest_stdlib.mli create mode 100644 ocamltest/ocamltest_stdlib_stubs.c create mode 100644 ocamltest/result.ml create mode 100644 ocamltest/result.mli delete mode 100644 ocamltest/testlib.ml delete mode 100644 ocamltest/testlib.mli delete mode 100644 otherlibs/bigarray/bigarray_stubs.c rename {asmrun => otherlibs/raw_spacetime_lib}/spacetime_offline.c (100%) delete mode 100644 otherlibs/threads/pervasives.ml create mode 100644 otherlibs/threads/stdlib.ml create mode 100644 otherlibs/win32unix/utimes.c create mode 100644 stdlib/bigarray.ml create mode 100644 stdlib/bigarray.mli delete mode 100644 stdlib/camlinternalBigarray.ml create mode 100644 stdlib/expand_module_aliases.awk create mode 100644 stdlib/float.ml create mode 100644 stdlib/float.mli delete mode 100644 stdlib/pervasives.ml delete mode 100644 stdlib/pervasives.mli create mode 100644 stdlib/remove_module_aliases.awk create mode 100644 stdlib/seq.ml create mode 100644 stdlib/seq.mli create mode 100644 stdlib/stdlib.ml create mode 100644 stdlib/stdlib.mli rename testsuite/{tests/tool-ocaml => lib}/lib.ml (100%) delete mode 100644 testsuite/tests/afl-instrumentation/Makefile create mode 100644 testsuite/tests/afl-instrumentation/afltest.ml create mode 100755 testsuite/tests/afl-instrumentation/afltest.run create mode 100644 testsuite/tests/afl-instrumentation/has-afl-showmap.sh create mode 100644 testsuite/tests/afl-instrumentation/ocamltests delete mode 100755 testsuite/tests/afl-instrumentation/test.sh delete mode 100644 testsuite/tests/asmcomp/Makefile delete mode 100644 testsuite/tests/asmcomp/alpha.S delete mode 100644 testsuite/tests/asmcomp/amd64.S delete mode 100644 testsuite/tests/asmcomp/arm.S delete mode 100644 testsuite/tests/asmcomp/arm64.S mode change 100755 => 100644 testsuite/tests/asmcomp/bind_tuples.ml delete mode 100644 testsuite/tests/asmcomp/hppa.S delete mode 100644 testsuite/tests/asmcomp/i386.S delete mode 100644 testsuite/tests/asmcomp/ia64.S delete mode 100644 testsuite/tests/asmcomp/lexcmm.mll delete mode 100644 testsuite/tests/asmcomp/m68k.S delete mode 100644 testsuite/tests/asmcomp/mips.s create mode 100644 testsuite/tests/asmcomp/ocamltests delete mode 100644 testsuite/tests/asmcomp/parsecmm.mly delete mode 100644 testsuite/tests/asmcomp/power.S delete mode 100644 testsuite/tests/asmcomp/s390x.S delete mode 100644 testsuite/tests/asmcomp/sparc.S create mode 100644 testsuite/tests/asmgen/Makefile create mode 100644 testsuite/tests/asmgen/amd64.S rename testsuite/tests/{asmcomp => asmgen}/arith.cmm (100%) create mode 100644 testsuite/tests/asmgen/arm.S create mode 100644 testsuite/tests/asmgen/arm64.S rename testsuite/tests/{asmcomp => asmgen}/catch-rec.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/catch-try.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/checkbound.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/even-odd-spill.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/even-odd.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/fib.cmm (100%) create mode 100644 testsuite/tests/asmgen/i386.S rename testsuite/tests/{asmcomp => asmgen}/i386nt.asm (100%) rename testsuite/tests/{asmcomp => asmgen}/integr.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/lexcmm.mli (100%) create mode 100644 testsuite/tests/asmgen/lexcmm.mll rename testsuite/tests/{asmcomp => asmgen}/main.c (100%) rename testsuite/tests/{asmcomp => asmgen}/main.ml (100%) rename testsuite/tests/{asmcomp => asmgen}/mainarith.c (100%) create mode 100644 testsuite/tests/asmgen/parsecmm.mly rename testsuite/tests/{asmcomp => asmgen}/parsecmmaux.ml (100%) rename testsuite/tests/{asmcomp => asmgen}/parsecmmaux.mli (100%) rename testsuite/tests/{asmcomp => asmgen}/pgcd.cmm (100%) create mode 100644 testsuite/tests/asmgen/power.S rename testsuite/tests/{asmcomp => asmgen}/quicksort.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/quicksort2.cmm (100%) create mode 100644 testsuite/tests/asmgen/s390x.S rename testsuite/tests/{asmcomp => asmgen}/soli.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/tagged-fib.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/tagged-integr.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/tagged-quicksort.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/tagged-tak.cmm (100%) rename testsuite/tests/{asmcomp => asmgen}/tak.cmm (100%) delete mode 100644 testsuite/tests/ast-invariants/Makefile create mode 100644 testsuite/tests/ast-invariants/ocamltests delete mode 100644 testsuite/tests/backtrace/Makefile delete mode 100644 testsuite/tests/backtrace/backtrace..byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace..native.reference delete mode 100644 testsuite/tests/backtrace/backtrace.a.byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace.a.native.reference delete mode 100644 testsuite/tests/backtrace/backtrace.b.byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace.b.native.reference create mode 100644 testsuite/tests/backtrace/backtrace.byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace.c.byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace.c.native.reference delete mode 100644 testsuite/tests/backtrace/backtrace.d.byte.reference delete mode 100644 testsuite/tests/backtrace/backtrace.d.native.reference create mode 100644 testsuite/tests/backtrace/backtrace.opt.reference create mode 100644 testsuite/tests/backtrace/backtrace.run delete mode 100644 testsuite/tests/backtrace/backtrace2.native.reference create mode 100644 testsuite/tests/backtrace/backtrace2.opt.reference delete mode 100644 testsuite/tests/backtrace/backtrace3.native.reference create mode 100644 testsuite/tests/backtrace/backtrace3.opt.reference delete mode 100644 testsuite/tests/backtrace/backtrace_deprecated.native.reference create mode 100644 testsuite/tests/backtrace/backtrace_deprecated.opt.reference delete mode 100644 testsuite/tests/backtrace/backtrace_slots.native.reference create mode 100644 testsuite/tests/backtrace/backtrace_slots.opt.reference rename testsuite/tests/backtrace/{backtraces_and_finalizers.native.reference => backtraces_and_finalizers.reference} (100%) create mode 100755 testsuite/tests/backtrace/filter-locations.sh delete mode 100644 testsuite/tests/backtrace/inline_test.native.reference create mode 100644 testsuite/tests/backtrace/inline_test.opt.reference create mode 100755 testsuite/tests/backtrace/inline_test.run delete mode 100644 testsuite/tests/backtrace/inline_traversal_test.native.reference create mode 100644 testsuite/tests/backtrace/inline_traversal_test.opt.reference create mode 100755 testsuite/tests/backtrace/inline_traversal_test.run create mode 100644 testsuite/tests/backtrace/ocamltests delete mode 100644 testsuite/tests/backtrace/pr6920_why_at.native.reference create mode 100644 testsuite/tests/backtrace/pr6920_why_at.opt.reference delete mode 100644 testsuite/tests/backtrace/pr6920_why_swallow.native.reference create mode 100644 testsuite/tests/backtrace/pr6920_why_swallow.opt.reference delete mode 100644 testsuite/tests/backtrace/raw_backtrace.native.reference create mode 100644 testsuite/tests/backtrace/raw_backtrace.opt.reference delete mode 100644 testsuite/tests/basic-float/Makefile create mode 100644 testsuite/tests/basic-float/ocamltests delete mode 100644 testsuite/tests/basic-manyargs/Makefile create mode 100644 testsuite/tests/basic-manyargs/ocamltests create mode 100644 testsuite/tests/basic-modules/recursive_module_evaluation_errors.ml delete mode 100644 testsuite/tests/basic-more/Makefile create mode 100644 testsuite/tests/basic-more/morematch.compilers.reference create mode 100644 testsuite/tests/basic-more/ocamltests delete mode 100644 testsuite/tests/basic/Makefile delete mode 100644 testsuite/tests/basic/constprop.mlp create mode 100644 testsuite/tests/basic/ocamltests create mode 100644 testsuite/tests/basic/pr7253.ml create mode 100644 testsuite/tests/basic/pr7253.reference delete mode 100644 testsuite/tests/callback/Makefile create mode 100644 testsuite/tests/callback/ocamltests rename testsuite/tests/callback/{reference => tcallback.reference} (100%) delete mode 100644 testsuite/tests/docstrings/Makefile delete mode 100644 testsuite/tests/docstrings/empty.ml delete mode 100644 testsuite/tests/docstrings/empty.ml.reference delete mode 100644 testsuite/tests/embedded/Makefile rename testsuite/tests/embedded/{program.reference => cmcaml.reference} (100%) create mode 100644 testsuite/tests/embedded/ocamltests delete mode 100644 testsuite/tests/exotic-syntax/Makefile create mode 100644 testsuite/tests/exotic-syntax/ocamltests delete mode 100644 testsuite/tests/extension-constructor/Makefile create mode 100644 testsuite/tests/extension-constructor/ocamltests delete mode 100644 testsuite/tests/flambda/Makefile create mode 100644 testsuite/tests/flambda/approx_meet.ml create mode 100644 testsuite/tests/flambda/approx_meet.reference create mode 100644 testsuite/tests/flambda/ocamltests create mode 100644 testsuite/tests/flambda/specialise.ml rename testsuite/tests/{basic/trigraph.ml.silent-compilation => flambda/specialise.reference} (100%) delete mode 100644 testsuite/tests/float-unboxing/Makefile delete mode 100644 testsuite/tests/float-unboxing/float_flambda.ml create mode 100644 testsuite/tests/float-unboxing/ocamltests delete mode 100644 testsuite/tests/formats-transition/Makefile delete mode 100644 testsuite/tests/formats-transition/deprecated_unsigned_printers.ml.reference create mode 100644 testsuite/tests/formats-transition/deprecated_unsigned_printers.ocaml.reference delete mode 100644 testsuite/tests/formats-transition/ignored_scan_counters.ml.reference create mode 100644 testsuite/tests/formats-transition/ignored_scan_counters.ocaml.reference delete mode 100644 testsuite/tests/formats-transition/legacy_incompatible_flags.ml.reference create mode 100644 testsuite/tests/formats-transition/legacy_incompatible_flags.ocaml.reference delete mode 100644 testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml.reference create mode 100644 testsuite/tests/formats-transition/legacy_unfinished_modifiers.ocaml.reference create mode 100644 testsuite/tests/formats-transition/ocamltests delete mode 100644 testsuite/tests/formatting/Makefile delete mode 100644 testsuite/tests/formatting/margins.ml.reference create mode 100644 testsuite/tests/formatting/margins.ocaml.reference create mode 100644 testsuite/tests/formatting/ocamltests delete mode 100644 testsuite/tests/functors/Makefile create mode 100644 testsuite/tests/functors/functors.compilers.reference delete mode 100644 testsuite/tests/functors/functors.ml.reference create mode 100644 testsuite/tests/functors/ocamltests delete mode 100644 testsuite/tests/gc-roots/Makefile create mode 100644 testsuite/tests/gc-roots/ocamltests delete mode 100644 testsuite/tests/int64-unboxing/Makefile create mode 100644 testsuite/tests/int64-unboxing/ocamltests delete mode 100644 testsuite/tests/lazy/Makefile create mode 100644 testsuite/tests/lazy/ocamltests delete mode 100644 testsuite/tests/letrec-disallowed/Makefile delete mode 100644 testsuite/tests/letrec-disallowed/disallowed.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/disallowed.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/extension_constructor.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/extension_constructor.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/float_block.ml delete mode 100644 testsuite/tests/letrec-disallowed/float_block.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/float_block_allowed.ml create mode 100644 testsuite/tests/letrec-disallowed/float_block_allowed.ocaml.reference create mode 100644 testsuite/tests/letrec-disallowed/float_block_disallowed.ml create mode 100644 testsuite/tests/letrec-disallowed/float_block_disallowed.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/generic_arrays.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/generic_arrays.ocaml.reference create mode 100644 testsuite/tests/letrec-disallowed/labels.ml create mode 100644 testsuite/tests/letrec-disallowed/labels.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/lazy_.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/lazy_.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/module_constraints.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/module_constraints.ocaml.reference create mode 100644 testsuite/tests/letrec-disallowed/ocamltests delete mode 100644 testsuite/tests/letrec-disallowed/pr7215.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/pr7215.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/pr7231.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/pr7231.ocaml.reference create mode 100644 testsuite/tests/letrec-disallowed/pr7706.ml create mode 100644 testsuite/tests/letrec-disallowed/pr7706.ocaml.reference delete mode 100644 testsuite/tests/letrec-disallowed/unboxed.ml.reference create mode 100644 testsuite/tests/letrec-disallowed/unboxed.ocaml.reference delete mode 100644 testsuite/tests/letrec/Makefile delete mode 100644 testsuite/tests/letrec/disallowed.reference create mode 100644 testsuite/tests/letrec/labels.ml rename testsuite/tests/{float-unboxing/float_subst_boxed_number.reference => letrec/labels.reference} (100%) create mode 100644 testsuite/tests/letrec/ocamltests delete mode 100644 testsuite/tests/lexing/Makefile create mode 100644 testsuite/tests/lexing/ocamltests delete mode 100644 testsuite/tests/lexing/uchar_esc.ml.reference create mode 100644 testsuite/tests/lexing/uchar_esc.ocaml.reference delete mode 100644 testsuite/tests/lib-arg/Makefile create mode 100644 testsuite/tests/lib-arg/ocamltests delete mode 100644 testsuite/tests/lib-bigarray-file/Makefile create mode 100644 testsuite/tests/lib-bigarray-file/ocamltests delete mode 100644 testsuite/tests/lib-bigarray/Makefile create mode 100644 testsuite/tests/lib-bigarray/ocamltests delete mode 100644 testsuite/tests/lib-buffer/Makefile create mode 100644 testsuite/tests/lib-buffer/ocamltests delete mode 100644 testsuite/tests/lib-bytes/Makefile create mode 100644 testsuite/tests/lib-bytes/ocamltests delete mode 100644 testsuite/tests/lib-digest/Makefile create mode 100644 testsuite/tests/lib-digest/ocamltests delete mode 100644 testsuite/tests/lib-filename/Makefile create mode 100644 testsuite/tests/lib-filename/ocamltests delete mode 100644 testsuite/tests/lib-format/Makefile create mode 100644 testsuite/tests/lib-format/ocamltests delete mode 100644 testsuite/tests/lib-hashtbl/Makefile create mode 100644 testsuite/tests/lib-hashtbl/ocamltests delete mode 100644 testsuite/tests/lib-list/Makefile create mode 100644 testsuite/tests/lib-list/ocamltests delete mode 100644 testsuite/tests/lib-marshal/Makefile create mode 100644 testsuite/tests/lib-marshal/ocamltests delete mode 100755 testsuite/tests/lib-obj/Makefile create mode 100644 testsuite/tests/lib-obj/ocamltests delete mode 100644 testsuite/tests/lib-printf/Makefile create mode 100644 testsuite/tests/lib-printf/ocamltests delete mode 100644 testsuite/tests/lib-queue/Makefile create mode 100644 testsuite/tests/lib-queue/ocamltests delete mode 100644 testsuite/tests/lib-random/Makefile create mode 100644 testsuite/tests/lib-random/ocamltests delete mode 100644 testsuite/tests/lib-scanf-2/Makefile create mode 100644 testsuite/tests/lib-scanf-2/ocamltests delete mode 100644 testsuite/tests/lib-scanf/Makefile create mode 100644 testsuite/tests/lib-scanf/ocamltests create mode 100644 testsuite/tests/lib-seq/ocamltests create mode 100644 testsuite/tests/lib-seq/test.ml create mode 100644 testsuite/tests/lib-seq/test.reference delete mode 100644 testsuite/tests/lib-set/Makefile create mode 100644 testsuite/tests/lib-set/ocamltests delete mode 100644 testsuite/tests/lib-stack/Makefile create mode 100644 testsuite/tests/lib-stack/ocamltests delete mode 100644 testsuite/tests/lib-stdlabels/Makefile create mode 100644 testsuite/tests/lib-stdlabels/ocamltests delete mode 100644 testsuite/tests/lib-str/Makefile create mode 100644 testsuite/tests/lib-str/ocamltests delete mode 100644 testsuite/tests/lib-stream/Makefile create mode 100755 testsuite/tests/lib-stream/mpr7769.ml create mode 100755 testsuite/tests/lib-stream/mpr7769.reference create mode 100644 testsuite/tests/lib-stream/mpr7769.txt create mode 100644 testsuite/tests/lib-stream/ocamltests delete mode 100644 testsuite/tests/lib-string/Makefile create mode 100644 testsuite/tests/lib-string/ocamltests delete mode 100644 testsuite/tests/lib-sys/Makefile create mode 100644 testsuite/tests/lib-sys/ocamltests delete mode 100644 testsuite/tests/lib-systhreads/Makefile create mode 100644 testsuite/tests/lib-systhreads/ocamltests delete mode 100644 testsuite/tests/lib-systhreads/testfork.precheck create mode 100644 testsuite/tests/lib-systhreads/testpreempt.ml create mode 100644 testsuite/tests/lib-systhreads/testpreempt.reference delete mode 100644 testsuite/tests/lib-threads/Makefile create mode 100644 testsuite/tests/lib-threads/ocamltests create mode 100644 testsuite/tests/lib-threads/signal.check-program-output delete mode 100644 testsuite/tests/lib-threads/signal.checker delete mode 100644 testsuite/tests/lib-threads/signal.precheck create mode 100644 testsuite/tests/lib-threads/signal.run delete mode 100644 testsuite/tests/lib-threads/signal.runner delete mode 100644 testsuite/tests/lib-threads/socketsbuf.ml delete mode 100644 testsuite/tests/lib-threads/socketsbuf.reference delete mode 100644 testsuite/tests/lib-threads/swapchan.checker create mode 100644 testsuite/tests/lib-threads/swapchan.run delete mode 100644 testsuite/tests/lib-threads/tls.checker create mode 100644 testsuite/tests/lib-threads/tls.run delete mode 100644 testsuite/tests/lib-threads/token2.reference delete mode 100644 testsuite/tests/lib-uchar/Makefile create mode 100644 testsuite/tests/lib-uchar/ocamltests delete mode 100644 testsuite/tests/lib-unix/common/Makefile delete mode 100644 testsuite/tests/lib-unix/common/cmdline_prog.c create mode 100644 testsuite/tests/lib-unix/common/cmdline_prog.ml delete mode 100644 testsuite/tests/lib-unix/common/fdstatus.c create mode 100644 testsuite/tests/lib-unix/common/fdstatus_aux.c create mode 100644 testsuite/tests/lib-unix/common/fdstatus_main.ml create mode 100644 testsuite/tests/lib-unix/common/ocamltests delete mode 100644 testsuite/tests/lib-unix/common/reflector.c create mode 100644 testsuite/tests/lib-unix/common/reflector.ml create mode 100644 testsuite/tests/lib-unix/common/utimes.ml create mode 100644 testsuite/tests/lib-unix/common/utimes.reference rename testsuite/tests/{letrec/float_block_2.reference => lib-unix/common/utimes.txt} (100%) delete mode 100644 testsuite/tests/lib-unix/isatty/Makefile delete mode 100644 testsuite/tests/lib-unix/isatty/isatty_tty.precheck create mode 100644 testsuite/tests/lib-unix/isatty/ocamltests delete mode 100644 testsuite/tests/lib-unix/unix-execvpe/Makefile create mode 100755 testsuite/tests/lib-unix/unix-execvpe/has-execvpe.sh create mode 100644 testsuite/tests/lib-unix/unix-execvpe/ocamltests delete mode 100755 testsuite/tests/lib-unix/win-env/Makefile create mode 100644 testsuite/tests/lib-unix/win-env/ocamltests mode change 100755 => 100644 testsuite/tests/lib-unix/win-env/test_env.ml delete mode 100755 testsuite/tests/lib-unix/win-env/test_env2.ml delete mode 100755 testsuite/tests/lib-unix/win-env/test_env2.precheck delete mode 100755 testsuite/tests/lib-unix/win-env/test_env2.reference delete mode 100644 testsuite/tests/lib-unix/win-stat/Makefile create mode 100644 testsuite/tests/lib-unix/win-stat/ocamltests create mode 100644 testsuite/tests/lib-unix/win-stat/test.run delete mode 100755 testsuite/tests/lib-unix/win-symlink/Makefile delete mode 100755 testsuite/tests/lib-unix/win-symlink/precheck.ml mode change 100755 => 100644 testsuite/tests/lib-unix/win-symlink/test.ml delete mode 100644 testsuite/tests/link-test/Makefile create mode 100644 testsuite/tests/link-test/ocamltests delete mode 100644 testsuite/tests/manual-intf-c/Makefile create mode 100644 testsuite/tests/manual-intf-c/ocamltests delete mode 100644 testsuite/tests/match-exception-warnings/Makefile create mode 100644 testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ocaml.reference create mode 100644 testsuite/tests/match-exception-warnings/ocamltests delete mode 100644 testsuite/tests/match-exception/Makefile create mode 100644 testsuite/tests/match-exception/ocamltests delete mode 100644 testsuite/tests/messages/Makefile create mode 100644 testsuite/tests/messages/ocamltests delete mode 100644 testsuite/tests/misc-kb/Makefile create mode 100644 testsuite/tests/misc-kb/ocamltests delete mode 100644 testsuite/tests/misc-unsafe/Makefile create mode 100644 testsuite/tests/misc-unsafe/ocamltests delete mode 100644 testsuite/tests/misc/Makefile create mode 100644 testsuite/tests/misc/gpr1370.ml rename testsuite/tests/{lib-threads/backtrace_threads.reference => misc/gpr1370.reference} (100%) create mode 100644 testsuite/tests/misc/ocamltests delete mode 100644 testsuite/tests/no-alias-deps/Makefile delete mode 100644 testsuite/tests/no-alias-deps/aliases.cmo.reference create mode 100644 testsuite/tests/no-alias-deps/aliases.compilers.reference delete mode 100644 testsuite/tests/no-alias-deps/aliases.ml.reference create mode 100644 testsuite/tests/no-alias-deps/aliases.reference rename testsuite/tests/no-alias-deps/{b.cmi.pre => b.cmi.invalid} (100%) create mode 100644 testsuite/tests/no-alias-deps/ocamltests delete mode 100644 testsuite/tests/opaque/Makefile create mode 100644 testsuite/tests/opaque/ocamltests delete mode 100644 testsuite/tests/parsetree/Makefile create mode 100644 testsuite/tests/parsetree/ocamltests delete mode 100644 testsuite/tests/parsing/Makefile create mode 100644 testsuite/tests/parsing/attributes.compilers.reference delete mode 100644 testsuite/tests/parsing/attributes.ml.reference delete mode 100644 testsuite/tests/parsing/docstrings.ml.reference create mode 100644 testsuite/tests/parsing/extended_indexoperators.compilers.reference delete mode 100644 testsuite/tests/parsing/extended_indexoperators.ml.reference create mode 100644 testsuite/tests/parsing/extensions.compilers.reference delete mode 100644 testsuite/tests/parsing/extensions.ml.reference create mode 100644 testsuite/tests/parsing/int_and_float_with_modifier.compilers.reference delete mode 100644 testsuite/tests/parsing/int_and_float_with_modifier.ml.reference create mode 100644 testsuite/tests/parsing/ocamltests create mode 100644 testsuite/tests/parsing/pr6604.compilers.reference create mode 100644 testsuite/tests/parsing/pr6604.ml create mode 100644 testsuite/tests/parsing/pr6604_2.compilers.reference create mode 100644 testsuite/tests/parsing/pr6604_2.ml create mode 100644 testsuite/tests/parsing/pr6604_3.compilers.reference create mode 100644 testsuite/tests/parsing/pr6604_3.ml create mode 100644 testsuite/tests/parsing/pr6865.compilers.reference delete mode 100644 testsuite/tests/parsing/pr6865.ml.reference create mode 100644 testsuite/tests/parsing/pr7165.compilers.reference delete mode 100644 testsuite/tests/parsing/pr7165.ml.reference create mode 100644 testsuite/tests/parsing/shortcut_ext_attr.compilers.reference delete mode 100644 testsuite/tests/parsing/shortcut_ext_attr.ml.reference delete mode 100644 testsuite/tests/ppx-attributes/Makefile create mode 100644 testsuite/tests/ppx-attributes/ocamltests delete mode 100644 testsuite/tests/ppx-contexts/Makefile rename testsuite/tests/ppx-contexts/{program.ml => myppx.ml} (100%) create mode 100644 testsuite/tests/ppx-contexts/ocamltests rename testsuite/tests/ppx-contexts/{test.reference => test.compilers.reference} (100%) delete mode 100644 testsuite/tests/prim-bigstring/Makefile create mode 100644 testsuite/tests/prim-bigstring/ocamltests delete mode 100644 testsuite/tests/prim-bswap/Makefile create mode 100644 testsuite/tests/prim-bswap/ocamltests delete mode 100644 testsuite/tests/prim-revapply/Makefile create mode 100644 testsuite/tests/prim-revapply/ocamltests delete mode 100644 testsuite/tests/printing-types/Makefile create mode 100644 testsuite/tests/printing-types/ocamltests delete mode 100644 testsuite/tests/printing-types/pr248.ml.reference create mode 100644 testsuite/tests/printing-types/pr248.ocaml.reference create mode 100644 testsuite/tests/regression/gpr1623/gpr1623.ml rename testsuite/tests/{lib-threads/token1.reference => regression/gpr1623/gpr1623.reference} (100%) create mode 100644 testsuite/tests/regression/gpr1623/ocamltests delete mode 100644 testsuite/tests/regression/missing_set_of_closures/Makefile create mode 100644 testsuite/tests/regression/missing_set_of_closures/missing_set_of_closures.ml create mode 100644 testsuite/tests/regression/missing_set_of_closures/ocamltests delete mode 100644 testsuite/tests/regression/pr3612/Makefile create mode 100644 testsuite/tests/regression/pr3612/ocamltests delete mode 100644 testsuite/tests/regression/pr5080-notes/Makefile delete mode 100644 testsuite/tests/regression/pr5080-notes/pr5080_notes_ok.ml delete mode 100644 testsuite/tests/regression/pr5233/Makefile create mode 100644 testsuite/tests/regression/pr5233/ocamltests delete mode 100644 testsuite/tests/regression/pr5757/Makefile create mode 100644 testsuite/tests/regression/pr5757/ocamltests delete mode 100644 testsuite/tests/regression/pr6024/Makefile create mode 100644 testsuite/tests/regression/pr6024/ocamltests delete mode 100644 testsuite/tests/regression/pr7042/Makefile create mode 100644 testsuite/tests/regression/pr7042/ocamltests delete mode 100644 testsuite/tests/regression/pr7426/Makefile create mode 100644 testsuite/tests/regression/pr7426/ocamltests delete mode 100644 testsuite/tests/required-external/Makefile create mode 100644 testsuite/tests/required-external/ocamltests delete mode 100644 testsuite/tests/runtime-C-exceptions/Makefile create mode 100644 testsuite/tests/runtime-C-exceptions/ocamltests delete mode 100644 testsuite/tests/self-contained-toplevel/Makefile create mode 100644 testsuite/tests/self-contained-toplevel/ocamltests delete mode 100644 testsuite/tests/tool-command-line/Makefile create mode 100644 testsuite/tests/tool-command-line/ocamltests create mode 100644 testsuite/tests/tool-command-line/test.ml create mode 100644 testsuite/tests/tool-command-line/test.ocamlc.byte.reference create mode 100644 testsuite/tests/tool-command-line/test.ocamlopt.byte.flambda.reference create mode 100644 testsuite/tests/tool-command-line/test.ocamlopt.byte.reference delete mode 100644 testsuite/tests/tool-command-line/unknown-file.byte.reference delete mode 100644 testsuite/tests/tool-command-line/unknown-file.opt.reference delete mode 100644 testsuite/tests/tool-debugger/basic/Makefile mode change 100755 => 100644 testsuite/tests/tool-debugger/basic/input_script create mode 100644 testsuite/tests/tool-debugger/basic/ocamltests delete mode 100644 testsuite/tests/tool-debugger/find-artifacts/Makefile create mode 100644 testsuite/tests/tool-debugger/find-artifacts/debuggee.ml create mode 100644 testsuite/tests/tool-debugger/find-artifacts/ocamltests delete mode 100644 testsuite/tests/tool-debugger/no_debug_event/Makefile create mode 100644 testsuite/tests/tool-debugger/no_debug_event/noev.ml create mode 100644 testsuite/tests/tool-debugger/no_debug_event/ocamltests delete mode 100644 testsuite/tests/tool-lexyacc/Makefile create mode 100644 testsuite/tests/tool-lexyacc/main.compilers.reference create mode 100644 testsuite/tests/tool-lexyacc/ocamltests delete mode 100644 testsuite/tests/tool-ocaml/Makefile create mode 100644 testsuite/tests/tool-ocaml/ocamltests delete mode 100644 testsuite/tests/tool-ocamlc-compat32/Makefile delete mode 100644 testsuite/tests/tool-ocamlc-compat32/a.ml create mode 100644 testsuite/tests/tool-ocamlc-compat32/compat32.compilers.reference create mode 100644 testsuite/tests/tool-ocamlc-compat32/compat32.ml create mode 100644 testsuite/tests/tool-ocamlc-compat32/ocamltests delete mode 100644 testsuite/tests/tool-ocamlc-compat32/test.reference delete mode 100644 testsuite/tests/tool-ocamlc-open/Makefile create mode 100644 testsuite/tests/tool-ocamlc-open/ocamltests create mode 100644 testsuite/tests/tool-ocamlc-open/tool-ocamlc-open.ml delete mode 100644 testsuite/tests/tool-ocamldoc-2/Makefile delete mode 100644 testsuite/tests/tool-ocamldoc-2/extensible_variant.ml delete mode 100644 testsuite/tests/tool-ocamldoc-2/inline_records.mli delete mode 100644 testsuite/tests/tool-ocamldoc-2/inline_records_bis.ml delete mode 100644 testsuite/tests/tool-ocamldoc-2/level_0.mli delete mode 100644 testsuite/tests/tool-ocamldoc-2/loop.ml delete mode 100644 testsuite/tests/tool-ocamldoc-2/short_description.reference delete mode 100644 testsuite/tests/tool-ocamldoc-2/short_description.txt delete mode 100644 testsuite/tests/tool-ocamldoc-2/test.mli delete mode 100644 testsuite/tests/tool-ocamldoc-2/variants.mli delete mode 100644 testsuite/tests/tool-ocamldoc-2/variants.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Documentation_tags.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Documentation_tags.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Inline_records.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Inline_records.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Item_ids.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Item_ids.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Linebreaks.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Linebreaks.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Loop.ml delete mode 100644 testsuite/tests/tool-ocamldoc-html/Loop.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Makefile delete mode 100644 testsuite/tests/tool-ocamldoc-html/Module_whitespace.ml delete mode 100644 testsuite/tests/tool-ocamldoc-html/Module_whitespace.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/No_preamble.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/No_preamble.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Paragraph.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Paragraph.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/Variants.mli delete mode 100644 testsuite/tests/tool-ocamldoc-html/Variants.reference delete mode 100644 testsuite/tests/tool-ocamldoc-html/type_Linebreaks.reference delete mode 100644 testsuite/tests/tool-ocamldoc-man/Inline_records.mli delete mode 100644 testsuite/tests/tool-ocamldoc-man/Inline_records.reference delete mode 100644 testsuite/tests/tool-ocamldoc-man/Makefile delete mode 100644 testsuite/tests/tool-ocamldoc-open/Makefile rename testsuite/tests/tool-ocamldoc-open/{doc.reference => main.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc-open/main.ocamldoc.latex.reference create mode 100644 testsuite/tests/tool-ocamldoc-open/ocamltests create mode 100644 testsuite/tests/tool-ocamldoc/Documentation_tags.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Documentation_tags.mli rename testsuite/tests/{tool-ocamldoc-2/extensible_variant.reference => tool-ocamldoc/Extensible_variant.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Extensible_variant.ml create mode 100644 testsuite/tests/tool-ocamldoc/Extensible_variant.ocamldoc.latex.reference create mode 100644 testsuite/tests/tool-ocamldoc/Inline_records.html.reference rename testsuite/tests/{tool-ocamldoc-2/inline_records.reference => tool-ocamldoc/Inline_records.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Inline_records.man.reference create mode 100644 testsuite/tests/tool-ocamldoc/Inline_records.mli rename testsuite/tests/{tool-ocamldoc-2/inline_records_bis.reference => tool-ocamldoc/Inline_records_bis.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Inline_records_bis.ml create mode 100644 testsuite/tests/tool-ocamldoc/Item_ids.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Item_ids.mli rename testsuite/tests/{tool-ocamldoc-2/level_0.reference => tool-ocamldoc/Level_0.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Level_0.mli create mode 100644 testsuite/tests/tool-ocamldoc/Linebreaks.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Linebreaks.mli create mode 100644 testsuite/tests/tool-ocamldoc/Loop.html.reference rename testsuite/tests/{tool-ocamldoc-2/loop.reference => tool-ocamldoc/Loop.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Loop.ml delete mode 100644 testsuite/tests/tool-ocamldoc/Makefile create mode 100644 testsuite/tests/tool-ocamldoc/Module_whitespace.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Module_whitespace.ml create mode 100644 testsuite/tests/tool-ocamldoc/Module_whitespace.ocamldoc.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/No_preamble.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/No_preamble.mli create mode 100644 testsuite/tests/tool-ocamldoc/Paragraph.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Paragraph.mli create mode 100644 testsuite/tests/tool-ocamldoc/Short_description.latex.reference create mode 100644 testsuite/tests/tool-ocamldoc/Short_description.txt rename testsuite/tests/{tool-ocamldoc-2/test.reference => tool-ocamldoc/Test.latex.reference} (100%) create mode 100644 testsuite/tests/tool-ocamldoc/Test.mli create mode 100644 testsuite/tests/tool-ocamldoc/Variants.html.reference create mode 100644 testsuite/tests/tool-ocamldoc/Variants.latex.reference create mode 100644 testsuite/tests/tool-ocamldoc/Variants.mli create mode 100644 testsuite/tests/tool-ocamldoc/ocamltests create mode 100644 testsuite/tests/tool-ocamldoc/t03.ocamldoc.reference create mode 100644 testsuite/tests/tool-ocamldoc/type_Linebreaks.reference delete mode 100644 testsuite/tests/tool-ocamlobjinfo/Makefile create mode 100644 testsuite/tests/tool-ocamlobjinfo/has-lib-bfd.sh create mode 100644 testsuite/tests/tool-ocamlobjinfo/ocamltests create mode 100644 testsuite/tests/tool-ocamlobjinfo/question.reference delete mode 100644 testsuite/tests/tool-ocamlobjinfo/test.reference delete mode 100644 testsuite/tests/tool-toplevel-invocation/Makefile create mode 100644 testsuite/tests/tool-toplevel-invocation/ocamltests delete mode 100644 testsuite/tests/tool-toplevel/Makefile create mode 100644 testsuite/tests/tool-toplevel/exotic_lists.compilers.reference delete mode 100644 testsuite/tests/tool-toplevel/exotic_lists.ml.reference create mode 100644 testsuite/tests/tool-toplevel/ocamltests create mode 100644 testsuite/tests/tool-toplevel/pr7060.compilers.reference delete mode 100644 testsuite/tests/tool-toplevel/pr7060.ml.reference create mode 100644 testsuite/tests/tool-toplevel/pr7751.compilers.reference create mode 100644 testsuite/tests/tool-toplevel/pr7751.ml create mode 100644 testsuite/tests/tool-toplevel/strings.compilers.reference delete mode 100644 testsuite/tests/tool-toplevel/strings.ml.reference create mode 100644 testsuite/tests/tool-toplevel/tracing.compilers.reference delete mode 100644 testsuite/tests/tool-toplevel/tracing.ml.reference delete mode 100644 testsuite/tests/translprim/Makefile create mode 100644 testsuite/tests/translprim/array_spec.compilers.reference.flat create mode 100644 testsuite/tests/translprim/array_spec.compilers.reference.no-flat delete mode 100644 testsuite/tests/translprim/array_spec.ml.reference-flat delete mode 100644 testsuite/tests/translprim/array_spec.ml.reference-noflat create mode 100644 testsuite/tests/translprim/comparison_table.compilers.reference delete mode 100644 testsuite/tests/translprim/comparison_table.ml.reference create mode 100644 testsuite/tests/translprim/locs.ml create mode 100644 testsuite/tests/translprim/locs.reference create mode 100644 testsuite/tests/translprim/module_coercion.compilers.reference.flat create mode 100644 testsuite/tests/translprim/module_coercion.compilers.reference.no-flat delete mode 100644 testsuite/tests/translprim/module_coercion.ml.reference-flat delete mode 100644 testsuite/tests/translprim/module_coercion.ml.reference-noflat create mode 100644 testsuite/tests/translprim/ocamltests create mode 100644 testsuite/tests/translprim/ref_spec.compilers.reference delete mode 100644 testsuite/tests/translprim/ref_spec.ml.reference create mode 100644 testsuite/tests/typing-core-bugs/ocamltests create mode 100644 testsuite/tests/typing-core-bugs/type_expected_explanation.ml create mode 100644 testsuite/tests/typing-core-bugs/unit_fun_hints.ml delete mode 100644 testsuite/tests/typing-deprecated/Makefile mode change 100755 => 100644 testsuite/tests/typing-deprecated/deprecated.ml create mode 100644 testsuite/tests/typing-deprecated/ocamltests delete mode 100644 testsuite/tests/typing-extension-constructor/Makefile create mode 100644 testsuite/tests/typing-extension-constructor/ocamltests delete mode 100644 testsuite/tests/typing-extension-constructor/test.ml.reference create mode 100644 testsuite/tests/typing-extension-constructor/test.ocaml.reference delete mode 100644 testsuite/tests/typing-extensions/Makefile delete mode 100644 testsuite/tests/typing-extensions/cast.ml.reference create mode 100644 testsuite/tests/typing-extensions/cast.ocaml.reference delete mode 100644 testsuite/tests/typing-extensions/extensions.ml.reference create mode 100644 testsuite/tests/typing-extensions/extensions.ocaml.reference delete mode 100644 testsuite/tests/typing-extensions/msg.ml.reference create mode 100644 testsuite/tests/typing-extensions/msg.ocaml.reference create mode 100644 testsuite/tests/typing-extensions/ocamltests delete mode 100644 testsuite/tests/typing-extensions/open_types.ml.reference create mode 100644 testsuite/tests/typing-extensions/open_types.ocaml.reference delete mode 100644 testsuite/tests/typing-fstclassmod/Makefile create mode 100644 testsuite/tests/typing-fstclassmod/ocamltests delete mode 100644 testsuite/tests/typing-gadts/Makefile create mode 100644 testsuite/tests/typing-gadts/ambiguity.ml create mode 100644 testsuite/tests/typing-gadts/ocamltests delete mode 100644 testsuite/tests/typing-gadts/pr7518.ml create mode 100644 testsuite/tests/typing-gadts/pr7618.ml create mode 100644 testsuite/tests/typing-gadts/pr7747.ml create mode 100644 testsuite/tests/typing-gadts/variables_in_mcomp.ml delete mode 100644 testsuite/tests/typing-immediate/Makefile create mode 100644 testsuite/tests/typing-immediate/ocamltests delete mode 100644 testsuite/tests/typing-implicit_unpack/Makefile delete mode 100644 testsuite/tests/typing-implicit_unpack/implicit_unpack.ml.reference create mode 100644 testsuite/tests/typing-implicit_unpack/implicit_unpack.ocaml.reference create mode 100644 testsuite/tests/typing-implicit_unpack/ocamltests delete mode 100644 testsuite/tests/typing-labels/Makefile create mode 100644 testsuite/tests/typing-labels/ocamltests delete mode 100644 testsuite/tests/typing-misc-bugs/Makefile create mode 100644 testsuite/tests/typing-misc-bugs/ocamltests create mode 100644 testsuite/tests/typing-misc-bugs/pr6303_bad.compilers.reference create mode 100644 testsuite/tests/typing-misc-bugs/pr6946_bad.compilers.reference delete mode 100644 testsuite/tests/typing-misc/Makefile create mode 100644 testsuite/tests/typing-misc/disambiguate_principality.ml create mode 100644 testsuite/tests/typing-misc/empty_variant.ml create mode 100644 testsuite/tests/typing-misc/enrich_typedecl.ml create mode 100644 testsuite/tests/typing-misc/inside_out.ml create mode 100644 testsuite/tests/typing-misc/ocamltests create mode 100644 testsuite/tests/typing-misc/pr6939-flat-float-array.ml create mode 100644 testsuite/tests/typing-misc/pr6939-no-flat-float-array.ml delete mode 100644 testsuite/tests/typing-misc/pr6939.ml-flat delete mode 100644 testsuite/tests/typing-misc/pr6939.ml-noflat mode change 100755 => 100644 testsuite/tests/typing-misc/pr7228.ml create mode 100644 testsuite/tests/typing-misc/pr7668_bad.ml create mode 100644 testsuite/tests/typing-misc/pr7712.ml delete mode 100644 testsuite/tests/typing-missing-cmi/Makefile create mode 100644 testsuite/tests/typing-missing-cmi/ocamltests create mode 100644 testsuite/tests/typing-missing-cmi/test.compilers.reference create mode 100644 testsuite/tests/typing-missing-cmi/test.ml delete mode 100644 testsuite/tests/typing-modules-bugs/Makefile create mode 100644 testsuite/tests/typing-modules-bugs/ocamltests create mode 100644 testsuite/tests/typing-modules-bugs/pr6293_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr6427_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr6752_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr6899_first_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr6899_second_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr6992_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr7112_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr7414_2_bad.compilers.reference create mode 100644 testsuite/tests/typing-modules-bugs/pr7414_2_bad.ml create mode 100644 testsuite/tests/typing-modules-bugs/pr7414_bad.compilers.reference delete mode 100644 testsuite/tests/typing-modules/Makefile create mode 100644 testsuite/tests/typing-modules/applicative_functor_type.ml create mode 100644 testsuite/tests/typing-modules/ocamltests create mode 100644 testsuite/tests/typing-modules/pr6394.ml create mode 100644 testsuite/tests/typing-modules/pr7787.ml delete mode 100644 testsuite/tests/typing-multifile/Makefile create mode 100644 testsuite/tests/typing-multifile/a.ml create mode 100644 testsuite/tests/typing-multifile/b.ml create mode 100644 testsuite/tests/typing-multifile/c.ml create mode 100644 testsuite/tests/typing-multifile/d.mli create mode 100644 testsuite/tests/typing-multifile/e.ml create mode 100644 testsuite/tests/typing-multifile/f.ml create mode 100644 testsuite/tests/typing-multifile/ocamltests create mode 100644 testsuite/tests/typing-multifile/pr6372.ml create mode 100644 testsuite/tests/typing-multifile/pr7325.ml create mode 100644 testsuite/tests/typing-multifile/pr7563.ml delete mode 100644 testsuite/tests/typing-objects-bugs/Makefile create mode 100644 testsuite/tests/typing-objects-bugs/ocamltests create mode 100644 testsuite/tests/typing-objects-bugs/pr3968_bad.compilers.reference create mode 100644 testsuite/tests/typing-objects-bugs/pr4018_bad.compilers.reference create mode 100644 testsuite/tests/typing-objects-bugs/pr4435_bad.compilers.reference create mode 100644 testsuite/tests/typing-objects-bugs/pr4824a_bad.compilers.reference create mode 100644 testsuite/tests/typing-objects-bugs/pr7284_bad.compilers.reference delete mode 100644 testsuite/tests/typing-objects/Exemples.ml.principal.reference delete mode 100644 testsuite/tests/typing-objects/Exemples.ml.reference delete mode 100644 testsuite/tests/typing-objects/Makefile delete mode 100644 testsuite/tests/typing-objects/Tests.ml.principal.reference delete mode 100644 testsuite/tests/typing-objects/Tests.ml.reference create mode 100644 testsuite/tests/typing-objects/dummy.ml create mode 100644 testsuite/tests/typing-objects/ocamltests mode change 100755 => 100644 testsuite/tests/typing-objects/open_in_classes.ml delete mode 100644 testsuite/tests/typing-objects/open_in_classes.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr5545.ml.principal.reference delete mode 100644 testsuite/tests/typing-objects/pr5545.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr5619_bad.ml.principal.reference delete mode 100644 testsuite/tests/typing-objects/pr5619_bad.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr5858.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr6123_bad.ml.principal.reference delete mode 100644 testsuite/tests/typing-objects/pr6123_bad.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr6383.ml.reference delete mode 100644 testsuite/tests/typing-objects/pr6907_bad.ml.reference create mode 100644 testsuite/tests/typing-objects/pr7711_ok.ml delete mode 100644 testsuite/tests/typing-ocamlc-i/Makefile create mode 100644 testsuite/tests/typing-ocamlc-i/ocamltests create mode 100644 testsuite/tests/typing-ocamlc-i/pr7620_bad.compilers.reference delete mode 100644 testsuite/tests/typing-pattern_open/Makefile create mode 100644 testsuite/tests/typing-pattern_open/ocamltests delete mode 100644 testsuite/tests/typing-pattern_open/pattern_open.ml.reference create mode 100644 testsuite/tests/typing-pattern_open/pattern_open.ocaml.reference delete mode 100644 testsuite/tests/typing-poly-bugs/Makefile create mode 100644 testsuite/tests/typing-poly-bugs/ocamltests create mode 100644 testsuite/tests/typing-poly-bugs/pr5673_bad.compilers.reference delete mode 100644 testsuite/tests/typing-poly/Makefile create mode 100644 testsuite/tests/typing-poly/ocamltests delete mode 100644 testsuite/tests/typing-polyvariants-bugs-2/Makefile create mode 100644 testsuite/tests/typing-polyvariants-bugs-2/ocamltests create mode 100644 testsuite/tests/typing-polyvariants-bugs-2/pr3918c.compilers.reference delete mode 100644 testsuite/tests/typing-polyvariants-bugs/Makefile create mode 100644 testsuite/tests/typing-polyvariants-bugs/ocamltests create mode 100644 testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.compilers.reference delete mode 100644 testsuite/tests/typing-private-bugs/Makefile create mode 100644 testsuite/tests/typing-private-bugs/ocamltests create mode 100644 testsuite/tests/typing-private-bugs/pr5026_bad.compilers.reference delete mode 100644 testsuite/tests/typing-private/Makefile create mode 100644 testsuite/tests/typing-private/ocamltests create mode 100644 testsuite/tests/typing-private/private.compilers.principal.reference create mode 100644 testsuite/tests/typing-private/private.compilers.reference delete mode 100644 testsuite/tests/typing-private/private.ml.principal.reference delete mode 100644 testsuite/tests/typing-private/private.ml.reference delete mode 100644 testsuite/tests/typing-recmod/Makefile create mode 100644 testsuite/tests/typing-recmod/ocamltests create mode 100644 testsuite/tests/typing-recmod/t01bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t02bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t04bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t05bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t07bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t08bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t09bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t11bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t12bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t14bad.compilers.reference create mode 100644 testsuite/tests/typing-recmod/t15bad.compilers.reference delete mode 100644 testsuite/tests/typing-recordarg/Makefile create mode 100644 testsuite/tests/typing-recordarg/ocamltests delete mode 100644 testsuite/tests/typing-recordarg/recordarg.ml.reference create mode 100644 testsuite/tests/typing-recordarg/recordarg.ocaml.reference delete mode 100644 testsuite/tests/typing-rectypes-bugs/Makefile create mode 100644 testsuite/tests/typing-rectypes-bugs/ocamltests create mode 100644 testsuite/tests/typing-rectypes-bugs/pr5343_bad.compilers.reference create mode 100644 testsuite/tests/typing-rectypes-bugs/pr6174_bad.compilers.reference create mode 100644 testsuite/tests/typing-rectypes-bugs/pr6870_bad.compilers.reference delete mode 100644 testsuite/tests/typing-safe-linking/Makefile create mode 100644 testsuite/tests/typing-safe-linking/b_bad.compilers.reference create mode 100644 testsuite/tests/typing-safe-linking/ocamltests create mode 100644 testsuite/tests/typing-shadowing-of-pervasives-submodules/largeFile.ml create mode 100644 testsuite/tests/typing-shadowing-of-pervasives-submodules/ocamltests create mode 100644 testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.ml create mode 100644 testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.reference delete mode 100644 testsuite/tests/typing-short-paths/Makefile create mode 100644 testsuite/tests/typing-short-paths/gpr1223.compilers.reference delete mode 100644 testsuite/tests/typing-short-paths/gpr1223.ml.reference create mode 100644 testsuite/tests/typing-short-paths/ocamltests create mode 100644 testsuite/tests/typing-short-paths/pr5918.compilers.reference delete mode 100644 testsuite/tests/typing-short-paths/pr5918.ml.reference create mode 100644 testsuite/tests/typing-short-paths/pr6836.compilers.reference delete mode 100644 testsuite/tests/typing-short-paths/pr6836.ml.reference create mode 100644 testsuite/tests/typing-short-paths/pr7543.compilers.reference delete mode 100644 testsuite/tests/typing-short-paths/pr7543.ml.reference create mode 100644 testsuite/tests/typing-short-paths/short-paths.compilers.reference delete mode 100644 testsuite/tests/typing-short-paths/short-paths.ml.reference delete mode 100644 testsuite/tests/typing-signatures/Makefile delete mode 100644 testsuite/tests/typing-signatures/els.ml.reference create mode 100644 testsuite/tests/typing-signatures/els.ocaml.reference create mode 100644 testsuite/tests/typing-signatures/ocamltests delete mode 100644 testsuite/tests/typing-signatures/pr6371.ml.reference create mode 100644 testsuite/tests/typing-signatures/pr6371.ocaml.reference delete mode 100644 testsuite/tests/typing-signatures/pr6672.ml.reference create mode 100644 testsuite/tests/typing-signatures/pr6672.ocaml.reference delete mode 100644 testsuite/tests/typing-sigsubst/Makefile create mode 100644 testsuite/tests/typing-sigsubst/ocamltests delete mode 100644 testsuite/tests/typing-typeparam/Makefile delete mode 100644 testsuite/tests/typing-typeparam/newtype.ml.reference create mode 100644 testsuite/tests/typing-typeparam/newtype.ocaml.reference create mode 100644 testsuite/tests/typing-typeparam/ocamltests delete mode 100644 testsuite/tests/typing-unboxed-types/Makefile create mode 100644 testsuite/tests/typing-unboxed-types/ocamltests delete mode 100644 testsuite/tests/typing-unboxed/Makefile create mode 100644 testsuite/tests/typing-unboxed/ocamltests delete mode 100644 testsuite/tests/typing-unboxed/test.ml.reference create mode 100644 testsuite/tests/typing-unboxed/test.ocaml.reference delete mode 100644 testsuite/tests/typing-warnings/Makefile create mode 100644 testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml.reference create mode 100644 testsuite/tests/typing-warnings/application.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/application.ml.reference create mode 100644 testsuite/tests/typing-warnings/coercions.compilers.principal.reference create mode 100644 testsuite/tests/typing-warnings/coercions.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/coercions.ml.principal.reference delete mode 100644 testsuite/tests/typing-warnings/coercions.ml.reference create mode 100644 testsuite/tests/typing-warnings/exhaustiveness.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/exhaustiveness.ml.reference create mode 100644 testsuite/tests/typing-warnings/ocamltests create mode 100644 testsuite/tests/typing-warnings/pr5892.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr5892.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr6587.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr6587.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr6872.compilers.principal.reference create mode 100644 testsuite/tests/typing-warnings/pr6872.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr6872.ml.principal.reference delete mode 100644 testsuite/tests/typing-warnings/pr6872.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr7085.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr7085.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr7115.compilers.reference mode change 100755 => 100644 testsuite/tests/typing-warnings/pr7115.ml delete mode 100644 testsuite/tests/typing-warnings/pr7115.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr7261.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr7261.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr7297.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr7297.ml.reference create mode 100644 testsuite/tests/typing-warnings/pr7553.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/pr7553.ml.reference create mode 100644 testsuite/tests/typing-warnings/records.compilers.principal.reference create mode 100644 testsuite/tests/typing-warnings/records.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/records.ml.principal.reference delete mode 100644 testsuite/tests/typing-warnings/records.ml.reference create mode 100644 testsuite/tests/typing-warnings/unused_types.compilers.reference delete mode 100644 testsuite/tests/typing-warnings/unused_types.ml.reference delete mode 100644 testsuite/tests/utils/Makefile create mode 100644 testsuite/tests/utils/ocamltests create mode 100644 testsuite/tests/utils/overflow_detection.ml create mode 100644 testsuite/tests/utils/overflow_detection.reference delete mode 100644 testsuite/tests/warnings/Makefile create mode 100644 testsuite/tests/warnings/deprecated_module.compilers.reference delete mode 100644 testsuite/tests/warnings/deprecated_module.reference create mode 100644 testsuite/tests/warnings/deprecated_module_assigment.compilers.reference delete mode 100644 testsuite/tests/warnings/deprecated_module_assigment.reference create mode 100644 testsuite/tests/warnings/deprecated_module_use.compilers.reference delete mode 100644 testsuite/tests/warnings/deprecated_module_use.reference create mode 100644 testsuite/tests/warnings/ocamltests create mode 100644 testsuite/tests/warnings/w01.compilers.reference delete mode 100644 testsuite/tests/warnings/w01.reference create mode 100644 testsuite/tests/warnings/w04.compilers.reference delete mode 100644 testsuite/tests/warnings/w04.reference create mode 100644 testsuite/tests/warnings/w04_failure.compilers.reference delete mode 100644 testsuite/tests/warnings/w04_failure.reference create mode 100644 testsuite/tests/warnings/w06.compilers.reference delete mode 100644 testsuite/tests/warnings/w06.reference create mode 100644 testsuite/tests/warnings/w32.compilers.reference delete mode 100644 testsuite/tests/warnings/w32.reference create mode 100644 testsuite/tests/warnings/w32b.compilers.reference create mode 100644 testsuite/tests/warnings/w32b.ml create mode 100644 testsuite/tests/warnings/w33.compilers.reference delete mode 100644 testsuite/tests/warnings/w33.reference create mode 100644 testsuite/tests/warnings/w45.compilers.reference delete mode 100644 testsuite/tests/warnings/w45.reference create mode 100644 testsuite/tests/warnings/w47_inline.compilers.reference delete mode 100644 testsuite/tests/warnings/w47_inline.reference create mode 100644 testsuite/tests/warnings/w50.compilers.reference delete mode 100644 testsuite/tests/warnings/w50.reference create mode 100644 testsuite/tests/warnings/w51.compilers.reference delete mode 100644 testsuite/tests/warnings/w51.reference create mode 100644 testsuite/tests/warnings/w51_bis.compilers.reference delete mode 100644 testsuite/tests/warnings/w51_bis.reference create mode 100644 testsuite/tests/warnings/w52.compilers.reference create mode 100644 testsuite/tests/warnings/w52.ml create mode 100644 testsuite/tests/warnings/w53.compilers.reference delete mode 100644 testsuite/tests/warnings/w53.reference create mode 100644 testsuite/tests/warnings/w54.compilers.reference delete mode 100644 testsuite/tests/warnings/w54.reference create mode 100644 testsuite/tests/warnings/w55.flambda.reference create mode 100644 testsuite/tests/warnings/w55.ml create mode 100644 testsuite/tests/warnings/w55.native.reference delete mode 100644 testsuite/tests/warnings/w55.opt_backend.clambda.opt_reference delete mode 100644 testsuite/tests/warnings/w55.opt_backend.flambda.opt_reference delete mode 100644 testsuite/tests/warnings/w55.opt_backend.ml delete mode 100644 testsuite/tests/warnings/w55.opt_backend.reference create mode 100644 testsuite/tests/warnings/w58.ml rename testsuite/tests/warnings/{w58.opt.opt_reference => w58.native.reference} (100%) delete mode 100644 testsuite/tests/warnings/w58.opt.ml delete mode 100644 testsuite/tests/warnings/w58.opt.reference create mode 100644 testsuite/tests/warnings/w59.flambda.reference create mode 100644 testsuite/tests/warnings/w59.ml delete mode 100644 testsuite/tests/warnings/w59.opt_backend.clambda.opt_reference delete mode 100644 testsuite/tests/warnings/w59.opt_backend.flambda.opt_reference delete mode 100644 testsuite/tests/warnings/w59.opt_backend.ml delete mode 100644 testsuite/tests/warnings/w59.opt_backend.reference delete mode 100644 testsuite/tests/warnings/w60.reference delete mode 100755 tools/ci-build delete mode 100755 tools/ci-build-other-configs create mode 100644 tools/ci/appveyor/appveyor_build.cmd rename appveyor_build.sh => tools/ci/appveyor/appveyor_build.sh (100%) create mode 100755 tools/ci/inria/main create mode 100755 tools/ci/inria/other-configs create mode 100755 tools/ci/travis/travis-ci.sh create mode 100644 typing/printpat.ml create mode 100644 typing/printpat.mli create mode 100644 utils/build_path_prefix_map.ml create mode 100644 utils/build_path_prefix_map.mli diff --git a/.depend b/.depend index 8efabcb0..891a9c9b 100644 --- a/.depend +++ b/.depend @@ -1,6 +1,9 @@ utils/arg_helper.cmo : utils/arg_helper.cmi utils/arg_helper.cmx : utils/arg_helper.cmi utils/arg_helper.cmi : +utils/build_path_prefix_map.cmo : utils/build_path_prefix_map.cmi +utils/build_path_prefix_map.cmx : utils/build_path_prefix_map.cmi +utils/build_path_prefix_map.cmi : utils/ccomp.cmo : utils/misc.cmi utils/config.cmi utils/clflags.cmi \ utils/ccomp.cmi utils/ccomp.cmx : utils/misc.cmx utils/config.cmx utils/clflags.cmx \ @@ -105,9 +108,9 @@ parsing/lexer.cmx : utils/warnings.cmx parsing/parser.cmx utils/misc.cmx \ parsing/location.cmx parsing/docstrings.cmx parsing/lexer.cmi parsing/lexer.cmi : parsing/parser.cmi parsing/location.cmi parsing/location.cmo : utils/warnings.cmi utils/terminfo.cmi utils/misc.cmi \ - utils/clflags.cmi parsing/location.cmi + utils/clflags.cmi utils/build_path_prefix_map.cmi parsing/location.cmi parsing/location.cmx : utils/warnings.cmx utils/terminfo.cmx utils/misc.cmx \ - utils/clflags.cmx parsing/location.cmi + utils/clflags.cmx utils/build_path_prefix_map.cmx parsing/location.cmi parsing/location.cmi : utils/warnings.cmi parsing/longident.cmo : utils/misc.cmi parsing/longident.cmi parsing/longident.cmx : utils/misc.cmx parsing/longident.cmi @@ -199,16 +202,16 @@ typing/env.cmx : utils/warnings.cmx typing/types.cmx utils/tbl.cmx \ typing/cmi_format.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \ typing/btype.cmx parsing/asttypes.cmi typing/env.cmi typing/env.cmi : utils/warnings.cmi typing/types.cmi typing/subst.cmi \ - typing/path.cmi parsing/longident.cmi parsing/location.cmi \ + typing/path.cmi utils/misc.cmi parsing/longident.cmi parsing/location.cmi \ typing/ident.cmi utils/consistbl.cmi typing/cmi_format.cmi \ parsing/asttypes.cmi typing/envaux.cmo : typing/subst.cmi typing/printtyp.cmi typing/path.cmi \ - typing/ident.cmi typing/env.cmi parsing/asttypes.cmi typing/envaux.cmi + typing/ident.cmi typing/env.cmi typing/envaux.cmi typing/envaux.cmx : typing/subst.cmx typing/printtyp.cmx typing/path.cmx \ - typing/ident.cmx typing/env.cmx parsing/asttypes.cmi typing/envaux.cmi + typing/ident.cmx typing/env.cmx typing/envaux.cmi typing/envaux.cmi : typing/subst.cmi typing/path.cmi typing/env.cmi -typing/ident.cmo : utils/identifiable.cmi typing/ident.cmi -typing/ident.cmx : utils/identifiable.cmx typing/ident.cmi +typing/ident.cmo : utils/identifiable.cmi utils/clflags.cmi typing/ident.cmi +typing/ident.cmx : utils/identifiable.cmx utils/clflags.cmx typing/ident.cmi typing/ident.cmi : utils/identifiable.cmi typing/includeclass.cmo : typing/types.cmi typing/printtyp.cmi \ typing/path.cmi typing/ctype.cmi parsing/builtin_attributes.cmi \ @@ -261,21 +264,21 @@ typing/oprint.cmi : typing/outcometree.cmi typing/outcometree.cmi : parsing/asttypes.cmi typing/parmatch.cmo : utils/warnings.cmi typing/untypeast.cmi \ typing/types.cmi typing/typedtreeIter.cmi typing/typedtree.cmi \ - typing/subst.cmi typing/predef.cmi typing/path.cmi parsing/parsetree.cmi \ - utils/misc.cmi parsing/longident.cmi parsing/location.cmi \ - typing/ident.cmi typing/env.cmi typing/ctype.cmi utils/config.cmi \ - typing/btype.cmi parsing/asttypes.cmi parsing/ast_helper.cmi \ - typing/parmatch.cmi + typing/subst.cmi typing/printpat.cmi typing/predef.cmi typing/path.cmi \ + parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \ + parsing/location.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \ + utils/config.cmi typing/btype.cmi parsing/asttypes.cmi \ + parsing/ast_helper.cmi typing/parmatch.cmi typing/parmatch.cmx : utils/warnings.cmx typing/untypeast.cmx \ typing/types.cmx typing/typedtreeIter.cmx typing/typedtree.cmx \ - typing/subst.cmx typing/predef.cmx typing/path.cmx parsing/parsetree.cmi \ - utils/misc.cmx parsing/longident.cmx parsing/location.cmx \ - typing/ident.cmx typing/env.cmx typing/ctype.cmx utils/config.cmx \ - typing/btype.cmx parsing/asttypes.cmi parsing/ast_helper.cmx \ - typing/parmatch.cmi + typing/subst.cmx typing/printpat.cmx typing/predef.cmx typing/path.cmx \ + parsing/parsetree.cmi utils/misc.cmx parsing/longident.cmx \ + parsing/location.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \ + utils/config.cmx typing/btype.cmx parsing/asttypes.cmi \ + parsing/ast_helper.cmx typing/parmatch.cmi typing/parmatch.cmi : typing/types.cmi typing/typedtree.cmi \ - parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ - typing/env.cmi parsing/asttypes.cmi + parsing/parsetree.cmi parsing/location.cmi typing/env.cmi \ + parsing/asttypes.cmi typing/path.cmo : typing/ident.cmi typing/path.cmi typing/path.cmx : typing/ident.cmx typing/path.cmi typing/path.cmi : typing/ident.cmi @@ -294,6 +297,11 @@ typing/primitive.cmx : parsing/parsetree.cmi typing/outcometree.cmi \ typing/primitive.cmi typing/primitive.cmi : parsing/parsetree.cmi typing/outcometree.cmi \ parsing/location.cmi +typing/printpat.cmo : typing/types.cmi typing/typedtree.cmi typing/ident.cmi \ + parsing/asttypes.cmi typing/printpat.cmi +typing/printpat.cmx : typing/types.cmx typing/typedtree.cmx typing/ident.cmx \ + parsing/asttypes.cmi typing/printpat.cmi +typing/printpat.cmi : typing/typedtree.cmi parsing/asttypes.cmi typing/printtyp.cmo : typing/types.cmi typing/primitive.cmi \ typing/predef.cmi typing/path.cmi parsing/parsetree.cmi \ typing/outcometree.cmi typing/oprint.cmi utils/misc.cmi \ @@ -363,23 +371,25 @@ typing/typeclass.cmi : typing/types.cmi typing/typedtree.cmi \ typing/typecore.cmo : utils/warnings.cmi typing/typetexp.cmi \ typing/types.cmi typing/typeopt.cmi typing/typedtree.cmi \ typing/typedecl.cmi typing/subst.cmi typing/stypes.cmi \ - typing/printtyp.cmi typing/primitive.cmi typing/predef.cmi \ - typing/path.cmi parsing/parsetree.cmi typing/parmatch.cmi \ - typing/oprint.cmi utils/misc.cmi parsing/longident.cmi \ - parsing/location.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \ - typing/cmt_format.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \ - typing/btype.cmi parsing/asttypes.cmi parsing/ast_helper.cmi \ - typing/annot.cmi typing/typecore.cmi + typing/printtyp.cmi typing/printpat.cmi typing/primitive.cmi \ + typing/predef.cmi typing/path.cmi parsing/parsetree.cmi \ + typing/parmatch.cmi typing/oprint.cmi typing/mtype.cmi utils/misc.cmi \ + parsing/longident.cmi parsing/location.cmi typing/ident.cmi \ + typing/env.cmi typing/ctype.cmi utils/config.cmi typing/cmt_format.cmi \ + utils/clflags.cmi parsing/builtin_attributes.cmi typing/btype.cmi \ + parsing/asttypes.cmi parsing/ast_helper.cmi typing/annot.cmi \ + typing/typecore.cmi typing/typecore.cmx : utils/warnings.cmx typing/typetexp.cmx \ typing/types.cmx typing/typeopt.cmx typing/typedtree.cmx \ typing/typedecl.cmx typing/subst.cmx typing/stypes.cmx \ - typing/printtyp.cmx typing/primitive.cmx typing/predef.cmx \ - typing/path.cmx parsing/parsetree.cmi typing/parmatch.cmx \ - typing/oprint.cmx utils/misc.cmx parsing/longident.cmx \ - parsing/location.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \ - typing/cmt_format.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \ - typing/btype.cmx parsing/asttypes.cmi parsing/ast_helper.cmx \ - typing/annot.cmi typing/typecore.cmi + typing/printtyp.cmx typing/printpat.cmx typing/primitive.cmx \ + typing/predef.cmx typing/path.cmx parsing/parsetree.cmi \ + typing/parmatch.cmx typing/oprint.cmx typing/mtype.cmx utils/misc.cmx \ + parsing/longident.cmx parsing/location.cmx typing/ident.cmx \ + typing/env.cmx typing/ctype.cmx utils/config.cmx typing/cmt_format.cmx \ + utils/clflags.cmx parsing/builtin_attributes.cmx typing/btype.cmx \ + parsing/asttypes.cmi parsing/ast_helper.cmx typing/annot.cmi \ + typing/typecore.cmi typing/typecore.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ typing/ident.cmi typing/env.cmi parsing/asttypes.cmi typing/annot.cmi @@ -434,7 +444,8 @@ typing/typemod.cmo : utils/warnings.cmi typing/typetexp.cmi typing/types.cmi \ parsing/location.cmi typing/includemod.cmi typing/ident.cmi \ typing/env.cmi typing/ctype.cmi utils/config.cmi typing/cmt_format.cmi \ typing/cmi_format.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \ - typing/btype.cmi parsing/asttypes.cmi typing/annot.cmi typing/typemod.cmi + typing/btype.cmi parsing/attr_helper.cmi parsing/asttypes.cmi \ + typing/annot.cmi typing/typemod.cmi typing/typemod.cmx : utils/warnings.cmx typing/typetexp.cmx typing/types.cmx \ typing/typedtree.cmx typing/typedecl.cmx typing/typecore.cmx \ typing/typeclass.cmx typing/subst.cmx typing/stypes.cmx \ @@ -443,7 +454,8 @@ typing/typemod.cmx : utils/warnings.cmx typing/typetexp.cmx typing/types.cmx \ parsing/location.cmx typing/includemod.cmx typing/ident.cmx \ typing/env.cmx typing/ctype.cmx utils/config.cmx typing/cmt_format.cmx \ typing/cmi_format.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \ - typing/btype.cmx parsing/asttypes.cmi typing/annot.cmi typing/typemod.cmi + typing/btype.cmx parsing/attr_helper.cmx parsing/asttypes.cmi \ + typing/annot.cmi typing/typemod.cmi typing/typemod.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \ parsing/location.cmi typing/includemod.cmi typing/ident.cmi \ @@ -470,18 +482,20 @@ typing/types.cmi : typing/primitive.cmi typing/path.cmi \ typing/typetexp.cmo : typing/types.cmi typing/typedtree.cmi utils/tbl.cmi \ typing/printtyp.cmi typing/predef.cmi typing/path.cmi \ parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \ - parsing/location.cmi typing/env.cmi typing/ctype.cmi utils/clflags.cmi \ - parsing/builtin_attributes.cmi typing/btype.cmi parsing/asttypes.cmi \ - parsing/ast_helper.cmi typing/typetexp.cmi + parsing/location.cmi typing/includemod.cmi typing/env.cmi \ + typing/ctype.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \ + typing/btype.cmi parsing/asttypes.cmi parsing/ast_helper.cmi \ + typing/typetexp.cmi typing/typetexp.cmx : typing/types.cmx typing/typedtree.cmx utils/tbl.cmx \ typing/printtyp.cmx typing/predef.cmx typing/path.cmx \ parsing/parsetree.cmi utils/misc.cmx parsing/longident.cmx \ - parsing/location.cmx typing/env.cmx typing/ctype.cmx utils/clflags.cmx \ - parsing/builtin_attributes.cmx typing/btype.cmx parsing/asttypes.cmi \ - parsing/ast_helper.cmx typing/typetexp.cmi + parsing/location.cmx typing/includemod.cmx typing/env.cmx \ + typing/ctype.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \ + typing/btype.cmx parsing/asttypes.cmi parsing/ast_helper.cmx \ + typing/typetexp.cmi typing/typetexp.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \ parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \ - typing/env.cmi parsing/asttypes.cmi + typing/includemod.cmi typing/env.cmi parsing/asttypes.cmi typing/untypeast.cmo : typing/typedtree.cmi typing/path.cmi \ parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \ parsing/location.cmi typing/ident.cmi typing/env.cmi parsing/asttypes.cmi \ @@ -511,16 +525,16 @@ bytecomp/bytelibrarian.cmx : utils/misc.cmx parsing/location.cmx \ bytecomp/bytelibrarian.cmi : bytecomp/bytelink.cmo : utils/warnings.cmi bytecomp/symtable.cmi \ bytecomp/opcodes.cmo utils/misc.cmi parsing/location.cmi \ - bytecomp/lambda.cmi bytecomp/instruct.cmi typing/ident.cmi \ - bytecomp/emitcode.cmi bytecomp/dll.cmi utils/consistbl.cmi \ - utils/config.cmi bytecomp/cmo_format.cmi utils/clflags.cmi \ - utils/ccomp.cmi bytecomp/bytesections.cmi bytecomp/bytelink.cmi + bytecomp/instruct.cmi typing/ident.cmi bytecomp/emitcode.cmi \ + bytecomp/dll.cmi utils/consistbl.cmi utils/config.cmi \ + bytecomp/cmo_format.cmi utils/clflags.cmi utils/ccomp.cmi \ + bytecomp/bytesections.cmi bytecomp/bytelink.cmi bytecomp/bytelink.cmx : utils/warnings.cmx bytecomp/symtable.cmx \ bytecomp/opcodes.cmx utils/misc.cmx parsing/location.cmx \ - bytecomp/lambda.cmx bytecomp/instruct.cmx typing/ident.cmx \ - bytecomp/emitcode.cmx bytecomp/dll.cmx utils/consistbl.cmx \ - utils/config.cmx bytecomp/cmo_format.cmi utils/clflags.cmx \ - utils/ccomp.cmx bytecomp/bytesections.cmx bytecomp/bytelink.cmi + bytecomp/instruct.cmx typing/ident.cmx bytecomp/emitcode.cmx \ + bytecomp/dll.cmx utils/consistbl.cmx utils/config.cmx \ + bytecomp/cmo_format.cmi utils/clflags.cmx utils/ccomp.cmx \ + bytecomp/bytesections.cmx bytecomp/bytelink.cmi bytecomp/bytelink.cmi : bytecomp/symtable.cmi bytecomp/cmo_format.cmi bytecomp/bytepackager.cmo : typing/typemod.cmi bytecomp/translmod.cmi \ typing/subst.cmi bytecomp/printlambda.cmi typing/path.cmi utils/misc.cmi \ @@ -546,14 +560,14 @@ bytecomp/emitcode.cmo : bytecomp/translmod.cmi typing/primitive.cmi \ bytecomp/opcodes.cmo utils/misc.cmi bytecomp/meta.cmi \ parsing/location.cmi bytecomp/lambda.cmi bytecomp/instruct.cmi \ typing/ident.cmi typing/env.cmi utils/config.cmi bytecomp/cmo_format.cmi \ - utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \ - bytecomp/emitcode.cmi + utils/clflags.cmi bytecomp/bytegen.cmi typing/btype.cmi \ + parsing/asttypes.cmi bytecomp/emitcode.cmi bytecomp/emitcode.cmx : bytecomp/translmod.cmx typing/primitive.cmx \ bytecomp/opcodes.cmx utils/misc.cmx bytecomp/meta.cmx \ parsing/location.cmx bytecomp/lambda.cmx bytecomp/instruct.cmx \ typing/ident.cmx typing/env.cmx utils/config.cmx bytecomp/cmo_format.cmi \ - utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \ - bytecomp/emitcode.cmi + utils/clflags.cmx bytecomp/bytegen.cmx typing/btype.cmx \ + parsing/asttypes.cmi bytecomp/emitcode.cmi bytecomp/emitcode.cmi : bytecomp/instruct.cmi typing/ident.cmi \ bytecomp/cmo_format.cmi bytecomp/instruct.cmo : typing/types.cmi typing/subst.cmi \ @@ -573,16 +587,16 @@ bytecomp/lambda.cmx : typing/types.cmx typing/primitive.cmx typing/path.cmx \ bytecomp/lambda.cmi : typing/types.cmi typing/primitive.cmi typing/path.cmi \ parsing/location.cmi typing/ident.cmi typing/env.cmi parsing/asttypes.cmi bytecomp/matching.cmo : typing/types.cmi typing/typeopt.cmi \ - typing/typedtree.cmi bytecomp/switch.cmi bytecomp/printlambda.cmi \ - typing/primitive.cmi typing/predef.cmi typing/path.cmi \ - typing/parmatch.cmi utils/misc.cmi parsing/longident.cmi \ + typing/typedtree.cmi bytecomp/switch.cmi typing/printpat.cmi \ + bytecomp/printlambda.cmi typing/primitive.cmi typing/predef.cmi \ + typing/path.cmi typing/parmatch.cmi utils/misc.cmi parsing/longident.cmi \ parsing/location.cmi bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi \ utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \ bytecomp/matching.cmi bytecomp/matching.cmx : typing/types.cmx typing/typeopt.cmx \ - typing/typedtree.cmx bytecomp/switch.cmx bytecomp/printlambda.cmx \ - typing/primitive.cmx typing/predef.cmx typing/path.cmx \ - typing/parmatch.cmx utils/misc.cmx parsing/longident.cmx \ + typing/typedtree.cmx bytecomp/switch.cmx typing/printpat.cmx \ + bytecomp/printlambda.cmx typing/primitive.cmx typing/predef.cmx \ + typing/path.cmx typing/parmatch.cmx utils/misc.cmx parsing/longident.cmx \ parsing/location.cmx bytecomp/lambda.cmx typing/ident.cmx typing/env.cmx \ utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \ bytecomp/matching.cmi @@ -663,36 +677,38 @@ bytecomp/translclass.cmx : typing/types.cmx typing/typeopt.cmx \ bytecomp/translclass.cmi : typing/typedtree.cmi parsing/location.cmi \ bytecomp/lambda.cmi typing/ident.cmi parsing/asttypes.cmi bytecomp/translcore.cmo : typing/types.cmi typing/typeopt.cmi \ - typing/typedtree.cmi typing/typecore.cmi bytecomp/translobj.cmi \ - bytecomp/translattribute.cmi typing/primitive.cmi typing/predef.cmi \ - typing/path.cmi typing/parmatch.cmi utils/misc.cmi bytecomp/matching.cmi \ + typing/typedtree.cmi typing/typecore.cmi bytecomp/translprim.cmi \ + bytecomp/translobj.cmi bytecomp/translattribute.cmi typing/printtyp.cmi \ + typing/primitive.cmi typing/predef.cmi typing/path.cmi \ + typing/parmatch.cmi utils/misc.cmi bytecomp/matching.cmi \ parsing/longident.cmi parsing/location.cmi bytecomp/lambda.cmi \ typing/ident.cmi typing/env.cmi utils/config.cmi utils/clflags.cmi \ typing/btype.cmi parsing/asttypes.cmi bytecomp/translcore.cmi bytecomp/translcore.cmx : typing/types.cmx typing/typeopt.cmx \ - typing/typedtree.cmx typing/typecore.cmx bytecomp/translobj.cmx \ - bytecomp/translattribute.cmx typing/primitive.cmx typing/predef.cmx \ - typing/path.cmx typing/parmatch.cmx utils/misc.cmx bytecomp/matching.cmx \ + typing/typedtree.cmx typing/typecore.cmx bytecomp/translprim.cmx \ + bytecomp/translobj.cmx bytecomp/translattribute.cmx typing/printtyp.cmx \ + typing/primitive.cmx typing/predef.cmx typing/path.cmx \ + typing/parmatch.cmx utils/misc.cmx bytecomp/matching.cmx \ parsing/longident.cmx parsing/location.cmx bytecomp/lambda.cmx \ typing/ident.cmx typing/env.cmx utils/config.cmx utils/clflags.cmx \ typing/btype.cmx parsing/asttypes.cmi bytecomp/translcore.cmi -bytecomp/translcore.cmi : typing/types.cmi typing/typedtree.cmi \ - typing/primitive.cmi typing/path.cmi parsing/location.cmi \ - bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi parsing/asttypes.cmi +bytecomp/translcore.cmi : typing/typedtree.cmi typing/path.cmi \ + parsing/location.cmi bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi \ + parsing/asttypes.cmi bytecomp/translmod.cmo : typing/types.cmi typing/typedtree.cmi \ - bytecomp/translobj.cmi bytecomp/translcore.cmi bytecomp/translclass.cmi \ - bytecomp/translattribute.cmi typing/printtyp.cmi typing/primitive.cmi \ - typing/predef.cmi typing/path.cmi typing/mtype.cmi utils/misc.cmi \ - parsing/longident.cmi parsing/location.cmi bytecomp/lambda.cmi \ - typing/ident.cmi typing/env.cmi typing/ctype.cmi utils/clflags.cmi \ - parsing/asttypes.cmi bytecomp/translmod.cmi + bytecomp/translprim.cmi bytecomp/translobj.cmi bytecomp/translcore.cmi \ + bytecomp/translclass.cmi bytecomp/translattribute.cmi typing/printtyp.cmi \ + typing/primitive.cmi typing/predef.cmi typing/path.cmi typing/mtype.cmi \ + utils/misc.cmi parsing/longident.cmi parsing/location.cmi \ + bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \ + utils/clflags.cmi parsing/asttypes.cmi bytecomp/translmod.cmi bytecomp/translmod.cmx : typing/types.cmx typing/typedtree.cmx \ - bytecomp/translobj.cmx bytecomp/translcore.cmx bytecomp/translclass.cmx \ - bytecomp/translattribute.cmx typing/printtyp.cmx typing/primitive.cmx \ - typing/predef.cmx typing/path.cmx typing/mtype.cmx utils/misc.cmx \ - parsing/longident.cmx parsing/location.cmx bytecomp/lambda.cmx \ - typing/ident.cmx typing/env.cmx typing/ctype.cmx utils/clflags.cmx \ - parsing/asttypes.cmi bytecomp/translmod.cmi + bytecomp/translprim.cmx bytecomp/translobj.cmx bytecomp/translcore.cmx \ + bytecomp/translclass.cmx bytecomp/translattribute.cmx typing/printtyp.cmx \ + typing/primitive.cmx typing/predef.cmx typing/path.cmx typing/mtype.cmx \ + utils/misc.cmx parsing/longident.cmx parsing/location.cmx \ + bytecomp/lambda.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \ + utils/clflags.cmx parsing/asttypes.cmi bytecomp/translmod.cmi bytecomp/translmod.cmi : typing/typedtree.cmi typing/primitive.cmi \ parsing/location.cmi bytecomp/lambda.cmi typing/ident.cmi bytecomp/translobj.cmo : typing/primitive.cmi utils/misc.cmi \ @@ -704,6 +720,19 @@ bytecomp/translobj.cmx : typing/primitive.cmx utils/misc.cmx \ typing/ident.cmx typing/env.cmx utils/config.cmx utils/clflags.cmx \ typing/btype.cmx parsing/asttypes.cmi bytecomp/translobj.cmi bytecomp/translobj.cmi : bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi +bytecomp/translprim.cmo : typing/types.cmi typing/typeopt.cmi \ + typing/typedtree.cmi typing/primitive.cmi typing/predef.cmi \ + typing/path.cmi utils/misc.cmi bytecomp/matching.cmi parsing/location.cmi \ + bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi utils/config.cmi \ + utils/clflags.cmi parsing/asttypes.cmi bytecomp/translprim.cmi +bytecomp/translprim.cmx : typing/types.cmx typing/typeopt.cmx \ + typing/typedtree.cmx typing/primitive.cmx typing/predef.cmx \ + typing/path.cmx utils/misc.cmx bytecomp/matching.cmx parsing/location.cmx \ + bytecomp/lambda.cmx typing/ident.cmx typing/env.cmx utils/config.cmx \ + utils/clflags.cmx parsing/asttypes.cmi bytecomp/translprim.cmi +bytecomp/translprim.cmi : typing/types.cmi typing/typedtree.cmi \ + typing/primitive.cmi typing/path.cmi parsing/location.cmi \ + bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi asmcomp/CSE.cmo : asmcomp/mach.cmi asmcomp/CSEgen.cmi asmcomp/arch.cmo asmcomp/CSE.cmx : asmcomp/mach.cmx asmcomp/CSEgen.cmx asmcomp/arch.cmx asmcomp/CSEgen.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \ @@ -766,13 +795,13 @@ asmcomp/asmlibrarian.cmi : asmcomp/asmlink.cmo : bytecomp/runtimedef.cmi utils/profile.cmi \ utils/misc.cmi parsing/location.cmi asmcomp/emitaux.cmi asmcomp/emit.cmi \ utils/consistbl.cmi utils/config.cmi asmcomp/compilenv.cmi \ - asmcomp/cmx_format.cmi asmcomp/cmmgen.cmi utils/clflags.cmi \ - utils/ccomp.cmi asmcomp/asmgen.cmi asmcomp/asmlink.cmi + asmcomp/cmx_format.cmi asmcomp/cmmgen.cmi asmcomp/cmm.cmi \ + utils/clflags.cmi utils/ccomp.cmi asmcomp/asmgen.cmi asmcomp/asmlink.cmi asmcomp/asmlink.cmx : bytecomp/runtimedef.cmx utils/profile.cmx \ utils/misc.cmx parsing/location.cmx asmcomp/emitaux.cmx asmcomp/emit.cmx \ utils/consistbl.cmx utils/config.cmx asmcomp/compilenv.cmx \ - asmcomp/cmx_format.cmi asmcomp/cmmgen.cmx utils/clflags.cmx \ - utils/ccomp.cmx asmcomp/asmgen.cmx asmcomp/asmlink.cmi + asmcomp/cmx_format.cmi asmcomp/cmmgen.cmx asmcomp/cmm.cmx \ + utils/clflags.cmx utils/ccomp.cmx asmcomp/asmgen.cmx asmcomp/asmlink.cmi asmcomp/asmlink.cmi : asmcomp/cmx_format.cmi asmcomp/asmpackager.cmo : typing/typemod.cmi bytecomp/translmod.cmi \ utils/profile.cmi utils/misc.cmi middle_end/middle_end.cmi \ @@ -805,21 +834,27 @@ asmcomp/branch_relaxation_intf.cmx : asmcomp/linearize.cmx asmcomp/cmm.cmx \ asmcomp/arch.cmx asmcomp/build_export_info.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ - middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ + asmcomp/traverse_for_exported_symbols.cmi middle_end/base_types/tag.cmi \ + middle_end/base_types/symbol.cmi middle_end/simple_value_approx.cmi \ middle_end/base_types/set_of_closures_id.cmi utils/misc.cmi \ - middle_end/invariant_params.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi asmcomp/export_info.cmi \ + middle_end/invariant_params.cmi middle_end/inline_and_simplify_aux.cmi \ + middle_end/flambda_utils.cmi middle_end/flambda.cmi \ + middle_end/find_recursive_functions.cmi asmcomp/export_info.cmi \ middle_end/base_types/export_id.cmi asmcomp/compilenv.cmi \ + middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ middle_end/backend_intf.cmi middle_end/allocated_const.cmi \ asmcomp/build_export_info.cmi asmcomp/build_export_info.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ - middle_end/base_types/tag.cmx middle_end/base_types/symbol.cmx \ + asmcomp/traverse_for_exported_symbols.cmx middle_end/base_types/tag.cmx \ + middle_end/base_types/symbol.cmx middle_end/simple_value_approx.cmx \ middle_end/base_types/set_of_closures_id.cmx utils/misc.cmx \ - middle_end/invariant_params.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx asmcomp/export_info.cmx \ + middle_end/invariant_params.cmx middle_end/inline_and_simplify_aux.cmx \ + middle_end/flambda_utils.cmx middle_end/flambda.cmx \ + middle_end/find_recursive_functions.cmx asmcomp/export_info.cmx \ middle_end/base_types/export_id.cmx asmcomp/compilenv.cmx \ + middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ middle_end/backend_intf.cmi middle_end/allocated_const.cmx \ asmcomp/build_export_info.cmi @@ -848,14 +883,12 @@ asmcomp/closure.cmx : utils/warnings.cmx utils/tbl.cmx bytecomp/switch.cmx \ asmcomp/closure.cmi : bytecomp/lambda.cmi asmcomp/clambda.cmi asmcomp/closure_offsets.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi utils/misc.cmi \ - middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ - middle_end/flambda.cmi middle_end/base_types/closure_id.cmi \ - asmcomp/closure_offsets.cmi + middle_end/flambda_utils.cmi middle_end/flambda.cmi \ + middle_end/base_types/closure_id.cmi asmcomp/closure_offsets.cmi asmcomp/closure_offsets.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx utils/misc.cmx \ - middle_end/flambda_utils.cmx middle_end/flambda_iterators.cmx \ - middle_end/flambda.cmx middle_end/base_types/closure_id.cmx \ - asmcomp/closure_offsets.cmi + middle_end/flambda_utils.cmx middle_end/flambda.cmx \ + middle_end/base_types/closure_id.cmx asmcomp/closure_offsets.cmi asmcomp/closure_offsets.cmi : middle_end/base_types/var_within_closure.cmi \ middle_end/flambda.cmi middle_end/base_types/closure_id.cmi asmcomp/cmm.cmo : bytecomp/lambda.cmi typing/ident.cmi \ @@ -892,27 +925,28 @@ asmcomp/comballoc.cmx : asmcomp/reg.cmx asmcomp/mach.cmx utils/config.cmx \ asmcomp/arch.cmx asmcomp/comballoc.cmi asmcomp/comballoc.cmi : asmcomp/mach.cmi asmcomp/compilenv.cmo : utils/warnings.cmi middle_end/base_types/symbol.cmi \ + middle_end/simple_value_approx.cmi \ middle_end/base_types/set_of_closures_id.cmi utils/misc.cmi \ parsing/location.cmi middle_end/base_types/linkage_name.cmi \ - typing/ident.cmi middle_end/flambda.cmi asmcomp/export_info.cmi \ - typing/env.cmi utils/config.cmi \ + typing/ident.cmi asmcomp/export_info.cmi typing/env.cmi utils/config.cmi \ middle_end/base_types/compilation_unit.cmi asmcomp/cmx_format.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ asmcomp/clambda.cmi asmcomp/compilenv.cmi asmcomp/compilenv.cmx : utils/warnings.cmx middle_end/base_types/symbol.cmx \ + middle_end/simple_value_approx.cmx \ middle_end/base_types/set_of_closures_id.cmx utils/misc.cmx \ parsing/location.cmx middle_end/base_types/linkage_name.cmx \ - typing/ident.cmx middle_end/flambda.cmx asmcomp/export_info.cmx \ - typing/env.cmx utils/config.cmx \ + typing/ident.cmx asmcomp/export_info.cmx typing/env.cmx utils/config.cmx \ middle_end/base_types/compilation_unit.cmx asmcomp/cmx_format.cmi \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ asmcomp/clambda.cmx asmcomp/compilenv.cmi asmcomp/compilenv.cmi : middle_end/base_types/symbol.cmi \ + middle_end/simple_value_approx.cmi \ middle_end/base_types/set_of_closures_id.cmi \ middle_end/base_types/linkage_name.cmi typing/ident.cmi \ - middle_end/flambda.cmi asmcomp/export_info.cmi \ - middle_end/base_types/compilation_unit.cmi asmcomp/cmx_format.cmi \ - middle_end/base_types/closure_id.cmi asmcomp/clambda.cmi + asmcomp/export_info.cmi middle_end/base_types/compilation_unit.cmi \ + asmcomp/cmx_format.cmi middle_end/base_types/closure_id.cmi \ + asmcomp/clambda.cmi asmcomp/deadcode.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \ utils/config.cmi asmcomp/deadcode.cmi asmcomp/deadcode.cmx : asmcomp/reg.cmx asmcomp/proc.cmx asmcomp/mach.cmx \ @@ -962,22 +996,20 @@ asmcomp/export_info.cmi : middle_end/base_types/variable.cmi \ middle_end/base_types/closure_id.cmi asmcomp/export_info_for_pack.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ - middle_end/base_types/symbol.cmi \ + middle_end/base_types/symbol.cmi middle_end/simple_value_approx.cmi \ middle_end/base_types/set_of_closures_origin.cmi \ middle_end/base_types/set_of_closures_id.cmi utils/misc.cmi \ - middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ - middle_end/flambda.cmi asmcomp/export_info.cmi \ - middle_end/base_types/export_id.cmi \ + middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ + asmcomp/export_info.cmi middle_end/base_types/export_id.cmi \ middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/closure_id.cmi asmcomp/export_info_for_pack.cmi asmcomp/export_info_for_pack.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ - middle_end/base_types/symbol.cmx \ + middle_end/base_types/symbol.cmx middle_end/simple_value_approx.cmx \ middle_end/base_types/set_of_closures_origin.cmx \ middle_end/base_types/set_of_closures_id.cmx utils/misc.cmx \ - middle_end/flambda_utils.cmx middle_end/flambda_iterators.cmx \ - middle_end/flambda.cmx asmcomp/export_info.cmx \ - middle_end/base_types/export_id.cmx \ + middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ + asmcomp/export_info.cmx middle_end/base_types/export_id.cmx \ middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/closure_id.cmx asmcomp/export_info_for_pack.cmi asmcomp/export_info_for_pack.cmi : asmcomp/export_info.cmi \ @@ -986,10 +1018,12 @@ asmcomp/flambda_to_clambda.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ middle_end/base_types/static_exception.cmi \ + middle_end/simple_value_approx.cmi \ middle_end/base_types/set_of_closures_id.cmi typing/primitive.cmi \ middle_end/parameter.cmi utils/numbers.cmi \ middle_end/base_types/mutable_variable.cmi utils/misc.cmi \ - middle_end/base_types/linkage_name.cmi typing/ident.cmi \ + middle_end/base_types/linkage_name.cmi \ + middle_end/initialize_symbol_to_let_symbol.cmi typing/ident.cmi \ middle_end/flambda_utils.cmi middle_end/flambda.cmi \ asmcomp/export_info.cmi middle_end/debuginfo.cmi asmcomp/compilenv.cmi \ asmcomp/closure_offsets.cmi middle_end/base_types/closure_id.cmi \ @@ -999,10 +1033,12 @@ asmcomp/flambda_to_clambda.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ middle_end/base_types/tag.cmx middle_end/base_types/symbol.cmx \ middle_end/base_types/static_exception.cmx \ + middle_end/simple_value_approx.cmx \ middle_end/base_types/set_of_closures_id.cmx typing/primitive.cmx \ middle_end/parameter.cmx utils/numbers.cmx \ middle_end/base_types/mutable_variable.cmx utils/misc.cmx \ - middle_end/base_types/linkage_name.cmx typing/ident.cmx \ + middle_end/base_types/linkage_name.cmx \ + middle_end/initialize_symbol_to_let_symbol.cmx typing/ident.cmx \ middle_end/flambda_utils.cmx middle_end/flambda.cmx \ asmcomp/export_info.cmx middle_end/debuginfo.cmx asmcomp/compilenv.cmx \ asmcomp/closure_offsets.cmx middle_end/base_types/closure_id.cmx \ @@ -1017,6 +1053,7 @@ asmcomp/import_approx.cmo : middle_end/base_types/variable.cmi \ middle_end/freshening.cmi middle_end/flambda_iterators.cmi \ middle_end/flambda.cmi asmcomp/export_info.cmi \ middle_end/base_types/export_id.cmi asmcomp/compilenv.cmi \ + middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/closure_id.cmi asmcomp/import_approx.cmi asmcomp/import_approx.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ @@ -1025,6 +1062,7 @@ asmcomp/import_approx.cmx : middle_end/base_types/variable.cmx \ middle_end/freshening.cmx middle_end/flambda_iterators.cmx \ middle_end/flambda.cmx asmcomp/export_info.cmx \ middle_end/base_types/export_id.cmx asmcomp/compilenv.cmx \ + middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/closure_id.cmx asmcomp/import_approx.cmi asmcomp/import_approx.cmi : middle_end/base_types/symbol.cmi \ middle_end/simple_value_approx.cmi @@ -1177,6 +1215,32 @@ asmcomp/strmatch.cmx : parsing/location.cmx bytecomp/lambda.cmx \ parsing/asttypes.cmi asmcomp/arch.cmx asmcomp/strmatch.cmi asmcomp/strmatch.cmi : parsing/location.cmi middle_end/debuginfo.cmi \ asmcomp/cmm.cmi +asmcomp/traverse_for_exported_symbols.cmo : \ + middle_end/base_types/variable.cmi \ + middle_end/base_types/var_within_closure.cmi \ + middle_end/base_types/symbol.cmi middle_end/simple_value_approx.cmi \ + middle_end/base_types/set_of_closures_id.cmi utils/misc.cmi \ + middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ + asmcomp/export_info.cmi middle_end/base_types/export_id.cmi \ + middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_id.cmi \ + asmcomp/traverse_for_exported_symbols.cmi +asmcomp/traverse_for_exported_symbols.cmx : \ + middle_end/base_types/variable.cmx \ + middle_end/base_types/var_within_closure.cmx \ + middle_end/base_types/symbol.cmx middle_end/simple_value_approx.cmx \ + middle_end/base_types/set_of_closures_id.cmx utils/misc.cmx \ + middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ + asmcomp/export_info.cmx middle_end/base_types/export_id.cmx \ + middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_id.cmx \ + asmcomp/traverse_for_exported_symbols.cmi +asmcomp/traverse_for_exported_symbols.cmi : \ + middle_end/base_types/var_within_closure.cmi \ + middle_end/base_types/symbol.cmi middle_end/simple_value_approx.cmi \ + middle_end/base_types/set_of_closures_id.cmi middle_end/flambda.cmi \ + asmcomp/export_info.cmi middle_end/base_types/export_id.cmi \ + middle_end/base_types/closure_id.cmi asmcomp/un_anf.cmo : bytecomp/semantics_of_primitives.cmi \ asmcomp/printclambda.cmi utils/misc.cmi bytecomp/lambda.cmi \ typing/ident.cmi middle_end/debuginfo.cmi utils/clflags.cmi \ @@ -1228,20 +1292,22 @@ middle_end/allocated_const.cmx : middle_end/allocated_const.cmi middle_end/allocated_const.cmi : middle_end/augment_specialised_args.cmo : middle_end/base_types/variable.cmi \ middle_end/projection.cmi middle_end/pass_wrapper.cmi \ - middle_end/parameter.cmi utils/misc.cmi middle_end/inlining_cost.cmi \ + middle_end/parameter.cmi utils/misc.cmi \ + middle_end/internal_variable_names.cmi middle_end/inlining_cost.cmi \ middle_end/inline_and_simplify_aux.cmi utils/identifiable.cmi \ middle_end/flambda_utils.cmi middle_end/flambda.cmi \ - middle_end/debuginfo.cmi middle_end/base_types/closure_id.cmi \ - utils/clflags.cmi middle_end/backend_intf.cmi \ - middle_end/augment_specialised_args.cmi + middle_end/debuginfo.cmi middle_end/base_types/closure_origin.cmi \ + middle_end/base_types/closure_id.cmi utils/clflags.cmi \ + middle_end/backend_intf.cmi middle_end/augment_specialised_args.cmi middle_end/augment_specialised_args.cmx : middle_end/base_types/variable.cmx \ middle_end/projection.cmx middle_end/pass_wrapper.cmx \ - middle_end/parameter.cmx utils/misc.cmx middle_end/inlining_cost.cmx \ + middle_end/parameter.cmx utils/misc.cmx \ + middle_end/internal_variable_names.cmx middle_end/inlining_cost.cmx \ middle_end/inline_and_simplify_aux.cmx utils/identifiable.cmx \ middle_end/flambda_utils.cmx middle_end/flambda.cmx \ - middle_end/debuginfo.cmx middle_end/base_types/closure_id.cmx \ - utils/clflags.cmx middle_end/backend_intf.cmi \ - middle_end/augment_specialised_args.cmi + middle_end/debuginfo.cmx middle_end/base_types/closure_origin.cmx \ + middle_end/base_types/closure_id.cmx utils/clflags.cmx \ + middle_end/backend_intf.cmi middle_end/augment_specialised_args.cmi middle_end/augment_specialised_args.cmi : middle_end/base_types/variable.cmi \ middle_end/projection.cmi middle_end/inlining_cost.cmi \ middle_end/inline_and_simplify_aux.cmi middle_end/flambda.cmi @@ -1251,26 +1317,28 @@ middle_end/backend_intf.cmi : middle_end/base_types/symbol.cmi \ middle_end/closure_conversion.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ middle_end/base_types/static_exception.cmi bytecomp/simplif.cmi \ - bytecomp/printlambda.cmi typing/predef.cmi middle_end/parameter.cmi \ - utils/numbers.cmi middle_end/base_types/mutable_variable.cmi \ - utils/misc.cmi parsing/location.cmi \ - middle_end/base_types/linkage_name.cmi middle_end/lift_code.cmi \ - bytecomp/lambda.cmi typing/ident.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi middle_end/debuginfo.cmi utils/config.cmi \ + typing/predef.cmi middle_end/parameter.cmi utils/numbers.cmi \ + middle_end/base_types/mutable_variable.cmi utils/misc.cmi \ + middle_end/lift_code.cmi bytecomp/lambda.cmi \ + middle_end/internal_variable_names.cmi typing/ident.cmi \ + middle_end/flambda_utils.cmi middle_end/flambda.cmi \ + middle_end/debuginfo.cmi utils/config.cmi \ middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi \ middle_end/closure_conversion_aux.cmi utils/clflags.cmi \ middle_end/backend_intf.cmi middle_end/closure_conversion.cmi middle_end/closure_conversion.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/tag.cmx middle_end/base_types/symbol.cmx \ middle_end/base_types/static_exception.cmx bytecomp/simplif.cmx \ - bytecomp/printlambda.cmx typing/predef.cmx middle_end/parameter.cmx \ - utils/numbers.cmx middle_end/base_types/mutable_variable.cmx \ - utils/misc.cmx parsing/location.cmx \ - middle_end/base_types/linkage_name.cmx middle_end/lift_code.cmx \ - bytecomp/lambda.cmx typing/ident.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx middle_end/debuginfo.cmx utils/config.cmx \ + typing/predef.cmx middle_end/parameter.cmx utils/numbers.cmx \ + middle_end/base_types/mutable_variable.cmx utils/misc.cmx \ + middle_end/lift_code.cmx bytecomp/lambda.cmx \ + middle_end/internal_variable_names.cmx typing/ident.cmx \ + middle_end/flambda_utils.cmx middle_end/flambda.cmx \ + middle_end/debuginfo.cmx utils/config.cmx \ middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx \ middle_end/closure_conversion_aux.cmx utils/clflags.cmx \ middle_end/backend_intf.cmi middle_end/closure_conversion.cmi @@ -1335,6 +1403,7 @@ middle_end/flambda.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/mutable_variable.cmi utils/misc.cmi \ bytecomp/lambda.cmi utils/identifiable.cmi middle_end/debuginfo.cmi \ middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ parsing/asttypes.cmi middle_end/allocated_const.cmi \ middle_end/flambda.cmi @@ -1347,6 +1416,7 @@ middle_end/flambda.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/mutable_variable.cmx utils/misc.cmx \ bytecomp/lambda.cmx utils/identifiable.cmx middle_end/debuginfo.cmx \ middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ parsing/asttypes.cmi middle_end/allocated_const.cmx \ middle_end/flambda.cmi @@ -1358,6 +1428,7 @@ middle_end/flambda.cmi : middle_end/base_types/variable.cmi \ middle_end/parameter.cmi utils/numbers.cmi \ middle_end/base_types/mutable_variable.cmi bytecomp/lambda.cmi \ utils/identifiable.cmi middle_end/debuginfo.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi parsing/asttypes.cmi \ middle_end/allocated_const.cmi middle_end/flambda_invariants.cmo : middle_end/base_types/variable.cmi \ @@ -1399,9 +1470,10 @@ middle_end/flambda_utils.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/static_exception.cmi \ middle_end/base_types/set_of_closures_id.cmi middle_end/projection.cmi \ middle_end/parameter.cmi middle_end/base_types/mutable_variable.cmi \ - utils/misc.cmi middle_end/base_types/linkage_name.cmi bytecomp/lambda.cmi \ + utils/misc.cmi bytecomp/lambda.cmi middle_end/internal_variable_names.cmi \ middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ middle_end/debuginfo.cmi middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi middle_end/backend_intf.cmi \ middle_end/allocated_const.cmi middle_end/flambda_utils.cmi middle_end/flambda_utils.cmx : middle_end/base_types/variable.cmx \ @@ -1410,9 +1482,10 @@ middle_end/flambda_utils.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/static_exception.cmx \ middle_end/base_types/set_of_closures_id.cmx middle_end/projection.cmx \ middle_end/parameter.cmx middle_end/base_types/mutable_variable.cmx \ - utils/misc.cmx middle_end/base_types/linkage_name.cmx bytecomp/lambda.cmx \ + utils/misc.cmx bytecomp/lambda.cmx middle_end/internal_variable_names.cmx \ middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ middle_end/debuginfo.cmx middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx middle_end/backend_intf.cmi \ middle_end/allocated_const.cmx middle_end/flambda_utils.cmi middle_end/flambda_utils.cmi : middle_end/base_types/variable.cmi \ @@ -1420,8 +1493,9 @@ middle_end/flambda_utils.cmi : middle_end/base_types/variable.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ bytecomp/switch.cmi middle_end/base_types/static_exception.cmi \ middle_end/base_types/set_of_closures_id.cmi middle_end/projection.cmi \ - middle_end/parameter.cmi middle_end/flambda.cmi \ - middle_end/base_types/closure_id.cmi middle_end/backend_intf.cmi + middle_end/parameter.cmi middle_end/internal_variable_names.cmi \ + middle_end/flambda.cmi middle_end/base_types/closure_id.cmi \ + middle_end/backend_intf.cmi middle_end/freshening.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ middle_end/base_types/symbol.cmi \ @@ -1482,12 +1556,13 @@ middle_end/inline_and_simplify.cmo : utils/warnings.cmi \ middle_end/remove_free_vars_equal_to_args.cmi middle_end/projection.cmi \ typing/predef.cmi middle_end/parameter.cmi utils/misc.cmi \ parsing/location.cmi middle_end/lift_code.cmi bytecomp/lambda.cmi \ - middle_end/invariant_params.cmi middle_end/inlining_stats.cmi \ - middle_end/inlining_decision.cmi middle_end/inlining_cost.cmi \ - middle_end/inline_and_simplify_aux.cmi typing/ident.cmi \ - middle_end/freshening.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi middle_end/effect_analysis.cmi \ - middle_end/debuginfo.cmi utils/config.cmi \ + middle_end/invariant_params.cmi middle_end/internal_variable_names.cmi \ + middle_end/inlining_stats.cmi middle_end/inlining_decision.cmi \ + middle_end/inlining_cost.cmi middle_end/inline_and_simplify_aux.cmi \ + typing/ident.cmi middle_end/freshening.cmi middle_end/flambda_utils.cmi \ + middle_end/flambda.cmi middle_end/find_recursive_functions.cmi \ + middle_end/effect_analysis.cmi middle_end/debuginfo.cmi utils/config.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ middle_end/backend_intf.cmi middle_end/allocated_const.cmi \ middle_end/inline_and_simplify.cmi @@ -1503,12 +1578,13 @@ middle_end/inline_and_simplify.cmx : utils/warnings.cmx \ middle_end/remove_free_vars_equal_to_args.cmx middle_end/projection.cmx \ typing/predef.cmx middle_end/parameter.cmx utils/misc.cmx \ parsing/location.cmx middle_end/lift_code.cmx bytecomp/lambda.cmx \ - middle_end/invariant_params.cmx middle_end/inlining_stats.cmx \ - middle_end/inlining_decision.cmx middle_end/inlining_cost.cmx \ - middle_end/inline_and_simplify_aux.cmx typing/ident.cmx \ - middle_end/freshening.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx middle_end/effect_analysis.cmx \ - middle_end/debuginfo.cmx utils/config.cmx \ + middle_end/invariant_params.cmx middle_end/internal_variable_names.cmx \ + middle_end/inlining_stats.cmx middle_end/inlining_decision.cmx \ + middle_end/inlining_cost.cmx middle_end/inline_and_simplify_aux.cmx \ + typing/ident.cmx middle_end/freshening.cmx middle_end/flambda_utils.cmx \ + middle_end/flambda.cmx middle_end/find_recursive_functions.cmx \ + middle_end/effect_analysis.cmx middle_end/debuginfo.cmx utils/config.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ middle_end/backend_intf.cmi middle_end/allocated_const.cmx \ middle_end/inline_and_simplify.cmi @@ -1524,8 +1600,10 @@ middle_end/inline_and_simplify_aux.cmo : middle_end/base_types/variable.cmi \ middle_end/projection.cmi middle_end/parameter.cmi \ middle_end/base_types/mutable_variable.cmi utils/misc.cmi \ middle_end/inlining_stats.cmi middle_end/inlining_cost.cmi \ - middle_end/freshening.cmi middle_end/flambda.cmi middle_end/debuginfo.cmi \ + middle_end/freshening.cmi middle_end/flambda_utils.cmi \ + middle_end/flambda.cmi middle_end/debuginfo.cmi \ middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ middle_end/backend_intf.cmi middle_end/inline_and_simplify_aux.cmi middle_end/inline_and_simplify_aux.cmx : middle_end/base_types/variable.cmx \ @@ -1537,8 +1615,10 @@ middle_end/inline_and_simplify_aux.cmx : middle_end/base_types/variable.cmx \ middle_end/projection.cmx middle_end/parameter.cmx \ middle_end/base_types/mutable_variable.cmx utils/misc.cmx \ middle_end/inlining_stats.cmx middle_end/inlining_cost.cmx \ - middle_end/freshening.cmx middle_end/flambda.cmx middle_end/debuginfo.cmx \ + middle_end/freshening.cmx middle_end/flambda_utils.cmx \ + middle_end/flambda.cmx middle_end/debuginfo.cmx \ middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ middle_end/backend_intf.cmi middle_end/inline_and_simplify_aux.cmi middle_end/inline_and_simplify_aux.cmi : middle_end/base_types/variable.cmi \ @@ -1549,6 +1629,7 @@ middle_end/inline_and_simplify_aux.cmi : middle_end/base_types/variable.cmi \ middle_end/projection.cmi middle_end/base_types/mutable_variable.cmi \ middle_end/inlining_stats_types.cmi middle_end/inlining_cost.cmi \ middle_end/freshening.cmi middle_end/flambda.cmi middle_end/debuginfo.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi middle_end/backend_intf.cmi middle_end/inlining_cost.cmo : middle_end/base_types/variable.cmi \ middle_end/projection.cmi typing/primitive.cmi utils/misc.cmi \ @@ -1565,8 +1646,7 @@ middle_end/inlining_decision.cmo : middle_end/base_types/variable.cmi \ middle_end/simple_value_approx.cmi middle_end/parameter.cmi \ utils/misc.cmi bytecomp/lambda.cmi middle_end/inlining_transforms.cmi \ middle_end/inlining_stats_types.cmi middle_end/inlining_cost.cmi \ - middle_end/inline_and_simplify_aux.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi middle_end/find_recursive_functions.cmi \ + middle_end/inline_and_simplify_aux.cmi middle_end/flambda.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ middle_end/inlining_decision.cmi middle_end/inlining_decision.cmx : middle_end/base_types/variable.cmx \ @@ -1574,8 +1654,7 @@ middle_end/inlining_decision.cmx : middle_end/base_types/variable.cmx \ middle_end/simple_value_approx.cmx middle_end/parameter.cmx \ utils/misc.cmx bytecomp/lambda.cmx middle_end/inlining_transforms.cmx \ middle_end/inlining_stats_types.cmx middle_end/inlining_cost.cmx \ - middle_end/inline_and_simplify_aux.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx middle_end/find_recursive_functions.cmx \ + middle_end/inline_and_simplify_aux.cmx middle_end/flambda.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ middle_end/inlining_decision.cmi middle_end/inlining_decision.cmi : middle_end/base_types/variable.cmi \ @@ -1604,27 +1683,37 @@ middle_end/inlining_stats_types.cmx : middle_end/inlining_cost.cmx \ middle_end/inlining_stats_types.cmi : middle_end/inlining_cost.cmi middle_end/inlining_transforms.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ - middle_end/simple_value_approx.cmi middle_end/parameter.cmi \ - utils/misc.cmi bytecomp/lambda.cmi middle_end/inlining_cost.cmi \ - middle_end/inline_and_simplify_aux.cmi middle_end/freshening.cmi \ - middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ - middle_end/flambda.cmi middle_end/base_types/compilation_unit.cmi \ - middle_end/base_types/closure_id.cmi middle_end/backend_intf.cmi \ - middle_end/inlining_transforms.cmi + middle_end/simple_value_approx.cmi middle_end/projection.cmi \ + middle_end/parameter.cmi bytecomp/lambda.cmi \ + middle_end/internal_variable_names.cmi \ + middle_end/inlining_decision_intf.cmi middle_end/inlining_cost.cmi \ + middle_end/inline_and_simplify_aux.cmi middle_end/flambda_utils.cmi \ + middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ + middle_end/debuginfo.cmi middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ + middle_end/base_types/closure_id.cmi middle_end/inlining_transforms.cmi middle_end/inlining_transforms.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ - middle_end/simple_value_approx.cmx middle_end/parameter.cmx \ - utils/misc.cmx bytecomp/lambda.cmx middle_end/inlining_cost.cmx \ - middle_end/inline_and_simplify_aux.cmx middle_end/freshening.cmx \ - middle_end/flambda_utils.cmx middle_end/flambda_iterators.cmx \ - middle_end/flambda.cmx middle_end/base_types/compilation_unit.cmx \ - middle_end/base_types/closure_id.cmx middle_end/backend_intf.cmi \ - middle_end/inlining_transforms.cmi + middle_end/simple_value_approx.cmx middle_end/projection.cmx \ + middle_end/parameter.cmx bytecomp/lambda.cmx \ + middle_end/internal_variable_names.cmx \ + middle_end/inlining_decision_intf.cmi middle_end/inlining_cost.cmx \ + middle_end/inline_and_simplify_aux.cmx middle_end/flambda_utils.cmx \ + middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ + middle_end/debuginfo.cmx middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ + middle_end/base_types/closure_id.cmx middle_end/inlining_transforms.cmi middle_end/inlining_transforms.cmi : middle_end/base_types/variable.cmi \ middle_end/simple_value_approx.cmi bytecomp/lambda.cmi \ middle_end/inlining_decision_intf.cmi \ middle_end/inline_and_simplify_aux.cmi middle_end/flambda.cmi \ middle_end/debuginfo.cmi middle_end/base_types/closure_id.cmi +middle_end/internal_variable_names.cmo : parsing/location.cmi \ + bytecomp/lambda.cmi middle_end/internal_variable_names.cmi +middle_end/internal_variable_names.cmx : parsing/location.cmx \ + bytecomp/lambda.cmx middle_end/internal_variable_names.cmi +middle_end/internal_variable_names.cmi : parsing/location.cmi \ + bytecomp/lambda.cmi middle_end/invariant_params.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/symbol.cmi middle_end/parameter.cmi \ middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ @@ -1648,13 +1737,13 @@ middle_end/lift_code.cmx : middle_end/base_types/variable.cmx \ middle_end/flambda.cmx middle_end/base_types/compilation_unit.cmx \ middle_end/lift_code.cmi middle_end/lift_code.cmi : middle_end/base_types/variable.cmi \ - middle_end/flambda.cmi + middle_end/internal_variable_names.cmi middle_end/flambda.cmi middle_end/lift_constants.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ utils/strongly_connected_components.cmi \ middle_end/simple_value_approx.cmi utils/misc.cmi \ - middle_end/base_types/linkage_name.cmi middle_end/inconstant_idents.cmi \ + middle_end/internal_variable_names.cmi middle_end/inconstant_idents.cmi \ middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ middle_end/flambda.cmi middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/closure_id.cmi middle_end/backend_intf.cmi \ @@ -1665,7 +1754,7 @@ middle_end/lift_constants.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/tag.cmx middle_end/base_types/symbol.cmx \ utils/strongly_connected_components.cmx \ middle_end/simple_value_approx.cmx utils/misc.cmx \ - middle_end/base_types/linkage_name.cmx middle_end/inconstant_idents.cmx \ + middle_end/internal_variable_names.cmx middle_end/inconstant_idents.cmx \ middle_end/flambda_utils.cmx middle_end/flambda_iterators.cmx \ middle_end/flambda.cmx middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/closure_id.cmx middle_end/backend_intf.cmi \ @@ -1675,13 +1764,15 @@ middle_end/lift_constants.cmi : middle_end/flambda.cmi \ middle_end/backend_intf.cmi middle_end/lift_let_to_initialize_symbol.cmo : \ middle_end/base_types/variable.cmi middle_end/base_types/tag.cmi \ - middle_end/base_types/symbol.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi middle_end/debuginfo.cmi parsing/asttypes.cmi \ + middle_end/base_types/symbol.cmi middle_end/internal_variable_names.cmi \ + middle_end/flambda_utils.cmi middle_end/flambda.cmi \ + middle_end/debuginfo.cmi parsing/asttypes.cmi \ middle_end/lift_let_to_initialize_symbol.cmi middle_end/lift_let_to_initialize_symbol.cmx : \ middle_end/base_types/variable.cmx middle_end/base_types/tag.cmx \ - middle_end/base_types/symbol.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx middle_end/debuginfo.cmx parsing/asttypes.cmi \ + middle_end/base_types/symbol.cmx middle_end/internal_variable_names.cmx \ + middle_end/flambda_utils.cmx middle_end/flambda.cmx \ + middle_end/debuginfo.cmx parsing/asttypes.cmi \ middle_end/lift_let_to_initialize_symbol.cmi middle_end/lift_let_to_initialize_symbol.cmi : middle_end/flambda.cmi \ middle_end/backend_intf.cmi @@ -1735,14 +1826,14 @@ middle_end/projection.cmi : middle_end/base_types/variable.cmi \ middle_end/base_types/closure_id.cmi middle_end/ref_to_variables.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/mutable_variable.cmi utils/misc.cmi \ - bytecomp/lambda.cmi middle_end/flambda_iterators.cmi \ - middle_end/flambda.cmi parsing/asttypes.cmi \ - middle_end/ref_to_variables.cmi + bytecomp/lambda.cmi middle_end/internal_variable_names.cmi \ + middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ + parsing/asttypes.cmi middle_end/ref_to_variables.cmi middle_end/ref_to_variables.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/mutable_variable.cmx utils/misc.cmx \ - bytecomp/lambda.cmx middle_end/flambda_iterators.cmx \ - middle_end/flambda.cmx parsing/asttypes.cmi \ - middle_end/ref_to_variables.cmi + bytecomp/lambda.cmx middle_end/internal_variable_names.cmx \ + middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ + parsing/asttypes.cmi middle_end/ref_to_variables.cmi middle_end/ref_to_variables.cmi : middle_end/flambda.cmi middle_end/remove_free_vars_equal_to_args.cmo : \ middle_end/base_types/variable.cmi middle_end/pass_wrapper.cmi \ @@ -1759,6 +1850,7 @@ middle_end/remove_unused_arguments.cmo : middle_end/base_types/variable.cmi \ middle_end/flambda_iterators.cmi middle_end/flambda.cmi \ middle_end/find_recursive_functions.cmi \ middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ middle_end/base_types/closure_id.cmi utils/clflags.cmi \ middle_end/remove_unused_arguments.cmi middle_end/remove_unused_arguments.cmx : middle_end/base_types/variable.cmx \ @@ -1767,6 +1859,7 @@ middle_end/remove_unused_arguments.cmx : middle_end/base_types/variable.cmx \ middle_end/flambda_iterators.cmx middle_end/flambda.cmx \ middle_end/find_recursive_functions.cmx \ middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ middle_end/base_types/closure_id.cmx utils/clflags.cmx \ middle_end/remove_unused_arguments.cmi middle_end/remove_unused_arguments.cmi : middle_end/flambda.cmi \ @@ -1803,27 +1896,38 @@ middle_end/share_constants.cmi : middle_end/flambda.cmi middle_end/simple_value_approx.cmo : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ + middle_end/base_types/set_of_closures_origin.cmi \ middle_end/base_types/set_of_closures_id.cmi middle_end/parameter.cmi \ - utils/misc.cmi bytecomp/lambda.cmi middle_end/inlining_cost.cmi \ - middle_end/freshening.cmi middle_end/flambda_utils.cmi \ - middle_end/flambda.cmi middle_end/base_types/export_id.cmi \ - middle_end/effect_analysis.cmi middle_end/base_types/closure_id.cmi \ - middle_end/allocated_const.cmi middle_end/simple_value_approx.cmi + utils/misc.cmi bytecomp/lambda.cmi middle_end/internal_variable_names.cmi \ + middle_end/inlining_cost.cmi middle_end/freshening.cmi \ + middle_end/flambda_utils.cmi middle_end/flambda.cmi \ + middle_end/base_types/export_id.cmi middle_end/effect_analysis.cmi \ + middle_end/debuginfo.cmi middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_origin.cmi \ + middle_end/base_types/closure_id.cmi middle_end/allocated_const.cmi \ + middle_end/simple_value_approx.cmi middle_end/simple_value_approx.cmx : middle_end/base_types/variable.cmx \ middle_end/base_types/var_within_closure.cmx \ middle_end/base_types/tag.cmx middle_end/base_types/symbol.cmx \ + middle_end/base_types/set_of_closures_origin.cmx \ middle_end/base_types/set_of_closures_id.cmx middle_end/parameter.cmx \ - utils/misc.cmx bytecomp/lambda.cmx middle_end/inlining_cost.cmx \ - middle_end/freshening.cmx middle_end/flambda_utils.cmx \ - middle_end/flambda.cmx middle_end/base_types/export_id.cmx \ - middle_end/effect_analysis.cmx middle_end/base_types/closure_id.cmx \ - middle_end/allocated_const.cmx middle_end/simple_value_approx.cmi + utils/misc.cmx bytecomp/lambda.cmx middle_end/internal_variable_names.cmx \ + middle_end/inlining_cost.cmx middle_end/freshening.cmx \ + middle_end/flambda_utils.cmx middle_end/flambda.cmx \ + middle_end/base_types/export_id.cmx middle_end/effect_analysis.cmx \ + middle_end/debuginfo.cmx middle_end/base_types/compilation_unit.cmx \ + middle_end/base_types/closure_origin.cmx \ + middle_end/base_types/closure_id.cmx middle_end/allocated_const.cmx \ + middle_end/simple_value_approx.cmi middle_end/simple_value_approx.cmi : middle_end/base_types/variable.cmi \ middle_end/base_types/var_within_closure.cmi \ middle_end/base_types/tag.cmi middle_end/base_types/symbol.cmi \ - middle_end/base_types/set_of_closures_id.cmi bytecomp/lambda.cmi \ - middle_end/freshening.cmi middle_end/flambda.cmi \ - middle_end/base_types/export_id.cmi middle_end/base_types/closure_id.cmi + middle_end/base_types/set_of_closures_origin.cmi \ + middle_end/base_types/set_of_closures_id.cmi middle_end/parameter.cmi \ + bytecomp/lambda.cmi middle_end/freshening.cmi middle_end/flambda.cmi \ + middle_end/base_types/export_id.cmi middle_end/debuginfo.cmi \ + middle_end/base_types/closure_origin.cmi \ + middle_end/base_types/closure_id.cmi middle_end/simplify_boxed_integer_ops.cmo : middle_end/simplify_common.cmi \ middle_end/simplify_boxed_integer_ops_intf.cmi \ middle_end/simple_value_approx.cmi bytecomp/lambda.cmi \ @@ -1880,13 +1984,15 @@ middle_end/unbox_closures.cmi : middle_end/base_types/variable.cmi \ middle_end/flambda.cmi middle_end/unbox_free_vars_of_closures.cmo : \ middle_end/base_types/variable.cmi middle_end/projection.cmi \ - middle_end/pass_wrapper.cmi utils/misc.cmi middle_end/inlining_cost.cmi \ + middle_end/pass_wrapper.cmi utils/misc.cmi \ + middle_end/internal_variable_names.cmi middle_end/inlining_cost.cmi \ middle_end/flambda_utils.cmi middle_end/flambda_iterators.cmi \ middle_end/flambda.cmi middle_end/extract_projections.cmi \ utils/clflags.cmi middle_end/unbox_free_vars_of_closures.cmi middle_end/unbox_free_vars_of_closures.cmx : \ middle_end/base_types/variable.cmx middle_end/projection.cmx \ - middle_end/pass_wrapper.cmx utils/misc.cmx middle_end/inlining_cost.cmx \ + middle_end/pass_wrapper.cmx utils/misc.cmx \ + middle_end/internal_variable_names.cmx middle_end/inlining_cost.cmx \ middle_end/flambda_utils.cmx middle_end/flambda_iterators.cmx \ middle_end/flambda.cmx middle_end/extract_projections.cmx \ utils/clflags.cmx middle_end/unbox_free_vars_of_closures.cmi @@ -1924,6 +2030,15 @@ middle_end/base_types/closure_id.cmx : \ middle_end/base_types/closure_id.cmi middle_end/base_types/closure_id.cmi : \ middle_end/base_types/closure_element.cmi +middle_end/base_types/closure_origin.cmo : \ + middle_end/base_types/closure_id.cmi \ + middle_end/base_types/closure_origin.cmi +middle_end/base_types/closure_origin.cmx : \ + middle_end/base_types/closure_id.cmx \ + middle_end/base_types/closure_origin.cmi +middle_end/base_types/closure_origin.cmi : utils/identifiable.cmi \ + middle_end/base_types/compilation_unit.cmi \ + middle_end/base_types/closure_id.cmi middle_end/base_types/compilation_unit.cmo : utils/misc.cmi \ middle_end/base_types/linkage_name.cmi utils/identifiable.cmi \ typing/ident.cmi middle_end/base_types/compilation_unit.cmi @@ -1953,14 +2068,16 @@ middle_end/base_types/linkage_name.cmo : utils/identifiable.cmi \ middle_end/base_types/linkage_name.cmx : utils/identifiable.cmx \ middle_end/base_types/linkage_name.cmi middle_end/base_types/linkage_name.cmi : utils/identifiable.cmi -middle_end/base_types/mutable_variable.cmo : utils/identifiable.cmi \ - typing/ident.cmi middle_end/base_types/compilation_unit.cmi \ +middle_end/base_types/mutable_variable.cmo : \ + middle_end/base_types/variable.cmi \ middle_end/base_types/mutable_variable.cmi -middle_end/base_types/mutable_variable.cmx : utils/identifiable.cmx \ - typing/ident.cmx middle_end/base_types/compilation_unit.cmx \ +middle_end/base_types/mutable_variable.cmx : \ + middle_end/base_types/variable.cmx \ middle_end/base_types/mutable_variable.cmi -middle_end/base_types/mutable_variable.cmi : utils/identifiable.cmi \ - typing/ident.cmi middle_end/base_types/compilation_unit.cmi +middle_end/base_types/mutable_variable.cmi : \ + middle_end/base_types/variable.cmi middle_end/internal_variable_names.cmi \ + utils/identifiable.cmi typing/ident.cmi \ + middle_end/base_types/compilation_unit.cmi middle_end/base_types/set_of_closures_id.cmo : utils/identifiable.cmi \ middle_end/base_types/id_types.cmi \ middle_end/base_types/compilation_unit.cmi \ @@ -1985,16 +2102,17 @@ middle_end/base_types/static_exception.cmo : utils/numbers.cmi \ middle_end/base_types/static_exception.cmx : utils/numbers.cmx \ bytecomp/lambda.cmx middle_end/base_types/static_exception.cmi middle_end/base_types/static_exception.cmi : utils/identifiable.cmi -middle_end/base_types/symbol.cmo : utils/misc.cmi \ - middle_end/base_types/linkage_name.cmi utils/identifiable.cmi \ - middle_end/base_types/compilation_unit.cmi \ +middle_end/base_types/symbol.cmo : middle_end/base_types/variable.cmi \ + utils/misc.cmi middle_end/base_types/linkage_name.cmi \ + utils/identifiable.cmi middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/symbol.cmi -middle_end/base_types/symbol.cmx : utils/misc.cmx \ - middle_end/base_types/linkage_name.cmx utils/identifiable.cmx \ - middle_end/base_types/compilation_unit.cmx \ +middle_end/base_types/symbol.cmx : middle_end/base_types/variable.cmx \ + utils/misc.cmx middle_end/base_types/linkage_name.cmx \ + utils/identifiable.cmx middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/symbol.cmi -middle_end/base_types/symbol.cmi : middle_end/base_types/linkage_name.cmi \ - utils/identifiable.cmi middle_end/base_types/compilation_unit.cmi +middle_end/base_types/symbol.cmi : middle_end/base_types/variable.cmi \ + middle_end/base_types/linkage_name.cmi utils/identifiable.cmi \ + middle_end/base_types/compilation_unit.cmi middle_end/base_types/tag.cmo : utils/numbers.cmi utils/misc.cmi \ utils/identifiable.cmi middle_end/base_types/tag.cmi middle_end/base_types/tag.cmx : utils/numbers.cmx utils/misc.cmx \ @@ -2008,13 +2126,16 @@ middle_end/base_types/var_within_closure.cmx : \ middle_end/base_types/var_within_closure.cmi middle_end/base_types/var_within_closure.cmi : \ middle_end/base_types/closure_element.cmi -middle_end/base_types/variable.cmo : utils/misc.cmi utils/identifiable.cmi \ +middle_end/base_types/variable.cmo : utils/misc.cmi \ + middle_end/internal_variable_names.cmi utils/identifiable.cmi \ typing/ident.cmi middle_end/base_types/compilation_unit.cmi \ middle_end/base_types/variable.cmi -middle_end/base_types/variable.cmx : utils/misc.cmx utils/identifiable.cmx \ +middle_end/base_types/variable.cmx : utils/misc.cmx \ + middle_end/internal_variable_names.cmx utils/identifiable.cmx \ typing/ident.cmx middle_end/base_types/compilation_unit.cmx \ middle_end/base_types/variable.cmi -middle_end/base_types/variable.cmi : utils/identifiable.cmi typing/ident.cmi \ +middle_end/base_types/variable.cmi : middle_end/internal_variable_names.cmi \ + utils/identifiable.cmi typing/ident.cmi \ middle_end/base_types/compilation_unit.cmi asmcomp/debug/available_regs.cmo : asmcomp/debug/reg_with_debug_info.cmi \ asmcomp/debug/reg_availability_set.cmi asmcomp/reg.cmi asmcomp/proc.cmi \ @@ -2066,13 +2187,11 @@ driver/compile.cmx : utils/warnings.cmx typing/typemod.cmx \ bytecomp/bytegen.cmx parsing/builtin_attributes.cmx driver/compile.cmi driver/compile.cmi : driver/compmisc.cmo : utils/warnings.cmi typing/typemod.cmi utils/misc.cmi \ - parsing/longident.cmi parsing/location.cmi typing/ident.cmi \ - typing/env.cmi utils/config.cmi driver/compenv.cmi utils/clflags.cmi \ - parsing/asttypes.cmi driver/compmisc.cmi + parsing/location.cmi typing/ident.cmi typing/env.cmi utils/config.cmi \ + driver/compenv.cmi utils/clflags.cmi driver/compmisc.cmi driver/compmisc.cmx : utils/warnings.cmx typing/typemod.cmx utils/misc.cmx \ - parsing/longident.cmx parsing/location.cmx typing/ident.cmx \ - typing/env.cmx utils/config.cmx driver/compenv.cmx utils/clflags.cmx \ - parsing/asttypes.cmi driver/compmisc.cmi + parsing/location.cmx typing/ident.cmx typing/env.cmx utils/config.cmx \ + driver/compenv.cmx utils/clflags.cmx driver/compmisc.cmi driver/compmisc.cmi : typing/env.cmi driver/compplugin.cmo : utils/misc.cmi parsing/location.cmi utils/config.cmi \ driver/compmisc.cmi driver/compenv.cmi driver/compdynlink.cmi \ diff --git a/.gitattributes b/.gitattributes index 0d7fefb0..60c928da 100644 --- a/.gitattributes +++ b/.gitattributes @@ -47,10 +47,10 @@ README* ocaml-typo=missing-header /Changes ocaml-typo=non-ascii,missing-header /INSTALL ocaml-typo=missing-header /LICENSE ocaml-typo=long-line,very-long-line,missing-header -# appveyor_build.cmd only has missing-header because dra27 too lazy to update -# check-typo to interpret Cmd-style comments! -/appveyor_build.cmd ocaml-typo=long-line,very-long-line,missing-header text eol=crlf -/appveyor_build.sh ocaml-typo=non-ascii +# tools/ci/appveyor/appveyor_build.cmd only has missing-header because +# dra27 too lazy to update check-typo to interpret Cmd-style comments! +/tools/ci/appveyor/appveyor_build.cmd ocaml-typo=long-line,very-long-line,missing-header text eol=crlf +/tools/ci/appveyor/appveyor_build.sh ocaml-typo=non-ascii asmcomp/*/emit.mlp ocaml-typo=tab,long-line,unused-prop @@ -101,7 +101,9 @@ yacc/*.[ch] ocaml-typo=long-line,very-long-line,unused-prop # Test suite command fragments *.checker text eol=lf *.precheck text eol=lf -*.runner text eol=lf +# ocamltest hooks which are used in the testsuite +*.check-program-output text eol=lf +*.run text eol=lf configure text eol=lf config/auto-aux/hasgot text eol=lf @@ -142,10 +144,15 @@ manual/tools/texexpand text eol=lf # Tests which include references spanning multiple lines fail with \r\n # endings, so use \n endings only, even on Windows. +testsuite/tests/basic-more/morematch.ml text eol=lf +testsuite/tests/basic-more/robustmatch.ml text eol=lf testsuite/tests/parsing/*.ml text eol=lf testsuite/tests/docstrings/empty.ml text eol=lf testsuite/tests/functors/functors.ml text eol=lf testsuite/tests/translprim/module_coercion.ml text eol=lf +testsuite/tests/typing-objects-bugs/pr3968_bad.ml text eol=lf +testsuite/tests/typing-recmod/t12bad.ml text eol=lf +testsuite/tests/typing-safe-linking/b_bad.ml text eol=lf testsuite/tests/warnings/w04.ml text eol=lf testsuite/tests/warnings/w04_failure.ml text eol=lf testsuite/tests/warnings/w32.ml text eol=lf @@ -155,12 +162,18 @@ testsuite/tests/warnings/w32.ml text eol=lf testsuite/tests/formatting/margins.ml text eol=lf testsuite/tests/letrec-disallowed/disallowed.ml text eol=lf testsuite/tests/letrec-disallowed/extension_constructor.ml text eol=lf -testsuite/tests/letrec-disallowed/float_block.ml text eol=lf +testsuite/tests/letrec-disallowed/float_block_allowed.ml text eol=lf +testsuite/tests/letrec-disallowed/float_block_disallowed.ml text eol=lf testsuite/tests/letrec-disallowed/generic_arrays.ml text eol=lf +testsuite/tests/letrec-disallowed/lazy_.ml text eol=lf testsuite/tests/letrec-disallowed/module_constraints.ml text eol=lf +testsuite/tests/letrec-disallowed/unboxed.ml text eol=lf testsuite/tests/letrec-disallowed/pr7215.ml text eol=lf +testsuite/tests/letrec-disallowed/pr7231.ml text eol=lf +testsuite/tests/letrec-disallowed/pr7706.ml text eol=lf testsuite/tests/lexing/uchar_esc.ml text eol=lf testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ml text eol=lf +testsuite/tests/tool-toplevel/pr7060.ml text eol=lf testsuite/tests/typing-extension-constructor/test.ml text eol=lf testsuite/tests/typing-extensions/extensions.ml text eol=lf testsuite/tests/typing-extensions/open_types.ml text eol=lf diff --git a/.gitignore b/.gitignore index 3657bd96..4b78128f 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ *.out.dSYM *.swp _ocamltest +_ocamltestd +*.odoc # local to root directory @@ -157,6 +159,7 @@ _ocamltest /ocamldoc/ocamldoc /ocamldoc/ocamldoc.opt +/ocamldoc/odoc /ocamldoc/odoc_crc.ml /ocamldoc/odoc_lexer.ml /ocamldoc/odoc_ocamlhtml.ml @@ -167,6 +170,7 @@ _ocamltest /ocamldoc/odoc_text_parser.ml /ocamldoc/odoc_text_parser.mli /ocamldoc/stdlib_man +/ocamldoc/stdlib_non_prefixed/*.mli /ocamldoc/stdlib_html /ocamldoc/*.output /ocamldoc/test_stdlib @@ -182,7 +186,7 @@ _ocamltest /otherlibs/dynlink/extract_crc /otherlibs/threads/marshal.mli -/otherlibs/threads/pervasives.mli +/otherlibs/threads/stdlib.mli /otherlibs/threads/unix.mli /otherlibs/win32graph/graphics.ml /otherlibs/win32graph/graphics.mli @@ -213,7 +217,6 @@ _ocamltest /otherlibs/win32unix/strofaddr.c /otherlibs/win32unix/time.c /otherlibs/win32unix/unlink.c -/otherlibs/win32unix/utimes.c /parsing/parser.ml /parsing/parser.mli @@ -240,25 +243,21 @@ _ocamltest /testsuite/**/*.byte /testsuite/**/*.native /testsuite/**/program -/testsuite/**/_log +/testsuite/**/_log* /testsuite/failure.stamp /testsuite/_retries -/testsuite/tests/asmcomp/codegen -/testsuite/tests/asmcomp/parsecmm.ml -/testsuite/tests/asmcomp/parsecmm.mli -/testsuite/tests/asmcomp/lexcmm.ml -/testsuite/tests/asmcomp/*.s -/testsuite/tests/asmcomp/*.out.manifest +/testsuite/tests/asmgen/codegen +/testsuite/tests/asmgen/parsecmm.ml +/testsuite/tests/asmgen/parsecmm.mli +/testsuite/tests/asmgen/lexcmm.ml +/testsuite/tests/asmgen/*.s +/testsuite/tests/asmgen/*.out.manifest -/testsuite/tests/basic/*.safe-string /testsuite/tests/embedded/caml -/testsuite/tests/float-unboxing/*.flambda -/testsuite/tests/float-unboxing/float_inline.ml - /testsuite/tests/lib-dynlink-bytecode/main /testsuite/tests/lib-dynlink-bytecode/static /testsuite/tests/lib-dynlink-bytecode/custom @@ -276,15 +275,6 @@ _ocamltest /testsuite/tests/lib-threads/*.byt -/testsuite/tests/lib-unix/win-stat/*-file -/testsuite/tests/lib-unix/win-symlink/link* -/testsuite/tests/lib-unix/win-symlink/test.txt - -/testsuite/tests/lib-unix/win-symlink/link* -/testsuite/tests/lib-unix/win-symlink/test.txt - -/testsuite/tests/opaque/*/*.mli - /testsuite/tests/output_obj/*.bc.c /testsuite/tests/output_obj/*_stub /testsuite/tests/output_obj/*_stub @@ -293,11 +283,6 @@ _ocamltest /testsuite/tests/self-contained-toplevel/cached_cmi.ml -/testsuite/tests/tool-debugger/**/compiler-libs -/testsuite/tests/tool-debugger/find-artifacts/out -/testsuite/tests/tool-debugger/no_debug_event/out -/testsuite/tests/tool-debugger/no_debug_event/c - /testsuite/tests/tool-ocamldep-modalias/*.byt* /testsuite/tests/tool-ocamldep-modalias/*.opt* /testsuite/tests/tool-ocamldep-modalias/depend.mk @@ -326,36 +311,15 @@ _ocamltest /testsuite/tests/tool-lexyacc/grammar.mli /testsuite/tests/tool-lexyacc/grammar.ml -/testsuite/tests/typing-misc/false.flat-float -/testsuite/tests/typing-misc/true.flat-float -/testsuite/tests/typing-misc/pr6939.ml - -/testsuite/tests/typing-multifile/a.ml -/testsuite/tests/typing-multifile/b.ml -/testsuite/tests/typing-multifile/c.ml -/testsuite/tests/typing-multifile/d.mli -/testsuite/tests/typing-multifile/e.ml -/testsuite/tests/typing-multifile/f.ml -/testsuite/tests/typing-multifile/g.ml -/testsuite/tests/typing-multifile/test - /testsuite/tests/typing-unboxed-types/false.flat-float /testsuite/tests/typing-unboxed-types/true.flat-float /testsuite/tests/typing-unboxed-types/test.ml.reference -/testsuite/tests/translprim/false.flat-float -/testsuite/tests/translprim/true.flat-float -/testsuite/tests/translprim/array_spec.ml.reference -/testsuite/tests/translprim/module_coercion.ml.reference - /testsuite/tests/unboxed-primitive-args/main.ml /testsuite/tests/unboxed-primitive-args/stubs.c /testsuite/tests/unwind/unwind_test -/testsuite/tests/warnings/w55.opt.opt_result -/testsuite/tests/warnings/w58.opt.opt_result - /testsuite/tests/win-unicode/symlink_tests.precheck /testsuite/tools/expect_test diff --git a/.mailmap b/.mailmap index 772aac57..9635a00a 100644 --- a/.mailmap +++ b/.mailmap @@ -27,6 +27,7 @@ Damien Doligez doligez Mohamed Iguernelala Jérémie Dimino Jeremy Yallop yallop +Nicolás Ojeda Bär # The aliases below correspond to preference expressed by # contributors on the name under which they credited, for example @@ -67,6 +68,7 @@ Stephen Dolan Junsong Li Junsong Li Christophe Raffali +Christophe Raffali Anton Bachin Reed Wilson David Scott @@ -86,9 +88,11 @@ Dwight Guth Dwight Guth Andreas Hauptmann fdopen Andreas Hauptmann +Andreas Hauptmann Hendrik Tews Hugo Heuzard Miod Vallat +Christoph Spiel # These contributors prefer to be referred to pseudonymously whitequark diff --git a/.merlin b/.merlin index 096ee297..5649a110 100644 --- a/.merlin +++ b/.merlin @@ -25,9 +25,6 @@ B ./otherlibs/dynlink S ./otherlibs/graph B ./otherlibs/graph -S ./otherlibs/num -B ./otherlibs/num - S ./otherlibs/str B ./otherlibs/str @@ -43,8 +40,8 @@ B ./otherlibs/unix S ./parsing B ./parsing -S ./stdlib -B ./stdlib +STDLIB ./stdlib +FLG -open Stdlib -nopervasives S ./toplevel B ./toplevel diff --git a/.travis-ci.sh b/.travis-ci.sh deleted file mode 100755 index f30d64dc..00000000 --- a/.travis-ci.sh +++ /dev/null @@ -1,154 +0,0 @@ -#!/bin/bash -#************************************************************************** -#* * -#* OCaml * -#* * -#* Anil Madhavapeddy, OCaml Labs * -#* * -#* Copyright 2014 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -PREFIX=~/local - -MAKE=make SHELL=dash - -# TRAVIS_COMMIT_RANGE has the form ... -# TRAVIS_CUR_HEAD is -# TRAVIS_PR_HEAD is -# -# The following diagram illustrates the relationship between -# the commits: -# -# (trunk) (pr branch) -# TRAVIS_CUR_HEAD TRAVIS_PR_HEAD -# | / -# ... ... -# | / -# TRAVIS_MERGE_BASE -# -echo TRAVIS_COMMIT_RANGE=$TRAVIS_COMMIT_RANGE -TRAVIS_CUR_HEAD=${TRAVIS_COMMIT_RANGE%%...*} -TRAVIS_PR_HEAD=${TRAVIS_COMMIT_RANGE##*...} -case $TRAVIS_EVENT_TYPE in - # If this is not a pull request then TRAVIS_COMMIT_RANGE may be empty. - pull_request) - TRAVIS_MERGE_BASE=$(git merge-base $TRAVIS_CUR_HEAD $TRAVIS_PR_HEAD);; -esac - -BuildAndTest () { - mkdir -p $PREFIX - cat< /dev/null && CheckNoChangesMessage || echo pass -} - -CheckNoChangesMessage () { - API_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/issues/$TRAVIS_PULL_REQUEST/labels - if test -n "$(git log --grep="[Nn]o [Cc]hange.* needed" --max-count=1 \ - ${TRAVIS_MERGE_BASE}..${TRAVIS_PR_HEAD})" - then echo pass - elif test -n "$(curl $API_URL | grep 'no-change-entry-needed')" - then echo pass - else exit 1 - fi -} - -CheckTestsuiteModified () { - cat< /dev/null && exit 1 || echo pass -} - -case $CI_KIND in -build) BuildAndTest;; -changes) - case $TRAVIS_EVENT_TYPE in - pull_request) CheckChangesModified;; - esac;; -tests) - case $TRAVIS_EVENT_TYPE in - pull_request) CheckTestsuiteModified;; - esac;; -*) echo unknown CI kind - exit 1 - ;; -esac diff --git a/.travis.yml b/.travis.yml index 3a220a6a..eb065cd3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ sudo: false language: c git: submodules: false -script: bash -ex .travis-ci.sh +script: bash -ex tools/ci/travis/travis-ci.sh matrix: include: - env: CI_KIND=build XARCH=i386 diff --git a/Changes b/Changes index 7128bbe8..25976617 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,579 @@ +OCaml 4.07.0 (10 July 2018) +--------------------------- + +(Changes that can break existing programs are marked with a "*") + +### Language features: + +- MPR#6023, GPR#1648: Allow type-based selection of GADT constructors + (Thomas Refis and Leo White, review by Jacques Garrigue and Gabriel Scherer) + +- GPR#1546: Allow empty variants + (Runhang Li, review by Gabriel Radanne and Jacques Garrigue) + +### Standard library: + +- MPR#4170, GPR#1674: add the constant `Float.pi`. + (Christophe Troestler, review by Damien Doligez) + +- MPR#6139, GPR#1685: Move the Bigarray module to the standard library. Keep the + bigarray library as on overlay adding the deprecated map_file functions + (Jérémie Dimino, review by Mark Shinwell) + +- MPR#7690, GPR#1528: fix the float_of_string function for hexadecimal floats + with very large values of the exponent. + (Olivier Andrieu) + +- GPR#1002: add a new `Seq` module defining a list-of-thunks style iterator. + Also add `{to,of}_seq` to several standard modules. + (Simon Cruanes, review by Alain Frisch and François Bobot) + +* GPR#1010: pack all standard library modules into a single module Stdlib + which is the default opened module (Stdlib itself includes Pervasives) to free + up the global namespace for other standard libraries, while still allowing any + OCaml standard library module to be referred to as Stdlib.Module). This is + implemented efficiently using module aliases (prefixing all modules with + Stdlib__, e.g. Stdlib__string). + (Jérémie Dimino, David Allsopp and Florian Angeletti, review by David Allsopp + and Gabriel Radanne) + +- GPR#1637: String.escaped is faster and does not allocate when called with a + string that does not contain any characters needing to be escaped. + (Alain Frisch, review by Xavier Leroy and Gabriel Scherer) + +- GPR#1638: add a Float module. + (Nicolás Ojeda Bär, review by Alain Frisch and Jeremy Yallop) + +- GPR#1697: Tune [List.init] tailrec threshold so that it does not stack overflow + when compiled with the Js_of_ocaml backend. + (Hugo Heuzard, reviewed by Gabriel Scherer) + +### Other libraries: + +- MPR#7745, GPR#1629: Graphics.open_graph displays the correct window title on + Windows again (fault introduced by 4.06 Unicode changes). + (David Allsopp) + +* GPR#1406: Unix.isatty now returns true in the native Windows ports when + passed a file descriptor connected to a Cygwin PTY. In particular, compiler + colors for the native Windows ports now work under Cygwin/MSYS2. + (Nicolás Ojeda Bär, review by Gabriel Scherer, David Allsopp, Xavier Leroy) + +- GPR#1451: [getpwuid], [getgrgid], [getpwnam], [getgrnam] now raise Unix error + instead of returning [Not_found] when interrupted by a signal. + (Arseniy Alekseyev, review by Mark Shinwell and Xavier Leroy) + +- GPR#1477: raw_spacetime_lib can now be used in bytecode. + (Nicolás Ojeda Bär, review by Mark Shinwell) + +- GPR#1533: (a) The implementation of Thread.yield for system thread + now uses nanosleep(1) for enabling better preemption. + (b) Thread.delay is now an alias for Unix.sleepf. + (Jacques-Henri Jourdan, review by Xavier Leroy and David Allsopp) + +### Compiler user-interface and warnings: + +- MPR#7663, GPR#1694: print the whole cycle and add a reference to the manual in + the unsafe recursive module evaluation error message. + (Florian Angeletti, report by Matej Košík, review by Gabriel Scherer) + +- GPR#1166: In OCAMLPARAM, an alternative separator can be specified as + first character (instead of comma) in the set ":|; ," + (Fabrice Le Fessant) + +- GPR#1358: Fix usage warnings with no mli file + (Leo White, review by Alain Frisch) + +- GPR#1428: give a non dummy location for warning 49 (no cmi found) + (Valentin Gatien-Baron) + +- GPR#1491: Improve error reporting for ill-typed applicative functor + types, F(M).t. + (Valentin Gatien-Baron, review by Florian Angeletti and Gabriel Radanne) + +- GPR#1496: Refactor the code printing explanation for unification type errors, + in order to avoid duplicating pattern matches + (Armaël Guéneau, review by Florian Angeletti and Gabriel Scherer) + +- GPR#1505: Add specific error messages for unification errors involving + functions of type "unit -> _" + (Arthur Charguéraud and Armaël Guéneau, with help from Leo White, review by + Florian Angeletti and Gabriel Radanne) + +- GPR#1510: Add specific explanation for unification errors caused by type + constraints propagated by keywords (such as if, while, for...) + (Armaël Guéneau and Gabriel Scherer, original design by Arthur Charguéraud, + review by Frédéric Bour, Gabriel Radanne and Alain Frisch) + +- GPR#1515: honor the BUILD_PATH_PREFIX_MAP environment variable + to enable reproducible builds + (Gabriel Scherer, with help from Ximin Luo, review by Damien Doligez) + +- GPR#1534: Extend the warning printed when (*) is used, adding a hint to + suggest using ( * ) instead + (Armaël Guéneau, with help and review from Florian Angeletti and Gabriel + Scherer) + +- GPR#1552, GPR#1577: do not warn about ambiguous variables in guards + (warning 57) when the ambiguous values have been filtered by + a previous clause + (Gabriel Scherer and Thomas Refis, review by Luc Maranget) + +- GPR#1554: warnings 52 and 57: fix reference to manual detailed explanation + (Florian Angeletti, review by Thomas Refis and Gabriel Scherer) + +- GPR#1618: add the -dno-unique-ids and -dunique-ids compiler flags + (Sébastien Hinderer, review by Leo White and Damien Doligez) + +- GPR#1649 change compilation order of toplevel definitions, so that some warnings + emitted by the bytecode compiler appear more in-order than before. + (Luc Maranget, advice and review by Damien Doligez) + +- GPR#1806: add linscan to OCAMLPARAM options + (Raja Boujbel) + +### Code generation and optimizations: + +- MPR#7630, GPR#1401: Faster compilation of large modules with Flambda. + (Pierre Chambart, report by Emilio Jesús Gallego Arias, + Pierre-Marie Pédrot and Paul Steckler, review by Gabriel Scherer + and Leo White) + +- MPR#7630, GPR#1455: Disable CSE for the initialization function + (Pierre Chambart, report by Emilio Jesús Gallego Arias, + review by Gabriel Scherer and Xavier Leroy) + +- GPR#1370: Fix code duplication in Cmmgen + (Vincent Laviron, with help from Pierre Chambart, + reviews by Gabriel Scherer and Luc Maranget) + +- GPR#1486: ARM 32-bit port: add support for ARMv8 in 32-bit mode, + a.k.a. AArch32. + For this platform, avoid ITE conditional instruction blocks and use + simpler IT blocks instead + (Xavier Leroy, review by Mark Shinwell) + +- GPR#1487: Treat negated float comparisons more directly + (Leo White, review by Xavier Leroy) + +- GPR#1573: emitcode: merge events after instructions reordering + (Thomas Refis and Leo White, with help from David Allsopp, review by Frédéric + Bour) + +- GPR#1606: Simplify the semantics of Lambda.free_variables and Lambda.subst, + including some API changes in bytecomp/lambda.mli + (Pierre Chambart, review by Gabriel Scherer) + +- GPR#1613: ensure that set-of-closures are processed first so that other + entries in the let-rec symbol do not get dummy approximations + (Leo White and Xavier Clerc, review by Pierre Chambart) + +* GPR#1617: Make string/bytes distinguishable in the bytecode. + (Hugo Heuzard, reviewed by Nicolás Ojeda Bär) + +- GPR#1627: Reduce cmx sizes by sharing variable names (Flambda only) + (Fuyong Quah, Leo White, review by Xavier Clerc) + +- GPR#1665: reduce the size of cmx files in classic mode by droping the + bodies of functions that will not be inlined + (Fuyong Quah, review by Leo White and Pierre Chambart) + +- GPR#1666: reduce the size of cmx files in classic mode by droping the + bodies of functions that cannot be reached from the module block + (Fuyong Quah, review by Leo White and Pierre Chambart) + +- GPR#1686: Turn off by default flambda invariants checks. + (Pierre Chambart) + +- GPR#1707: Add [Closure_origin.t] to trace inlined functions to prevent + infinite loops from repeatedly inlining copies of the same function. + (Fu Yong Quah) + +- GPR#1740: make sure startup.o is always linked in when using + "-output-complete-obj". Previously, it was always linked in only on some + platforms, making this option unusable on platforms where it wasn't + (Jérémie Dimino, review by Sébastien Hinderer and Xavier Leroy) + +### Runtime system: + +- MPR#6411, GPR#1535: don't compile everything with -static-libgcc on mingw32, + only dllbigarray.dll and libbigarray.a. Allows the use of C++ libraries which + raise exceptions. + (David Allsopp) + +- MPR#7100, GPR#1476: trigger a minor GC when custom blocks accumulate + in minor heap + (Alain Frisch, report by talex, review by Damien Doligez, Leo White, + Gabriel Scherer) + +- GPR#1431: remove ocamlrun dependencies on curses/terminfo/termcap C library + (Xavier Leroy, review by Daniel Bünzli) + +- GPR#1478: The Spacetime profiler now works under Windows (but it is not yet + able to collect profiling information from C stubs). + (Nicolás Ojeda Bär, review by Xavier Leroy, Mark Shinwell) + +- GPR#1483: fix GC freelist accounting for chunks larger than the maximum block + size. + (David Allsopp and Damien Doligez) + +- GPR#1526: install the debug and instrumented runtimes + (lib{caml,asm}run{d,i}.a) + (Gabriel Scherer, reminded by Julia Lawall) + +- GPR#1563: simplify implementation of LSRINT and ASRINT + (Max Mouratov, review by Frédéric Bour) + +- GPR#1644: remove caml_alloc_float_array from the bytecode primitives list + (it's a native code primitive) + (David Allsopp) + +- GPR#1701: fix missing root bug in GPR#1476 + (Mark Shinwell) + +- GPR#1752: do not alias function arguments to sigprocmask (Anil Madhavapeddy) + +- GPR#1753: avoid potential off-by-one overflow in debugger socket path + length (Anil Madhavapeddy) + +### Tools: + +- MPR#7643, GPR#1377: ocamldep, fix an exponential blowup in presence of nested + structures and signatures (e.g. "include struct … include(struct … end) … end") + (Florian Angeletti, review by Gabriel Scherer, report by Christophe Raffalli) + +- MPR#7687, GPR#1653: deprecate -thread option, + which is equivalent to -I +threads. + (Nicolás Ojeda Bär, report by Daniel Bünzli) + +- MPR#7710: `ocamldep -sort` should exit with nonzero code in case of + cyclic dependencies + (Xavier Leroy, report by Mantis user baileyparker) + +- GPR#1537: boot/ocamldep is no longer included in the source distribution; + boot/ocamlc -depend can be used in its place. + (Nicolás Ojeda Bär, review by Xavier Leroy and Damien Doligez) + +- GPR#1585: optimize output of "ocamllex -ml" + (Alain Frisch, review by Frédéric Bour and Gabriel Scherer) + +- GPR#1667: add command-line options -no-propt, -no-version, -no-time, + -no-breakpoint and -topdirs-path to ocamldebug + (Sébastien Hinderer, review by Damien Doligez) + +- GPR#1695: add the -null-crc command-line option to ocamlobjinfo. + (Sébastien Hinderer, review by David Allsopp and Gabriel Scherer) + +- GPR#1710: ocamldoc, improve the 'man' rendering of subscripts and + superscripts. + (Gabriel Scherer) + +- GPR#1771: ocamdebug, avoid out of bound access + (Thomas Refis) + +### Manual and documentation: + +- MPR#7613: minor reword of the "refutation cases" paragraph + (Florian Angeletti, review by Jacques Garrigue) + +- PR#7647, GPR#1384: emphasize ocaml.org website and forum in README + (Yawar Amin, review by Gabriel Scherer) + +- PR#7698, GPR#1545: improve wording in OCaml manual in several places, + mostly in Chapter 1. This addresses the easier changes suggested in the PR. + (Jim Fehrle, review by Florian Angeletti and David Allsopp) + +- GPR#1540: manual, decouple verbatim and toplevel style in code examples + (Florian Angeletti, review by Gabriel Scherer) + +- GPR#1556: manual, add a consistency test for manual references inside + the compiler source code. + (Florian Angeletti, review by Gabriel Scherer) + +- GPR#1647: manual, subsection on record and variant disambiguation + (Florian Angeletti, review by Alain Frisch and Gabriel Scherer) + +- GPR#1702: manual, add a signature mode for code examples + (Florian Angeletti, review by Gabriel Scherer) + +- GPR#1741: manual, improve typesetting and legibility in HTML output + (steinuil, review by Gabriel Scherer) + +- GPR#1757: style the html manual, changing type and layout + (Charles Chamberlain, review by Florian Angeletti, Xavier Leroy, + Gabriel Radanne, Perry E. Metzger, and Gabriel Scherer) + +- GPR#1765: manual, ellipsis in code examples + (Florian Angeletti, review and suggestion by Gabriel Scherer) + +- GPR#1767: change html manual to use relative font sizes + (Charles Chamberlain, review by Daniel Bünzli, Perry E. Metzger, + Josh Berdine, and Gabriel Scherer) + +- GPR#1779: integrate the Bigarray documentation into the main manual. + (Perry E. Metzger, review by Florian Angeletti and Xavier Clerc) + +### Type system: + +- MPR#7611, GPR#1491: reject the use of generative functors as applicative + (Valentin Gatien-Baron) + +- MPR#7706, GPR#1565: in recursive value declarations, track + static size of locally-defined variables + (Gabriel Scherer, review by Jeremy Yallop and Leo White, report by Leo White) + +- MPR#7717, GPR#1593: in recursive value declarations, don't treat + unboxed constructor size as statically known + (Jeremy Yallop, report by Pierre Chambart, review by Gabriel Scherer) + +- MPR#7767, GPR#1712: restore legacy treatment of partially-applied + labeled functions in 'let rec' bindings. + (Jeremy Yallop, report by Ivan Gotovchits, review by Gabriel Scherer) + +* MPR#7787, GPR#1652, GPR#1743: Don't remove module aliases in `module type of` + and `with module`. + The old behaviour can be obtained using the `[@remove_aliases]` attribute. + (Leo White and Thomas Refis, review by Jacques Garrigue) + +- GPR#1468: Do not enrich type_decls with incoherent manifests + (Thomas Refis and Leo White, review by Jacques Garrigue) + +- GPR#1469: Use the information from [@@immediate] annotations when + computing whether a type can be [@@unboxed] + (Damien Doligez, report by Stephan Muenzel, review by Alain Frisch) + +- GPR#1513: Allow compilation units to shadow sub-modules of Pervasives. + For instance users can now use a largeFile.ml file in their project. + (Jérémie Dimino, review by Nicolas Ojeda Bar, Alain Frisch and Gabriel Radanne) + +- GPR#1516: Allow float array construction in recursive bindings + when configured with -no-flat-float-array + (Jeremy Yallop, report by Gabriel Scherer) + +- GPR#1583: propagate refined ty_arg to Parmatch checks + (Thomas Refis, review by Jacques Garrigue) + +- GPR#1609: Changes to ambivalence scope tracking + (Thomas Refis and Leo White, review by Jacques Garrigue) + +- GPR#1628: Treat reraise and raise_notrace as nonexpansive. + (Leo White, review by Alain Frisch) + +* GPR#1778: Fix Soundness bug with non-generalized type variable and + local modules. This is the same bug as MPR#7414, but using local + modules instead of non-local ones. + (Leo White, review by Jacques Garrigue) + +### Compiler distribution build system + +- MPR#5219, GPR#1680, GPR#1877: use 'install' instead of 'cp' + in install scripts. + (Gabriel Scherer, review by Sébastien Hinderer and Valentin Gatien-Baron) + +- MPR#7679: make sure .a files are erased before calling ar rc, otherwise + leftover .a files from an earlier compilation may contain unwanted modules + (Xavier Leroy) + +- GPR#1571: do not perform architecture tests on 32-bit platforms, allowing + 64-bit back-ends to use 64-bit specific constructs + (Xavier Clerc, review by Damien Doligez) + +### Internal/compiler-libs changes: + +- MPR#7738, GPR#1624: Asmlink.reset also resets lib_ccobjs/ccopts + (Cedric Cellier, review by Gabriel Scherer) + +- GPR#1488, GPR#1560: Refreshing parmatch + (Gabriel Scherer and Thomas Refis, review by Luc Maranget) + +- GPR#1502: more command line options for expect tests + (Florian Angeletti, review by Gabriel Scherer) + +- GPR#1511: show code at error location in expect-style tests, + using new Location.show_code_at_location function + (Gabriel Scherer and Armaël Guéneau, + review by Valentin Gatien-Baron and Damien Doligez) + +- GPR#1519, GPR#1532, GRP#1570: migrate tests to ocamltest + (Sébastien Hinderer, review by Gabriel Scherer, Valentin Gatien-Baron + and Nicolás Ojeda Bär) + +- GPR#1520: more robust implementation of Misc.no_overflow_mul + (Max Mouratov, review by Xavier Leroy) + +- GPR#1557: Organise and simplify translation of primitives + (Leo White, review by François Bobot and Nicolás Ojeda Bär) + +- GPR#1567: register all idents relevant for reraise + (Thomas Refis, review by Alain Frisch and Frédéric Bour) + +- GPR#1586: testsuite: 'make promote' for ocamltest tests + (The new "-promote" option for ocamltest is experimental + and subject to change/removal). + (Gabriel Scherer) + +- GPR#1619: expect_test: print all the exceptions, even the unexpected ones + (Thomas Refis, review by Jérémie Dimino) + +- GPR#1621: expect_test: make sure to not use the installed stdlib + (Jérémie Dimino, review by Thomas Refis) + +- GPR#1646 : add ocamldoc test to ocamltest and + migrate ocamldoc tests to ocamltest + (Florian Angeletti, review by Sébastien Hinderer) + +- GPR#1663: refactor flambda specialise/inlining handling + (Leo White and Xavier Clerc, review by Pierre Chambart) + +- GPR#1679 : remove Pbittest from primitives in lambda + (Hugo Heuzard, review by Mark Shinwell) + +* GPR#1704: Make Ident.t abstract and immutable. + (Gabriel Radanne, review by Mark Shinwell) + +### Bug fixes + +- MPR#4499, GPR#1479: Use native Windows API to implement Sys.getenv, + Unix.getenv and Unix.environment under Windows. + (Nicolás Ojeda Bär, report by Alain Frisch, review by David Allsopp, Xavier + Leroy) + +- MPR#5250, GPR#1435: on Cygwin, when ocamlrun searches the path + for a bytecode executable file, skip directories and other + non-regular files, like other Unix variants do. + (Xavier Leroy) + +- MPR#6394, GPR#1425: fix fatal_error from Parmatch.get_type_path + (Virgile Prevosto, review by David Allsopp, Thomas Refis and Jacques Garrigue) + +* MPR#6604, GPR#931: Only allow directives with filename and at the beginning of + the line + (Tadeu Zagallo, report by Roberto Di Cosmo, + review by Hongbo Zhang, David Allsopp, Gabriel Scherer, Xavier Leroy) + +- MPR#7138, MPR#7701, GPR#1693: Keep documentation comments + even in empty structures and signatures + (Leo White, Florian Angeletti, report by Anton Bachin) + +- MPR#7178, MPR#7253, MPR#7796, GPR#1790: Make sure a function + registered with "at_exit" is executed only once when the program exits + (Nicolás Ojeda Bär and Xavier Leroy, review by Max Mouratov) + +- MPR#7391, GPR#1620: Do not put a dummy method in object types + (Thomas Refis, review by Jacques Garrigue) + +- PR#7660, GPR#1445: Use native Windows API to implement Unix.utimes in order to + avoid unintended shifts of the argument timestamp depending on DST setting. + (Nicolás Ojeda Bär, review by David Allsopp, Xavier Leroy) + +- MPR#7668: -principal is broken with polymorphic variants + (Jacques Garrigue, report by Jun Furuse) + +- MPR#7680, GPR#1497: Incorrect interaction between Matching.for_let and + Simplif.simplify_exits + (Alain Frisch, report and review by Vincent Laviron) + +- MPR#7682, GPR#1495: fix [@@unboxed] for records with 1 polymorphic field + (Alain Frisch, report by Stéphane Graham-Lengrand, review by Gabriel Scherer) + +- MPR#7695, GPR#1541: Fatal error: exception Ctype.Unify(_) with field override + (Jacques Garrigue, report by Nicolás Ojeda Bär) + +- MPR#7704, GPR#1564: use proper variant tag in non-exhaustiveness warning + (Jacques Garrigue, report by Thomas Refis) + +- MPR#7711, GPR#1581: Internal typechecker error triggered by a constraint on + self type in a class type + (Jacques Garrigue, report and review by Florian Angeletti) + +- MPR#7712, GPR#1576: assertion failure with type abbreviations + (Thomas Refis, report by Michael O'Connor, review by Jacques Garrigue) + +- MPR#7747: Type checker can loop infinitly and consumes all computer memory + (Jacques Garrigue, report by kantian) + +- MPR#7751, GPR#1657: The toplevel prints some concrete types as abstract + (Jacques Garrigue, report by Matej Kosik) + +- MPR#7765, GPR#1718: When unmarshaling bigarrays, protect against integer + overflows in size computations + (Xavier Leroy, report by Maximilian Tschirschnitz, + review by Gabriel Scherer) + +- MPR#7760, GPR#1713: Exact selection of lexing engine, that is + correct "Segfault in ocamllex-generated code using 'shortest'" + (Luc Maranget, Frédéric Bour, report by Stephen Dolan, + review by Gabriel Scherer) + +- MPR#7769, GPR#1714: calls to Stream.junk could, under some conditions, be + ignored when used on streams based on input channels. + (Nicolás Ojeda Bär, report by Michael Perin, review by Gabriel Scherer) + +- MPR#7793, GPR#1766: the toplevel #use directive now accepts sequences of ';;' + tokens. This fixes a bug in which certain files accepted by the compiler were + rejected by ocamldep. + (Nicolás Ojeda Bär, report by Hugo Heuzard, review by Hugo Heuzard) + +- GPR#1517: More robust handling of type variables in mcomp + (Leo White and Thomas Refis, review by Jacques Garrigue) + +- GPR#1530, GPR#1574: testsuite, fix 'make parallel' and 'make one DIR=...' + to work on ocamltest-based tests. + (Runhang Li and Sébastien Hinderer, review by Gabriel Scherer) + +- GPR#1550, GPR#1555: Make pattern matching warnings more robust + to ill-typed columns + (Thomas Refis, with help from Gabriel Scherer and Luc Maranget) + +- GPR#1614: consider all bound variables when inlining, fixing a compiler + fatal error. + (Xavier Clerc, review by Pierre Chambart, Leo White) + +- GPR#1622: fix bug in the expansion of command-line arguments under Windows + which could result in some elements of Sys.argv being truncated in some cases. + (Nicolás Ojeda Bär, review by Sébastien Hinderer) + +- GPR#1623: Segfault on Windows 64 bits when expanding wildcards in arguments. + (Marc Lasson, review by David Allsopp, Alain Frisch, Sébastien Hinderer, + Xavier Leroy, Nicolas Ojeda Bar) + +- GPR#1661: more precise principality warning regarding record fields + disambiguation + (Thomas Refis, review by Leo White) + +- GPR#1687: fix bug in the printing of short functor types "(S1 -> S2) -> S3" + (Pieter Goetschalckx, review by Gabriel Scherer) + +- GPR#1722: Scrape types in Typeopt.maybe_pointer + (Leo White, review by Thomas Refis) + +- GPR#1755: ensure that a bigarray is never collected while reading complex + values (Xavier Clerc, Mark Shinwell and Leo White, report by Chris Hardin, + reviews by Stephen Dolan and Xavier Leroy) + +- GPR#1764: in byterun/memory.c, struct pool_block, use C99 flexible arrays + if available + (Xavier Leroy, review by Max Mouratov) + +- GPR#1774: ocamlopt for ARM could generate VFP loads and stores with bad + offsets, rejected by the assembler. + (Xavier Leroy, review by Mark Shinwell) + +- GPR#1808: handle `[@inlined]` attributes under a module constraint + (Xavier Clerc, review by Leo White) + +- GPR#1810: use bit-pattern comparison when meeting float approximations + (Xavier Clerc, report by Christophe Troestler, review by Nicolás Ojeda Bär + and Gabriel Scherer) + +- GPR#1835: Fix off-by-one errors in Weak.get_copy and Weak.blit + (KC Sivaramakrishnan) + +- GPR#1849: bug in runtime function generic_final_minor_update() + that could lead to crashes when Gc.finalise_last is used + (report and fix by Yuriy Vostrikov, review by François Bobot) + + OCaml 4.06.1 (16 Feb 2018): --------------------------- @@ -460,6 +1036,9 @@ OCaml 4.06.0 (3 Nov 2017): (Florian Angeletti, review by Daniel Bünzli, Xavier Leroy and Gabriel Scherer) +- GPR#1688: Fix printing of -0. + (Nicolás Ojeda Bär, review by Jérémie Dimino) + ### Runtime system: * MPR#3771, GPR#153, GPR#1200, GPR#1357, GPR#1362, GPR#1363, GPR#1369, GPR#1398, diff --git a/HACKING.adoc b/HACKING.adoc index 9de68b54..0770d4af 100644 --- a/HACKING.adoc +++ b/HACKING.adoc @@ -236,7 +236,7 @@ found in link:INSTALL.adoc#bootstrap[INSTALL.adoc]. ==== Github's CI: Travis and AppVeyor The script that is run on Travis continuous integration servers is -link:.travis-ci.sh[]; its configuration can be found as +link:tools/ci/travis/travis-ci.sh[]; its configuration can be found as a Travis configuration file in link:.travis.yml[]. For example, if you want to reproduce the default build on your @@ -244,7 +244,7 @@ machine, you can use the configuration values and run command taken from link:.travis.yml[]: ---- -CI_KIND=build XARCH=x64 bash -ex .travis-ci.sh +CI_KIND=build XARCH=x64 bash -ex tools/ci/travis/travis-ci.sh ---- The scripts support two other kinds of tests (values of the @@ -274,11 +274,11 @@ You do not need to be an INRIA employee to open an account on this jenkins service; anyone can create an account there to access build logs and manually restart builds. If you would like to do this but have trouble doing it, please email -ocaml-ci-admin@inria.fr +ocaml-ci-admin@inria.fr. To be notified by email of build failures, you can subscribe to the ocaml-ci-notifications@inria.fr mailing list by visiting -https://sympa.inria.fr/sympa/info/ocaml-ci-notifications[its web page] +https://sympa.inria.fr/sympa/info/ocaml-ci-notifications[its web page.] ==== Running INRIA's CI on a publicly available git branch @@ -307,4 +307,25 @@ OCaml's GitHub repository and then push "mybranch" to your fork. 7. You should receive a bunch of e-mails with the build logs for each slave and each tested configuration (with and without flambda) attached. +==== Changing what the CI does + +INRIA's CI "main" and "precheck" jobs run the script +tools/ci-build. In particular, when running the CI on a publicly +available branch via the "precheck" job as explained in the previous +section, you can edit this script to change what the CI will test. + +For instance, parallel builds are only tested for the "trunk" +branch. In order to use "precheck" to test parallel build on a custom +branch, add this at the beginning of tools/ci-build: + +---- +OCAML_JOBS=10 +---- + +=== The `caml-commits` mailing list + +If you would like to receive email notifications of all commits made to the main +git repository, you can subscribe to the caml-commits@inria.fr mailing list by +visiting https://sympa.inria.fr/sympa/info/caml-commits[its web page.] + Happy Hacking! diff --git a/INSTALL.adoc b/INSTALL.adoc index 03a00b62..bf3990fd 100644 --- a/INSTALL.adoc +++ b/INSTALL.adoc @@ -198,8 +198,15 @@ for guidance on how to edit the generated files by hand. 2. From the top directory, do: + make world.opt ++ +if your platform is supported by the native-code compiler (as reported during + the auto-configuration), or + make world + +if not. + This builds the OCaml bytecode compiler for the first time. This phase is fairly verbose; consider redirecting the output to a file: @@ -226,38 +233,7 @@ best thing to do is to try a second bootstrapping phase: just do `make bootstrap` again. It will either crash almost immediately, or re-re-compile everything correctly and reach the fix-point. -4. If your platform is supported by the native-code compiler (as reported during - the auto-configuration), you can now build the native-code compiler. From - the top directory, do: - - make opt -+ -or: - - make opt > log.opt 2>&1 # in sh - make opt >& log.opt # in csh - -5. anchor:step-5[] Compile fast versions of the OCaml compilers, by compiling - them with the native-code compiler (you will have only compiled them to - bytecode in steps 2-4). Just do: - - make opt.opt -+ -Later, you can compile your programs to bytecode using ocamlc.opt instead of -ocamlc, and to native-code using ocamlopt.opt instead of ocamlopt. The ".opt" -compilers should run faster than the normal compilers, especially on large input -files, but they may take longer to start due to increased code size. If -compilation times are an issue on your programs, try the ".opt" compilers to see -if they make a significant difference. -+ -An alternative, and faster approach to steps 2 to 5 is - - make world.opt # to build using native-code compilers -+ -The result is equivalent to `make world opt opt.opt`, but this may fail if -anything goes wrong in native-code generation. - -6. You can now install the OCaml system. This will create the following commands +4. You can now install the OCaml system. This will create the following commands (in the binary directory selected during autoconfiguration): + [width="70%",frame="topbot",cols="25%,75%"] @@ -277,20 +253,17 @@ anything goes wrong in native-code generation. | `ocamlcp` | the bytecode compiler in profiling mode |=============================================================================== + -and also, if you built them during <>: `ocamlc.opt`, -`ocamlopt.opt`, `ocamllex.opt`, `ocamldep.opt` and `ocamldoc.opt` -+ From the top directory, become superuser and do: umask 022 # make sure to give read & execute permission to all make install -7. Installation is complete. Time to clean up. From the toplevel directory, +5. Installation is complete. Time to clean up. From the toplevel directory, do: make clean -8. (Optional) The `emacs/` subdirectory contains Emacs-Lisp files for an OCaml +6. (Optional) The `emacs/` subdirectory contains Emacs-Lisp files for an OCaml editing mode and an interface for the debugger. To install these files, change to the `emacs/` subdirectory and do: @@ -303,7 +276,7 @@ or In the latter case, the destination directory defaults to the `site-lisp` directory of your Emacs installation. -9. After installation, do *not* strip the `ocamldebug` and `ocamlbrowser` +7. After installation, do *not* strip the `ocamldebug` and `ocamlbrowser` executables. These are mixed-mode executables (containing both compiled C code and OCaml bytecode) and stripping erases the bytecode! Other executables such as `ocamlrun` can safely be stripped. diff --git a/Makefile b/Makefile index 0875c099..1b4bec8e 100644 --- a/Makefile +++ b/Makefile @@ -16,16 +16,22 @@ # The main Makefile # Hard bootstrap how-to: -# (only necessary in some cases, for example if you remove some primitive) +# (only necessary if you remove or rename some primitive) # -# make coreboot [old system -- you were in a stable state] -# -# make clean runtime coreall -# -# make clean runtime coreall +# make core [old system -- you were in a stable state] +# make coreboot [optional -- check state stability] +# +# make clean && make core +# if the above fails: +# +# make clean && make core +# make coreboot [intermediate state with both old and new primitives] +# +# make clean && make runtime && make coreall # make coreboot [new system -- now in a stable state] include config/Makefile +include Makefile.common # For users who don't read the INSTALL file .PHONY: defaultentry @@ -72,7 +78,7 @@ endif YACCFLAGS=-v --strict CAMLLEX=$(CAMLRUN) boot/ocamllex -CAMLDEP=$(CAMLRUN) tools/ocamldep +CAMLDEP=$(CAMLRUN) boot/ocamlc -depend DEPFLAGS=$(INCLUDES) OCAMLDOC_OPT=$(WITH_OCAMLDOC:=.opt) @@ -83,6 +89,7 @@ UTILS=utils/config.cmo utils/misc.cmo \ utils/terminfo.cmo utils/ccomp.cmo utils/warnings.cmo \ utils/consistbl.cmo \ utils/strongly_connected_components.cmo \ + utils/build_path_prefix_map.cmo \ utils/targetint.cmo PARSING=parsing/location.cmo parsing/longident.cmo \ @@ -104,16 +111,15 @@ TYPING=typing/ident.cmo typing/path.cmo \ typing/typedtreeIter.cmo typing/typedtreeMap.cmo \ typing/tast_mapper.cmo \ typing/cmt_format.cmo typing/untypeast.cmo \ - typing/includemod.cmo typing/typetexp.cmo typing/parmatch.cmo \ - typing/stypes.cmo typing/typedecl.cmo typing/typeopt.cmo typing/typecore.cmo \ - typing/typeclass.cmo \ - typing/typemod.cmo + typing/includemod.cmo typing/typetexp.cmo typing/printpat.cmo \ + typing/parmatch.cmo typing/stypes.cmo typing/typedecl.cmo typing/typeopt.cmo \ + typing/typecore.cmo typing/typeclass.cmo typing/typemod.cmo COMP=bytecomp/lambda.cmo bytecomp/printlambda.cmo \ bytecomp/semantics_of_primitives.cmo \ bytecomp/switch.cmo bytecomp/matching.cmo \ bytecomp/translobj.cmo bytecomp/translattribute.cmo \ - bytecomp/translcore.cmo \ + bytecomp/translprim.cmo bytecomp/translcore.cmo \ bytecomp/translclass.cmo bytecomp/translmod.cmo \ bytecomp/simplif.cmo bytecomp/runtimedef.cmo \ bytecomp/meta.cmo bytecomp/opcodes.cmo \ @@ -161,6 +167,7 @@ ASMCOMP=\ asmcomp/export_info_for_pack.cmo \ asmcomp/compilenv.cmo \ asmcomp/closure.cmo \ + asmcomp/traverse_for_exported_symbols.cmo \ asmcomp/build_export_info.cmo \ asmcomp/closure_offsets.cmo \ asmcomp/flambda_to_clambda.cmo \ @@ -193,6 +200,7 @@ MIDDLE_END=\ middle_end/base_types/tag.cmo \ middle_end/base_types/linkage_name.cmo \ middle_end/base_types/compilation_unit.cmo \ + middle_end/internal_variable_names.cmo \ middle_end/base_types/variable.cmo \ middle_end/base_types/mutable_variable.cmo \ middle_end/base_types/id_types.cmo \ @@ -200,6 +208,7 @@ MIDDLE_END=\ middle_end/base_types/set_of_closures_origin.cmo \ middle_end/base_types/closure_element.cmo \ middle_end/base_types/closure_id.cmo \ + middle_end/base_types/closure_origin.cmo \ middle_end/base_types/var_within_closure.cmo \ middle_end/base_types/static_exception.cmo \ middle_end/base_types/export_id.cmo \ @@ -269,19 +278,14 @@ MAXSAVED=boot/Saved/Saved.prev/Saved.prev/Saved.prev/Saved.prev/Saved.prev COMPLIBDIR=$(LIBDIR)/compiler-libs -INSTALL_BINDIR=$(DESTDIR)$(BINDIR) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) -INSTALL_COMPLIBDIR=$(DESTDIR)$(COMPLIBDIR) -INSTALL_STUBLIBDIR=$(DESTDIR)$(STUBLIBDIR) -INSTALL_MANDIR=$(DESTDIR)$(MANDIR) -INSTALL_FLEXDLL=$(INSTALL_LIBDIR)/flexdll - +TOPINCLUDES=$(addprefix -I otherlibs/,$(filter-out %threads,$(OTHERLIBRARIES))) RUNTOP=./byterun/ocamlrun ./ocaml \ -nostdlib -I stdlib \ - -noinit $(TOPFLAGS) \ - -I otherlibs/$(UNIXLIB) -NATRUNTOP=./ocamlnat$(EXE) -nostdlib -I stdlib -noinit $(TOPFLAGS) -ifeq "UNIX_OR_WIN32" "unix" + -noinit $(TOPFLAGS) $(TOPINCLUDES) +NATRUNTOP=./ocamlnat$(EXE) \ + -nostdlib -I stdlib \ + -noinit $(TOPFLAGS) $(TOPINCLUDES) +ifeq "$(UNIX_OR_WIN32)" "unix" EXTRAPATH= else EXTRAPATH = PATH="otherlibs/win32unix:$(PATH)" @@ -332,6 +336,7 @@ utils/config.ml: utils/config.mlp config/Makefile Makefile $(call SUBST,EXT_LIB) \ $(call SUBST,EXT_OBJ) \ $(call SUBST,FLAMBDA) \ + $(call SUBST,WITH_FLAMBDA_INVARIANTS) \ $(call SUBST,FLEXLINK_FLAGS) \ $(call SUBST_QUOTE,FLEXDLL_DIR) \ $(call SUBST,HOST) \ @@ -399,11 +404,7 @@ coreall: # Build the core system: the minimum needed to make depend and bootstrap .PHONY: core core: -ifeq "$(UNIX_OR_WIN32)" "unix" $(MAKE) coldstart -else # Windows, to be fixed! - $(MAKE) runtime -endif $(MAKE) coreall # Save the current bootstrap compiler @@ -415,7 +416,7 @@ backup: mkdir boot/Saved mv boot/Saved.prev boot/Saved/Saved.prev cp boot/ocamlrun$(EXE) boot/Saved - cd boot; mv ocamlc ocamllex ocamlyacc$(EXE) ocamldep Saved + cd boot; mv ocamlc ocamllex ocamlyacc$(EXE) Saved cd boot; cp $(LIBFILES) Saved # Restore the saved bootstrap compiler if a problem arises @@ -427,8 +428,7 @@ restore: .PHONY: compare compare: @if $(CAMLRUN) tools/cmpbyt boot/ocamlc ocamlc \ - && $(CAMLRUN) tools/cmpbyt boot/ocamllex lex/ocamllex \ - && $(CAMLRUN) tools/cmpbyt boot/ocamldep tools/ocamldep; \ + && $(CAMLRUN) tools/cmpbyt boot/ocamllex lex/ocamllex; \ then echo "Fixpoint reached, bootstrap succeeded."; \ else echo "Fixpoint not reached, try one more bootstrapping cycle."; \ fi @@ -440,7 +440,6 @@ promote-cross: $(CAMLRUN) tools/stripdebug ocamlc boot/ocamlc $(CAMLRUN) tools/stripdebug lex/ocamllex boot/ocamllex cp yacc/ocamlyacc$(EXE) boot/ocamlyacc$(EXE) - $(CAMLRUN) tools/stripdebug tools/ocamldep boot/ocamldep cd stdlib; cp $(LIBFILES) ../boot # Promote the newly compiled system to the rank of bootstrap compiler @@ -462,19 +461,13 @@ opt-core: runtimeopt .PHONY: opt opt: -ifeq "$(UNIX_OR_WIN32)" "unix" $(MAKE) runtimeopt $(MAKE) ocamlopt $(MAKE) libraryopt $(MAKE) otherlibrariesopt ocamltoolsopt -else - $(MAKE) opt-core - $(MAKE) otherlibrariesopt ocamltoolsopt -endif # Native-code versions of the tools .PHONY: opt.opt -ifeq "$(UNIX_OR_WIN32)" "unix" opt.opt: $(MAKE) checkstack $(MAKE) runtime @@ -487,23 +480,6 @@ opt.opt: $(MAKE) otherlibrariesopt $(MAKE) ocamllex.opt ocamltoolsopt ocamltoolsopt.opt $(OCAMLDOC_OPT) \ ocamltest.opt -else -opt.opt: core opt-core ocamlc.opt all ocamlopt.opt ocamllex.opt \ - ocamltoolsopt ocamltoolsopt.opt otherlibrariesopt $(OCAMLDOC_OPT) \ - ocamltest.opt -endif - -.PHONY: base.opt -base.opt: - $(MAKE) checkstack - $(MAKE) runtime - $(MAKE) core - $(MAKE) ocaml - $(MAKE) opt-core - $(MAKE) ocamlc.opt - $(MAKE) otherlibraries $(WITH_DEBUGGER) $(WITH_OCAMLDOC) ocamltest - $(MAKE) ocamlopt.opt - $(MAKE) otherlibrariesopt # Core bootstrapping cycle .PHONY: coreboot @@ -602,17 +578,20 @@ flexlink.opt: mv flexlink.exe flexlink.opt && \ mv flexlink flexlink.exe +INSTALL_COMPLIBDIR=$(DESTDIR)$(COMPLIBDIR) +INSTALL_FLEXDLLDIR=$(INSTALL_LIBDIR)/flexdll + .PHONY: install-flexdll install-flexdll: cat stdlib/camlheader flexdll/flexlink.exe > \ "$(INSTALL_BINDIR)/flexlink.exe" ifneq "$(filter-out mingw,$(TOOLCHAIN))" "" - cp flexdll/default$(filter-out _i386,_$(ARCH)).manifest \ + $(INSTALL_DATA) flexdll/default$(filter-out _i386,_$(ARCH)).manifest \ "$(INSTALL_BINDIR)/" endif if test -n "$(wildcard flexdll/flexdll_*.$(O))" ; then \ - $(MKDIR) "$(INSTALL_FLEXDLL)" ; \ - cp flexdll/flexdll_*.$(O) "$(INSTALL_FLEXDLL)" ; \ + $(MKDIR) "$(INSTALL_FLEXDLLDIR)" ; \ + $(INSTALL_DATA) flexdll/flexdll_*.$(O) "$(INSTALL_FLEXDLLDIR)" ; \ fi # Installation @@ -622,26 +601,33 @@ install: $(MKDIR) "$(INSTALL_LIBDIR)" $(MKDIR) "$(INSTALL_STUBLIBDIR)" $(MKDIR) "$(INSTALL_COMPLIBDIR)" - cp VERSION "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) \ + VERSION \ + "$(INSTALL_LIBDIR)" $(MAKE) -C byterun install - cp ocaml "$(INSTALL_BINDIR)/ocaml$(EXE)" - cp ocamlc "$(INSTALL_BINDIR)/ocamlc.byte$(EXE)" + $(INSTALL_PROG) ocaml "$(INSTALL_BINDIR)/ocaml$(EXE)" + $(INSTALL_PROG) ocamlc "$(INSTALL_BINDIR)/ocamlc.byte$(EXE)" $(MAKE) -C stdlib install - cp lex/ocamllex "$(INSTALL_BINDIR)/ocamllex.byte$(EXE)" - cp yacc/ocamlyacc$(EXE) "$(INSTALL_BINDIR)/ocamlyacc$(EXE)" - cp utils/*.cmi utils/*.cmt utils/*.cmti utils/*.mli \ + $(INSTALL_PROG) lex/ocamllex "$(INSTALL_BINDIR)/ocamllex.byte$(EXE)" + $(INSTALL_PROG) yacc/ocamlyacc$(EXE) "$(INSTALL_BINDIR)/ocamlyacc$(EXE)" + $(INSTALL_DATA) \ + utils/*.cmi utils/*.cmt utils/*.cmti utils/*.mli \ parsing/*.cmi parsing/*.cmt parsing/*.cmti parsing/*.mli \ typing/*.cmi typing/*.cmt typing/*.cmti typing/*.mli \ bytecomp/*.cmi bytecomp/*.cmt bytecomp/*.cmti bytecomp/*.mli \ driver/*.cmi driver/*.cmt driver/*.cmti driver/*.mli \ toplevel/*.cmi toplevel/*.cmt toplevel/*.cmti toplevel/*.mli \ "$(INSTALL_COMPLIBDIR)" - cp compilerlibs/ocamlcommon.cma compilerlibs/ocamlbytecomp.cma \ + $(INSTALL_DATA) \ + compilerlibs/ocamlcommon.cma compilerlibs/ocamlbytecomp.cma \ compilerlibs/ocamltoplevel.cma $(BYTESTART) $(TOPLEVELSTART) \ "$(INSTALL_COMPLIBDIR)" - cp expunge "$(INSTALL_LIBDIR)/expunge$(EXE)" - cp toplevel/topdirs.cmi toplevel/topdirs.cmt toplevel/topdirs.cmti \ - toplevel/topdirs.mli "$(INSTALL_LIBDIR)" + $(INSTALL_PROG) expunge "$(INSTALL_LIBDIR)/expunge$(EXE)" + $(INSTALL_DATA) \ + toplevel/topdirs.cmi \ + toplevel/topdirs.cmt toplevel/topdirs.cmti \ + toplevel/topdirs.mli \ + "$(INSTALL_LIBDIR)" $(MAKE) -C tools install ifeq "$(UNIX_OR_WIN32)" "unix" # Install manual pages only on Unix $(MKDIR) "$(INSTALL_MANDIR)/man$(PROGRAMS_MAN_SECTION)" @@ -665,7 +651,7 @@ ifeq "$(UNIX_OR_WIN32)" "win32" $(MAKE) install-flexdll; \ fi endif - cp config/Makefile "$(INSTALL_LIBDIR)/Makefile.config" + $(INSTALL_DATA) config/Makefile "$(INSTALL_LIBDIR)/Makefile.config" if test -f ocamlopt; then $(MAKE) installopt; else \ cd "$(INSTALL_BINDIR)"; \ $(LN) ocamlc.byte$(EXE) ocamlc$(EXE); \ @@ -676,17 +662,26 @@ endif .PHONY: installopt installopt: $(MAKE) -C asmrun install - cp ocamlopt "$(INSTALL_BINDIR)/ocamlopt.byte$(EXE)" + $(INSTALL_PROG) ocamlopt "$(INSTALL_BINDIR)/ocamlopt.byte$(EXE)" $(MAKE) -C stdlib installopt - cp middle_end/*.cmi middle_end/*.cmt middle_end/*.cmti \ + $(INSTALL_DATA) \ + middle_end/*.cmi \ + middle_end/*.cmt middle_end/*.cmti \ middle_end/*.mli \ - "$(INSTALL_COMPLIBDIR)" - cp middle_end/base_types/*.cmi middle_end/base_types/*.cmt \ - middle_end/base_types/*.cmti middle_end/base_types/*.mli \ - "$(INSTALL_COMPLIBDIR)" - cp asmcomp/*.cmi asmcomp/*.cmt asmcomp/*.cmti asmcomp/*.mli \ - "$(INSTALL_COMPLIBDIR)" - cp compilerlibs/ocamloptcomp.cma $(OPTSTART) "$(INSTALL_COMPLIBDIR)" + "$(INSTALL_COMPLIBDIR)" + $(INSTALL_DATA) \ + middle_end/base_types/*.cmi \ + middle_end/base_types/*.cmt middle_end/base_types/*.cmti \ + middle_end/base_types/*.mli \ + "$(INSTALL_COMPLIBDIR)" + $(INSTALL_DATA) \ + asmcomp/*.cmi \ + asmcomp/*.cmt asmcomp/*.cmti \ + asmcomp/*.mli \ + "$(INSTALL_COMPLIBDIR)" + $(INSTALL_DATA) \ + compilerlibs/ocamloptcomp.cma $(OPTSTART) \ + "$(INSTALL_COMPLIBDIR)" if test -n "$(WITH_OCAMLDOC)"; then \ $(MAKE) -C ocamldoc installopt; \ fi @@ -701,30 +696,39 @@ installopt: fi $(MAKE) -C tools installopt if test -f ocamlopt.opt -a -f flexdll/flexlink.opt ; then \ - cp -f flexdll/flexlink.opt "$(INSTALL_BINDIR)/flexlink$(EXE)" ; \ + $(INSTALL_PROG) \ + flexdll/flexlink.opt "$(INSTALL_BINDIR)/flexlink$(EXE)" ; \ fi .PHONY: installoptopt installoptopt: - cp ocamlc.opt "$(INSTALL_BINDIR)/ocamlc.opt$(EXE)" - cp ocamlopt.opt "$(INSTALL_BINDIR)/ocamlopt.opt$(EXE)" - cp lex/ocamllex.opt "$(INSTALL_BINDIR)/ocamllex.opt$(EXE)" + $(INSTALL_PROG) ocamlc.opt "$(INSTALL_BINDIR)/ocamlc.opt$(EXE)" + $(INSTALL_PROG) ocamlopt.opt "$(INSTALL_BINDIR)/ocamlopt.opt$(EXE)" + $(INSTALL_PROG) \ + lex/ocamllex.opt "$(INSTALL_BINDIR)/ocamllex.opt$(EXE)" cd "$(INSTALL_BINDIR)"; \ $(LN) ocamlc.opt$(EXE) ocamlc$(EXE); \ $(LN) ocamlopt.opt$(EXE) ocamlopt$(EXE); \ $(LN) ocamllex.opt$(EXE) ocamllex$(EXE) - cp utils/*.cmx parsing/*.cmx typing/*.cmx bytecomp/*.cmx \ - driver/*.cmx asmcomp/*.cmx "$(INSTALL_COMPLIBDIR)" - cp compilerlibs/ocamlcommon.cmxa compilerlibs/ocamlcommon.$(A) \ + $(INSTALL_DATA) \ + utils/*.cmx parsing/*.cmx typing/*.cmx bytecomp/*.cmx \ + driver/*.cmx asmcomp/*.cmx \ + "$(INSTALL_COMPLIBDIR)" + $(INSTALL_DATA) \ + compilerlibs/ocamlcommon.cmxa compilerlibs/ocamlcommon.$(A) \ compilerlibs/ocamlbytecomp.cmxa compilerlibs/ocamlbytecomp.$(A) \ - compilerlibs/ocamloptcomp.cmxa compilerlibs/ocamloptcomp.$(A) \ + compilerlibs/ocamloptcomp.cmxa compilerlibs/ocamloptcomp.$(A) \ $(BYTESTART:.cmo=.cmx) $(BYTESTART:.cmo=.$(O)) \ $(OPTSTART:.cmo=.cmx) $(OPTSTART:.cmo=.$(O)) \ "$(INSTALL_COMPLIBDIR)" if test -f ocamlnat$(EXE) ; then \ - cp ocamlnat$(EXE) "$(INSTALL_BINDIR)/ocamlnat$(EXE)"; \ - cp toplevel/opttopdirs.cmi "$(INSTALL_LIBDIR)"; \ - cp compilerlibs/ocamlopttoplevel.cmxa \ + $(INSTALL_PROG) \ + ocamlnat$(EXE) "$(INSTALL_BINDIR)/ocamlnat$(EXE)"; \ + $(INSTALL_DATA) \ + toplevel/opttopdirs.cmi \ + "$(INSTALL_LIBDIR)"; \ + $(INSTALL_DATA) \ + compilerlibs/ocamlopttoplevel.cmxa \ compilerlibs/ocamlopttoplevel.$(A) \ $(OPTTOPLEVELSTART:.cmo=.cmx) $(OPTTOPLEVELSTART:.cmo=.$(O)) \ "$(INSTALL_COMPLIBDIR)"; \ @@ -735,9 +739,11 @@ installoptopt: # Installation of the *.ml sources of compiler-libs .PHONY: install-compiler-sources install-compiler-sources: - cp utils/*.ml parsing/*.ml typing/*.ml bytecomp/*.ml driver/*.ml \ + $(INSTALL_DATA) \ + utils/*.ml parsing/*.ml typing/*.ml bytecomp/*.ml driver/*.ml \ toplevel/*.ml middle_end/*.ml middle_end/base_types/*.ml \ - asmcomp/*.ml $(INSTALL_COMPLIBDIR) + asmcomp/*.ml \ + "$(INSTALL_COMPLIBDIR)" # Run all tests @@ -819,22 +825,17 @@ partialclean:: .PHONY: runtop runtop: -ifeq "$(UNIX_OR_WIN32)" "unix" - $(MAKE) runtime - $(MAKE) coreall - $(MAKE) ocaml -else - $(MAKE) core + $(MAKE) coldstart + $(MAKE) ocamlc + $(MAKE) otherlibraries $(MAKE) ocaml -endif @rlwrap --help 2>/dev/null && $(EXTRAPATH) rlwrap $(RUNTOP) ||\ $(EXTRAPATH) $(RUNTOP) .PHONY: natruntop natruntop: - $(MAKE) runtime - $(MAKE) coreall - $(MAKE) opt.opt + $(MAKE) core + $(MAKE) opt $(MAKE) ocamlnat @rlwrap --help 2>/dev/null && $(EXTRAPATH) rlwrap $(NATRUNTOP) ||\ $(EXTRAPATH) $(NATRUNTOP) @@ -983,7 +984,8 @@ clean:: otherlibs_all := bigarray dynlink graph raw_spacetime_lib \ str systhreads threads unix win32graph win32unix subdirs := asmrun byterun debugger lex ocamldoc ocamltest stdlib tools \ - $(addprefix otherlibs/, $(otherlibs_all)) + $(addprefix otherlibs/, $(otherlibs_all)) \ + ocamldoc/stdlib_non_prefixed .PHONY: alldepend ifeq "$(TOOLCHAIN)" "msvc" @@ -1111,15 +1113,16 @@ ocamldebugger: ocamlc ocamlyacc ocamllex otherlibraries partialclean:: $(MAKE) -C debugger clean -# Check that the stack limit is reasonable. -ifeq "$(UNIX_OR_WIN32)" "unix" +# Check that the stack limit is reasonable (Unix-only) .PHONY: checkstack checkstack: +ifeq "$(UNIX_OR_WIN32)" "unix" if $(MKEXE) $(OUTPUTEXE)tools/checkstack$(EXE) tools/checkstack.c; \ then tools/checkstack$(EXE); \ - else :; \ fi rm -f tools/checkstack$(EXE) +else + @ endif # Lint @since and @deprecated annotations @@ -1137,19 +1140,6 @@ lintapidiff: clean:: cd testsuite; $(MAKE) clean -# Make MacOS X package -ifeq "$(UNIX_OR_WIN32)" "unix" -.PHONY: package-macosx -package-macosx: - sudo rm -rf package-macosx/root - $(MAKE) PREFIX="`pwd`"/package-macosx/root install - tools/make-package-macosx - sudo rm -rf package-macosx/root - -clean:: - rm -rf package-macosx/*.pkg package-macosx/*.dmg -endif - # The middle end (whose .cma library is currently only used for linking # the "ocamlobjinfo" program, since we cannot depend on the whole native code # compiler for "make world" and the list of dependencies for @@ -1205,11 +1195,15 @@ check_arch: .PHONY: check_all_arches check_all_arches: +ifneq ($(shell grep -E '^\#define ARCH_SIXTYFOUR$$' byterun/caml/m.h 2> /dev/null),) @STATUS=0; \ for i in $(ARCHES); do \ $(MAKE) --no-print-directory check_arch ARCH=$$i || STATUS=1; \ done; \ exit $$STATUS +else + @echo "Architecture tests are disabled on 32-bit platforms." +endif # Compiler Plugins @@ -1321,6 +1315,6 @@ distclean: clean rm -f config/Makefile byterun/caml/m.h byterun/caml/s.h rm -f tools/*.bak rm -f ocaml ocamlc - rm -f testsuite/_log + rm -f testsuite/_log* include .depend diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 00000000..cd9f676b --- /dev/null +++ b/Makefile.common @@ -0,0 +1,30 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Gabriel Scherer, projet Parsifal, INRIA Saclay * +#* * +#* Copyright 2018 Institut National de Recherche en Informatique et * +#* en Automatique. * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# This makefile contains common definitions shared by other Makefiles +# We assume that config/Makefile has already been included + +INSTALL ?= install +INSTALL_DATA ?= $(INSTALL) -m u=rw,g=rw,o=r +INSTALL_PROG ?= $(INSTALL) -m u=rwx,g=rwx,o=rx + +# note: these are defined by lazy expansions +# as some parts of the makefiles change BINDIR, etc. +# and expect INSTALL_BINDIR, etc. to stay in synch +# (see `shellquote` in tools/Makefile) +INSTALL_BINDIR = $(DESTDIR)$(BINDIR) +INSTALL_LIBDIR = $(DESTDIR)$(LIBDIR) +INSTALL_STUBLIBDIR = $(DESTDIR)$(STUBLIBDIR) +INSTALL_MANDIR = $(DESTDIR)$(MANDIR) diff --git a/README.adoc b/README.adoc index 34ca38a0..74d1ec25 100644 --- a/README.adoc +++ b/README.adoc @@ -1,8 +1,10 @@ |===== -| Branch `trunk` | Branch `4.05` | Branch `4.04` +| Branch `trunk` | Branch `4.06` | Branch `4.05` | Branch `4.04` | image:https://travis-ci.org/ocaml/ocaml.svg?branch=trunk["TravisCI Build Status (trunk branch)",link="https://travis-ci.org/ocaml/ocaml"] image:https://ci.appveyor.com/api/projects/status/github/ocaml/ocaml?branch=trunk&svg=true["AppVeyor Build Status (trunk branch)",link="https://ci.appveyor.com/project/avsm/ocaml"] +| image:https://travis-ci.org/ocaml/ocaml.svg?branch=4.06["TravisCI Build Status (4.06 branch)",link="https://travis-ci.org/ocaml/ocaml"] + image:https://ci.appveyor.com/api/projects/status/github/ocaml/ocaml?branch=4.06&svg=true["AppVeyor Build Status (4.06 branch)",link="https://ci.appveyor.com/project/avsm/ocaml"] | image:https://travis-ci.org/ocaml/ocaml.svg?branch=4.05["TravisCI Build Status (4.05 branch)",link="https://travis-ci.org/ocaml/ocaml"] image:https://ci.appveyor.com/api/projects/status/github/ocaml/ocaml?branch=4.05&svg=true["AppVeyor Build Status (4.05 branch)",link="https://ci.appveyor.com/project/avsm/ocaml"] | image:https://travis-ci.org/ocaml/ocaml.svg?branch=4.04["TravisCI Build Status (4.04 branch)",link="https://travis-ci.org/ocaml/ocaml"] @@ -73,45 +75,37 @@ Windows, see link:README.win32.adoc[]. The OCaml manual is distributed in HTML, PDF, Postscript, DVI, and Emacs Info files. It is available at -http://caml.inria.fr/ - -The community also maintains the Web site http://ocaml.org, with tutorials -and other useful information for OCaml users. +http://caml.inria.fr/pub/docs/manual-ocaml/ == Availability The complete OCaml distribution can be accessed at -http://caml.inria.fr/ +http://ocaml.org/docs/install.html == Keeping in Touch with the Caml Community -There exists a mailing list of users of the OCaml implementations developed -at INRIA. The purpose of this list is to share experience, exchange ideas -(and even code), and report on applications of the OCaml language. Messages -can be written in English or in French. The list has more than 1000 -subscribers. - -Messages to the list should be sent to: +The OCaml mailing list is the longest-running forum for OCaml users. +You can email it at mailto:caml-list@inria.fr[] -You can subscribe to this list via the Web interface at +You can subscribe and access list archives via the Web interface at https://sympa.inria.fr/sympa/subscribe/caml-list -Archives of the list are available on the Web site above. +You can also access a newer discussion forum at -The Usenet news `groups comp.lang.ml` and `comp.lang.functional` also -contains discussions about the ML family of programming languages, including -OCaml. +https://discuss.ocaml.org/ -The IRC channel `#ocaml` on https://freenode.net/[Freenode] also has several -hundred users and welcomes questions. +There also exist other mailing lists, chat channels, and various other forums +around the internet for getting in touch with the OCaml and ML family language +community. These can be accessed at -The OCaml Community website is +http://ocaml.org/community/ -http://ocaml.org/ +In particular, the IRC channel `#ocaml` on https://freenode.net/[Freenode] has a +long history and welcomes questions. == Bug Reports and User Feedback diff --git a/README.win32.adoc b/README.win32.adoc index 57ef54fa..8d9d110b 100644 --- a/README.win32.adoc +++ b/README.win32.adoc @@ -188,7 +188,7 @@ the top-level of the OCaml distribution by running: eval $(tools/msvs-promote-path) -If you forget to do this, `make world` will fail relatively +If you forget to do this, `make world.opt` will fail relatively quickly as it will be unable to link `ocamlrun`. Now run: @@ -210,7 +210,8 @@ which indicates where to install everything. Finally, use `make` to build the system, e.g. - make world bootstrap opt opt.opt install + make world.opt + make install After installing, it is not necessary to keep the Cygwin installation (although you may require it to build additional third party libraries and tools). You @@ -281,7 +282,8 @@ which indicates where to install everything. Finally, use `make` to build the system, e.g. - make world bootstrap opt opt.opt install + make world.opt + make install After installing, you will need to ensure that `ocamlopt` (or `ocamlc -custom`) can access the C compiler. You can do this either by using OCaml from Cygwin's @@ -292,12 +294,6 @@ bash or by adding Cygwin's bin directory (e.g. `C:\cygwin\bin`) to your `PATH`. * The replay debugger is partially supported (no reverse execution). -* The default `config/Makefile.mingw` and `config/Makefile.mingw64` pass - `-static-libgcc` to the linker. For more information on this topic: - - - http://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Link-Options.html#Link-Options - - http://caml.inria.fr/mantis/view.php?id=6411 - [[seflexdll]] == FlexDLL Although the core of FlexDLL is necessarily written in C, the `flexlink` program @@ -327,7 +323,10 @@ done in one of three ways: OCaml is then compiled as normal for the port you require, except that before compiling `world`, you must compile `flexdll`, i.e.: - make flexdll world [bootstrap] opt opt.opt flexlink.opt install + make flexdll + make world.opt + make flexlink.opt + make install * You should ignore the error messages that say ocamlopt was not found. * `make install` will install FlexDLL by placing `flexlink.exe` diff --git a/VERSION b/VERSION index 33d444c9..6d514477 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -4.06.1 +4.07.0 # The version string is the first line of this file. # It must be in the format described in stdlib/sys.mli diff --git a/appveyor.yml b/appveyor.yml index baa20dac..c07c60f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,10 +35,10 @@ cache: install: # This is a hangover from monitoring effects of MPR#7452 - wmic cpu get name - - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" install + - call "%APPVEYOR_BUILD_FOLDER%\tools\ci\appveyor\appveyor_build.cmd" install build_script: - - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" build + - call "%APPVEYOR_BUILD_FOLDER%\tools\ci\appveyor\appveyor_build.cmd" build test_script: - - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" test + - call "%APPVEYOR_BUILD_FOLDER%\tools\ci\appveyor\appveyor_build.cmd" test diff --git a/appveyor_build.cmd b/appveyor_build.cmd deleted file mode 100644 index 76093daf..00000000 --- a/appveyor_build.cmd +++ /dev/null @@ -1,113 +0,0 @@ -@rem *********************************************************************** -@rem * * -@rem * OCaml * -@rem * * -@rem * David Allsopp, OCaml Labs, Cambridge. * -@rem * * -@rem * Copyright 2017 MetaStack Solutions Ltd. * -@rem * * -@rem * All rights reserved. This file is distributed under the terms of * -@rem * the GNU Lesser General Public License version 2.1, with the * -@rem * special exception on linking described in the file LICENSE. * -@rem * * -@rem *********************************************************************** - -@rem BE CAREFUL ALTERING THIS FILE TO ENSURE THAT ERRORS PROPAGATE -@rem IF A COMMAND SHOULD FAIL IT PROBABLY NEEDS TO END WITH -@rem || exit /b 1 -@rem BASICALLY, DO THE TESTING IN BASH... - -@rem Do not call setlocal! -@echo off - -goto %1 - -goto :EOF - -:SaveVars -set OCAML_PREV_PATH=%PATH% -set OCAML_PREV_LIB=%LIB% -set OCAML_PREV_INCLUDE=%INCLUDE% -goto :EOF - -:RestoreVars -set PATH=%OCAML_PREV_PATH% -set LIB=%OCAML_PREV_LIB% -set INCLUDE=%OCAML_PREV_INCLUDE% -goto :EOF - -:CheckPackage -"%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %1" | findstr %1 > nul -if %ERRORLEVEL% equ 1 ( - echo Cygwin package %1 will be installed - set CYGWIN_INSTALL_PACKAGES=%CYGWIN_INSTALL_PACKAGES%,%1 -) -goto :EOF - -:UpgradeCygwin -if "%CYGWIN_INSTALL_PACKAGES%" neq "" "%CYG_ROOT%\setup-x86_64.exe" --quiet-mode --no-shortcuts --no-startmenu --no-desktop --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages %CYGWIN_INSTALL_PACKAGES:~1% > nul -for %%P in (%CYGWIN_COMMANDS%) do "%CYG_ROOT%\bin\%%P.exe" --version > nul || set CYGWIN_UPGRADE_REQUIRED=1 -"%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %CYGWIN_PACKAGES%" -if %CYGWIN_UPGRADE_REQUIRED% equ 1 ( - echo Cygwin package upgrade required - please go and drink coffee - "%CYG_ROOT%\setup-x86_64.exe" --quiet-mode --no-shortcuts --no-startmenu --no-desktop --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --upgrade-also > nul - "%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %CYGWIN_PACKAGES%" -) -goto :EOF - -:install -chcp 65001 > nul -rem This must be kept in sync with appveyor_build.sh -set BUILD_PREFIX=🐫реализация -git worktree add "..\%BUILD_PREFIX%-msvc64" -b appveyor-build-msvc64 -git worktree add "..\%BUILD_PREFIX%-mingw32" -b appveyor-build-mingw32 -git worktree add "..\%BUILD_PREFIX%-msvc32" -b appveyor-build-msvc32 -cd "..\%BUILD_PREFIX%-mingw32" -git submodule update --init flexdll - -cd "%APPVEYOR_BUILD_FOLDER%" -appveyor DownloadFile "https://github.com/alainfrisch/flexdll/archive/0.37.tar.gz" -FileName "flexdll.tar.gz" || exit /b 1 -appveyor DownloadFile "https://github.com/alainfrisch/flexdll/releases/download/0.37/flexdll-bin-0.37.zip" -FileName "flexdll.zip" || exit /b 1 -rem flexdll.zip is processed here, rather than in appveyor_build.sh because the -rem unzip command comes from MSYS2 (via Git for Windows) and it has to be -rem invoked via cmd /c in a bash script which is weird(er). -mkdir "%APPVEYOR_BUILD_FOLDER%\..\flexdll" -move flexdll.zip "%APPVEYOR_BUILD_FOLDER%\..\flexdll" -cd "%APPVEYOR_BUILD_FOLDER%\..\flexdll" && unzip -q flexdll.zip - -rem CYGWIN_PACKAGES is the list of required Cygwin packages (cygwin is included -rem in the list just so that the Cygwin version is always displayed on the log). -rem CYGWIN_COMMANDS is a corresponding command to run with --version to test -rem whether the package works. This is used to verify whether the installation -rem needs upgrading. -set CYGWIN_PACKAGES=cygwin make diffutils mingw64-i686-gcc-core -set CYGWIN_COMMANDS=cygcheck make diff i686-w64-mingw32-gcc - -set CYGWIN_INSTALL_PACKAGES= -set CYGWIN_UPGRADE_REQUIRED=0 - -for %%P in (%CYGWIN_PACKAGES%) do call :CheckPackage %%P -call :UpgradeCygwin - -"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/appveyor_build.sh install" || exit /b 1 - -call :SaveVars -goto :EOF - -:build -rem Run the msvc64 and mingw32 builds -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" -"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/appveyor_build.sh" || exit /b 1 - -rem Reconfigure the environment and run the msvc32 partial build -call :RestoreVars -call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x86 -"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/appveyor_build.sh msvc32-only" || exit /b 1 -goto :EOF - -:test -rem Reconfigure the environment for the msvc64 build -call :RestoreVars -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" -"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/appveyor_build.sh test" || exit /b 1 -goto :EOF diff --git a/asmcomp/CSEgen.ml b/asmcomp/CSEgen.ml index 7e585355..d0b6eb2a 100644 --- a/asmcomp/CSEgen.ml +++ b/asmcomp/CSEgen.ml @@ -362,6 +362,10 @@ method private cse n i = next = self#cse empty_numbering i.next} method fundecl f = - {f with fun_body = self#cse empty_numbering f.fun_body} + (* CSE can trigger bad register allocation behaviors, see MPR#7630 *) + if List.mem Cmm.No_CSE f.fun_codegen_options then + f + else + {f with fun_body = self#cse empty_numbering f.fun_body } end diff --git a/asmcomp/amd64/emit.mlp b/asmcomp/amd64/emit.mlp index 36ec47ed..cf261a06 100644 --- a/asmcomp/amd64/emit.mlp +++ b/asmcomp/amd64/emit.mlp @@ -385,7 +385,7 @@ let output_test_zero arg = (* Output a floating-point compare and branch *) -let emit_float_test cmp neg i lbl = +let emit_float_test cmp i lbl = (* Effect of comisd on flags and conditional branches: ZF PF CF cond. branches taken unordered 1 1 1 je, jb, jbe, jp @@ -395,33 +395,41 @@ let emit_float_test cmp neg i lbl = If FP traps are on (they are off by default), comisd traps on QNaN and SNaN but ucomisd traps on SNaN only. *) - match (cmp, neg) with - | (Ceq, false) | (Cne, true) -> + match cmp with + | CFeq -> let next = new_label() in I.ucomisd (arg i 1) (arg i 0); I.jp (label next); (* skip if unordered *) I.je lbl; (* branch taken if x=y *) def_label next - | (Cne, false) | (Ceq, true) -> + | CFneq -> I.ucomisd (arg i 1) (arg i 0); I.jp lbl; (* branch taken if unordered *) I.jne lbl (* branch taken if xy *) - | (Clt, _) -> + | CFlt -> I.comisd (arg i 0) (arg i 1); - if not neg then I.ja lbl (* branch taken if y>x i.e. x + I.ja lbl (* branch taken if y>x i.e. x + I.comisd (arg i 0) (arg i 1); + I.jbe lbl (* taken if unordered or y<=x i.e. !(x + I.comisd (arg i 0) (arg i 1);(* swap compare *) + I.jae lbl (* branch taken if y>=x i.e. x<=y *) + | CFnle -> I.comisd (arg i 0) (arg i 1);(* swap compare *) - if not neg then I.jae lbl (* branch taken if y>=x i.e. x<=y *) - else I.jb lbl (* taken if unordered or y + I.jb lbl (* taken if unordered or y I.comisd (arg i 1) (arg i 0); - if not neg then I.ja lbl (* branch taken if x>y *) - else I.jbe lbl (* taken if unordered or x<=y i.e. !(x>y) *) - | (Cge, _) -> + I.ja lbl (* branch taken if x>y *) + | CFngt -> + I.comisd (arg i 1) (arg i 0); + I.jbe lbl (* taken if unordered or x<=y i.e. !(x>y) *) + | CFge -> + I.comisd (arg i 1) (arg i 0);(* swap compare *) + I.jae lbl (* branch taken if x>=y *) + | CFnge -> I.comisd (arg i 1) (arg i 0);(* swap compare *) - if not neg then I.jae lbl (* branch taken if x>=y *) - else I.jb lbl (* taken if unordered or x=y) *) + I.jb lbl (* taken if unordered or x=y) *) (* Deallocate the stack frame before a return or tail call *) @@ -770,8 +778,8 @@ let emit_instr fallthrough i = | Iinttest_imm(cmp, n) -> I.cmp (int n) (arg i 0); I.j (cond cmp) lbl - | Ifloattest(cmp, neg) -> - emit_float_test cmp neg i lbl + | Ifloattest cmp -> + emit_float_test cmp i lbl | Ioddtest -> I.test (int 1) (arg8 i 0); I.jne lbl diff --git a/asmcomp/amd64/reload.ml b/asmcomp/amd64/reload.ml index 690e0165..a4070b47 100644 --- a/asmcomp/amd64/reload.ml +++ b/asmcomp/amd64/reload.ml @@ -107,13 +107,13 @@ method! reload_test tst arg = if stackp arg.(0) && stackp arg.(1) then [| self#makereg arg.(0); arg.(1) |] else arg - | Ifloattest((Clt|Cle), _) -> + | Ifloattest (CFlt | CFnlt | CFle | CFnle) -> (* Cf. emit.mlp: we swap arguments in this case *) (* First argument can be on stack, second must be in register *) if stackp arg.(1) then [| arg.(0); self#makereg arg.(1) |] else arg - | Ifloattest((Ceq|Cne|Cgt|Cge), _) -> + | Ifloattest (CFeq | CFneq | CFgt | CFngt | CFge | CFnge) -> (* Second argument can be on stack, first must be in register *) if stackp arg.(0) then [| self#makereg arg.(0); arg.(1) |] diff --git a/asmcomp/arm/arch.ml b/asmcomp/arm/arch.ml index 2ec00e01..becfff38 100644 --- a/asmcomp/arm/arch.ml +++ b/asmcomp/arm/arch.ml @@ -19,7 +19,7 @@ open Format type abi = EABI | EABI_HF -type arch = ARMv4 | ARMv5 | ARMv5TE | ARMv6 | ARMv6T2 | ARMv7 +type arch = ARMv4 | ARMv5 | ARMv5TE | ARMv6 | ARMv6T2 | ARMv7 | ARMv8 type fpu = Soft | VFPv2 | VFPv3_D16 | VFPv3 let abi = @@ -35,6 +35,7 @@ let string_of_arch = function | ARMv6 -> "armv6" | ARMv6T2 -> "armv6t2" | ARMv7 -> "armv7" + | ARMv8 -> "armv8" let string_of_fpu = function Soft -> "soft" @@ -53,8 +54,10 @@ let (arch, fpu, thumb) = | EABI, "armv6" -> ARMv6, Soft, false | EABI, "armv6t2" -> ARMv6T2, Soft, false | EABI, "armv7" -> ARMv7, Soft, false + | EABI, "armv8" -> ARMv8, Soft, false | EABI, _ -> ARMv4, Soft, false | EABI_HF, "armv6" -> ARMv6, VFPv2, false + | EABI_HF, "armv8" -> ARMv8, VFPv3, true | EABI_HF, _ -> ARMv7, VFPv3_D16, true end in (ref def_arch, ref def_fpu, ref def_thumb) @@ -67,6 +70,7 @@ let farch spec = | "armv6" -> ARMv6 | "armv6t2" -> ARMv6T2 | "armv7" -> ARMv7 + | "armv8" -> ARMv8 | spec -> raise (Arg.Bad ("wrong '-farch' option: " ^ spec)) end diff --git a/asmcomp/arm/emit.mlp b/asmcomp/arm/emit.mlp index 1531cb7a..182ccbdf 100644 --- a/asmcomp/arm/emit.mlp +++ b/asmcomp/arm/emit.mlp @@ -165,8 +165,8 @@ let emit_call_bound_error bd = (* Negate a comparison *) let negate_integer_comparison = function - Isigned cmp -> Isigned(negate_comparison cmp) - | Iunsigned cmp -> Iunsigned(negate_comparison cmp) + | Isigned cmp -> Isigned(negate_integer_comparison cmp) + | Iunsigned cmp -> Iunsigned(negate_integer_comparison cmp) (* Names of various instructions *) @@ -367,6 +367,35 @@ let emit_load_symbol_addr dst s = 1 end +(* Emit instructions that set [rd] to 1 if integer condition [cmp] holds + and set [rd] to 0 otherwise. *) + +let emit_set_condition cmp rd = + let compthen = name_for_comparison cmp in + let compelse = name_for_comparison (negate_integer_comparison cmp) in + if !arch < ARMv8 || not !thumb then begin + ` ite {emit_string compthen}\n`; + ` mov{emit_string compthen} {emit_reg rd}, #1\n`; + ` mov{emit_string compelse} {emit_reg rd}, #0\n`; + 3 + end else begin + (* T32 mode in ARMv8 deprecates general ITE blocks + and favors IT blocks containing only one 16-bit instruction. + mov , # is 16 bits if is R0...R7 + and fits in 8 bits. *) + let temp = + match rd.loc with + | Reg r when r < 8 -> rd (* can assign rd directly *) + | _ -> phys_reg 3 (* use r3 as temporary *) in + ` it {emit_string compthen}\n`; + ` mov{emit_string compthen} {emit_reg temp}, #1\n`; + ` it {emit_string compelse}\n`; + ` mov{emit_string compelse} {emit_reg temp}, #0\n`; + if temp.loc = rd.loc then 4 else begin + ` movs {emit_reg rd}, {emit_reg temp}\n`; 5 + end + end + (* Output the assembly code for an instruction *) let emit_instr i = @@ -572,19 +601,11 @@ let emit_instr i = 1 + ninstr end | Lop(Iintop(Icomp cmp)) -> - let compthen = name_for_comparison cmp in - let compelse = name_for_comparison (negate_integer_comparison cmp) in ` cmp {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; - ` ite {emit_string compthen}\n`; - ` mov{emit_string compthen} {emit_reg i.res.(0)}, #1\n`; - ` mov{emit_string compelse} {emit_reg i.res.(0)}, #0\n`; 4 + 1 + emit_set_condition cmp i.res.(0) | Lop(Iintop_imm(Icomp cmp, n)) -> - let compthen = name_for_comparison cmp in - let compelse = name_for_comparison (negate_integer_comparison cmp) in ` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`; - ` ite {emit_string compthen}\n`; - ` mov{emit_string compthen} {emit_reg i.res.(0)}, #1\n`; - ` mov{emit_string compelse} {emit_reg i.res.(0)}, #0\n`; 4 + 1 + emit_set_condition cmp i.res.(0) | Lop(Iintop (Icheckbound { label_after_error; } )) -> let lbl = bound_error_label ?label:label_after_error i.dbg in ` cmp {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; @@ -705,18 +726,20 @@ let emit_instr i = ` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`; let comp = name_for_comparison cmp in ` b{emit_string comp} {emit_label lbl}\n`; 2 - | Ifloattest(cmp, neg) -> - let comp = (match (cmp, neg) with - (Ceq, false) | (Cne, true) -> "eq" - | (Cne, false) | (Ceq, true) -> "ne" - | (Clt, false) -> "cc" - | (Clt, true) -> "cs" - | (Cle, false) -> "ls" - | (Cle, true) -> "hi" - | (Cgt, false) -> "gt" - | (Cgt, true) -> "le" - | (Cge, false) -> "ge" - | (Cge, true) -> "lt") in + | Ifloattest cmp -> + let comp = + match cmp with + | CFeq -> "eq" + | CFneq -> "ne" + | CFlt -> "cc" + | CFnlt -> "cs" + | CFle -> "ls" + | CFnle -> "hi" + | CFgt -> "gt" + | CFngt -> "le" + | CFge -> "ge" + | CFnge -> "lt" + in ` fcmpd {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ` fmstat\n`; ` b{emit_string comp} {emit_label lbl}\n`; 3 @@ -929,6 +952,7 @@ let begin_assembly() = | ARMv6 -> ` .arch armv6\n` | ARMv6T2 -> ` .arch armv6t2\n` | ARMv7 -> ` .arch armv7-a\n` + | ARMv8 -> ` .arch armv8-a\n` end; begin match !fpu with Soft -> ` .fpu softvfp\n` diff --git a/asmcomp/arm/proc.ml b/asmcomp/arm/proc.ml index df9aaeef..9e1bb648 100644 --- a/asmcomp/arm/proc.ml +++ b/asmcomp/arm/proc.ml @@ -265,6 +265,9 @@ let destroyed_at_oper = function [| phys_reg 3; phys_reg 8 |] (* r3 and r12 destroyed *) | Iop(Iintop Imulh) when !arch < ARMv6 -> [| phys_reg 8 |] (* r12 destroyed *) + | Iop(Iintop (Icomp _) | Iintop_imm(Icomp _, _)) + when !arch >= ARMv8 && !thumb -> + [| phys_reg 3 |] (* r3 destroyed *) | Iop(Iintoffloat | Ifloatofint | Iload(Single, _) | Istore(Single, _, _)) -> [| phys_reg 107 |] (* d7 (s14-s15) destroyed *) | _ -> [||] diff --git a/asmcomp/arm/selection.ml b/asmcomp/arm/selection.ml index 3a3a5c61..747e86a2 100644 --- a/asmcomp/arm/selection.ml +++ b/asmcomp/arm/selection.ml @@ -23,10 +23,10 @@ open Mach let is_offset chunk n = match chunk with - (* VFPv{2,3} load/store have -1020 to 1020 *) - Single | Double | Double_u + (* VFPv{2,3} load/store have -1020 to 1020. Offset must be multiple of 4 *) + | Single | Double | Double_u when !fpu >= VFPv2 -> - n >= -1020 && n <= 1020 + n >= -1020 && n <= 1020 && n mod 4 = 0 (* ARM load/store byte/word have -4095 to 4095 *) | Byte_unsigned | Byte_signed | Thirtytwo_unsigned | Thirtytwo_signed @@ -240,16 +240,19 @@ method private select_operation_softfp op args dbg = | (Cfloatofint, args) -> (self#iextcall("__aeabi_i2d", false), args) | (Cintoffloat, args) -> (self#iextcall("__aeabi_d2iz", false), args) | (Ccmpf comp, args) -> - let func = (match comp with - Cne (* there's no __aeabi_dcmpne *) - | Ceq -> "__aeabi_dcmpeq" - | Clt -> "__aeabi_dcmplt" - | Cle -> "__aeabi_dcmple" - | Cgt -> "__aeabi_dcmpgt" - | Cge -> "__aeabi_dcmpge") in - let comp = (match comp with - Cne -> Ceq (* eq 0 => false *) - | _ -> Cne (* ne 0 => true *)) in + let comp, func = + match comp with + | CFeq -> Cne, "__aeabi_dcmpeq" + | CFneq -> Ceq, "__aeabi_dcmpeq" + | CFlt -> Cne, "__aeabi_dcmplt" + | CFnlt -> Ceq, "__aeabi_dcmplt" + | CFle -> Cne, "__aeabi_dcmple" + | CFnle -> Ceq, "__aeabi_dcmple" + | CFgt -> Cne, "__aeabi_dcmpgt" + | CFngt -> Ceq, "__aeabi_dcmpgt" + | CFge -> Cne, "__aeabi_dcmpge" + | CFnge -> Ceq, "__aeabi_dcmpge" + in (Iintop_imm(Icomp(Iunsigned comp), 0), [Cop(Cextcall(func, typ_int, false, None), args, dbg)]) (* Add coercions around loads and stores of 32-bit floats *) diff --git a/asmcomp/arm64/emit.mlp b/asmcomp/arm64/emit.mlp index ba97d813..de15b744 100644 --- a/asmcomp/arm64/emit.mlp +++ b/asmcomp/arm64/emit.mlp @@ -792,18 +792,20 @@ let emit_instr i = ` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`; let comp = name_for_comparison cmp in ` b.{emit_string comp} {emit_label lbl}\n` - | Ifloattest(cmp, neg) -> - let comp = (match (cmp, neg) with - | (Ceq, false) | (Cne, true) -> "eq" - | (Cne, false) | (Ceq, true) -> "ne" - | (Clt, false) -> "cc" - | (Clt, true) -> "cs" - | (Cle, false) -> "ls" - | (Cle, true) -> "hi" - | (Cgt, false) -> "gt" - | (Cgt, true) -> "le" - | (Cge, false) -> "ge" - | (Cge, true) -> "lt") in + | Ifloattest cmp -> + let comp = + match cmp with + | CFeq -> "eq" + | CFneq -> "ne" + | CFlt -> "cc" + | CFnlt -> "cs" + | CFle -> "ls" + | CFnle -> "hi" + | CFgt -> "gt" + | CFngt -> "le" + | CFge -> "ge" + | CFnge -> "lt" + in ` fcmp {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ` b.{emit_string comp} {emit_label lbl}\n` | Ioddtest -> diff --git a/asmcomp/asmgen.ml b/asmcomp/asmgen.ml index 2d8dc3f8..c3bd1cb5 100644 --- a/asmcomp/asmgen.ml +++ b/asmcomp/asmgen.ml @@ -198,7 +198,7 @@ let end_gen_implementation ?toplevel ppf let flambda_gen_implementation ?toplevel ~backend ppf (program:Flambda.program) = - let export = Build_export_info.build_export_info ~backend program in + let export = Build_export_info.build_transient ~backend program in let (clambda, preallocated, constants) = Profile.record_call "backend" (fun () -> (program, export) @@ -230,7 +230,7 @@ let lambda_gen_implementation ?toplevel ppf symbol = Compilenv.make_symbol None; exported = true; tag = 0; - size = lambda.main_module_block_size; + fields = List.init lambda.main_module_block_size (fun _ -> None); } in let clambda_and_constants = diff --git a/asmcomp/asmlink.ml b/asmcomp/asmlink.ml index fe93e5e1..90617dc8 100644 --- a/asmcomp/asmlink.ml +++ b/asmcomp/asmlink.ml @@ -119,7 +119,7 @@ let object_file_name name = try find_in_path !load_path name with Not_found -> - fatal_error "Asmlink.object_file_name: not found" in + fatal_errorf "Asmlink.object_file_name: %s not found" name in if Filename.check_suffix file_name ".cmx" then Filename.chop_suffix file_name ".cmx" ^ ext_obj else if Filename.check_suffix file_name ".cmxa" then @@ -203,6 +203,9 @@ let scan_file obj_name tolink = match read_file obj_name with (* Second pass: generate the startup file and link it with everything else *) +let force_linking_of_startup ppf = + Asmgen.compile_phrase ppf (Cmm.Cdata ([Cmm.Csymbol_address "caml_startup"])) + let make_startup_file ppf units_list = let compile_phrase p = Asmgen.compile_phrase ppf p in Location.input_name := "caml_startup"; (* set name of "current" input *) @@ -238,6 +241,8 @@ let make_startup_file ppf units_list = if Config.spacetime then begin compile_phrase (Cmmgen.spacetime_shapes all_names); end; + if !Clflags.output_complete_object then + force_linking_of_startup ppf; Emit.end_assembly () let make_shared_startup_file ppf units = @@ -251,6 +256,8 @@ let make_shared_startup_file ppf units = compile_phrase (Cmmgen.global_table (List.map (fun (ui,_) -> ui.ui_symbol) units)); + if !Clflags.output_complete_object then + force_linking_of_startup ppf; (* this is to force a reference to all units, otherwise the linker might drop some of them (in case of libraries) *) Emit.end_assembly () @@ -422,4 +429,6 @@ let reset () = implementations_defined := []; cmx_required := []; interfaces := []; - implementations := [] + implementations := []; + lib_ccobjs := []; + lib_ccopts := [] diff --git a/asmcomp/build_export_info.ml b/asmcomp/build_export_info.ml index 80f97f05..bf37e609 100644 --- a/asmcomp/build_export_info.ml +++ b/asmcomp/build_export_info.ml @@ -20,7 +20,14 @@ module Env : sig type t val new_descr : t -> Export_info.descr -> Export_id.t + val record_descr : t -> Export_id.t -> Export_info.descr -> unit + val new_value_closure_descr + : t + -> closure_id:Closure_id.t + -> set_of_closures: Export_info.value_set_of_closures + -> Export_id.t + val get_descr : t -> Export_info.approx -> Export_info.descr option val add_approx : t -> Variable.t -> Export_info.approx -> t @@ -56,11 +63,13 @@ end = struct (* Note that [ex_table]s themselves are shared (hence [ref] and not [mutable]). *) ex_table : Export_info.descr Export_id.Map.t ref; + closure_table : Export_id.t Closure_id.Map.t ref; } let create_empty () = { sym = Symbol.Map.empty; ex_table = ref Export_id.Map.empty; + closure_table = ref Closure_id.Map.empty; } let add_symbol t sym export_id = @@ -85,12 +94,14 @@ end = struct { var : Export_info.approx Variable.Map.t; sym : Export_id.t Symbol.Map.t; ex_table : Export_info.descr Export_id.Map.t ref; + closure_table: Export_id.t Closure_id.Map.t ref; } let empty_of_global (env : Global.t) = { var = Variable.Map.empty; sym = env.sym; ex_table = env.ex_table; + closure_table = env.closure_table; } let extern_id_descr export_id = @@ -102,13 +113,17 @@ end = struct if Compilenv.is_predefined_exception sym then None else - let export = Compilenv.approx_for_global (Symbol.compilation_unit sym) in - try - let id = Symbol.Map.find sym export.symbol_id in - let descr = Export_info.find_description export id in - Some descr + match + Compilenv.approx_for_global (Symbol.compilation_unit sym) with - | Not_found -> None + | None -> None + | Some export -> + try + let id = Symbol.Map.find sym export.symbol_id in + let descr = Export_info.find_description export id in + Some descr + with + | Not_found -> None let get_id_descr t export_id = try Some (Export_id.Map.find export_id !(t.ex_table)) @@ -140,6 +155,17 @@ end = struct record_descr t id descr; id + let new_value_closure_descr t ~closure_id ~set_of_closures = + match Closure_id.Map.find closure_id !(t.closure_table) with + | exception Not_found -> + let export_id = + new_descr t (Value_closure { closure_id; set_of_closures }) + in + t.closure_table := + Closure_id.Map.add closure_id export_id !(t.closure_table); + export_id + | export_id -> export_id + let new_unit_descr t = new_descr t (Value_constptr 0) @@ -278,10 +304,9 @@ and descr_of_named (env : Env.t) (named : Flambda.named) [Project_closure]: closure ID %a not in set of closures" Closure_id.print closure_id end; - let descr : Export_info.descr = - Value_closure { closure_id = closure_id; set_of_closures; } - in - Value_id (Env.new_descr env descr) + Value_id ( + Env.new_value_closure_descr env ~closure_id ~set_of_closures + ) | _ -> (* It would be nice if this were [assert false], but owing to the fact that this pass may propagate less information than for example @@ -292,10 +317,9 @@ and descr_of_named (env : Env.t) (named : Flambda.named) begin match Env.get_descr env (Env.find_approx env closure) with | Some (Value_closure { set_of_closures; closure_id; }) -> assert (Closure_id.equal closure_id start_from); - let descr : Export_info.descr = - Value_closure { closure_id = move_to; set_of_closures; } - in - Value_id (Env.new_descr env descr) + Value_id ( + Env.new_value_closure_descr env ~closure_id:move_to ~set_of_closures + ) | _ -> Value_unknown end | Project_var { closure; closure_id = closure_id'; var; } -> @@ -343,6 +367,7 @@ and describe_set_of_closures env (set : Flambda.set_of_closures) { Export_info. set_of_closures_id = set.function_decls.set_of_closures_id; bound_vars = Var_within_closure.wrap_map bound_vars_approx; + free_vars = set.free_vars; results = Closure_id.wrap_map (Variable.Map.map (fun _ -> Export_info.Value_unknown) @@ -351,13 +376,12 @@ and describe_set_of_closures env (set : Flambda.set_of_closures) } in Variable.Map.mapi (fun fun_var _function_decl -> - let descr : Export_info.descr = - Value_closure - { closure_id = Closure_id.wrap fun_var; - set_of_closures = initial_value_set_of_closures; - } + let export_id = + let closure_id = Closure_id.wrap fun_var in + let set_of_closures = initial_value_set_of_closures in + Env.new_value_closure_descr env ~closure_id ~set_of_closures in - Export_info.Value_id (Env.new_descr env descr)) + Export_info.Value_id export_id) set.function_decls.funs in let closure_env = @@ -372,6 +396,7 @@ and describe_set_of_closures env (set : Flambda.set_of_closures) in { set_of_closures_id = set.function_decls.set_of_closures_id; bound_vars = Var_within_closure.wrap_map bound_vars_approx; + free_vars = set.free_vars; results = Closure_id.wrap_map results; aliased_symbol = None; } @@ -489,10 +514,13 @@ let describe_program (env : Env.Global.t) (program : Flambda.program) = in loop env program.program_body -let build_export_info ~(backend : (module Backend_intf.S)) - (program : Flambda.program) : Export_info.t = + +let build_transient ~(backend : (module Backend_intf.S)) + (program : Flambda.program) : Export_info.transient = if !Clflags.opaque then - Export_info.empty + let compilation_unit = Compilenv.current_unit () in + let root_symbol = Compilenv.current_unit_symbol () in + Export_info.opaque_transient ~root_symbol ~compilation_unit else (* CR-soon pchambart: Should probably use that instead of the ident of the module as global identifier. @@ -502,27 +530,44 @@ let build_export_info ~(backend : (module Backend_intf.S)) let _global_symbol, env = describe_program (Env.Global.create_empty ()) program in - let sets_of_closures = - Flambda_utils.all_function_decls_indexed_by_set_of_closures_id program + let sets_of_closures_map = + Flambda_utils.all_sets_of_closures_map program in - let closures = - Flambda_utils.all_function_decls_indexed_by_closure_id program - in - let invariant_params = - Set_of_closures_id.Map.map - (fun { Flambda. function_decls; _ } -> - Invariant_params.invariant_params_in_recursion - ~backend function_decls) - (Flambda_utils.all_sets_of_closures_map program) + let function_declarations_map = + let set_of_closures_approx { Flambda. function_decls; _ } = + let recursive = + lazy + (Find_recursive_functions.in_function_declarations + function_decls ~backend) + in + let keep_body = + Inline_and_simplify_aux.keep_body_check + ~is_classic_mode:function_decls.is_classic_mode ~recursive + in + Simple_value_approx.function_declarations_approx + ~keep_body function_decls + in + Set_of_closures_id.Map.map set_of_closures_approx sets_of_closures_map in let unnested_values = Env.Global.export_id_to_descr_map env in let invariant_params = + let invariant_params = + Set_of_closures_id.Map.map + (fun { Flambda. function_decls; _ } -> + if function_decls.is_classic_mode then begin + Variable.Map.empty + end else begin + Invariant_params.invariant_params_in_recursion + ~backend function_decls + end) + (Flambda_utils.all_sets_of_closures_map program) + in let export = Compilenv.approx_env () in - Export_id.Map.fold (fun _eid (descr:Export_info.descr) - (invariant_params) -> - match descr with + Export_id.Map.fold + (fun _eid (descr:Export_info.descr) invariant_params -> + match (descr : Export_info.descr) with | Value_closure { set_of_closures } | Value_set_of_closures set_of_closures -> let { Export_info.set_of_closures_id } = set_of_closures in @@ -532,20 +577,137 @@ let build_export_info ~(backend : (module Backend_intf.S)) with | exception Not_found -> invariant_params - | (set:Variable.Set.t Variable.Map.t) -> - Set_of_closures_id.Map.add set_of_closures_id set invariant_params + | (set : Variable.Set.t Variable.Map.t) -> + Set_of_closures_id.Map.add + set_of_closures_id set invariant_params end - | _ -> + | Export_info.Value_boxed_int (_, _) + | Value_block _ + | Value_mutable_block _ + | Value_int _ + | Value_char _ + | Value_constptr _ + | Value_float _ + | Value_float_array _ + | Value_string _ + | Value_unknown_descr -> invariant_params) unnested_values invariant_params in + let recursive = + let recursive = + Set_of_closures_id.Map.map + (fun { Flambda. function_decls; _ } -> + if function_decls.is_classic_mode then begin + Variable.Set.empty + end else begin + Find_recursive_functions.in_function_declarations + ~backend function_decls + end) + (Flambda_utils.all_sets_of_closures_map program) + in + let export = Compilenv.approx_env () in + Export_id.Map.fold + (fun _eid (descr:Export_info.descr) recursive -> + match (descr : Export_info.descr) with + | Value_closure { set_of_closures } + | Value_set_of_closures set_of_closures -> + let { Export_info.set_of_closures_id } = set_of_closures in + begin match + Set_of_closures_id.Map.find set_of_closures_id + export.recursive + with + | exception Not_found -> + recursive + | (set : Variable.Set.t) -> + Set_of_closures_id.Map.add + set_of_closures_id set recursive + end + | Export_info.Value_boxed_int (_, _) + | Value_block _ + | Value_mutable_block _ + | Value_int _ + | Value_char _ + | Value_constptr _ + | Value_float _ + | Value_float_array _ + | Value_string _ + | Value_unknown_descr -> + recursive) + unnested_values recursive + in + let values = Export_info.nest_eid_map unnested_values in + let symbol_id = Env.Global.symbol_to_export_id_map env in + let { Traverse_for_exported_symbols. + set_of_closure_ids = relevant_set_of_closures; + symbols = relevant_symbols; + export_ids = relevant_export_ids; + set_of_closure_ids_keep_declaration = + relevant_set_of_closures_declaration_only; + relevant_local_closure_ids; + relevant_imported_closure_ids; + relevant_local_vars_within_closure; + relevant_imported_vars_within_closure; + } = + let closure_id_to_set_of_closures_id = + Set_of_closures_id.Map.fold + (fun set_of_closure_id + (function_declarations : Simple_value_approx.function_declarations) acc -> + Variable.Map.fold + (fun fun_var _ acc -> + let closure_id = Closure_id.wrap fun_var in + Closure_id.Map.add closure_id set_of_closure_id acc) + function_declarations.funs + acc) + function_declarations_map + Closure_id.Map.empty + in + Traverse_for_exported_symbols.traverse + ~sets_of_closures_map + ~closure_id_to_set_of_closures_id + ~function_declarations_map + ~values:(Compilation_unit.Map.find (Compilenv.current_unit ()) values) + ~symbol_id + ~root_symbol:(Compilenv.current_unit_symbol ()) + in + let sets_of_closures = + Set_of_closures_id.Map.filter_map + function_declarations_map + ~f:(fun key (fun_decls : Simple_value_approx.function_declarations) -> + if Set_of_closures_id.Set.mem key relevant_set_of_closures then + Some fun_decls + else if begin + Set_of_closures_id.Set.mem key + relevant_set_of_closures_declaration_only + end then begin + if fun_decls.is_classic_mode then + Some (Simple_value_approx.clear_function_bodies fun_decls) + else + Some fun_decls + end else begin + None + end) + in + let values = - Export_info.nest_eid_map unnested_values + Compilation_unit.Map.map (fun map -> + Export_id.Map.filter (fun key _ -> + Export_id.Set.mem key relevant_export_ids) + map) + values in - Export_info.create ~values - ~symbol_id:(Env.Global.symbol_to_export_id_map env) - ~offset_fun:Closure_id.Map.empty - ~offset_fv:Var_within_closure.Map.empty - ~sets_of_closures ~closures - ~constant_sets_of_closures:Set_of_closures_id.Set.empty + let symbol_id = + Symbol.Map.filter + (fun key _ -> Symbol.Set.mem key relevant_symbols) + symbol_id + in + Export_info.create_transient ~values + ~symbol_id + ~sets_of_closures ~invariant_params + ~recursive + ~relevant_local_closure_ids + ~relevant_imported_closure_ids + ~relevant_local_vars_within_closure + ~relevant_imported_vars_within_closure + diff --git a/asmcomp/build_export_info.mli b/asmcomp/build_export_info.mli index 2a824ea3..0380604b 100644 --- a/asmcomp/build_export_info.mli +++ b/asmcomp/build_export_info.mli @@ -19,7 +19,7 @@ (** Construct export information, for emission into .cmx files, from an Flambda program. *) -val build_export_info : +val build_transient : backend:(module Backend_intf.S) -> Flambda.program -> - Export_info.t + Export_info.transient diff --git a/asmcomp/clambda.ml b/asmcomp/clambda.ml index b0fa607d..dc0d5fd3 100644 --- a/asmcomp/clambda.ml +++ b/asmcomp/clambda.ml @@ -95,11 +95,15 @@ type value_approximation = (* Preallocated globals *) +type uconstant_block_field = + | Uconst_field_ref of string + | Uconst_field_int of int + type preallocated_block = { symbol : string; exported : bool; tag : int; - size : int; + fields : uconstant_block_field option list; } type preallocated_constant = { diff --git a/asmcomp/clambda.mli b/asmcomp/clambda.mli index c2e5d137..e4db85a0 100644 --- a/asmcomp/clambda.mli +++ b/asmcomp/clambda.mli @@ -100,11 +100,15 @@ val compare_structured_constants: val compare_constants: uconstant -> uconstant -> int +type uconstant_block_field = + | Uconst_field_ref of string + | Uconst_field_int of int + type preallocated_block = { symbol : string; exported : bool; tag : int; - size : int; + fields : uconstant_block_field option list; } type preallocated_constant = { diff --git a/asmcomp/closure.ml b/asmcomp/closure.ml index 4fdb3778..a8a22253 100644 --- a/asmcomp/closure.ml +++ b/asmcomp/closure.ml @@ -131,7 +131,6 @@ let prim_size prim args = | Parraysetu kind -> if kind = Pgenarray then 16 else 4 | Parrayrefs kind -> if kind = Pgenarray then 18 else 8 | Parraysets kind -> if kind = Pgenarray then 22 else 10 - | Pbittest -> 3 | Pbigarrayref(_, ndims, _, _) -> 4 + ndims * 6 | Pbigarrayset(_, ndims, _, _) -> 4 + ndims * 6 | _ -> 2 (* arithmetic and comparisons *) @@ -226,15 +225,31 @@ let make_const_ref c = let make_const_int n = make_const (Uconst_int n) let make_const_ptr n = make_const (Uconst_ptr n) let make_const_bool b = make_const_ptr(if b then 1 else 0) -let make_comparison cmp x y = + +let make_integer_comparison cmp x y = make_const_bool (match cmp with Ceq -> x = y - | Cneq -> x <> y + | Cne -> x <> y | Clt -> x < y | Cgt -> x > y | Cle -> x <= y | Cge -> x >= y) + +let make_float_comparison cmp x y = + make_const_bool + (match cmp with + | CFeq -> x = y + | CFneq -> not (x = y) + | CFlt -> x < y + | CFnlt -> not (x < y) + | CFgt -> x > y + | CFngt -> not (x > y) + | CFle -> x <= y + | CFnle -> not (x <= y) + | CFge -> x >= y + | CFnge -> not (x >= y)) + let make_const_float n = make_const_ref (Uconst_float n) let make_const_natint n = make_const_ref (Uconst_nativeint n) let make_const_int32 n = make_const_ref (Uconst_int32 n) @@ -280,7 +295,7 @@ let simplif_arith_prim_pure fpc p (args, approxs) dbg = make_const_int (n1 lsr n2) | Pasrint when 0 <= n2 && n2 < 8 * Arch.size_int -> make_const_int (n1 asr n2) - | Pintcomp c -> make_comparison c n1 n2 + | Pintcomp c -> make_integer_comparison c n1 n2 | _ -> default end (* float *) @@ -299,7 +314,7 @@ let simplif_arith_prim_pure fpc p (args, approxs) dbg = | Psubfloat -> make_const_float (n1 -. n2) | Pmulfloat -> make_const_float (n1 *. n2) | Pdivfloat -> make_const_float (n1 /. n2) - | Pfloatcomp c -> make_comparison c n1 n2 + | Pfloatcomp c -> make_float_comparison c n1 n2 | _ -> default end (* nativeint *) @@ -325,7 +340,7 @@ let simplif_arith_prim_pure fpc p (args, approxs) dbg = | Pandbint Pnativeint -> make_const_natint (Nativeint.logand n1 n2) | Porbint Pnativeint -> make_const_natint (Nativeint.logor n1 n2) | Pxorbint Pnativeint -> make_const_natint (Nativeint.logxor n1 n2) - | Pbintcomp(Pnativeint, c) -> make_comparison c n1 n2 + | Pbintcomp(Pnativeint, c) -> make_integer_comparison c n1 n2 | _ -> default end (* nativeint, int *) @@ -363,7 +378,7 @@ let simplif_arith_prim_pure fpc p (args, approxs) dbg = | Pandbint Pint32 -> make_const_int32 (Int32.logand n1 n2) | Porbint Pint32 -> make_const_int32 (Int32.logor n1 n2) | Pxorbint Pint32 -> make_const_int32 (Int32.logxor n1 n2) - | Pbintcomp(Pint32, c) -> make_comparison c n1 n2 + | Pbintcomp(Pint32, c) -> make_integer_comparison c n1 n2 | _ -> default end (* int32, int *) @@ -401,7 +416,7 @@ let simplif_arith_prim_pure fpc p (args, approxs) dbg = | Pandbint Pint64 -> make_const_int64 (Int64.logand n1 n2) | Porbint Pint64 -> make_const_int64 (Int64.logor n1 n2) | Pxorbint Pint64 -> make_const_int64 (Int64.logxor n1 n2) - | Pbintcomp(Pint64, c) -> make_comparison c n1 n2 + | Pbintcomp(Pint64, c) -> make_integer_comparison c n1 n2 | _ -> default end (* int64, int *) @@ -1141,7 +1156,7 @@ and close_functions fenv cenv fun_defs = !function_nesting_depth < excessive_function_nesting_depth in (* Determine the free variables of the functions *) let fv = - IdentSet.elements (free_variables (Lletrec(fun_defs, lambda_unit))) in + Ident.Set.elements (free_variables (Lletrec(fun_defs, lambda_unit))) in (* Build the function descriptors for the functions. Initially all functions are assumed not to need their environment parameter. *) @@ -1274,13 +1289,13 @@ and close_switch fenv cenv cases num_keys default = (* First default case *) begin match default with | Some def when ncases < num_keys -> - assert (store.act_store def = 0) + assert (store.act_store () def = 0) | _ -> () end ; (* Then all other cases *) List.iter (fun (key,lam) -> - index.(key) <- store.act_store lam) + index.(key) <- store.act_store () lam) cases ; (* Explicit sharing with catch/exit, as switcher compilation may diff --git a/asmcomp/closure_offsets.ml b/asmcomp/closure_offsets.ml index 94eb4a1f..51a09f02 100644 --- a/asmcomp/closure_offsets.ml +++ b/asmcomp/closure_offsets.ml @@ -87,52 +87,3 @@ let compute (program:Flambda.program) = init (Flambda_utils.all_sets_of_closures program) in r - -let compute_reexported_offsets program - ~current_unit_offset_fun ~current_unit_offset_fv - ~imported_units_offset_fun ~imported_units_offset_fv = - let offset_fun = ref current_unit_offset_fun in - let offset_fv = ref current_unit_offset_fv in - let used_closure_id closure_id = - match Closure_id.Map.find closure_id imported_units_offset_fun with - | offset -> - assert (not (Closure_id.Map.mem closure_id current_unit_offset_fun)); - begin match Closure_id.Map.find closure_id !offset_fun with - | exception Not_found -> - offset_fun := Closure_id.Map.add closure_id offset !offset_fun - | offset' -> assert (offset = offset') - end - | exception Not_found -> - assert (Closure_id.Map.mem closure_id current_unit_offset_fun) - in - let used_var_within_closure var = - match Var_within_closure.Map.find var imported_units_offset_fv with - | offset -> - assert (not (Var_within_closure.Map.mem var current_unit_offset_fv)); - begin match Var_within_closure.Map.find var !offset_fv with - | exception Not_found -> - offset_fv := Var_within_closure.Map.add var offset !offset_fv - | offset' -> assert (offset = offset') - end - | exception Not_found -> - assert (Var_within_closure.Map.mem var current_unit_offset_fv) - in - Flambda_iterators.iter_named_of_program program - ~f:(fun (named : Flambda.named) -> - match named with - | Project_closure { closure_id; _ } -> - used_closure_id closure_id - | Move_within_set_of_closures { start_from; move_to; _ } -> - used_closure_id start_from; - used_closure_id move_to - | Project_var { closure_id; var; _ } -> - used_closure_id closure_id; - used_var_within_closure var - | Symbol _ | Const _ | Allocated_const _ | Read_mutable _ - | Read_symbol_field _ | Set_of_closures _ | Prim _ | Expr _ -> ()); - Flambda_iterators.iter_constant_defining_values_on_program program - ~f:(fun (const : Flambda.constant_defining_value) -> - match const with - | Project_closure (_, closure_id) -> used_closure_id closure_id - | Allocated_const _ | Block _ | Set_of_closures _ -> ()); - !offset_fun, !offset_fv diff --git a/asmcomp/closure_offsets.mli b/asmcomp/closure_offsets.mli index 7acb8449..7ecf9c27 100644 --- a/asmcomp/closure_offsets.mli +++ b/asmcomp/closure_offsets.mli @@ -25,20 +25,3 @@ type result = private { } val compute : Flambda.program -> result - -(** If compilation unit [C] references [B], which contains functions inlined - from another compilation unit [A], then we may need to know the layout of - closures inside (or constructed by code inside) a.cmx in order to - compile c.cmx. Unfortunately a.cmx is permitted to be absent during such - compilation; c.cmx will be compiled using just b.cmx. As such, when - building the .cmx export information for a given compilation unit, we - also include information about the layout of any closures that it depends - on from other compilation units. This means that when situations as just - describe arise, we always have access to the necessary closure offsets. *) -val compute_reexported_offsets - : Flambda.program - -> current_unit_offset_fun:int Closure_id.Map.t - -> current_unit_offset_fv:int Var_within_closure.Map.t - -> imported_units_offset_fun:int Closure_id.Map.t - -> imported_units_offset_fv:int Var_within_closure.Map.t - -> int Closure_id.Map.t * int Var_within_closure.Map.t diff --git a/asmcomp/cmm.ml b/asmcomp/cmm.ml index 5b2fd6b8..939298dd 100644 --- a/asmcomp/cmm.ml +++ b/asmcomp/cmm.ml @@ -89,24 +89,21 @@ let size_machtype mty = done; !size -type comparison = - Ceq - | Cne - | Clt - | Cle - | Cgt - | Cge - -let negate_comparison = function - Ceq -> Cne | Cne -> Ceq - | Clt -> Cge | Cle -> Cgt - | Cgt -> Cle | Cge -> Clt - -let swap_comparison = function - Ceq -> Ceq | Cne -> Cne - | Clt -> Cgt | Cle -> Cge - | Cgt -> Clt | Cge -> Cle +type integer_comparison = Lambda.integer_comparison = + | Ceq | Cne | Clt | Cgt | Cle | Cge +let negate_integer_comparison = Lambda.negate_integer_comparison + +let swap_integer_comparison = Lambda.swap_integer_comparison + +(* With floats [not (x < y)] is not the same as [x >= y] due to NaNs, + so we provide additional comparisons to represent the negations.*) +type float_comparison = Lambda.float_comparison = + | CFeq | CFneq | CFlt | CFnlt | CFgt | CFngt | CFle | CFnle | CFge | CFnge + +let negate_float_comparison = Lambda.negate_float_comparison + +let swap_float_comparison = Lambda.swap_float_comparison type label = int let label_counter = ref 99 @@ -142,13 +139,13 @@ and operation = | Cstore of memory_chunk * Lambda.initialization_or_assignment | Caddi | Csubi | Cmuli | Cmulhi | Cdivi | Cmodi | Cand | Cor | Cxor | Clsl | Clsr | Casr - | Ccmpi of comparison + | Ccmpi of integer_comparison | Caddv | Cadda - | Ccmpa of comparison + | Ccmpa of integer_comparison | Cnegf | Cabsf | Caddf | Csubf | Cmulf | Cdivf | Cfloatofint | Cintoffloat - | Ccmpf of comparison + | Ccmpf of float_comparison | Craise of raise_kind | Ccheckbound @@ -173,11 +170,15 @@ type expression = | Cexit of int * expression list | Ctrywith of expression * Ident.t * expression +type codegen_option = + | Reduce_code_size + | No_CSE + type fundecl = { fun_name: string; fun_args: (Ident.t * machtype) list; fun_body: expression; - fun_fast: bool; + fun_codegen_options : codegen_option list; fun_dbg : Debuginfo.t; } diff --git a/asmcomp/cmm.mli b/asmcomp/cmm.mli index a62578f6..01fe0c93 100644 --- a/asmcomp/cmm.mli +++ b/asmcomp/cmm.mli @@ -72,16 +72,17 @@ val ge_component val size_machtype: machtype -> int -type comparison = - Ceq - | Cne - | Clt - | Cle - | Cgt - | Cge +type integer_comparison = Lambda.integer_comparison = + | Ceq | Cne | Clt | Cgt | Cle | Cge -val negate_comparison: comparison -> comparison -val swap_comparison: comparison -> comparison +val negate_integer_comparison: integer_comparison -> integer_comparison +val swap_integer_comparison: integer_comparison -> integer_comparison + +type float_comparison = Lambda.float_comparison = + | CFeq | CFneq | CFlt | CFnlt | CFgt | CFngt | CFle | CFnle | CFge | CFnge + +val negate_float_comparison: float_comparison -> float_comparison +val swap_float_comparison: float_comparison -> float_comparison type label = int val new_label: unit -> label @@ -113,14 +114,14 @@ and operation = | Cstore of memory_chunk * Lambda.initialization_or_assignment | Caddi | Csubi | Cmuli | Cmulhi | Cdivi | Cmodi | Cand | Cor | Cxor | Clsl | Clsr | Casr - | Ccmpi of comparison + | Ccmpi of integer_comparison | Caddv (* pointer addition that produces a [Val] (well-formed Caml value) *) | Cadda (* pointer addition that produces a [Addr] (derived heap pointer) *) - | Ccmpa of comparison + | Ccmpa of integer_comparison | Cnegf | Cabsf | Caddf | Csubf | Cmulf | Cdivf | Cfloatofint | Cintoffloat - | Ccmpf of comparison + | Ccmpf of float_comparison | Craise of raise_kind | Ccheckbound @@ -149,11 +150,15 @@ and expression = | Cexit of int * expression list | Ctrywith of expression * Ident.t * expression +type codegen_option = + | Reduce_code_size + | No_CSE + type fundecl = { fun_name: string; fun_args: (Ident.t * machtype) list; fun_body: expression; - fun_fast: bool; + fun_codegen_options : codegen_option list; fun_dbg : Debuginfo.t; } diff --git a/asmcomp/cmmgen.ml b/asmcomp/cmmgen.ml index 483123f4..4509f58b 100644 --- a/asmcomp/cmmgen.ml +++ b/asmcomp/cmmgen.ml @@ -289,9 +289,14 @@ let mk_not dbg cmm = | Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1], _); Cconst_int 1], dbg') -> begin match c with | Cop(Ccmpi cmp, [c1; c2], dbg'') -> - tag_int (Cop(Ccmpi (negate_comparison cmp), [c1; c2], dbg'')) dbg' + tag_int + (Cop(Ccmpi (negate_integer_comparison cmp), [c1; c2], dbg'')) dbg' | Cop(Ccmpa cmp, [c1; c2], dbg'') -> - tag_int (Cop(Ccmpa (negate_comparison cmp), [c1; c2], dbg'')) dbg' + tag_int + (Cop(Ccmpa (negate_integer_comparison cmp), [c1; c2], dbg'')) dbg' + | Cop(Ccmpf cmp, [c1; c2], dbg'') -> + tag_int + (Cop(Ccmpf (negate_float_comparison cmp), [c1; c2], dbg'')) dbg' | _ -> (* 0 -> 3, 1 -> 1 *) Cop(Csubi, [Cconst_int 3; Cop(Clsl, [c; Cconst_int 1], dbg)], dbg) @@ -606,7 +611,10 @@ let get_field env ptr n dbg = let set_field ptr n newval init dbg = Cop(Cstore (Word_val, init), [field_address ptr n dbg; newval], dbg) -let non_profinfo_mask = (1 lsl (64 - Config.profinfo_width)) - 1 +let non_profinfo_mask = + if Config.profinfo + then (1 lsl (64 - Config.profinfo_width)) - 1 + else 0 (* [non_profinfo_mask] is unused in this case *) let get_header ptr dbg = (* We cannot deem this as [Immutable] due to the presence of [Obj.truncate] @@ -868,13 +876,9 @@ let curry_function n = (* Comparisons *) -let transl_comparison = function - Lambda.Ceq -> Ceq - | Lambda.Cneq -> Cne - | Lambda.Cge -> Cge - | Lambda.Cgt -> Cgt - | Lambda.Cle -> Cle - | Lambda.Clt -> Clt +let transl_int_comparison cmp = cmp + +let transl_float_comparison cmp = cmp (* Translate structured constants *) @@ -1077,7 +1081,7 @@ let bigarray_indexing unsafe elt_kind layout b args dbg = and elt_size = bigarray_elt_size elt_kind in (* [array_indexing] can simplify the given expressions *) - array_indexing ~typ:Int (log2 elt_size) + array_indexing ~typ:Addr (log2 elt_size) (Cop(Cload (Word_int, Mutable), [field_address b 1 dbg], dbg)) offset dbg @@ -1102,12 +1106,13 @@ let bigarray_get unsafe elt_kind layout b args dbg = Pbigarray_complex32 | Pbigarray_complex64 -> let kind = bigarray_word_kind elt_kind in let sz = bigarray_elt_size elt_kind / 2 in - bind "addr" (bigarray_indexing unsafe elt_kind layout b args dbg) - (fun addr -> - box_complex dbg - (Cop(Cload (kind, Mutable), [addr], dbg)) - (Cop(Cload (kind, Mutable), - [Cop(Cadda, [addr; Cconst_int sz], dbg)], dbg))) + bind "addr" (bigarray_indexing unsafe elt_kind layout b args dbg) (fun addr -> + bind "reval" + (Cop(Cload (kind, Mutable), [addr], dbg)) (fun reval -> + bind "imval" + (Cop(Cload (kind, Mutable), + [Cop(Cadda, [addr; Cconst_int sz], dbg)], dbg)) (fun imval -> + box_complex dbg reval imval))) | _ -> Cop(Cload (bigarray_word_kind elt_kind, Mutable), [bigarray_indexing unsafe elt_kind layout b args dbg], @@ -1363,7 +1368,7 @@ let simplif_primitive_32bits = function | Plsrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right_unsigned") | Pasrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right") | Pbintcomp(Pint64, Lambda.Ceq) -> Pccall (default_prim "caml_equal") - | Pbintcomp(Pint64, Lambda.Cneq) -> Pccall (default_prim "caml_notequal") + | Pbintcomp(Pint64, Lambda.Cne) -> Pccall (default_prim "caml_notequal") | Pbintcomp(Pint64, Lambda.Clt) -> Pccall (default_prim "caml_lessthan") | Pbintcomp(Pint64, Lambda.Cgt) -> Pccall (default_prim "caml_greaterthan") | Pbintcomp(Pint64, Lambda.Cle) -> Pccall (default_prim "caml_lessequal") @@ -1373,7 +1378,8 @@ let simplif_primitive_32bits = function | Pbigarrayset(_unsafe, n, Pbigarray_int64, _layout) -> Pccall (default_prim ("caml_ba_set_" ^ string_of_int n)) | Pstring_load_64(_) -> Pccall (default_prim "caml_string_get64") - | Pstring_set_64(_) -> Pccall (default_prim "caml_string_set64") + | Pbytes_load_64(_) -> Pccall (default_prim "caml_bytes_get64") + | Pbytes_set_64(_) -> Pccall (default_prim "caml_bytes_set64") | Pbigstring_load_64(_) -> Pccall (default_prim "caml_ba_uint8_get64") | Pbigstring_set_64(_) -> Pccall (default_prim "caml_ba_uint8_set64") | Pbbswap Pint64 -> Pccall (default_prim "caml_int64_bswap") @@ -1473,6 +1479,30 @@ end (* cmm store, as sharing as normally been detected in previous phases, we only share exits *) +(* Some specific patterns can lead to switches where several cases + point to the same action, but this action is not an exit (see GPR#1370). + The addition of the index in the action array as context allows to + share them correctly without duplication. *) +module StoreExpForSwitch = + Switch.CtxStore + (struct + type t = expression + type key = int option * int + type context = int + let make_key index expr = + let continuation = + match expr with + | Cexit (i,[]) -> Some i + | _ -> None + in + Some (continuation, index) + let compare_key (cont, index) (cont', index') = + match cont, cont' with + | Some i, Some i' when i = i' -> 0 + | _, _ -> Pervasives.compare index index' + end) + +(* For string switches, we can use a generic store *) module StoreExp = Switch.Store (struct @@ -1493,10 +1523,10 @@ let transl_int_switch loc arg low high cases default = match cases with | [] -> assert false | _::_ -> let store = StoreExp.mk_store () in - assert (store.Switch.act_store default = 0) ; + assert (store.Switch.act_store () default = 0) ; let cases = List.map - (fun (i,act) -> i,store.Switch.act_store act) + (fun (i,act) -> i,store.Switch.act_store () act) cases in let rec inters plow phigh pact = function | [] -> @@ -1622,8 +1652,10 @@ let rec is_unboxed_number ~strict env e = Boxed (Boxed_integer (Pint64, dbg), false) | Pbigarrayref(_, _, Pbigarray_native_int,_) -> Boxed (Boxed_integer (Pnativeint, dbg), false) - | Pstring_load_32(_) -> Boxed (Boxed_integer (Pint32, dbg), false) - | Pstring_load_64(_) -> Boxed (Boxed_integer (Pint64, dbg), false) + | Pstring_load_32(_) | Pbytes_load_32(_) -> + Boxed (Boxed_integer (Pint32, dbg), false) + | Pstring_load_64(_) | Pbytes_load_64(_) -> + Boxed (Boxed_integer (Pint64, dbg), false) | Pbigstring_load_32(_) -> Boxed (Boxed_integer (Pint32, dbg), false) | Pbigstring_load_64(_) -> Boxed (Boxed_integer (Pint64, dbg), false) | Praise _ -> No_result @@ -2174,7 +2206,7 @@ and transl_prim_2 env p arg1 arg2 dbg = Cop(Cor, [asr_int (transl env arg1) (untag_int(transl env arg2) dbg) dbg; Cconst_int 1], dbg) | Pintcomp cmp -> - tag_int(Cop(Ccmpi(transl_comparison cmp), + tag_int(Cop(Ccmpi(transl_int_comparison cmp), [transl env arg1; transl env arg2], dbg)) dbg | Pisout -> transl_isout (transl env arg1) (transl env arg2) dbg @@ -2196,7 +2228,7 @@ and transl_prim_2 env p arg1 arg2 dbg = [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2], dbg)) | Pfloatcomp cmp -> - tag_int(Cop(Ccmpf(transl_comparison cmp), + tag_int(Cop(Ccmpf(transl_float_comparison cmp), [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2], dbg)) dbg @@ -2215,7 +2247,7 @@ and transl_prim_2 env p arg1 arg2 dbg = Cop(Cload (Byte_unsigned, Mutable), [add_int str idx dbg], dbg))))) dbg - | Pstring_load_16(unsafe) -> + | Pstring_load_16(unsafe) | Pbytes_load_16(unsafe) -> tag_int (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2235,7 +2267,7 @@ and transl_prim_2 env p arg1 arg2 dbg = (Cconst_int 1) dbg) idx (unaligned_load_16 ba_data idx dbg))))) dbg - | Pstring_load_32(unsafe) -> + | Pstring_load_32(unsafe) | Pbytes_load_32(unsafe) -> box_int dbg Pint32 (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2255,7 +2287,7 @@ and transl_prim_2 env p arg1 arg2 dbg = (Cconst_int 3) dbg) idx (unaligned_load_32 ba_data idx dbg))))) - | Pstring_load_64(unsafe) -> + | Pstring_load_64(unsafe) | Pbytes_load_64(unsafe) -> box_int dbg Pint64 (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2331,18 +2363,6 @@ and transl_prim_2 env p arg1 arg2 dbg = unboxed_float_array_ref arr idx dbg)))) end - (* Operations on bitvects *) - | Pbittest -> - bind "index" (untag_int(transl env arg2) dbg) (fun idx -> - tag_int( - Cop(Cand, [Cop(Clsr, [Cop(Cload (Byte_unsigned, Mutable), - [add_int (transl env arg1) - (Cop(Clsr, [idx; Cconst_int 3], dbg)) - dbg], - dbg); - Cop(Cand, [idx; Cconst_int 7], dbg)], dbg); - Cconst_int 1], dbg)) dbg) - (* Boxed integers *) | Paddbint bi -> box_int dbg bi (Cop(Caddi, @@ -2391,7 +2411,7 @@ and transl_prim_2 env p arg1 arg2 dbg = [transl_unbox_int dbg env bi arg1; untag_int(transl env arg2) dbg], dbg)) | Pbintcomp(bi, cmp) -> - tag_int (Cop(Ccmpi(transl_comparison cmp), + tag_int (Cop(Ccmpi(transl_int_comparison cmp), [transl_unbox_int dbg env bi arg1; transl_unbox_int dbg env bi arg2], dbg)) dbg | prim -> @@ -2498,7 +2518,7 @@ and transl_prim_3 env p arg1 arg2 arg3 dbg = float_array_set arr idx newval dbg)))) end) - | Pstring_set_16(unsafe) -> + | Pbytes_set_16(unsafe) -> return_unit (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2521,7 +2541,7 @@ and transl_prim_3 env p arg1 arg2 arg3 dbg = dbg) idx (unaligned_set_16 ba_data idx newval dbg)))))) - | Pstring_set_32(unsafe) -> + | Pbytes_set_32(unsafe) -> return_unit (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2544,7 +2564,7 @@ and transl_prim_3 env p arg1 arg2 arg3 dbg = dbg) idx (unaligned_set_32 ba_data idx newval dbg)))))) - | Pstring_set_64(unsafe) -> + | Pbytes_set_64(unsafe) -> return_unit (bind "str" (transl env arg1) (fun str -> bind "index" (untag_int (transl env arg2) dbg) (fun idx -> @@ -2718,10 +2738,10 @@ and transl_switch loc env arg index cases = match Array.length cases with | 1 -> transl env cases.(0) | _ -> let cases = Array.map (transl env) cases in - let store = StoreExp.mk_store () in + let store = StoreExpForSwitch.mk_store () in let index = Array.map - (fun j -> store.Switch.act_store cases.(j)) + (fun j -> store.Switch.act_store j cases.(j)) index in let n_index = Array.length index in let inters = ref [] @@ -2801,10 +2821,16 @@ let transl_function f = Afl_instrument.instrument_function (transl env body) else transl env body in + let fun_codegen_options = + if !Clflags.optimize_for_speed then + [] + else + [ Reduce_code_size ] + in Cfunction {fun_name = f.label; fun_args = List.map (fun id -> (id, typ_val)) f.params; fun_body = cmm_body; - fun_fast = !Clflags.optimize_for_speed; + fun_codegen_options; fun_dbg = f.dbg} (* Translate all function definitions *) @@ -3019,18 +3045,24 @@ let emit_gc_roots_table ~symbols cont = (* Build preallocated blocks (used for Flambda [Initialize_symbol] constructs, and Clambda global module) *) -let preallocate_block cont { Clambda.symbol; exported; tag; size } = +let preallocate_block cont { Clambda.symbol; exported; tag; fields } = let space = (* These words will be registered as roots and as such must contain valid values, in case we are in no-naked-pointers mode. Likewise the block header must be black, below (see [caml_darken]), since the overall record may be referenced. *) - Array.to_list - (Array.init size (fun _index -> - Cint (Nativeint.of_int 1 (* Val_unit *)))) + List.map (fun field -> + match field with + | None -> + Cint (Nativeint.of_int 1 (* Val_unit *)) + | Some (Uconst_field_int n) -> + cint_const n + | Some (Uconst_field_ref label) -> + Csymbol_address label) + fields in let data = - Cint(black_block_header tag size) :: + Cint(black_block_header tag (List.length fields)) :: if exported then Cglobal_symbol symbol :: Cdefine_symbol symbol :: space @@ -3057,7 +3089,16 @@ let compunit (ulam, preallocated_blocks, constants) = transl empty_env ulam in let c1 = [Cfunction {fun_name = Compilenv.make_symbol (Some "entry"); fun_args = []; - fun_body = init_code; fun_fast = false; + fun_body = init_code; + (* This function is often large and run only once. + Compilation time matter more than runtime. + See MPR#7630 *) + fun_codegen_options = + if Config.flambda then [ + Reduce_code_size; + No_CSE; + ] + else [ Reduce_code_size ]; fun_dbg = Debuginfo.none }] in let c2 = emit_constants c1 constants in let c3 = transl_all_functions_and_emit_all_constants c2 in @@ -3198,7 +3239,7 @@ let send_function arity = {fun_name; fun_args = fun_args; fun_body = body; - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none } let apply_function arity = @@ -3209,7 +3250,7 @@ let apply_function arity = {fun_name; fun_args = List.map (fun id -> (id, typ_val)) all_args; fun_body = body; - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none; } @@ -3234,7 +3275,7 @@ let tuplify_function arity = Cop(Capply typ_val, get_field env (Cvar clos) 2 dbg :: access_components 0 @ [Cvar clos], dbg); - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none; } @@ -3297,7 +3338,7 @@ let final_curry_function arity = "_" ^ string_of_int (arity-1); fun_args = [last_arg, typ_val; last_clos, typ_val]; fun_body = curry_fun [] last_clos (arity-1); - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none } let rec intermediate_curry_functions arity num = @@ -3327,7 +3368,7 @@ let rec intermediate_curry_functions arity num = Cconst_symbol(name1 ^ "_" ^ string_of_int (num+1)); int_const 1; Cvar arg; Cvar clos], dbg); - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none } :: (if arity <= max_arity_optimized && arity - num > 2 then @@ -3355,7 +3396,7 @@ let rec intermediate_curry_functions arity num = fun_args = direct_args @ [clos, typ_val]; fun_body = iter (num+1) (List.map (fun (arg,_) -> Cvar arg) direct_args) clos; - fun_fast = true; + fun_codegen_options = []; fun_dbg = Debuginfo.none } in cf :: intermediate_curry_functions arity (num+1) @@ -3418,7 +3459,7 @@ let entry_point namelist = Cfunction {fun_name = "caml_program"; fun_args = []; fun_body = body; - fun_fast = false; + fun_codegen_options = [Reduce_code_size]; fun_dbg = Debuginfo.none } (* Generate the table of globals *) diff --git a/asmcomp/compilenv.ml b/asmcomp/compilenv.ml index a1332031..0eb7eab2 100644 --- a/asmcomp/compilenv.ml +++ b/asmcomp/compilenv.ml @@ -39,7 +39,8 @@ let export_infos_table = let imported_sets_of_closures_table = (Set_of_closures_id.Tbl.create 10 - : Flambda.function_declarations option Set_of_closures_id.Tbl.t) + : Simple_value_approx.function_declarations option + Set_of_closures_id.Tbl.t) module CstMap = Map.Make(struct @@ -145,12 +146,6 @@ let current_unit_infos () = let current_unit_name () = current_unit.ui_name -let make_symbol ?(unitname = current_unit.ui_symbol) idopt = - let prefix = "caml" ^ unitname in - match idopt with - | None -> prefix - | Some id -> prefix ^ "__" ^ id - let symbol_in_current_unit name = let prefix = "caml" ^ current_unit.ui_symbol in name = prefix || @@ -278,9 +273,9 @@ let is_predefined_exception sym = let symbol_for_global' id = let sym_label = Linkage_name.create (symbol_for_global id) in if Ident.is_predef_exn id then - Symbol.unsafe_create predefined_exception_compilation_unit sym_label + Symbol.of_global_linkage predefined_exception_compilation_unit sym_label else - Symbol.unsafe_create (unit_for_global id) sym_label + Symbol.of_global_linkage (unit_for_global id) sym_label let set_global_approx approx = assert(not Config.flambda); @@ -307,14 +302,16 @@ let approx_for_global comp_unit = || not (Ident.global id) then invalid_arg (Format.asprintf "approx_for_global %a" Ident.print id); let modname = Ident.name id in - try Hashtbl.find export_infos_table modname with - | Not_found -> - let exported = match get_global_info id with - | None -> Export_info.empty - | Some ui -> get_flambda_export_info ui in - Hashtbl.add export_infos_table modname exported; - merged_environment := Export_info.merge !merged_environment exported; - exported + match Hashtbl.find export_infos_table modname with + | otherwise -> Some otherwise + | exception Not_found -> + match get_global_info id with + | None -> None + | Some ui -> + let exported = get_flambda_export_info ui in + Hashtbl.add export_infos_table modname exported; + merged_environment := Export_info.merge !merged_environment exported; + Some exported let approx_env () = !merged_environment @@ -348,16 +345,13 @@ let save_unit_info filename = current_unit.ui_imports_cmi <- Env.imports(); write_unit_info current_unit filename -let current_unit_linkage_name () = - Linkage_name.create (make_symbol ~unitname:current_unit.ui_symbol None) - let current_unit () = match Compilation_unit.get_current () with | Some current_unit -> current_unit | None -> Misc.fatal_error "Compilenv.current_unit" let current_unit_symbol () = - Symbol.unsafe_create (current_unit ()) (current_unit_linkage_name ()) + Symbol.of_global_linkage (current_unit ()) (current_unit_linkage_name ()) let const_label = ref 0 @@ -414,7 +408,7 @@ let closure_symbol fv = let linkage_name = concat_symbol unitname ((Closure_id.unique_name fv) ^ "_closure") in - Symbol.unsafe_create compilation_unit (Linkage_name.create linkage_name) + Symbol.of_global_linkage compilation_unit (Linkage_name.create linkage_name) let function_label fv = let compilation_unit = Closure_id.get_compilation_unit fv in diff --git a/asmcomp/compilenv.mli b/asmcomp/compilenv.mli index 98d5f024..4fcd55e2 100644 --- a/asmcomp/compilenv.mli +++ b/asmcomp/compilenv.mli @@ -26,7 +26,7 @@ open Cmx_format improvement feature. *) val imported_sets_of_closures_table - : Flambda.function_declarations option Set_of_closures_id.Tbl.t + : Simple_value_approx.function_declarations option Set_of_closures_id.Tbl.t (* flambda-only *) val reset: ?packname:string -> string -> unit @@ -91,7 +91,7 @@ val set_export_info: Export_info.t -> unit val approx_env: unit -> Export_info.t (* Returns all the information loaded from external compilation units flambda-only *) -val approx_for_global: Compilation_unit.t -> Export_info.t +val approx_for_global: Compilation_unit.t -> Export_info.t option (* Loads the exported information declaring the compilation_unit flambda-only *) diff --git a/asmcomp/export_info.ml b/asmcomp/export_info.ml index 82123a92..9edc7c1b 100644 --- a/asmcomp/export_info.ml +++ b/asmcomp/export_info.ml @@ -16,6 +16,8 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] +module A = Simple_value_approx + type value_string_contents = | Contents of string | Unknown_or_mutable @@ -42,10 +44,11 @@ type descr = | Value_constptr of int | Value_float of float | Value_float_array of value_float_array - | Value_boxed_int : 'a Simple_value_approx.boxed_int * 'a -> descr + | Value_boxed_int : 'a A.boxed_int * 'a -> descr | Value_string of value_string | Value_closure of value_closure | Value_set_of_closures of value_set_of_closures + | Value_unknown_descr and value_closure = { closure_id : Closure_id.t; @@ -55,6 +58,7 @@ and value_closure = { and value_set_of_closures = { set_of_closures_id : Set_of_closures_id.t; bound_vars : approx Var_within_closure.Map.t; + free_vars : Flambda.specialised_to Variable.Map.t; results : approx Closure_id.Map.t; aliased_symbol : Symbol.t option; } @@ -98,6 +102,8 @@ let equal_set_of_closures (s1:value_set_of_closures) let equal_descr (d1:descr) (d2:descr) : bool = match d1, d2 with + | Value_unknown_descr, Value_unknown_descr -> + true | Value_block (t1, f1), Value_block (t2, f2) -> Tag.equal t1 t2 && equal_array equal_approx f1 f2 | Value_mutable_block (t1, s1), Value_mutable_block (t2, s2) -> @@ -114,7 +120,7 @@ let equal_descr (d1:descr) (d2:descr) : bool = | Value_float_array s1, Value_float_array s2 -> s1 = s2 | Value_boxed_int (t1, v1), Value_boxed_int (t2, v2) -> - Simple_value_approx.equal_boxed_int t1 v1 t2 v2 + A.equal_boxed_int t1 v1 t2 v2 | Value_string s1, Value_string s2 -> s1 = s2 | Value_closure c1, Value_closure c2 -> @@ -125,53 +131,135 @@ let equal_descr (d1:descr) (d2:descr) : bool = | ( Value_block (_, _) | Value_mutable_block (_, _) | Value_int _ | Value_char _ | Value_constptr _ | Value_float _ | Value_float_array _ | Value_boxed_int _ | Value_string _ | Value_closure _ - | Value_set_of_closures _ ), + | Value_set_of_closures _ + | Value_unknown_descr ), ( Value_block (_, _) | Value_mutable_block (_, _) | Value_int _ | Value_char _ | Value_constptr _ | Value_float _ | Value_float_array _ | Value_boxed_int _ | Value_string _ | Value_closure _ - | Value_set_of_closures _ ) -> + | Value_set_of_closures _ + | Value_unknown_descr ) -> false type t = { - sets_of_closures : Flambda.function_declarations Set_of_closures_id.Map.t; - closures : Flambda.function_declarations Closure_id.Map.t; + sets_of_closures : A.function_declarations Set_of_closures_id.Map.t; values : descr Export_id.Map.t Compilation_unit.Map.t; symbol_id : Export_id.t Symbol.Map.t; offset_fun : int Closure_id.Map.t; offset_fv : int Var_within_closure.Map.t; - constant_sets_of_closures : Set_of_closures_id.Set.t; + constant_closures : Closure_id.Set.t; + invariant_params : Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t; + recursive : Variable.Set.t Set_of_closures_id.Map.t; +} + +type transient = { + sets_of_closures : A.function_declarations Set_of_closures_id.Map.t; + values : descr Export_id.Map.t Compilation_unit.Map.t; + symbol_id : Export_id.t Symbol.Map.t; invariant_params : Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t; + recursive : Variable.Set.t Set_of_closures_id.Map.t; + relevant_local_closure_ids : Closure_id.Set.t; + relevant_imported_closure_ids : Closure_id.Set.t; + relevant_local_vars_within_closure : Var_within_closure.Set.t; + relevant_imported_vars_within_closure : Var_within_closure.Set.t; } let empty : t = { sets_of_closures = Set_of_closures_id.Map.empty; - closures = Closure_id.Map.empty; values = Compilation_unit.Map.empty; symbol_id = Symbol.Map.empty; offset_fun = Closure_id.Map.empty; offset_fv = Var_within_closure.Map.empty; - constant_sets_of_closures = Set_of_closures_id.Set.empty; + constant_closures = Closure_id.Set.empty; invariant_params = Set_of_closures_id.Map.empty; + recursive = Set_of_closures_id.Map.empty; } -let create ~sets_of_closures ~closures ~values ~symbol_id - ~offset_fun ~offset_fv ~constant_sets_of_closures - ~invariant_params = +let opaque_transient ~compilation_unit ~root_symbol : transient = + let export_id = Export_id.create compilation_unit in + let values = + let map = Export_id.Map.singleton export_id Value_unknown_descr in + Compilation_unit.Map.singleton compilation_unit map + in + let symbol_id = Symbol.Map.singleton root_symbol export_id in + { sets_of_closures = Set_of_closures_id.Map.empty; + values; + symbol_id; + invariant_params = Set_of_closures_id.Map.empty; + recursive = Set_of_closures_id.Map.empty; + relevant_local_closure_ids = Closure_id.Set.empty; + relevant_imported_closure_ids = Closure_id.Set.empty; + relevant_local_vars_within_closure = Var_within_closure.Set.empty; + relevant_imported_vars_within_closure = Var_within_closure.Set.empty; + } + +let create ~sets_of_closures ~values ~symbol_id + ~offset_fun ~offset_fv ~constant_closures + ~invariant_params ~recursive = { sets_of_closures; - closures; values; symbol_id; offset_fun; offset_fv; - constant_sets_of_closures; + constant_closures; invariant_params; + recursive; } -let add_clambda_info t ~offset_fun ~offset_fv ~constant_sets_of_closures = - assert (Closure_id.Map.cardinal t.offset_fun = 0); - assert (Var_within_closure.Map.cardinal t.offset_fv = 0); - assert (Set_of_closures_id.Set.cardinal t.constant_sets_of_closures = 0); - { t with offset_fun; offset_fv; constant_sets_of_closures; } +let create_transient + ~sets_of_closures ~values ~symbol_id ~invariant_params ~recursive + ~relevant_local_closure_ids ~relevant_imported_closure_ids + ~relevant_local_vars_within_closure + ~relevant_imported_vars_within_closure = + { sets_of_closures; + values; + symbol_id; + invariant_params; + recursive; + relevant_local_closure_ids; + relevant_imported_closure_ids; + relevant_local_vars_within_closure; + relevant_imported_vars_within_closure; + } + +let t_of_transient transient + ~program:_ + ~local_offset_fun ~local_offset_fv + ~imported_offset_fun ~imported_offset_fv + ~constant_closures = + let offset_fun = + let fold_map set = + Closure_id.Map.fold (fun key value unchanged -> + if Closure_id.Set.mem key set then + Closure_id.Map.add key value unchanged + else + unchanged) + in + Closure_id.Map.empty + |> fold_map transient.relevant_local_closure_ids local_offset_fun + |> fold_map transient.relevant_imported_closure_ids imported_offset_fun + in + let offset_fv = + let fold_map set = + Var_within_closure.Map.fold (fun key value unchanged -> + if Var_within_closure.Set.mem key set then + Var_within_closure.Map.add key value unchanged + else + unchanged) + in + Var_within_closure.Map.empty + |> fold_map transient.relevant_local_vars_within_closure local_offset_fv + |> fold_map transient.relevant_imported_vars_within_closure + imported_offset_fv + in + { sets_of_closures = transient.sets_of_closures; + values = transient.values; + symbol_id = transient.symbol_id; + invariant_params = transient.invariant_params; + recursive = transient.recursive; + offset_fun; + offset_fv; + constant_closures; + } let merge (t1 : t) (t2 : t) : t = let eidmap_disjoint_union ?eq map1 map2 = @@ -189,20 +277,23 @@ let merge (t1 : t) (t2 : t) : t = sets_of_closures = Set_of_closures_id.Map.disjoint_union t1.sets_of_closures t2.sets_of_closures; - closures = Closure_id.Map.disjoint_union t1.closures t2.closures; symbol_id = Symbol.Map.disjoint_union ~print:Export_id.print t1.symbol_id t2.symbol_id; offset_fun = Closure_id.Map.disjoint_union ~eq:int_eq t1.offset_fun t2.offset_fun; offset_fv = Var_within_closure.Map.disjoint_union ~eq:int_eq t1.offset_fv t2.offset_fv; - constant_sets_of_closures = - Set_of_closures_id.Set.union t1.constant_sets_of_closures - t2.constant_sets_of_closures; + constant_closures = + Closure_id.Set.union t1.constant_closures t2.constant_closures; invariant_params = Set_of_closures_id.Map.disjoint_union ~print:(Variable.Map.print Variable.Set.print) ~eq:(Variable.Map.equal Variable.Set.equal) t1.invariant_params t2.invariant_params; + recursive = + Set_of_closures_id.Map.disjoint_union + ~print:Variable.Set.print + ~eq:Variable.Set.equal + t1.recursive t2.recursive; } let find_value eid map = @@ -225,8 +316,103 @@ let nest_eid_map map = in Export_id.Map.fold add_map map Compilation_unit.Map.empty -let print_approx ppf ((t,root_symbols) : t * Symbol.t list) = - let values = t.values in +let print_raw_approx ppf approx = + let fprintf = Format.fprintf in + match approx with + | Value_unknown -> fprintf ppf "(Unknown)" + | Value_id export_id -> fprintf ppf "(Id %a)" Export_id.print export_id + | Value_symbol symbol -> fprintf ppf "(Symbol %a)" Symbol.print symbol + +let print_value_set_of_closures ppf (t : value_set_of_closures) = + let print_bound_vars ppf bound_vars = + Format.fprintf ppf "(%a)" + (Var_within_closure.Map.print print_raw_approx) + bound_vars + in + let print_free_vars ppf free_vars = + Format.fprintf ppf "(%a)" + (Variable.Map.print Flambda.print_specialised_to) + free_vars + in + let print_results ppf results = + Format.fprintf ppf "(%a)" (Closure_id.Map.print print_raw_approx) results + in + let print_aliased_symbol ppf aliased_symbol = + match aliased_symbol with + | None -> Format.fprintf ppf "" + | Some symbol -> Format.fprintf ppf "(%a)" Symbol.print symbol + in + Format.fprintf ppf + "((set_of_closures_id %a) \ + (bound_vars %a) \ + (free_vars %a) \ + (results %a) \ + (aliased_symbol %a))" + Set_of_closures_id.print t.set_of_closures_id + print_bound_vars t.bound_vars + print_free_vars t.free_vars + print_results t.results + print_aliased_symbol t.aliased_symbol + +let print_value_closure ppf (t : value_closure) = + Format.fprintf ppf "((closure_id %a) (set_of_closures %a))" + Closure_id.print t.closure_id + print_value_set_of_closures t.set_of_closures + +let print_value_float_array_contents + ppf (value : value_float_array_contents) = + match value with + | Unknown_or_mutable -> Format.fprintf ppf "(Unknown_or_mutable)" + | Contents _ -> Format.fprintf ppf "(Contents ...)" + +let print_value_float_array ppf (value : value_float_array) = + Format.fprintf ppf "((size %d) (contents %a))" + value.size + print_value_float_array_contents value.contents + +let print_value_string_contents ppf (value : value_string_contents) = + match value with + | Unknown_or_mutable -> Format.fprintf ppf "(Unknown_or_mutable)" + | Contents _ -> Format.fprintf ppf "(Contents ...)" + +let print_value_string ppf (value : value_string) = + Format.fprintf ppf "((size %d) (contents %a))" + value.size + print_value_string_contents value.contents + +let print_raw_descr ppf descr = + let fprintf = Format.fprintf in + let print_approx_array ppf arr = + Array.iter (fun approx -> fprintf ppf "%a " print_raw_approx approx) arr + in + match descr with + | Value_block (tag, approx_array) -> + fprintf ppf "(Value_block (%a %a))" + Tag.print tag + print_approx_array approx_array + | Value_mutable_block (tag, i) -> + fprintf ppf "(Value_mutable-block (%a %d))" Tag.print tag i + | Value_int i -> fprintf ppf "(Value_int %d)" i + | Value_char c -> fprintf ppf "(Value_char %c)" c + | Value_constptr p -> fprintf ppf "(Value_constptr %d)" p + | Value_float f -> fprintf ppf "(Value_float %.3f)" f + | Value_float_array value_float_array -> + fprintf ppf "(Value_float_array %a)" + print_value_float_array value_float_array + | Value_boxed_int _ -> + fprintf ppf "(Value_Boxed_int)" + | Value_string value_string -> + fprintf ppf "(Value_string %a)" print_value_string value_string + | Value_closure value_closure -> + fprintf ppf "(Value_closure %a)" + print_value_closure value_closure + | Value_set_of_closures value_set_of_closures -> + fprintf ppf "(Value_set_of_closures %a)" + print_value_set_of_closures value_set_of_closures + | Value_unknown_descr -> fprintf ppf "(Value_unknown_descr)" + +let print_approx_components ppf ~symbol_id ~values + (root_symbols : Symbol.t list) = let fprintf = Format.fprintf in let printed = ref Export_id.Set.empty in let recorded_symbol = ref Symbol.Set.empty in @@ -286,11 +472,12 @@ let print_approx ppf ((t,root_symbols) : t * Symbol.t list) = | Contents _ -> "_imm") float_array.size | Value_boxed_int (t, i) -> - let module A = Simple_value_approx in - match t with + begin match t with | A.Int32 -> Format.fprintf ppf "%li" i | A.Int64 -> Format.fprintf ppf "%Li" i | A.Nativeint -> Format.fprintf ppf "%ni" i + end + | Value_unknown_descr -> Format.fprintf ppf "?" and print_fields ppf fields = Array.iter (fun approx -> fprintf ppf "%a@ " print_approx approx) fields and print_set_of_closures ppf @@ -321,7 +508,7 @@ let print_approx ppf ((t,root_symbols) : t * Symbol.t list) = let rec print_recorded_symbols () = if not (Queue.is_empty symbols_to_print) then begin let sym = Queue.pop symbols_to_print in - begin match Symbol.Map.find sym t.symbol_id with + begin match Symbol.Map.find sym symbol_id with | exception Not_found -> () | id -> fprintf ppf "@[%a:@ %a@];@ " @@ -337,6 +524,11 @@ let print_approx ppf ((t,root_symbols) : t * Symbol.t list) = print_recorded_symbols (); fprintf ppf "@]" +let print_approx ppf ((t : t), symbols) = + let symbol_id = t.symbol_id in + let values = t.values in + print_approx_components ppf ~symbol_id ~values symbols + let print_offsets ppf (t : t) = Format.fprintf ppf "@[offset_fun:@ "; Closure_id.Map.iter (fun cid off -> @@ -349,7 +541,8 @@ let print_offsets ppf (t : t) = Format.fprintf ppf "@]@ " let print_functions ppf (t : t) = - Set_of_closures_id.Map.print Flambda.print_function_declarations ppf + Set_of_closures_id.Map.print + A.print_function_declarations ppf t.sets_of_closures let print_all ppf ((t, root_symbols) : t * Symbol.t list) = diff --git a/asmcomp/export_info.mli b/asmcomp/export_info.mli index d6fbd7ae..f93698be 100644 --- a/asmcomp/export_info.mli +++ b/asmcomp/export_info.mli @@ -19,6 +19,8 @@ (** Exported information (that is to say, information written into a .cmx file) about a compilation unit. *) +module A = Simple_value_approx + type value_string_contents = | Contents of string | Unknown_or_mutable @@ -45,10 +47,11 @@ type descr = | Value_constptr of int | Value_float of float | Value_float_array of value_float_array - | Value_boxed_int : 'a Simple_value_approx.boxed_int * 'a -> descr + | Value_boxed_int : 'a A.boxed_int * 'a -> descr | Value_string of value_string | Value_closure of value_closure | Value_set_of_closures of value_set_of_closures + | Value_unknown_descr and value_closure = { closure_id : Closure_id.t; @@ -58,6 +61,7 @@ and value_closure = { and value_set_of_closures = { set_of_closures_id : Set_of_closures_id.t; bound_vars : approx Var_within_closure.Map.t; + free_vars : Flambda.specialised_to Variable.Map.t; results : approx Closure_id.Map.t; aliased_symbol : Symbol.t option; } @@ -76,10 +80,8 @@ and approx = (** A structure that describes what a single compilation unit exports. *) type t = private { - sets_of_closures : Flambda.function_declarations Set_of_closures_id.Map.t; + sets_of_closures : A.function_declarations Set_of_closures_id.Map.t; (** Code of exported functions indexed by set of closures IDs. *) - closures : Flambda.function_declarations Closure_id.Map.t; - (** Code of exported functions indexed by closure IDs. *) values : descr Export_id.Map.t Compilation_unit.Map.t; (** Structure of exported values. *) symbol_id : Export_id.t Symbol.Map.t; @@ -88,28 +90,58 @@ type t = private { (** Positions of function pointers in their closures. *) offset_fv : int Var_within_closure.Map.t; (** Positions of value pointers in their closures. *) - constant_sets_of_closures : Set_of_closures_id.Set.t; + constant_closures : Closure_id.Set.t; (* CR-soon mshinwell for pchambart: Add comment *) invariant_params : Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t; (* Function parameters known to be invariant (see [Invariant_params]) indexed by set of closures ID. *) + recursive : Variable.Set.t Set_of_closures_id.Map.t; +} + +type transient = private { + sets_of_closures : A.function_declarations Set_of_closures_id.Map.t; + values : descr Export_id.Map.t Compilation_unit.Map.t; + symbol_id : Export_id.t Symbol.Map.t; + invariant_params : Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t; + recursive : Variable.Set.t Set_of_closures_id.Map.t; + relevant_local_closure_ids : Closure_id.Set.t; + relevant_imported_closure_ids : Closure_id.Set.t; + relevant_local_vars_within_closure : Var_within_closure.Set.t; + relevant_imported_vars_within_closure : Var_within_closure.Set.t; } (** Export information for a compilation unit that exports nothing. *) val empty : t +val opaque_transient + : compilation_unit:Compilation_unit.t + -> root_symbol:Symbol.t + -> transient + (** Create a new export information structure. *) val create - : sets_of_closures:Flambda.function_declarations Set_of_closures_id.Map.t - -> closures:Flambda.function_declarations Closure_id.Map.t + : sets_of_closures:(A.function_declarations Set_of_closures_id.Map.t) -> values:descr Export_id.Map.t Compilation_unit.Map.t -> symbol_id:Export_id.t Symbol.Map.t -> offset_fun:int Closure_id.Map.t -> offset_fv:int Var_within_closure.Map.t - -> constant_sets_of_closures:Set_of_closures_id.Set.t + -> constant_closures:Closure_id.Set.t -> invariant_params:Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t + -> recursive:Variable.Set.t Set_of_closures_id.Map.t -> t +val create_transient + : sets_of_closures:(A.function_declarations Set_of_closures_id.Map.t) + -> values:descr Export_id.Map.t Compilation_unit.Map.t + -> symbol_id:Export_id.t Symbol.Map.t + -> invariant_params:Variable.Set.t Variable.Map.t Set_of_closures_id.Map.t + -> recursive:Variable.Set.t Set_of_closures_id.Map.t + -> relevant_local_closure_ids: Closure_id.Set.t + -> relevant_imported_closure_ids : Closure_id.Set.t + -> relevant_local_vars_within_closure : Var_within_closure.Set.t + -> relevant_imported_vars_within_closure : Var_within_closure.Set.t + -> transient + (* CR-someday pchambart: Should we separate [t] in 2 types: one created by the current [create] function, returned by [Build_export_info]. And another built using t and offset_informations returned by @@ -119,11 +151,14 @@ val create (** Record information about the layout of closures and which sets of closures are constant. These are all worked out during the [Flambda_to_clambda] pass. *) -val add_clambda_info - : t - -> offset_fun:int Closure_id.Map.t - -> offset_fv:int Var_within_closure.Map.t - -> constant_sets_of_closures:Set_of_closures_id.Set.t +val t_of_transient + : transient + -> program: Flambda.program + -> local_offset_fun:int Closure_id.Map.t + -> local_offset_fv:int Var_within_closure.Map.t + -> imported_offset_fun:int Closure_id.Map.t + -> imported_offset_fv:int Var_within_closure.Map.t + -> constant_closures:Closure_id.Set.t -> t (** Union of export information. Verifies that there are no identifier @@ -143,7 +178,18 @@ val nest_eid_map (**/**) (* Debug printing functions. *) +val print_approx_components + : Format.formatter + -> symbol_id: Export_id.t Symbol.Map.t + -> values: descr Export_id.Map.t Compilation_unit.Map.t + -> Symbol.t list + -> unit val print_approx : Format.formatter -> t * Symbol.t list -> unit val print_functions : Format.formatter -> t -> unit val print_offsets : Format.formatter -> t -> unit val print_all : Format.formatter -> t * Symbol.t list -> unit + +(** Prints approx and descr as it is, without recursively looking up + [Export_id.t] *) +val print_raw_approx : Format.formatter -> approx -> unit +val print_raw_descr : Format.formatter -> descr -> unit diff --git a/asmcomp/export_info_for_pack.ml b/asmcomp/export_info_for_pack.ml index da413408..42a81553 100644 --- a/asmcomp/export_info_for_pack.ml +++ b/asmcomp/export_info_for_pack.ml @@ -16,11 +16,13 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] +module A = Simple_value_approx + let rename_id_state = Export_id.Tbl.create 100 let rename_set_of_closures_id_state = Set_of_closures_id.Tbl.create 10 let imported_function_declarations_table = (Set_of_closures_id.Tbl.create 10 - : Flambda.function_declarations Set_of_closures_id.Tbl.t) + : A.function_declarations Set_of_closures_id.Tbl.t) (* Rename export identifiers' compilation units to denote that they now live within a pack. *) @@ -82,6 +84,7 @@ let import_set_of_closures units pack bound_vars = Var_within_closure.Map.map (import_approx_for_pack units pack) set_of_closures.bound_vars; + free_vars = set_of_closures.free_vars; results = Closure_id.Map.map (import_approx_for_pack units pack) set_of_closures.results; @@ -111,6 +114,7 @@ let import_descr_for_pack units pack (descr : Export_info.descr) } | Value_set_of_closures set_of_closures -> Value_set_of_closures (import_set_of_closures units pack set_of_closures) + | Value_unknown_descr -> Value_unknown_descr let rec import_code_for_pack units pack expr = Flambda_iterators.map_named (function @@ -124,7 +128,7 @@ let rec import_code_for_pack units pack expr = ~specialised_args:set_of_closures.specialised_args ~direct_call_surrogates:set_of_closures.direct_call_surrogates ~function_decls: - (import_function_declarations_for_pack units pack + (import_function_declarations_for_pack_aux units pack set_of_closures.function_decls) in Set_of_closures set_of_closures @@ -134,13 +138,15 @@ let rec import_code_for_pack units pack expr = and import_function_declarations_for_pack_aux units pack (function_decls : Flambda.function_declarations) = let funs = - Variable.Map.map (fun (function_decl : Flambda.function_declaration) -> + Variable.Map.map + (fun (function_decl : Flambda.function_declaration) -> Flambda.create_function_declaration ~params:function_decl.params ~body:(import_code_for_pack units pack function_decl.body) ~stub:function_decl.stub ~dbg:function_decl.dbg ~inline:function_decl.inline ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor) + ~is_a_functor:function_decl.is_a_functor + ~closure_origin:function_decl.closure_origin) function_decls.funs in Flambda.import_function_declarations_for_pack @@ -148,8 +154,22 @@ and import_function_declarations_for_pack_aux units pack (import_set_of_closures_id_for_pack units pack) (import_set_of_closures_origin_for_pack units pack) -and import_function_declarations_for_pack units pack - (function_decls:Flambda.function_declarations) = +let import_function_declarations_for_pack_aux units pack + (function_decls : A.function_declarations) : A.function_declarations = + let funs = + Variable.Map.map + (fun (function_decl : A.function_declaration) -> + A.update_function_declaration_body function_decl + (fun body -> import_code_for_pack units pack body)) + function_decls.funs + in + A.import_function_declarations_for_pack + (A.update_function_declarations function_decls ~funs) + (import_set_of_closures_id_for_pack units pack) + (import_set_of_closures_origin_for_pack units pack) + +let import_function_declarations_approx_for_pack units pack + (function_decls: A.function_declarations) = let original_set_of_closures_id = function_decls.set_of_closures_id in try Set_of_closures_id.Tbl.find imported_function_declarations_table @@ -183,7 +203,7 @@ let import_for_pack ~pack_units ~pack (exp : Export_info.t) = import_set_of_closures_id_for_pack pack_units pack in let import_function_declarations = - import_function_declarations_for_pack pack_units pack + import_function_declarations_approx_for_pack pack_units pack in let sets_of_closures = Set_of_closures_id.Map.map_keys import_set_of_closures_id @@ -192,18 +212,18 @@ let import_for_pack ~pack_units ~pack (exp : Export_info.t) = exp.sets_of_closures) in Export_info.create ~sets_of_closures - ~closures:(Flambda_utils.make_closure_map' sets_of_closures) ~offset_fun:exp.offset_fun ~offset_fv:exp.offset_fv ~values:(import_eidmap import_descr exp.values) ~symbol_id:(Symbol.Map.map_keys import_sym (Symbol.Map.map import_eid exp.symbol_id)) - ~constant_sets_of_closures: - (Set_of_closures_id.Set.map import_set_of_closures_id - exp.constant_sets_of_closures) + ~constant_closures:exp.constant_closures ~invariant_params: (Set_of_closures_id.Map.map_keys import_set_of_closures_id exp.invariant_params) + ~recursive: + (Set_of_closures_id.Map.map_keys import_set_of_closures_id + exp.recursive) let clear_import_state () = Set_of_closures_id.Tbl.clear imported_function_declarations_table; diff --git a/asmcomp/flambda_to_clambda.ml b/asmcomp/flambda_to_clambda.ml index b9d2beb9..713e87bf 100644 --- a/asmcomp/flambda_to_clambda.ml +++ b/asmcomp/flambda_to_clambda.ml @@ -16,28 +16,25 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -type for_one_or_more_units = { +type 'a for_one_or_more_units = { fun_offset_table : int Closure_id.Map.t; fv_offset_table : int Var_within_closure.Map.t; - closures : Flambda.function_declarations Closure_id.Map.t; - constant_sets_of_closures : Set_of_closures_id.Set.t; + constant_closures : Closure_id.Set.t; + closures: Closure_id.Set.t; } type t = { - current_unit : for_one_or_more_units; - imported_units : for_one_or_more_units; + current_unit : Set_of_closures_id.t for_one_or_more_units; + imported_units : Simple_value_approx.function_declarations for_one_or_more_units; } -type ('a, 'b) declaration_position = - | Current_unit of 'a - | Imported_unit of 'b - | Not_declared - let get_fun_offset t closure_id = let fun_offset_table = if Closure_id.in_compilation_unit closure_id (Compilenv.current_unit ()) - then t.current_unit.fun_offset_table - else t.imported_units.fun_offset_table + then + t.current_unit.fun_offset_table + else + t.imported_units.fun_offset_table in try Closure_id.Map.find closure_id fun_offset_table with Not_found -> @@ -56,23 +53,12 @@ let get_fv_offset t var_within_closure = Misc.fatal_errorf "Flambda_to_clambda: missing offset for variable %a" Var_within_closure.print var_within_closure -let function_declaration_position t closure_id = - try - Current_unit (Closure_id.Map.find closure_id t.current_unit.closures) - with Not_found -> - try - Imported_unit (Closure_id.Map.find closure_id t.imported_units.closures) - with Not_found -> Not_declared - let is_function_constant t closure_id = - match function_declaration_position t closure_id with - | Current_unit { set_of_closures_id } -> - Set_of_closures_id.Set.mem set_of_closures_id - t.current_unit.constant_sets_of_closures - | Imported_unit { set_of_closures_id } -> - Set_of_closures_id.Set.mem set_of_closures_id - t.imported_units.constant_sets_of_closures - | Not_declared -> + if Closure_id.Set.mem closure_id t.current_unit.closures then + Closure_id.Set.mem closure_id t.current_unit.constant_closures + else if Closure_id.Set.mem closure_id t.imported_units.closures then + Closure_id.Set.mem closure_id t.imported_units.constant_closures + else Misc.fatal_errorf "Flambda_to_clambda: missing closure %a" Closure_id.print closure_id @@ -156,14 +142,14 @@ end = struct let ident_for_var_exn t id = Variable.Map.find id t.var let add_fresh_ident t var = - let id = Ident.create (Variable.unique_name var) in + let id = Ident.create (Variable.name var) in id, { t with var = Variable.Map.add var id t.var } let ident_for_mutable_var_exn t mut_var = Mutable_variable.Map.find mut_var t.mutable_var let add_fresh_mutable_ident t mut_var = - let id = Mutable_variable.unique_ident mut_var in + let id = Ident.create (Mutable_variable.name mut_var) in let mutable_var = Mutable_variable.Map.add mut_var id t.mutable_var in id, { t with mutable_var; } @@ -411,13 +397,28 @@ and to_clambda_switch t env cases num_keys default = if Numbers.Int.Set.cardinal num_keys = 0 then 0 else Numbers.Int.Set.max_elt num_keys + 1 in - let index = Array.make num_keys 0 in let store = Flambda_utils.Switch_storer.mk_store () in - begin match default with - | Some def when List.length cases < num_keys -> ignore (store.act_store def) - | _ -> () + let default_action = + match default with + | Some def when List.length cases < num_keys -> + store.act_store () def + | _ -> -1 + in + let index = Array.make num_keys default_action in + let smallest_key = ref num_keys in + List.iter + (fun (key, lam) -> + index.(key) <- store.act_store () lam; + smallest_key := min key !smallest_key + ) + cases; + if !smallest_key < num_keys then begin + let action = ref index.(!smallest_key) in + Array.iteri + (fun i act -> + if act >= 0 then action := act else index.(i) <- !action) + index end; - List.iter (fun (key, lam) -> index.(key) <- store.act_store lam) cases; let actions = Array.map (to_clambda t env) (store.act_get ()) in match actions with | [| |] -> [| |], [| |] (* May happen when [default] is [None]. *) @@ -569,7 +570,7 @@ and to_clambda_closed_set_of_closures t env symbol let to_clambda_initialize_symbol t env symbol fields : Clambda.ulambda = let fields = - List.mapi (fun index expr -> index, to_clambda t env expr) fields + List.map (fun (index, expr) -> index, to_clambda t env expr) fields in let build_setfield (index, field) : Clambda.ulambda = (* Note that this will never cause a write barrier hit, owing to @@ -602,7 +603,9 @@ let accumulate_structured_constants t env symbol let to_clambda_program t env constants (program : Flambda.program) = let rec loop env constants (program : Flambda.program_body) - : Clambda.ulambda * Clambda.ustructured_constant Symbol.Map.t = + : Clambda.ulambda * + Clambda.ustructured_constant Symbol.Map.t * + Clambda.preallocated_block list = match program with | Let_symbol (symbol, alloc, program) -> (* Useful only for unboxing. Since floats and boxed integers will @@ -624,19 +627,52 @@ let to_clambda_program t env constants (program : Flambda.program) = constants defs in loop env constants program - | Initialize_symbol (symbol, _tag, fields, program) -> - (* The tag is ignored here: It is used separately to generate the - preallocated block. Only the initialisation code is generated - here. *) - let e1 = to_clambda_initialize_symbol t env symbol fields in - let e2, constants = loop env constants program in - Usequence (e1, e2), constants + | Initialize_symbol (symbol, tag, fields, program) -> + let fields = + List.mapi (fun i field -> + i, field, + Initialize_symbol_to_let_symbol.constant_field field) + fields + in + let init_fields = + Misc.Stdlib.List.filter_map (function + | (i, field, None) -> Some (i, field) + | (_, _, Some _) -> None) + fields + in + let constant_fields = + List.map (fun (_, _, constant_field) -> + match constant_field with + | None -> None + | Some (Flambda.Const const) -> + let n = + match const with + | Int i -> i + | Char c -> Char.code c + | Const_pointer i -> i + in + Some (Clambda.Uconst_field_int n) + | Some (Flambda.Symbol sym) -> + let lbl = Linkage_name.to_string (Symbol.label sym) in + Some (Clambda.Uconst_field_ref lbl)) + fields + in + let e1 = to_clambda_initialize_symbol t env symbol init_fields in + let preallocated_block : Clambda.preallocated_block = + { symbol = Linkage_name.to_string (Symbol.label symbol); + exported = true; + tag = Tag.to_int tag; + fields = constant_fields; + } + in + let e2, constants, preallocated_blocks = loop env constants program in + Usequence (e1, e2), constants, preallocated_block :: preallocated_blocks | Effect (expr, program) -> let e1 = to_clambda t env expr in - let e2, constants = loop env constants program in - Usequence (e1, e2), constants + let e2, constants, preallocated_blocks = loop env constants program in + Usequence (e1, e2), constants, preallocated_blocks | End _ -> - Uconst (Uconst_ptr 0), constants + Uconst (Uconst_ptr 0), constants, [] in loop env constants program.program_body @@ -647,49 +683,52 @@ type result = { exported : Export_info.t; } -let convert (program, exported) : result = +let convert (program, exported_transient) : result = let current_unit = + let closures = + Closure_id.Map.keys (Flambda_utils.make_closure_map program) + in + let constant_closures = + Flambda_utils.all_lifted_constant_closures program + in let offsets = Closure_offsets.compute program in { fun_offset_table = offsets.function_offsets; fv_offset_table = offsets.free_variable_offsets; - closures = Flambda_utils.make_closure_map program; - constant_sets_of_closures = - Flambda_utils.all_lifted_constant_sets_of_closures program; + constant_closures; + closures; } in let imported_units = let imported = Compilenv.approx_env () in + let closures = + Set_of_closures_id.Map.fold + (fun (_ : Set_of_closures_id.t) fun_decls acc -> + Variable.Map.fold + (fun var (_ : Simple_value_approx.function_declaration) acc -> + let closure_id = Closure_id.wrap var in + Closure_id.Set.add closure_id acc) + fun_decls.Simple_value_approx.funs + acc) + imported.sets_of_closures + Closure_id.Set.empty + in { fun_offset_table = imported.offset_fun; fv_offset_table = imported.offset_fv; - closures = imported.closures; - constant_sets_of_closures = imported.constant_sets_of_closures; + constant_closures = imported.constant_closures; + closures; } in let t = { current_unit; imported_units; } in - let preallocated_blocks = - List.map (fun (symbol, tag, fields) -> - { Clambda. - symbol = Linkage_name.to_string (Symbol.label symbol); - exported = true; - tag = Tag.to_int tag; - size = List.length fields; - }) - (Flambda_utils.initialize_symbols program) - in - let expr, structured_constants = + let expr, structured_constants, preallocated_blocks = to_clambda_program t Env.empty Symbol.Map.empty program in - let offset_fun, offset_fv = - Closure_offsets.compute_reexported_offsets program - ~current_unit_offset_fun:current_unit.fun_offset_table - ~current_unit_offset_fv:current_unit.fv_offset_table - ~imported_units_offset_fun:imported_units.fun_offset_table - ~imported_units_offset_fv:imported_units.fv_offset_table - in let exported = - Export_info.add_clambda_info exported - ~offset_fun - ~offset_fv - ~constant_sets_of_closures:current_unit.constant_sets_of_closures + Export_info.t_of_transient exported_transient + ~program + ~local_offset_fun:current_unit.fun_offset_table + ~local_offset_fv:current_unit.fv_offset_table + ~imported_offset_fun:imported_units.fun_offset_table + ~imported_offset_fv:imported_units.fv_offset_table + ~constant_closures:current_unit.constant_closures in { expr; preallocated_blocks; structured_constants; exported; } diff --git a/asmcomp/flambda_to_clambda.mli b/asmcomp/flambda_to_clambda.mli index 39cbc40f..8c493d40 100644 --- a/asmcomp/flambda_to_clambda.mli +++ b/asmcomp/flambda_to_clambda.mli @@ -35,4 +35,4 @@ type result = { For direct calls, the hidden closure parameter is added. Switch tables are also built. *) -val convert : Flambda.program * Export_info.t -> result +val convert : Flambda.program * Export_info.transient -> result diff --git a/asmcomp/i386/emit.mlp b/asmcomp/i386/emit.mlp index 0d984d5d..2d633f55 100644 --- a/asmcomp/i386/emit.mlp +++ b/asmcomp/i386/emit.mlp @@ -356,7 +356,7 @@ let is_tos = function { loc = Reg _; typ = Float } -> true | _ -> false (* Emit the code for a floating-point comparison *) -let emit_float_test cmp neg arg lbl = +let emit_float_test cmp arg lbl = let actual_cmp = match (is_tos arg.(0), is_tos arg.(1)) with | (true, true) -> @@ -370,7 +370,7 @@ let emit_float_test cmp neg arg lbl = | (false, true) -> (* second arg on top of FP stack *) I.fcomp (reg arg.(0)); - Cmm.swap_comparison cmp + Cmm.swap_float_comparison cmp | (false, false) -> I.fld (reg arg.(0)); I.fcomp (reg arg.(1)); @@ -378,49 +378,44 @@ let emit_float_test cmp neg arg lbl = in I.fnstsw ax; match actual_cmp with - | Ceq -> - if neg then begin - I.and_ (int 68) ah; - I.xor (int 64) ah; - I.jne lbl - end else begin - I.and_ (int 69) ah; - I.cmp (int 64) ah; - I.je lbl - end - | Cne -> - if neg then begin - I.and_ (int 69) ah; - I.cmp (int 64) ah; - I.je lbl - end else begin - I.and_ (int 68) ah; - I.xor (int 64) ah; - I.jne lbl - end - | Cle -> + | CFeq -> + I.and_ (int 69) ah; + I.cmp (int 64) ah; + I.je lbl + | CFneq -> + I.and_ (int 68) ah; + I.xor (int 64) ah; + I.jne lbl + | CFle -> I.and_ (int 69) ah; I.dec ah; I.cmp (int 64) ah; - if neg - then I.jae lbl - else I.jb lbl - | Cge -> + I.jb lbl + | CFnle -> + I.and_ (int 69) ah; + I.dec ah; + I.cmp (int 64) ah; + I.jae lbl + | CFge -> + I.and_ (int 5) ah; + I.je lbl + | CFnge -> I.and_ (int 5) ah; - if neg - then I.jne lbl - else I.je lbl - | Clt -> + I.jne lbl + | CFlt -> I.and_ (int 69) ah; I.cmp (int 1) ah; - if neg - then I.jne lbl - else I.je lbl - | Cgt -> + I.je lbl + | CFnlt -> + I.and_ (int 69) ah; + I.cmp (int 1) ah; + I.jne lbl + | CFgt -> + I.and_ (int 69) ah; + I.je lbl + | CFngt -> I.and_ (int 69) ah; - if neg - then I.jne lbl - else I.je lbl + I.jne lbl (* Emit a Ifloatspecial instruction *) @@ -825,8 +820,8 @@ let emit_instr fallthrough i = | Iinttest_imm(cmp, n) -> I.cmp (int n) (reg i.arg.(0)); I.j (cond cmp) lbl - | Ifloattest(cmp, neg) -> - emit_float_test cmp neg i.arg lbl + | Ifloattest cmp -> + emit_float_test cmp i.arg lbl | Ioddtest -> I.test (int 1) (reg i.arg.(0)); I.jne lbl diff --git a/asmcomp/i386/proc.ml b/asmcomp/i386/proc.ml index 9350fc96..7e883fc7 100644 --- a/asmcomp/i386/proc.ml +++ b/asmcomp/i386/proc.ml @@ -191,7 +191,7 @@ let destroyed_at_oper = function | Iop(Ialloc _ | Iintop Imulh) -> [| eax |] | Iop(Iintop(Icomp _) | Iintop_imm(Icomp _, _)) -> [| eax |] | Iop(Iintoffloat) -> [| eax |] - | Iifthenelse(Ifloattest(_, _), _, _) -> [| eax |] + | Iifthenelse(Ifloattest _, _, _) -> [| eax |] | _ -> [||] let destroyed_at_raise = all_phys_regs diff --git a/asmcomp/import_approx.ml b/asmcomp/import_approx.ml index 0ab09ca0..64fbbb8b 100644 --- a/asmcomp/import_approx.ml +++ b/asmcomp/import_approx.ml @@ -19,11 +19,11 @@ module A = Simple_value_approx let import_set_of_closures = - let import_function_declarations (clos : Flambda.function_declarations) - : Flambda.function_declarations = + let import_function_declarations (clos : A.function_declarations) + : A.function_declarations = (* CR-soon mshinwell for pchambart: Do we still need to do this rewriting? I'm wondering if maybe we don't have to any more. *) - let sym_to_fun_var_map (clos : Flambda.function_declarations) = + let sym_to_fun_var_map (clos : A.function_declarations) = Variable.Map.fold (fun fun_var _ acc -> let closure_id = Closure_id.wrap fun_var in let sym = Compilenv.closure_symbol closure_id in @@ -40,118 +40,144 @@ let import_set_of_closures = | named -> named in let funs = - Variable.Map.map (fun (function_decl : Flambda.function_declaration) -> - let body = - Flambda_iterators.map_toplevel_named f_named function_decl.body - in - Flambda.create_function_declaration ~params:function_decl.params - ~body ~stub:function_decl.stub ~dbg:function_decl.dbg - ~inline:function_decl.inline - ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor) + Variable.Map.map (fun (function_decl : A.function_declaration) -> + A.update_function_declaration_body function_decl + (Flambda_iterators.map_toplevel_named f_named)) clos.funs in - Flambda.update_function_declarations clos ~funs + A.update_function_declarations clos ~funs in let aux set_of_closures_id = - ignore (Compilenv.approx_for_global - (Set_of_closures_id.get_compilation_unit set_of_closures_id)); - let ex_info = Compilenv.approx_env () in - let function_declarations = + match + Compilenv.approx_for_global + (Set_of_closures_id.get_compilation_unit set_of_closures_id) + with + | None -> None + | Some ex_info -> try - Some (Set_of_closures_id.Map.find set_of_closures_id - ex_info.sets_of_closures) + let function_declarations = + Set_of_closures_id.Map.find set_of_closures_id + ex_info.sets_of_closures + in + Some (import_function_declarations function_declarations) with Not_found -> - None - in - match function_declarations with - | None -> None - | Some function_declarations -> - Some (import_function_declarations function_declarations) + Misc.fatal_error "Cannot find set of closures" in Set_of_closures_id.Tbl.memoize Compilenv.imported_sets_of_closures_table aux let rec import_ex ex = - ignore (Compilenv.approx_for_global (Export_id.get_compilation_unit ex)); - let ex_info = Compilenv.approx_env () in - let import_value_set_of_closures ~set_of_closures_id ~bound_vars + let import_value_set_of_closures ~set_of_closures_id ~bound_vars ~free_vars ~(ex_info : Export_info.t) ~what : A.value_set_of_closures option = let bound_vars = Var_within_closure.Map.map import_approx bound_vars in - match - Set_of_closures_id.Map.find set_of_closures_id ex_info.invariant_params - with - | exception Not_found -> - Misc.fatal_errorf "Set of closures ID %a not found in invariant_params \ - (when importing [%a: %s])" - Set_of_closures_id.print set_of_closures_id - Export_id.print ex - what - | invariant_params -> - match import_set_of_closures set_of_closures_id with - | None -> None - | Some function_decls -> - Some (A.create_value_set_of_closures - ~function_decls - ~bound_vars - ~invariant_params:(lazy invariant_params) - ~specialised_args:Variable.Map.empty - ~freshening:Freshening.Project_var.empty - ~direct_call_surrogates:Closure_id.Map.empty) + match import_set_of_closures set_of_closures_id with + | None -> None + | Some function_decls -> + (* CR-someday xclerc: add a test to the test suite to ensure that + classic mode behaves as expected. *) + let is_classic_mode = function_decls.is_classic_mode in + let invariant_params = + match + Set_of_closures_id.Map.find set_of_closures_id + ex_info.invariant_params + with + | exception Not_found -> + if is_classic_mode then + Variable.Map.empty + else + Misc.fatal_errorf "Set of closures ID %a not found in \ + invariant_params (when importing [%a: %s])" + Set_of_closures_id.print set_of_closures_id + Export_id.print ex + what + | found -> found + in + let recursive = + match + Set_of_closures_id.Map.find set_of_closures_id ex_info.recursive + with + | exception Not_found -> + if is_classic_mode then + Variable.Set.empty + else + Misc.fatal_errorf "Set of closures ID %a not found in \ + recursive (when importing [%a: %s])" + Set_of_closures_id.print set_of_closures_id + Export_id.print ex + what + | found -> found + in + Some (A.create_value_set_of_closures + ~function_decls + ~bound_vars + ~free_vars + ~invariant_params:(lazy invariant_params) + ~recursive:(lazy recursive) + ~specialised_args:Variable.Map.empty + ~freshening:Freshening.Project_var.empty + ~direct_call_surrogates:Closure_id.Map.empty) in - match Export_info.find_description ex_info ex with - | exception Not_found -> A.value_unknown Other - | Value_int i -> A.value_int i - | Value_char c -> A.value_char c - | Value_constptr i -> A.value_constptr i - | Value_float f -> A.value_float f - | Value_float_array float_array -> - begin match float_array.contents with - | Unknown_or_mutable -> - A.value_mutable_float_array ~size:float_array.size - | Contents contents -> - A.value_immutable_float_array - (Array.map (function - | None -> A.value_any_float - | Some f -> A.value_float f) - contents) - end - | Export_info.Value_boxed_int (t, i) -> A.value_boxed_int t i - | Value_string { size; contents } -> - let contents = - match contents with - | Unknown_or_mutable -> None - | Contents contents -> Some contents - in - A.value_string size contents - | Value_mutable_block _ -> A.value_unknown Other - | Value_block (tag, fields) -> - A.value_block tag (Array.map import_approx fields) - | Value_closure { closure_id; - set_of_closures = - { set_of_closures_id; bound_vars; aliased_symbol } } -> - let value_set_of_closures = - import_value_set_of_closures ~set_of_closures_id ~bound_vars ~ex_info - ~what:(Format.asprintf "Value_closure %a" Closure_id.print closure_id) - in - begin match value_set_of_closures with - | None -> A.value_unresolved (Set_of_closures_id set_of_closures_id) - | Some value_set_of_closures -> - A.value_closure ?set_of_closures_symbol:aliased_symbol - value_set_of_closures closure_id - end - | Value_set_of_closures { set_of_closures_id; bound_vars; aliased_symbol } -> - let value_set_of_closures = - import_value_set_of_closures ~set_of_closures_id ~bound_vars ~ex_info - ~what:"Value_set_of_closures" - in - match value_set_of_closures with - | None -> - A.value_unresolved (Set_of_closures_id set_of_closures_id) - | Some value_set_of_closures -> - let approx = A.value_set_of_closures value_set_of_closures in - match aliased_symbol with - | None -> approx - | Some symbol -> A.augment_with_symbol approx symbol + let compilation_unit = Export_id.get_compilation_unit ex in + match Compilenv.approx_for_global compilation_unit with + | None -> A.value_unknown Other + | Some ex_info -> + match Export_info.find_description ex_info ex with + | exception Not_found -> + Misc.fatal_errorf "Cannot find export id %a" Export_id.print ex + | Value_unknown_descr -> A.value_unknown Other + | Value_int i -> A.value_int i + | Value_char c -> A.value_char c + | Value_constptr i -> A.value_constptr i + | Value_float f -> A.value_float f + | Value_float_array float_array -> + begin match float_array.contents with + | Unknown_or_mutable -> + A.value_mutable_float_array ~size:float_array.size + | Contents contents -> + A.value_immutable_float_array + (Array.map (function + | None -> A.value_any_float + | Some f -> A.value_float f) + contents) + end + | Export_info.Value_boxed_int (t, i) -> A.value_boxed_int t i + | Value_string { size; contents } -> + let contents = + match contents with + | Unknown_or_mutable -> None + | Contents contents -> Some contents + in + A.value_string size contents + | Value_mutable_block _ -> A.value_unknown Other + | Value_block (tag, fields) -> + A.value_block tag (Array.map import_approx fields) + | Value_closure { closure_id; + set_of_closures = + { set_of_closures_id; bound_vars; free_vars; aliased_symbol } } -> + let value_set_of_closures = + import_value_set_of_closures + ~set_of_closures_id ~bound_vars ~free_vars ~ex_info + ~what:(Format.asprintf "Value_closure %a" Closure_id.print closure_id) + in + begin match value_set_of_closures with + | None -> A.value_unresolved (Set_of_closures_id set_of_closures_id) + | Some value_set_of_closures -> + A.value_closure ?set_of_closures_symbol:aliased_symbol + value_set_of_closures closure_id + end + | Value_set_of_closures + { set_of_closures_id; bound_vars; free_vars; aliased_symbol } -> + let value_set_of_closures = + import_value_set_of_closures ~set_of_closures_id + ~bound_vars ~free_vars ~ex_info ~what:"Value_set_of_closures" + in + match value_set_of_closures with + | None -> + A.value_unresolved (Set_of_closures_id set_of_closures_id) + | Some value_set_of_closures -> + let approx = A.value_set_of_closures value_set_of_closures in + match aliased_symbol with + | None -> approx + | Some symbol -> A.augment_with_symbol approx symbol and import_approx (ap : Export_info.approx) = match ap with @@ -162,15 +188,19 @@ and import_approx (ap : Export_info.approx) = let import_symbol sym = if Compilenv.is_predefined_exception sym then A.value_unknown Other - else - let symbol_id_map = - let global = Symbol.compilation_unit sym in - (Compilenv.approx_for_global global).symbol_id - in - match Symbol.Map.find sym symbol_id_map with - | approx -> A.augment_with_symbol (import_ex approx) sym - | exception Not_found -> - A.value_unresolved (Symbol sym) + else begin + let compilation_unit = Symbol.compilation_unit sym in + match Compilenv.approx_for_global compilation_unit with + | None -> A.value_unresolved (Symbol sym) + | Some export_info -> + match Symbol.Map.find sym export_info.symbol_id with + | approx -> A.augment_with_symbol (import_ex approx) sym + | exception Not_found -> + Misc.fatal_errorf + "Compilation unit = %a Cannot find symbol %a" + Compilation_unit.print compilation_unit + Symbol.print sym + end (* Note for code reviewers: Observe that [really_import] iterates until the approximation description is fully resolved (or a necessary .cmx diff --git a/asmcomp/linearize.ml b/asmcomp/linearize.ml index 1aa5d90f..e915bb5e 100644 --- a/asmcomp/linearize.ml +++ b/asmcomp/linearize.ml @@ -59,15 +59,15 @@ type fundecl = (* Invert a test *) let invert_integer_test = function - Isigned cmp -> Isigned(Cmm.negate_comparison cmp) - | Iunsigned cmp -> Iunsigned(Cmm.negate_comparison cmp) + Isigned cmp -> Isigned(Cmm.negate_integer_comparison cmp) + | Iunsigned cmp -> Iunsigned(Cmm.negate_integer_comparison cmp) let invert_test = function Itruetest -> Ifalsetest | Ifalsetest -> Itruetest | Iinttest(cmp) -> Iinttest(invert_integer_test cmp) | Iinttest_imm(cmp, n) -> Iinttest_imm(invert_integer_test cmp, n) - | Ifloattest(cmp, neg) -> Ifloattest(cmp, not neg) + | Ifloattest(cmp) -> Ifloattest(Cmm.negate_float_comparison cmp) | Ieventest -> Ioddtest | Ioddtest -> Ieventest @@ -311,7 +311,7 @@ let rec linear i n = let fundecl f = { fun_name = f.Mach.fun_name; fun_body = linear f.Mach.fun_body end_instr; - fun_fast = f.Mach.fun_fast; + fun_fast = not (List.mem Cmm.Reduce_code_size f.Mach.fun_codegen_options); fun_dbg = f.Mach.fun_dbg; fun_spacetime_shape = f.Mach.fun_spacetime_shape; } diff --git a/asmcomp/mach.ml b/asmcomp/mach.ml index cfed6373..756ec61a 100644 --- a/asmcomp/mach.ml +++ b/asmcomp/mach.ml @@ -18,8 +18,8 @@ type label = Cmm.label type integer_comparison = - Isigned of Cmm.comparison - | Iunsigned of Cmm.comparison + Isigned of Cmm.integer_comparison + | Iunsigned of Cmm.integer_comparison type integer_operation = Iadd | Isub | Imul | Imulh | Idiv | Imod @@ -28,12 +28,14 @@ type integer_operation = | Icheckbound of { label_after_error : label option; spacetime_index : int; } +type float_comparison = Cmm.float_comparison + type test = Itruetest | Ifalsetest | Iinttest of integer_comparison | Iinttest_imm of integer_comparison * int - | Ifloattest of Cmm.comparison * bool + | Ifloattest of float_comparison | Ioddtest | Ieventest @@ -96,7 +98,7 @@ type fundecl = { fun_name: string; fun_args: Reg.t array; fun_body: instruction; - fun_fast: bool; + fun_codegen_options : Cmm.codegen_option list; fun_dbg : Debuginfo.t; fun_spacetime_shape : spacetime_shape option; } diff --git a/asmcomp/mach.mli b/asmcomp/mach.mli index 784bba62..be17ba2b 100644 --- a/asmcomp/mach.mli +++ b/asmcomp/mach.mli @@ -22,8 +22,8 @@ type label = Cmm.label type integer_comparison = - Isigned of Cmm.comparison - | Iunsigned of Cmm.comparison + Isigned of Cmm.integer_comparison + | Iunsigned of Cmm.integer_comparison type integer_operation = Iadd | Isub | Imul | Imulh | Idiv | Imod @@ -35,12 +35,14 @@ type integer_operation = second being the pointer to the trie node for the current function (and the first being as per non-Spacetime mode). *) +type float_comparison = Cmm.float_comparison + type test = Itruetest | Ifalsetest | Iinttest of integer_comparison | Iinttest_imm of integer_comparison * int - | Ifloattest of Cmm.comparison * bool + | Ifloattest of float_comparison | Ioddtest | Ieventest @@ -118,7 +120,7 @@ type fundecl = { fun_name: string; fun_args: Reg.t array; fun_body: instruction; - fun_fast: bool; + fun_codegen_options : Cmm.codegen_option list; fun_dbg : Debuginfo.t; fun_spacetime_shape : spacetime_shape option; } diff --git a/asmcomp/power/emit.mlp b/asmcomp/power/emit.mlp index 0ab36376..bd0c7134 100644 --- a/asmcomp/power/emit.mlp +++ b/asmcomp/power/emit.mlp @@ -847,22 +847,27 @@ let emit_instr i = let (comp, branch) = name_for_int_comparison cmp in ` {emit_string comp}i {emit_reg i.arg.(0)}, {emit_int n}\n`; ` {emit_string branch} {emit_label lbl}\n` - | Ifloattest(cmp, neg) -> + | Ifloattest cmp -> begin ` fcmpu 0, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; (* bit 0 = lt, bit 1 = gt, bit 2 = eq *) - let (bitnum, negtst) = + let bitnum = match cmp with - Ceq -> (2, neg) - | Cne -> (2, not neg) - | Cle -> ` cror 3, 0, 2\n`; (* lt or eq *) - (3, neg) - | Cgt -> (1, neg) - | Cge -> ` cror 3, 1, 2\n`; (* gt or eq *) - (3, neg) - | Clt -> (0, neg) in - if negtst - then ` bf {emit_int bitnum}, {emit_label lbl}\n` - else ` bt {emit_int bitnum}, {emit_label lbl}\n` + | CFeq | CFneq -> 2 + | CFle | CFnle -> + ` cror 3, 0, 2\n`; (* lt or eq *) + 3 + | CFgt | CFngt -> 1 + | CFge | CFnge -> + ` cror 3, 1, 2\n`; (* gt or eq *) + 3 + | CFlt | CFnlt -> 0 + in + match cmp with + | CFneq | CFngt | CFnge | CFnlt | CFnle -> + ` bf {emit_int bitnum}, {emit_label lbl}\n` + | CFeq | CFgt | CFge | CFlt | CFle -> + ` bt {emit_int bitnum}, {emit_label lbl}\n` + end | Ioddtest -> ` andi. 0, {emit_reg i.arg.(0)}, 1\n`; ` bne {emit_label lbl}\n` diff --git a/asmcomp/printcmm.ml b/asmcomp/printcmm.ml index 697ebca8..51682690 100644 --- a/asmcomp/printcmm.ml +++ b/asmcomp/printcmm.ml @@ -36,7 +36,7 @@ let machtype ppf mty = fprintf ppf "*%a" machtype_component mty.(i) done -let comparison = function +let integer_comparison = function | Ceq -> "==" | Cne -> "!=" | Clt -> "<" @@ -44,6 +44,18 @@ let comparison = function | Cgt -> ">" | Cge -> ">=" +let float_comparison = function + | CFeq -> "==" + | CFneq -> "!=" + | CFlt -> "<" + | CFnlt -> "!<" + | CFle -> "<=" + | CFnle -> "!<=" + | CFgt -> ">" + | CFngt -> "!>" + | CFge -> ">=" + | CFnge -> "!>=" + let chunk = function | Byte_unsigned -> "unsigned int8" | Byte_signed -> "signed int8" @@ -88,10 +100,10 @@ let operation d = function | Clsl -> "<<" | Clsr -> ">>u" | Casr -> ">>s" - | Ccmpi c -> comparison c + | Ccmpi c -> integer_comparison c | Caddv -> "+v" | Cadda -> "+a" - | Ccmpa c -> Printf.sprintf "%sa" (comparison c) + | Ccmpa c -> Printf.sprintf "%sa" (integer_comparison c) | Cnegf -> "~f" | Cabsf -> "absf" | Caddf -> "+f" @@ -100,7 +112,7 @@ let operation d = function | Cdivf -> "/f" | Cfloatofint -> "floatofint" | Cintoffloat -> "intoffloat" - | Ccmpf c -> Printf.sprintf "%sf" (comparison c) + | Ccmpf c -> Printf.sprintf "%sf" (float_comparison c) | Craise k -> Format.asprintf "%a%s" raise_kind k (Debuginfo.to_string d) | Ccheckbound -> "checkbound" ^ Debuginfo.to_string d diff --git a/asmcomp/printcmm.mli b/asmcomp/printcmm.mli index bd4739b2..0a631d3d 100644 --- a/asmcomp/printcmm.mli +++ b/asmcomp/printcmm.mli @@ -20,7 +20,8 @@ open Format val rec_flag : formatter -> Cmm.rec_flag -> unit val machtype_component : formatter -> Cmm.machtype_component -> unit val machtype : formatter -> Cmm.machtype_component array -> unit -val comparison : Cmm.comparison -> string +val integer_comparison : Cmm.integer_comparison -> string +val float_comparison : Cmm.float_comparison -> string val chunk : Cmm.memory_chunk -> string val operation : Debuginfo.t -> Cmm.operation -> string val expression : formatter -> Cmm.expression -> unit diff --git a/asmcomp/printmach.ml b/asmcomp/printmach.ml index cd7e8a77..57b111ce 100644 --- a/asmcomp/printmach.ml +++ b/asmcomp/printmach.ml @@ -68,11 +68,11 @@ let regsetaddr ppf s = s let intcomp = function - | Isigned c -> Printf.sprintf " %ss " (Printcmm.comparison c) - | Iunsigned c -> Printf.sprintf " %su " (Printcmm.comparison c) + | Isigned c -> Printf.sprintf " %ss " (Printcmm.integer_comparison c) + | Iunsigned c -> Printf.sprintf " %su " (Printcmm.integer_comparison c) let floatcomp c = - Printf.sprintf " %sf " (Printcmm.comparison c) + Printf.sprintf " %sf " (Printcmm.float_comparison c) let intop = function | Iadd -> " + " @@ -105,9 +105,8 @@ let test tst ppf arg = | Ifalsetest -> fprintf ppf "not %a" reg arg.(0) | Iinttest cmp -> fprintf ppf "%a%s%a" reg arg.(0) (intcomp cmp) reg arg.(1) | Iinttest_imm(cmp, n) -> fprintf ppf "%a%s%i" reg arg.(0) (intcomp cmp) n - | Ifloattest(cmp, neg) -> - fprintf ppf "%s%a%s%a" - (if neg then "not " else "") + | Ifloattest cmp -> + fprintf ppf "%a%s%a" reg arg.(0) (floatcomp cmp) reg arg.(1) | Ieventest -> fprintf ppf "%a & 1 == 0" reg arg.(0) | Ioddtest -> fprintf ppf "%a & 1 == 1" reg arg.(0) diff --git a/asmcomp/reloadgen.ml b/asmcomp/reloadgen.ml index 3c0b9873..d2bf9150 100644 --- a/asmcomp/reloadgen.ml +++ b/asmcomp/reloadgen.ml @@ -129,7 +129,7 @@ method fundecl f = redo_regalloc <- false; let new_body = self#reload f.fun_body in ({fun_name = f.fun_name; fun_args = f.fun_args; - fun_body = new_body; fun_fast = f.fun_fast; + fun_body = new_body; fun_codegen_options = f.fun_codegen_options; fun_dbg = f.fun_dbg; fun_spacetime_shape = f.fun_spacetime_shape}, redo_regalloc) end diff --git a/asmcomp/s390x/emit.mlp b/asmcomp/s390x/emit.mlp index 3487005e..cef1022a 100644 --- a/asmcomp/s390x/emit.mlp +++ b/asmcomp/s390x/emit.mlp @@ -238,10 +238,11 @@ let int_literals = ref ([] : (nativeint * int) list) (* Masks for conditional branches after comparisons *) +(* bit 0 = eq, bit 1 = lt, bit 2 = gt, bit 3 = overflow*) let branch_for_comparison = function - Ceq -> 8 | Cne -> 7 - | Cle -> 12 | Cgt -> 2 - | Cge -> 10 | Clt -> 4 + | Ceq -> 0b1000 | Cne -> 0b0111 (* BRNEL is 0111 rather than 0110 *) + | Cle -> 0b1100 | Cgt -> 0b0010 + | Cge -> 0b1010 | Clt -> 0b0100 let name_for_int_comparison = function Isigned cmp -> ("cgr", branch_for_comparison cmp) @@ -252,14 +253,21 @@ let name_for_int_comparison_imm = function | Iunsigned cmp -> ("clgfi", branch_for_comparison cmp) (* bit 0 = eq, bit 1 = lt, bit 2 = gt, bit 3 = unordered*) -let branch_for_float_comparison cmp neg = - match cmp with - Ceq -> if neg then 7 else 8 - | Cne -> if neg then 8 else 7 - | Cle -> if neg then 3 else 12 - | Cgt -> if neg then 13 else 2 - | Cge -> if neg then 5 else 10 - | Clt -> if neg then 11 else 4 +let branch_for_float_comparison = function + | CFeq -> 0b1000 + | CFneq -> 0b0111 + + | CFle -> 0b1100 + | CFnle -> 0b0011 + + | CFgt -> 0b0010 + | CFngt -> 0b1101 + + | CFge -> 0b1010 + | CFnge -> 0b0101 + + | CFlt -> 0b0100 + | CFnlt -> 0b1011 (* Names for various instructions *) @@ -554,9 +562,9 @@ let emit_instr i = let (comp, mask) = name_for_int_comparison_imm cmp in ` {emit_string comp} {emit_reg i.arg.(0)}, {emit_int n}\n`; ` brcl {emit_int mask}, {emit_label lbl}\n` - | Ifloattest(cmp, neg) -> + | Ifloattest cmp -> ` cdbr {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; - let mask = branch_for_float_comparison cmp neg in + let mask = branch_for_float_comparison cmp in ` brcl {emit_int mask}, {emit_label lbl}\n` | Ioddtest -> ` tmll {emit_reg i.arg.(0)}, 1\n`; diff --git a/asmcomp/selectgen.ml b/asmcomp/selectgen.ml index 1158fc0d..d0520ba9 100644 --- a/asmcomp/selectgen.ml +++ b/asmcomp/selectgen.ml @@ -105,8 +105,8 @@ let size_expr (env:environment) exp = (* Swap the two arguments of an integer comparison *) let swap_intcomp = function - Isigned cmp -> Isigned(swap_comparison cmp) - | Iunsigned cmp -> Iunsigned(swap_comparison cmp) + Isigned cmp -> Isigned(swap_integer_comparison cmp) + | Iunsigned cmp -> Iunsigned(swap_integer_comparison cmp) (* Naming of registers *) @@ -511,11 +511,11 @@ method select_condition = function Cop(Ccmpi cmp, [arg1; Cconst_int n], _) when self#is_immediate n -> (Iinttest_imm(Isigned cmp, n), arg1) | Cop(Ccmpi cmp, [Cconst_int n; arg2], _) when self#is_immediate n -> - (Iinttest_imm(Isigned(swap_comparison cmp), n), arg2) + (Iinttest_imm(Isigned(swap_integer_comparison cmp), n), arg2) | Cop(Ccmpi cmp, [arg1; Cconst_pointer n], _) when self#is_immediate n -> (Iinttest_imm(Isigned cmp, n), arg1) | Cop(Ccmpi cmp, [Cconst_pointer n; arg2], _) when self#is_immediate n -> - (Iinttest_imm(Isigned(swap_comparison cmp), n), arg2) + (Iinttest_imm(Isigned(swap_integer_comparison cmp), n), arg2) | Cop(Ccmpi cmp, args, _) -> (Iinttest(Isigned cmp), Ctuple args) | Cop(Ccmpa cmp, [arg1; Cconst_pointer n], _) when self#is_immediate n -> @@ -523,13 +523,13 @@ method select_condition = function | Cop(Ccmpa cmp, [arg1; Cconst_int n], _) when self#is_immediate n -> (Iinttest_imm(Iunsigned cmp, n), arg1) | Cop(Ccmpa cmp, [Cconst_pointer n; arg2], _) when self#is_immediate n -> - (Iinttest_imm(Iunsigned(swap_comparison cmp), n), arg2) + (Iinttest_imm(Iunsigned(swap_integer_comparison cmp), n), arg2) | Cop(Ccmpa cmp, [Cconst_int n; arg2], _) when self#is_immediate n -> - (Iinttest_imm(Iunsigned(swap_comparison cmp), n), arg2) + (Iinttest_imm(Iunsigned(swap_integer_comparison cmp), n), arg2) | Cop(Ccmpa cmp, args, _) -> (Iinttest(Iunsigned cmp), Ctuple args) | Cop(Ccmpf cmp, args, _) -> - (Ifloattest(cmp, false), Ctuple args) + (Ifloattest cmp, Ctuple args) | Cop(Cand, [arg; Cconst_int 1], _) -> (Ioddtest, arg) | arg -> @@ -1215,7 +1215,7 @@ method emit_fundecl f = { fun_name = f.Cmm.fun_name; fun_args = loc_arg; fun_body = body; - fun_fast = f.Cmm.fun_fast; + fun_codegen_options = f.Cmm.fun_codegen_options; fun_dbg = f.Cmm.fun_dbg; fun_spacetime_shape; } diff --git a/asmcomp/spill.ml b/asmcomp/spill.ml index a02b0c36..7e3a3188 100644 --- a/asmcomp/spill.ml +++ b/asmcomp/spill.ml @@ -471,7 +471,7 @@ let fundecl f = { fun_name = f.fun_name; fun_args = f.fun_args; fun_body = new_body; - fun_fast = f.fun_fast; + fun_codegen_options = f.fun_codegen_options; fun_dbg = f.fun_dbg; fun_spacetime_shape = f.fun_spacetime_shape; } diff --git a/asmcomp/split.ml b/asmcomp/split.ml index ec1a52de..59826284 100644 --- a/asmcomp/split.ml +++ b/asmcomp/split.ml @@ -221,7 +221,7 @@ let fundecl f = { fun_name = f.fun_name; fun_args = new_args; fun_body = new_body; - fun_fast = f.fun_fast; + fun_codegen_options = f.fun_codegen_options; fun_dbg = f.fun_dbg; fun_spacetime_shape = f.fun_spacetime_shape; } diff --git a/asmcomp/traverse_for_exported_symbols.ml b/asmcomp/traverse_for_exported_symbols.ml new file mode 100644 index 00000000..1b7ce57f --- /dev/null +++ b/asmcomp/traverse_for_exported_symbols.ml @@ -0,0 +1,267 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-9-30-40-41-42"] + +module A = Simple_value_approx + +type queue_elem = + | Q_symbol of Symbol.t + | Q_set_of_closures_id of Set_of_closures_id.t + | Q_export_id of Export_id.t + +type symbols_to_export = + { symbols : Symbol.Set.t; + export_ids : Export_id.Set.t; + set_of_closure_ids : Set_of_closures_id.Set.t; + set_of_closure_ids_keep_declaration : Set_of_closures_id.Set.t; + relevant_imported_closure_ids : Closure_id.Set.t; + relevant_local_closure_ids : Closure_id.Set.t; + relevant_imported_vars_within_closure : Var_within_closure.Set.t; + relevant_local_vars_within_closure : Var_within_closure.Set.t; + } + +let traverse + ~(sets_of_closures_map : + Flambda.set_of_closures Set_of_closures_id.Map.t) + ~(closure_id_to_set_of_closures_id : + Set_of_closures_id.t Closure_id.Map.t) + ~(function_declarations_map : + A.function_declarations Set_of_closures_id.Map.t) + ~(values : Export_info.descr Export_id.Map.t) + ~(symbol_id : Export_id.t Symbol.Map.t) + ~(root_symbol: Symbol.t) = + let relevant_set_of_closures_declaration_only = + ref Set_of_closures_id.Set.empty + in + let relevant_symbols = ref (Symbol.Set.singleton root_symbol) in + let relevant_set_of_closures = ref Set_of_closures_id.Set.empty in + let relevant_export_ids = ref Export_id.Set.empty in + let relevant_imported_closure_ids = ref Closure_id.Set.empty in + let relevant_local_closure_ids = ref Closure_id.Set.empty in + let relevant_imported_vars_within_closure = + ref Var_within_closure.Set.empty + in + let relevant_local_vars_with_closure = ref Var_within_closure.Set.empty in + let (queue : queue_elem Queue.t) = Queue.create () in + let conditionally_add_symbol symbol = + if not (Symbol.Set.mem symbol !relevant_symbols) then begin + relevant_symbols := + Symbol.Set.add symbol !relevant_symbols; + Queue.add (Q_symbol symbol) queue + end + in + let conditionally_add_set_of_closures_id set_of_closures_id = + if not (Set_of_closures_id.Set.mem + set_of_closures_id !relevant_set_of_closures) then begin + relevant_set_of_closures := + Set_of_closures_id.Set.add set_of_closures_id + !relevant_set_of_closures; + Queue.add (Q_set_of_closures_id set_of_closures_id) queue + end + in + let conditionally_add_export_id export_id = + if not (Export_id.Set.mem export_id !relevant_export_ids) then begin + relevant_export_ids := + Export_id.Set.add export_id !relevant_export_ids; + Queue.add (Q_export_id export_id) queue + end + in + let process_approx (approx : Export_info.approx) = + match approx with + | Value_id export_id -> + conditionally_add_export_id export_id + | Value_symbol symbol -> + conditionally_add_symbol symbol + | Value_unknown -> () + in + let process_value_set_of_closures + (soc : Export_info.value_set_of_closures) = + conditionally_add_set_of_closures_id soc.set_of_closures_id; + Var_within_closure.Map.iter + (fun _ value -> process_approx value) soc.bound_vars; + Closure_id.Map.iter + (fun _ value -> process_approx value) soc.results; + begin match soc.aliased_symbol with + | None -> () + | Some symbol -> conditionally_add_symbol symbol + end + in + let process_function_body (function_body : A.function_body) = + Flambda_iterators.iter + (fun (term : Flambda.t) -> + match term with + | Flambda.Apply { kind ; _ } -> + begin match kind with + | Indirect -> () + | Direct closure_id -> + begin match + Closure_id.Map.find + closure_id + closure_id_to_set_of_closures_id + with + | exception Not_found -> + relevant_imported_closure_ids := + Closure_id.Set.add closure_id + !relevant_imported_closure_ids + | set_of_closures_id -> + relevant_local_closure_ids := + Closure_id.Set.add closure_id + !relevant_local_closure_ids; + conditionally_add_set_of_closures_id + set_of_closures_id + end + end + | _ -> ()) + (fun (named : Flambda.named) -> + let process_closure_id closure_id = + match + Closure_id.Map.find closure_id closure_id_to_set_of_closures_id + with + | exception Not_found -> + relevant_imported_closure_ids := + Closure_id.Set.add closure_id !relevant_imported_closure_ids + | set_of_closure_id -> + relevant_local_closure_ids := + Closure_id.Set.add closure_id !relevant_local_closure_ids; + relevant_set_of_closures_declaration_only := + Set_of_closures_id.Set.add + set_of_closure_id + !relevant_set_of_closures_declaration_only + in + match named with + | Symbol symbol + | Read_symbol_field (symbol, _) -> + conditionally_add_symbol symbol + | Set_of_closures soc -> + conditionally_add_set_of_closures_id + soc.function_decls.set_of_closures_id + | Project_closure { closure_id; _ } -> + process_closure_id closure_id + | Move_within_set_of_closures { start_from; move_to; _ } -> + process_closure_id start_from; + process_closure_id move_to + | Project_var { closure_id ; var; _ } -> + begin match + Closure_id.Map.find + closure_id closure_id_to_set_of_closures_id + with + | exception Not_found -> + relevant_imported_closure_ids := + Closure_id.Set.add closure_id + !relevant_imported_closure_ids; + relevant_imported_vars_within_closure := + Var_within_closure.Set.add var + !relevant_imported_vars_within_closure + | set_of_closure_id -> + relevant_local_closure_ids := + Closure_id.Set.add closure_id + !relevant_local_closure_ids; + relevant_local_vars_with_closure := + Var_within_closure.Set.add var + !relevant_local_vars_with_closure; + relevant_set_of_closures_declaration_only := + Set_of_closures_id.Set.add + set_of_closure_id + !relevant_set_of_closures_declaration_only + end + | Prim _ + | Expr _ + | Const _ + | Allocated_const _ + | Read_mutable _ -> ()) + function_body.body + in + let rec loop () = + if Queue.is_empty queue then + () + else begin + begin match Queue.pop queue with + | Q_export_id export_id -> + begin match Export_id.Map.find export_id values with + | exception Not_found -> () + | Value_block (_, approxes) -> + Array.iter process_approx approxes + | Value_closure value_closure -> + process_value_set_of_closures value_closure.set_of_closures + | Value_set_of_closures soc -> + process_value_set_of_closures soc + | _ -> () + end + | Q_symbol symbol -> + let compilation_unit = Symbol.compilation_unit symbol in + if Compilation_unit.is_current compilation_unit then begin + match Symbol.Map.find symbol symbol_id with + | exception Not_found -> + Misc.fatal_errorf "cannot find symbol's export id %a\n" + Symbol.print symbol + | export_id -> + conditionally_add_export_id export_id + end + | Q_set_of_closures_id set_of_closures_id -> + begin match + Set_of_closures_id.Map.find + set_of_closures_id function_declarations_map + with + | exception Not_found -> () + | function_declarations -> + Variable.Map.iter + (fun (_ : Variable.t) (fun_decl : A.function_declaration) -> + match fun_decl.function_body with + | None -> () + | Some function_body -> process_function_body function_body) + function_declarations.funs + end + end; + loop () + end + in + Queue.add (Q_symbol root_symbol) queue; + loop (); + + Closure_id.Map.iter (fun closure_id set_of_closure_id -> + if Set_of_closures_id.Set.mem + set_of_closure_id !relevant_set_of_closures + then begin + relevant_local_closure_ids := + Closure_id.Set.add closure_id !relevant_local_closure_ids + end) + closure_id_to_set_of_closures_id; + + Set_of_closures_id.Set.iter (fun set_of_closures_id -> + match + Set_of_closures_id.Map.find set_of_closures_id sets_of_closures_map + with + | exception Not_found -> () + | set_of_closures -> + Variable.Map.iter (fun var _ -> + relevant_local_vars_with_closure := + Var_within_closure.Set.add + (Var_within_closure.wrap var) + !relevant_local_vars_with_closure) + set_of_closures.free_vars) + !relevant_set_of_closures; + + { symbols = !relevant_symbols; + export_ids = !relevant_export_ids; + set_of_closure_ids = !relevant_set_of_closures; + set_of_closure_ids_keep_declaration = + !relevant_set_of_closures_declaration_only; + relevant_imported_closure_ids = !relevant_imported_closure_ids; + relevant_local_closure_ids = !relevant_local_closure_ids; + relevant_imported_vars_within_closure = + !relevant_imported_vars_within_closure; + relevant_local_vars_within_closure = + !relevant_local_vars_with_closure; + } diff --git a/asmcomp/traverse_for_exported_symbols.mli b/asmcomp/traverse_for_exported_symbols.mli new file mode 100644 index 00000000..2825a386 --- /dev/null +++ b/asmcomp/traverse_for_exported_symbols.mli @@ -0,0 +1,41 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-9-30-40-41-42"] + +type symbols_to_export = + { symbols : Symbol.Set.t; + export_ids : Export_id.Set.t; + set_of_closure_ids : Set_of_closures_id.Set.t; + set_of_closure_ids_keep_declaration : Set_of_closures_id.Set.t; + relevant_imported_closure_ids : Closure_id.Set.t; + relevant_local_closure_ids : Closure_id.Set.t; + relevant_imported_vars_within_closure : Var_within_closure.Set.t; + relevant_local_vars_within_closure : Var_within_closure.Set.t; + } + +(** Computes the transitive closure in [Symbol.t], [Closure_id.t] and + [Set_of_closures_id.t] and determines which ones of those should be + exported (i.e: included in the cmx files). +**) +val traverse + : sets_of_closures_map: Flambda.set_of_closures Set_of_closures_id.Map.t + -> closure_id_to_set_of_closures_id: + Set_of_closures_id.t Closure_id.Map.t + -> function_declarations_map: + Simple_value_approx.function_declarations Set_of_closures_id.Map.t + -> values: Export_info.descr Export_id.Map.t + -> symbol_id: Export_id.t Symbol.Map.t + -> root_symbol: Symbol.t + -> symbols_to_export diff --git a/asmrun/.depend b/asmrun/.depend index 2a253ebe..f80abd3f 100644 --- a/asmrun/.depend +++ b/asmrun/.depend @@ -193,9 +193,6 @@ gc_ctrl.$(O): gc_ctrl.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ ../byterun/caml/gc_ctrl.h ../byterun/caml/signals.h \ ../byterun/caml/stack.h ../byterun/caml/startup_aux.h -terminfo.$(O): terminfo.c ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/alloc.h ../byterun/caml/misc.h \ - ../byterun/caml/mlvalues.h ../byterun/caml/fail.h ../byterun/caml/io.h md5.$(O): md5.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ @@ -269,7 +266,8 @@ custom.$(O): custom.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/mlvalues.h ../byterun/caml/custom.h \ ../byterun/caml/fail.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h globroots.$(O): globroots.c ../byterun/caml/memory.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/gc.h ../byterun/caml/mlvalues.h ../byterun/caml/misc.h \ @@ -351,15 +349,6 @@ spacetime_snapshot.$(O): spacetime_snapshot.c ../byterun/caml/alloc.h \ ../byterun/caml/address_class.h ../byterun/caml/roots.h \ ../byterun/caml/signals.h ../byterun/caml/stack.h \ ../byterun/caml/sys.h ../byterun/caml/spacetime.h -spacetime_offline.$(O): spacetime_offline.c ../byterun/caml/alloc.h \ - ../byterun/caml/misc.h ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ - ../byterun/caml/gc.h ../byterun/caml/intext.h ../byterun/caml/io.h \ - ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/memory.h ../byterun/caml/minor_gc.h \ - ../byterun/caml/address_class.h ../byterun/caml/roots.h \ - ../byterun/caml/signals.h ../byterun/caml/stack.h \ - ../byterun/caml/sys.h ../byterun/caml/spacetime.h afl.$(O): afl.c ../byterun/caml/config.h ../byterun/caml/m.h \ ../byterun/caml/s.h ../byterun/caml/misc.h ../byterun/caml/mlvalues.h \ ../byterun/caml/osdeps.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ @@ -372,7 +361,8 @@ bigarray.$(O): bigarray.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/intext.h ../byterun/caml/io.h ../byterun/caml/hash.h \ ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h startup_aux.p.$(O): startup_aux.c ../byterun/caml/backtrace.h \ ../byterun/caml/mlvalues.h ../byterun/caml/config.h \ ../byterun/caml/m.h ../byterun/caml/s.h ../byterun/caml/misc.h \ @@ -568,9 +558,6 @@ gc_ctrl.p.$(O): gc_ctrl.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ ../byterun/caml/gc_ctrl.h ../byterun/caml/signals.h \ ../byterun/caml/stack.h ../byterun/caml/startup_aux.h -terminfo.p.$(O): terminfo.c ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/alloc.h ../byterun/caml/misc.h \ - ../byterun/caml/mlvalues.h ../byterun/caml/fail.h ../byterun/caml/io.h md5.p.$(O): md5.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ @@ -644,7 +631,8 @@ custom.p.$(O): custom.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/mlvalues.h ../byterun/caml/custom.h \ ../byterun/caml/fail.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h globroots.p.$(O): globroots.c ../byterun/caml/memory.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/gc.h ../byterun/caml/mlvalues.h ../byterun/caml/misc.h \ @@ -726,15 +714,6 @@ spacetime_snapshot.p.$(O): spacetime_snapshot.c ../byterun/caml/alloc.h \ ../byterun/caml/address_class.h ../byterun/caml/roots.h \ ../byterun/caml/signals.h ../byterun/caml/stack.h \ ../byterun/caml/sys.h ../byterun/caml/spacetime.h -spacetime_offline.p.$(O): spacetime_offline.c ../byterun/caml/alloc.h \ - ../byterun/caml/misc.h ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ - ../byterun/caml/gc.h ../byterun/caml/intext.h ../byterun/caml/io.h \ - ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/memory.h ../byterun/caml/minor_gc.h \ - ../byterun/caml/address_class.h ../byterun/caml/roots.h \ - ../byterun/caml/signals.h ../byterun/caml/stack.h \ - ../byterun/caml/sys.h ../byterun/caml/spacetime.h afl.p.$(O): afl.c ../byterun/caml/config.h ../byterun/caml/m.h \ ../byterun/caml/s.h ../byterun/caml/misc.h ../byterun/caml/mlvalues.h \ ../byterun/caml/osdeps.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ @@ -747,7 +726,8 @@ bigarray.p.$(O): bigarray.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/intext.h ../byterun/caml/io.h ../byterun/caml/hash.h \ ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h startup_aux.d.$(O): startup_aux.c ../byterun/caml/backtrace.h \ ../byterun/caml/mlvalues.h ../byterun/caml/config.h \ ../byterun/caml/m.h ../byterun/caml/s.h ../byterun/caml/misc.h \ @@ -943,9 +923,6 @@ gc_ctrl.d.$(O): gc_ctrl.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ ../byterun/caml/gc_ctrl.h ../byterun/caml/signals.h \ ../byterun/caml/stack.h ../byterun/caml/startup_aux.h -terminfo.d.$(O): terminfo.c ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/alloc.h ../byterun/caml/misc.h \ - ../byterun/caml/mlvalues.h ../byterun/caml/fail.h ../byterun/caml/io.h md5.d.$(O): md5.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ @@ -1019,7 +996,8 @@ custom.d.$(O): custom.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/mlvalues.h ../byterun/caml/custom.h \ ../byterun/caml/fail.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h globroots.d.$(O): globroots.c ../byterun/caml/memory.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/gc.h ../byterun/caml/mlvalues.h ../byterun/caml/misc.h \ @@ -1101,15 +1079,6 @@ spacetime_snapshot.d.$(O): spacetime_snapshot.c ../byterun/caml/alloc.h \ ../byterun/caml/address_class.h ../byterun/caml/roots.h \ ../byterun/caml/signals.h ../byterun/caml/stack.h \ ../byterun/caml/sys.h ../byterun/caml/spacetime.h -spacetime_offline.d.$(O): spacetime_offline.c ../byterun/caml/alloc.h \ - ../byterun/caml/misc.h ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ - ../byterun/caml/gc.h ../byterun/caml/intext.h ../byterun/caml/io.h \ - ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/memory.h ../byterun/caml/minor_gc.h \ - ../byterun/caml/address_class.h ../byterun/caml/roots.h \ - ../byterun/caml/signals.h ../byterun/caml/stack.h \ - ../byterun/caml/sys.h ../byterun/caml/spacetime.h afl.d.$(O): afl.c ../byterun/caml/config.h ../byterun/caml/m.h \ ../byterun/caml/s.h ../byterun/caml/misc.h ../byterun/caml/mlvalues.h \ ../byterun/caml/osdeps.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ @@ -1122,7 +1091,8 @@ bigarray.d.$(O): bigarray.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/intext.h ../byterun/caml/io.h ../byterun/caml/hash.h \ ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h startup_aux.i.$(O): startup_aux.c ../byterun/caml/backtrace.h \ ../byterun/caml/mlvalues.h ../byterun/caml/config.h \ ../byterun/caml/m.h ../byterun/caml/s.h ../byterun/caml/misc.h \ @@ -1318,9 +1288,6 @@ gc_ctrl.i.$(O): gc_ctrl.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ ../byterun/caml/gc_ctrl.h ../byterun/caml/signals.h \ ../byterun/caml/stack.h ../byterun/caml/startup_aux.h -terminfo.i.$(O): terminfo.c ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/alloc.h ../byterun/caml/misc.h \ - ../byterun/caml/mlvalues.h ../byterun/caml/fail.h ../byterun/caml/io.h md5.i.$(O): md5.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ @@ -1394,7 +1361,8 @@ custom.i.$(O): custom.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/mlvalues.h ../byterun/caml/custom.h \ ../byterun/caml/fail.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h globroots.i.$(O): globroots.c ../byterun/caml/memory.h \ ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ ../byterun/caml/gc.h ../byterun/caml/mlvalues.h ../byterun/caml/misc.h \ @@ -1476,15 +1444,6 @@ spacetime_snapshot.i.$(O): spacetime_snapshot.c ../byterun/caml/alloc.h \ ../byterun/caml/address_class.h ../byterun/caml/roots.h \ ../byterun/caml/signals.h ../byterun/caml/stack.h \ ../byterun/caml/sys.h ../byterun/caml/spacetime.h -spacetime_offline.i.$(O): spacetime_offline.c ../byterun/caml/alloc.h \ - ../byterun/caml/misc.h ../byterun/caml/config.h ../byterun/caml/m.h \ - ../byterun/caml/s.h ../byterun/caml/mlvalues.h ../byterun/caml/fail.h \ - ../byterun/caml/gc.h ../byterun/caml/intext.h ../byterun/caml/io.h \ - ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/memory.h ../byterun/caml/minor_gc.h \ - ../byterun/caml/address_class.h ../byterun/caml/roots.h \ - ../byterun/caml/signals.h ../byterun/caml/stack.h \ - ../byterun/caml/sys.h ../byterun/caml/spacetime.h afl.i.$(O): afl.c ../byterun/caml/config.h ../byterun/caml/m.h \ ../byterun/caml/s.h ../byterun/caml/misc.h ../byterun/caml/mlvalues.h \ ../byterun/caml/osdeps.h ../byterun/caml/memory.h ../byterun/caml/gc.h \ @@ -1497,4 +1456,5 @@ bigarray.i.$(O): bigarray.c ../byterun/caml/alloc.h ../byterun/caml/misc.h \ ../byterun/caml/intext.h ../byterun/caml/io.h ../byterun/caml/hash.h \ ../byterun/caml/memory.h ../byterun/caml/gc.h \ ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ - ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/signals.h diff --git a/asmrun/Makefile b/asmrun/Makefile index 62608a46..f275e2a0 100644 --- a/asmrun/Makefile +++ b/asmrun/Makefile @@ -14,10 +14,11 @@ #************************************************************************** include ../config/Makefile +include ../Makefile.common LINKEDFILES=misc.c freelist.c major_gc.c minor_gc.c memory.c alloc.c array.c \ compare.c ints.c floats.c str.c io.c extern.c intern.c hash.c sys.c \ - parsing.c gc_ctrl.c terminfo.c md5.c obj.c lexing.c printexc.c callback.c \ + parsing.c gc_ctrl.c md5.c obj.c lexing.c printexc.c callback.c \ weak.c compact.c finalise.c meta.c custom.c main.c globroots.c \ $(UNIX_OR_WIN32).c dynlink.c signals.c debugger.c startup_aux.c \ backtrace.c afl.c bigarray.c @@ -27,8 +28,6 @@ LINKEDFILES=misc.c freelist.c major_gc.c minor_gc.c memory.c alloc.c array.c \ # compiled on the platform where make depend is run sources := $(LINKEDFILES) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) - ifeq "$(UNIX_OR_WIN32)" "win32" LN = cp sources += ../byterun/unix.c @@ -53,6 +52,10 @@ ifeq "$(TOOLCHAIN)" "msvc" DFLAGS = $(CFLAGS) -DDEBUG PFLAGS=$(CFLAGS) -DPROFILING $(NATIVECCPROFOPTS) ASMOBJS=$(ARCH)nt.$(O) +ASMFLAGS= +ifeq ($(WITH_SPACETIME),true) +ASMFLAGS=/DWITH_SPACETIME +endif else DFLAGS = $(CFLAGS) -g -DDEBUG PFLAGS=$(CFLAGS) -pg -DPROFILING $(NATIVECCPROFOPTS) @@ -72,12 +75,12 @@ COBJS=startup_aux.$(O) startup.$(O) main.$(O) fail.$(O) \ major_gc.$(O) minor_gc.$(O) memory.$(O) alloc.$(O) compare.$(O) \ ints.$(O) floats.$(O) str.$(O) array.$(O) io.$(O) extern.$(O) \ intern.$(O) hash.$(O) sys.$(O) parsing.$(O) gc_ctrl.$(O) \ - terminfo.$(O) md5.$(O) obj.$(O) lexing.$(O) $(UNIX_OR_WIN32).$(O) \ + md5.$(O) obj.$(O) lexing.$(O) $(UNIX_OR_WIN32).$(O) \ printexc.$(O) callback.$(O) weak.$(O) compact.$(O) finalise.$(O) \ custom.$(O) globroots.$(O) backtrace_prim.$(O) backtrace.$(O) \ natdynlink.$(O) debugger.$(O) meta.$(O) dynlink.$(O) \ clambda_checks.$(O) spacetime.$(O) spacetime_snapshot.$(O) \ - spacetime_offline.$(O) afl.$(O) bigarray.$(O) + afl.$(O) bigarray.$(O) OBJS=$(COBJS) $(ASMOBJS) @@ -86,28 +89,30 @@ IOBJS=$(COBJS:.$(O)=.i.$(O)) $(ASMOBJS) POBJS=$(COBJS:.$(O)=.p.$(O)) $(ASMOBJS:.$(O)=.p.$(O)) PICOBJS=$(COBJS:.$(O)=.pic.$(O)) $(ASMOBJS:.$(O)=.pic.$(O)) -TARGETS = libasmrun.$(A) +TARGETS_A = libasmrun.$(A) +TARGETS_SO= ifeq "$(RUNTIMED)" "true" -TARGETS += libasmrund.$(A) +TARGETS_A += libasmrund.$(A) endif ifeq "$(RUNTIMEI)" "true" -TARGETS += libasmruni.$(A) +TARGETS_A += libasmruni.$(A) endif ifeq "$(PROFILING)" "true" -TARGETS += libasmrunp.$(A) +TARGETS_A += libasmrunp.$(A) endif ifeq "$(UNIX_OR_WIN32)" "unix" ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true" -TARGETS += libasmrun_pic.$(A) libasmrun_shared.$(SO) +TARGETS_A += libasmrun_pic.$(A) +TARGETS_SO += libasmrun_shared.$(SO) endif endif .PHONY: all -all: $(TARGETS) +all: $(TARGETS_A) $(TARGETS_SO) libasmrun.$(A): $(OBJS) $(call MKLIB,$@, $^) @@ -129,7 +134,10 @@ libasmrun_shared.$(SO): $(PICOBJS) .PHONY: install install: - cp $(TARGETS) "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) $(TARGETS_A) "$(INSTALL_LIBDIR)" + if test -n "$(TARGETS_SO)"; then \ + $(INSTALL_PROG) $(TARGETS_SO) "$(INSTALL_LIBDIR)"; \ + fi $(LINKEDFILES): %.c: ../byterun/%.c $(LN) $< $@ @@ -163,10 +171,10 @@ $(LINKEDFILES): %.c: ../byterun/%.c $(ASPP) $(ASPPFLAGS) $(SHAREDCCCOMPOPTS) -o $@ $< %.obj: %.asm - $(ASM)$@ $< + $(ASM)$@ $(ASMFLAGS) $< %.pic.obj: %.asm - $(ASM)$@ $< + $(ASM)$@ $(ASMFLAGS) $< .PHONY: clean clean: diff --git a/asmrun/amd64.S b/asmrun/amd64.S index 237510dd..3e3bf83e 100644 --- a/asmrun/amd64.S +++ b/asmrun/amd64.S @@ -266,6 +266,20 @@ # define PREPARE_FOR_C_CALL # define CLEANUP_AFTER_C_CALL # define STACK_PROBE_SIZE $32768 +#endif + +/* Registers holding arguments of C functions. */ + +#if defined(SYS_mingw64) || defined(SYS_cygwin) +#define C_ARG_1 %rcx +#define C_ARG_2 %rdx +#define C_ARG_3 %r8 +#define C_ARG_4 %r9 +#else +#define C_ARG_1 %rdi +#define C_ARG_2 %rsi +#define C_ARG_3 %rdx +#define C_ARG_4 %rcx #endif .text @@ -508,8 +522,8 @@ LBL(caml_start_program): pushq %rdi; CFI_ADJUST (8) pushq %rsi; CFI_ADJUST (8) /* No need to push %r12: it's callee-save. */ - movq %r12, %rdi - LEA_VAR(caml_start_program, %rsi) + movq %r12, C_ARG_1 + LEA_VAR(caml_start_program, C_ARG_2) call GCALL(caml_spacetime_c_to_ocaml) popq %rsi; CFI_ADJUST (-8) popq %rdi; CFI_ADJUST (-8) @@ -557,20 +571,6 @@ LBL(108): jmp LBL(109) CFI_ENDPROC -/* Registers holding arguments of C functions. */ - -#if defined(SYS_mingw64) || defined(SYS_cygwin) -#define C_ARG_1 %rcx -#define C_ARG_2 %rdx -#define C_ARG_3 %r8 -#define C_ARG_4 %r9 -#else -#define C_ARG_1 %rdi -#define C_ARG_2 %rsi -#define C_ARG_3 %rdx -#define C_ARG_4 %rcx -#endif - /* Raise an exception from OCaml */ FUNCTION(G(caml_raise_exn)) diff --git a/asmrun/amd64nt.asm b/asmrun/amd64nt.asm index c4534ea0..7915c1e3 100644 --- a/asmrun/amd64nt.asm +++ b/asmrun/amd64nt.asm @@ -34,6 +34,10 @@ EXTRN caml_backtrace_pos: DWORD EXTRN caml_backtrace_active: DWORD EXTRN caml_stash_backtrace: NEAR +IFDEF WITH_SPACETIME + EXTRN caml_spacetime_trie_node_ptr: QWORD + EXTRN caml_spacetime_c_to_ocaml: NEAR +ENDIF .CODE @@ -61,6 +65,9 @@ L105: ; Save caml_young_ptr, caml_exception_pointer mov caml_young_ptr, r15 mov caml_exception_pointer, r14 +IFDEF WITH_SPACETIME + mov caml_spacetime_trie_node_ptr, r13 +ENDIF ; Build array of registers, save it into caml_gc_regs push rbp push r11 @@ -212,6 +219,11 @@ caml_c_call: pop r12 mov caml_last_return_address, r12 mov caml_bottom_of_stack, rsp +IFDEF WITH_SPACETIME + ; Record the trie node hole pointer that corresponds to + ; [caml_last_return_address] + mov caml_spacetime_trie_node_ptr, r13 +ENDIF ; Touch the stack to trigger a recoverable segfault ; if insufficient space remains sub rsp, 01000h @@ -258,10 +270,29 @@ caml_start_program: ; Common code for caml_start_program and caml_callback* L106: ; Build a callback link +IFDEF WITH_SPACETIME + push caml_spacetime_trie_node_ptr +ELSE sub rsp, 8 ; stack 16-aligned +ENDIF push caml_gc_regs push caml_last_return_address push caml_bottom_of_stack +IFDEF WITH_SPACETIME + ; Save arguments to caml_callback + push rax + push rbx + push rdi + push rsi + ; No need to push r12: it is callee-save. + mov rcx, r12 + lea rdx, caml_start_program + call caml_spacetime_c_to_ocaml + pop rsi + pop rdi + pop rbx + pop rax +ENDIF ; Setup alloc ptr and exception ptr mov r15, caml_young_ptr mov r14, caml_exception_pointer @@ -270,6 +301,9 @@ L106: push r13 push r14 mov r14, rsp +IFDEF WITH_SPACETIME + mov r13, caml_spacetime_trie_node_ptr +ENDIF ; Call the OCaml code call r12 L107: @@ -284,7 +318,11 @@ L109: pop caml_bottom_of_stack pop caml_last_return_address pop caml_gc_regs +IFDEF WITH_SPACETIME + pop caml_spacetime_trie_node_ptr +ELSE add rsp, 8 +ENDIF ; Restore callee-save registers. movapd xmm6, OWORD PTR [rsp + 0*16] movapd xmm7, OWORD PTR [rsp + 1*16] @@ -472,6 +510,19 @@ caml_system__frametable LABEL QWORD WORD 0 ; no roots here ALIGN 8 +IFDEF WITH_SPACETIME + .DATA + PUBLIC caml_system__spacetime_shapes + ALIGN 8 +caml_system__spacetime_shapes LABEL QWORD + QWORD caml_start_program + QWORD 2 ; indirect call point to OCaml code + QWORD L107 ; in caml_start_program / caml_callback* + QWORD 0 ; end of shapes in caml_start_program + QWORD 0 ; end of shape table + ALIGN 8 +ENDIF + PUBLIC caml_negf_mask ALIGN 16 caml_negf_mask LABEL QWORD diff --git a/asmrun/spacetime.c b/asmrun/spacetime.c index bf4b6f3c..f6fc5c30 100644 --- a/asmrun/spacetime.c +++ b/asmrun/spacetime.c @@ -27,6 +27,10 @@ #ifdef HAS_UNISTD #include #endif +#ifdef _WIN32 +#include /* for _getpid */ +#include /* for _wgetcwd */ +#endif #include "caml/alloc.h" #include "caml/backtrace_prim.h" @@ -49,7 +53,11 @@ /* We force "noinline" in certain places to be sure we know how many frames there will be on the stack. */ +#ifdef _MSC_VER +#define NOINLINE __declspec(noinline) +#else #define NOINLINE __attribute__((noinline)) +#endif #ifdef HAS_LIBUNWIND #define UNW_LOCAL_ONLY @@ -99,6 +107,14 @@ allocation_point* caml_all_allocation_points = NULL; static const uintnat chunk_size = 1024 * 1024; +#ifdef _WIN32 +#define strdup_os wcsdup +#define snprintf_os _snwprintf +#else +#define strdup_os strdup +#define snprintf_os snprintf +#endif + static void reinitialise_free_node_block(void) { size_t index; @@ -115,10 +131,6 @@ static void reinitialise_free_node_block(void) #define O_BINARY 0 #endif -#if defined (_WIN32) || defined (_WIN64) -extern value val_process_id; -#endif - enum { FEATURE_CALL_COUNTS = 1, } features; @@ -151,21 +163,23 @@ CAMLprim value caml_spacetime_write_magic_number(value v_channel) return Val_unit; } -static char* automatic_snapshot_dir; +static char_os* automatic_snapshot_dir; static void open_snapshot_channel(void) { int fd; - char filename[8192]; + char_os filename[8192]; int pid; -#if defined (_WIN32) || defined (_WIN64) - pid = Int_val(val_process_id); + int filename_len = sizeof(filename)/sizeof(char_os); +#ifdef _WIN32 + pid = _getpid(); #else pid = getpid(); #endif - snprintf(filename, 8192, "%s/spacetime-%d", automatic_snapshot_dir, pid); - filename[8191] = '\0'; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + snprintf_os(filename, filename_len, _T("%s/spacetime-%d"), + automatic_snapshot_dir, pid); + filename[filename_len-1] = _T('\0'); + fd = open_os(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); if (fd == -1) { automatic_snapshots = 0; } @@ -187,8 +201,8 @@ static void maybe_reopen_snapshot_channel(void) was written during that time) and then open a new one. */ int pid; -#if defined (_WIN32) || defined (_WIN64) - pid = Int_val(val_process_id); +#ifdef _WIN32 + pid = _getpid(); #else pid = getpid(); #endif @@ -205,40 +219,40 @@ void caml_spacetime_initialize(void) { /* Note that this is called very early (even prior to GC initialisation). */ - char *ap_interval; + char_os *ap_interval; reinitialise_free_node_block(); caml_spacetime_static_shape_tables = &caml_spacetime_shapes; - ap_interval = caml_secure_getenv ("OCAML_SPACETIME_INTERVAL"); + ap_interval = caml_secure_getenv (_T("OCAML_SPACETIME_INTERVAL")); if (ap_interval != NULL) { unsigned int interval = 0; - sscanf(ap_interval, "%u", &interval); + sscanf_os(ap_interval, _T("%u"), &interval); if (interval != 0) { double time; - char cwd[4096]; - char* user_specified_automatic_snapshot_dir; + char_os cwd[4096]; + char_os* user_specified_automatic_snapshot_dir; int dir_ok = 1; user_specified_automatic_snapshot_dir = - caml_secure_getenv("OCAML_SPACETIME_SNAPSHOT_DIR"); + caml_secure_getenv(_T("OCAML_SPACETIME_SNAPSHOT_DIR")); if (user_specified_automatic_snapshot_dir == NULL) { #if defined(HAS_GETCWD) - if (getcwd(cwd, sizeof(cwd)) == NULL) { + if (getcwd_os(cwd, sizeof(cwd)/sizeof(char_os)) == NULL) { dir_ok = 0; } #else dir_ok = 0; #endif if (dir_ok) { - automatic_snapshot_dir = strdup(cwd); + automatic_snapshot_dir = strdup_os(cwd); } } else { automatic_snapshot_dir = - strdup(user_specified_automatic_snapshot_dir); + strdup_os(user_specified_automatic_snapshot_dir); } if (dir_ok) { diff --git a/asmrun/startup.c b/asmrun/startup.c index 60dca013..070f0c64 100644 --- a/asmrun/startup.c +++ b/asmrun/startup.c @@ -46,6 +46,7 @@ extern int caml_parser_trace; CAMLexport header_t caml_atom_table[256]; char * caml_code_area_start, * caml_code_area_end; +struct ext_table caml_code_fragments_table; /* Initialize the atom table and the static data and code area limits. */ diff --git a/boot/ocamlc b/boot/ocamlc index a73dfdead12b0b7c8f83ae6c2a6e177c3ae417bb..beac6097bd73382a6496d7dabe31d7ac75befeb3 100755 GIT binary patch delta 516565 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

h@L~r}E58nZ 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 diff --git a/boot/ocamldep b/boot/ocamldep deleted file mode 100755 index feec830cfeae2eef6a7c4137f03fc64ada83db26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2158089 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�TOH$|8J$*I4bp6rJtLGrs9u-o(X;mRcc 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 z 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 H>gxXk1d?0c diff --git a/boot/ocamllex b/boot/ocamllex index 36fe17f9811f598d62c9982799c394b6746e0abd..1b3e201ed4082b6f8853f9973d9a8f06fe039662 100755 GIT binary patch delta 51782 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 delta 36078 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 diff --git a/bytecomp/bytegen.ml b/bytecomp/bytegen.ml index 6368cdca..afb6530e 100644 --- a/bytecomp/bytegen.ml +++ b/bytecomp/bytegen.ml @@ -146,7 +146,7 @@ let rec size_of_lambda env = function | Lvar id -> begin try Ident.find_same id env with Not_found -> RHS_nonrec end | Lfunction{params} as funct -> - RHS_function (1 + IdentSet.cardinal(free_variables funct), + RHS_function (1 + Ident.Set.cardinal(free_variables funct), List.length params) | Llet (Strict, _k, id, Lprim (Pduprecord (kind, size), _, _), body) when check_recordwith_updates id body -> @@ -355,25 +355,23 @@ let comp_primitive p args = | Psubfloat -> Kccall("caml_sub_float", 2) | Pmulfloat -> Kccall("caml_mul_float", 2) | Pdivfloat -> Kccall("caml_div_float", 2) - | Pfloatcomp Ceq -> Kccall("caml_eq_float", 2) - | Pfloatcomp Cneq -> Kccall("caml_neq_float", 2) - | Pfloatcomp Clt -> Kccall("caml_lt_float", 2) - | Pfloatcomp Cgt -> Kccall("caml_gt_float", 2) - | Pfloatcomp Cle -> Kccall("caml_le_float", 2) - | Pfloatcomp Cge -> Kccall("caml_ge_float", 2) | Pstringlength -> Kccall("caml_ml_string_length", 1) | Pbyteslength -> Kccall("caml_ml_bytes_length", 1) | Pstringrefs -> Kccall("caml_string_get", 2) | Pbytesrefs -> Kccall("caml_bytes_get", 2) | Pbytessets -> Kccall("caml_bytes_set", 3) - | Pstringrefu | Pbytesrefu -> Kgetstringchar - | Pbytessetu -> Ksetstringchar + | Pstringrefu -> Kgetstringchar + | Pbytesrefu -> Kgetbyteschar + | Pbytessetu -> Ksetbyteschar | Pstring_load_16(_) -> Kccall("caml_string_get16", 2) | Pstring_load_32(_) -> Kccall("caml_string_get32", 2) | Pstring_load_64(_) -> Kccall("caml_string_get64", 2) - | Pstring_set_16(_) -> Kccall("caml_string_set16", 3) - | Pstring_set_32(_) -> Kccall("caml_string_set32", 3) - | Pstring_set_64(_) -> Kccall("caml_string_set64", 3) + | Pbytes_set_16(_) -> Kccall("caml_bytes_set16", 3) + | Pbytes_set_32(_) -> Kccall("caml_bytes_set32", 3) + | Pbytes_set_64(_) -> Kccall("caml_bytes_set64", 3) + | Pbytes_load_16(_) -> Kccall("caml_bytes_get16", 2) + | Pbytes_load_32(_) -> Kccall("caml_bytes_get32", 2) + | Pbytes_load_64(_) -> Kccall("caml_bytes_get64", 2) | Parraylength _ -> Kvectlength | Parrayrefs Pgenarray -> Kccall("caml_array_get", 2) | Parrayrefs Pfloatarray -> Kccall("caml_floatarray_get", 2) @@ -400,7 +398,6 @@ let comp_primitive p args = Kccall(Printf.sprintf "caml_sys_const_%s" const_name, 1) | Pisint -> Kisint | Pisout -> Kisout - | Pbittest -> Kccall("caml_bitvect_test", 2) | Pbintofint bi -> comp_bint_primitive bi "of_int" args | Pintofbint bi -> comp_bint_primitive bi "to_int" args | Pcvtbint(Pint32, Pnativeint) -> Kccall("caml_nativeint_of_int32", 1) @@ -422,7 +419,7 @@ let comp_primitive p args = | Plsrbint bi -> comp_bint_primitive bi "shift_right_unsigned" args | Pasrbint bi -> comp_bint_primitive bi "shift_right" args | Pbintcomp(_, Ceq) -> Kccall("caml_equal", 2) - | Pbintcomp(_, Cneq) -> Kccall("caml_notequal", 2) + | Pbintcomp(_, Cne) -> Kccall("caml_notequal", 2) | Pbintcomp(_, Clt) -> Kccall("caml_lessthan", 2) | Pbintcomp(_, Cgt) -> Kccall("caml_greaterthan", 2) | Pbintcomp(_, Cle) -> Kccall("caml_lessequal", 2) @@ -439,6 +436,8 @@ let comp_primitive p args = | Pbswap16 -> Kccall("caml_bswap16", 1) | Pbbswap(bi) -> comp_bint_primitive bi "bswap" args | Pint_as_pointer -> Kccall("caml_int_as_pointer", 1) + | Pbytes_to_string -> Kccall("caml_string_of_bytes", 1) + | Pbytes_of_string -> Kccall("caml_bytes_of_string", 1) | _ -> fatal_error "Bytegen.comp_primitive" let is_immed n = immed_min <= n && n <= immed_max @@ -519,7 +518,7 @@ let rec comp_expr env exp sz cont = end | Lfunction{params; body} -> (* assume kind = Curried *) let lbl = new_label() in - let fv = IdentSet.elements(free_variables exp) in + let fv = Ident.Set.elements(free_variables exp) in let to_compile = { params = params; body = body; label = lbl; free_vars = fv; num_defs = 1; rec_vars = []; rec_pos = 0 } in @@ -536,7 +535,7 @@ let rec comp_expr env exp sz cont = decl then begin (* let rec of functions *) let fv = - IdentSet.elements (free_variables (Lletrec(decl, lambda_unit))) in + Ident.Set.elements (free_variables (Lletrec(decl, lambda_unit))) in let rec_idents = List.map (fun (id, _lam) -> id) decl in let rec comp_fun pos = function [] -> [] @@ -595,8 +594,7 @@ let rec comp_expr env exp sz cont = in comp_init env sz decl_size end - | Lprim((Pidentity | Popaque | Pbytes_to_string | Pbytes_of_string), [arg], _) - -> + | Lprim((Pidentity | Popaque), [arg], _) -> comp_expr env arg sz cont | Lprim(Pignore, [arg], _) -> comp_expr env arg sz (add_const_unit cont) @@ -684,9 +682,24 @@ let rec comp_expr env exp sz cont = Misc.fatal_error "Bytegen.comp_expr: Pduparray takes exactly one arg" (* Integer first for enabling further optimization (cf. emitcode.ml) *) | Lprim (Pintcomp c, [arg ; (Lconst _ as k)], _) -> - let p = Pintcomp (commute_comparison c) + let p = Pintcomp (swap_integer_comparison c) and args = [k ; arg] in comp_args env args sz (comp_primitive p args :: cont) + | Lprim (Pfloatcomp cmp, args, _) -> + let cont = + match cmp with + | CFeq -> Kccall("caml_eq_float", 2) :: cont + | CFneq -> Kccall("caml_neq_float", 2) :: cont + | CFlt -> Kccall("caml_lt_float", 2) :: cont + | CFnlt -> Kccall("caml_lt_float", 2) :: Kboolnot :: cont + | CFgt -> Kccall("caml_gt_float", 2) :: cont + | CFngt -> Kccall("caml_gt_float", 2) :: Kboolnot :: cont + | CFle -> Kccall("caml_le_float", 2) :: cont + | CFnle -> Kccall("caml_le_float", 2) :: Kboolnot :: cont + | CFge -> Kccall("caml_ge_float", 2) :: cont + | CFnge -> Kccall("caml_ge_float", 2) :: Kboolnot :: cont + in + comp_args env args sz cont | Lprim(p, args, _) -> comp_args env args sz (comp_primitive p args :: cont) | Lstaticcatch (body, (i, vars) , handler) -> @@ -765,7 +778,7 @@ let rec comp_expr env exp sz cont = Klabel lbl_loop :: Kcheck_signals :: comp_expr (add_var param (sz+1) env) body (sz+2) (Kacc 1 :: Kpush :: Koffsetint offset :: Kassign 2 :: - Kacc 1 :: Kintcomp Cneq :: Kbranchif lbl_loop :: + Kacc 1 :: Kintcomp Cne :: Kbranchif lbl_loop :: Klabel lbl_exit :: add_const_unit (add_pop 2 cont)))) | Lswitch(arg, sw, _loc) -> let (branch, cont1) = make_branch cont in @@ -776,13 +789,13 @@ let rec comp_expr env exp sz cont = let act_consts = Array.make sw.sw_numconsts 0 and act_blocks = Array.make sw.sw_numblocks 0 in begin match sw.sw_failaction with (* default is index 0 *) - | Some fail -> ignore (store.act_store fail) + | Some fail -> ignore (store.act_store () fail) | None -> () end ; List.iter - (fun (n, act) -> act_consts.(n) <- store.act_store act) sw.sw_consts; + (fun (n, act) -> act_consts.(n) <- store.act_store () act) sw.sw_consts; List.iter - (fun (n, act) -> act_blocks.(n) <- store.act_store act) sw.sw_blocks; + (fun (n, act) -> act_blocks.(n) <- store.act_store () act) sw.sw_blocks; (* Compile and label actions *) let acts = store.act_get () in (* diff --git a/bytecomp/bytegen.mli b/bytecomp/bytegen.mli index b23a1dc6..24855ec6 100644 --- a/bytecomp/bytegen.mli +++ b/bytecomp/bytegen.mli @@ -21,3 +21,5 @@ open Instruct val compile_implementation: string -> lambda -> instruction list val compile_phrase: lambda -> instruction list * instruction list val reset: unit -> unit + +val merge_events : Instruct.debug_event -> Instruct.debug_event -> Instruct.debug_event diff --git a/bytecomp/bytelink.ml b/bytecomp/bytelink.ml index 3ed3e68c..87e0d62b 100644 --- a/bytecomp/bytelink.ml +++ b/bytecomp/bytelink.ml @@ -85,25 +85,23 @@ let add_ccobjs origin l = (* First pass: determine which units are needed *) -module IdentSet = Lambda.IdentSet - -let missing_globals = ref IdentSet.empty +let missing_globals = ref Ident.Set.empty let is_required (rel, _pos) = match rel with Reloc_setglobal id -> - IdentSet.mem id !missing_globals + Ident.Set.mem id !missing_globals | _ -> false let add_required compunit = let add_required_by_reloc (rel, _pos) = match rel with Reloc_getglobal id -> - missing_globals := IdentSet.add id !missing_globals + missing_globals := Ident.Set.add id !missing_globals | _ -> () in let add_required_for_effects id = - missing_globals := IdentSet.add id !missing_globals + missing_globals := Ident.Set.add id !missing_globals in List.iter add_required_by_reloc compunit.cu_reloc; List.iter add_required_for_effects compunit.cu_required_globals @@ -111,7 +109,7 @@ let add_required compunit = let remove_required (rel, _pos) = match rel with Reloc_setglobal id -> - missing_globals := IdentSet.remove id !missing_globals + missing_globals := Ident.Set.remove id !missing_globals | _ -> () let scan_file obj_name tolink = @@ -294,9 +292,9 @@ let output_stringlist oc l = (* Transform a file name into an absolute file name *) let make_absolute file = - if Filename.is_relative file - then Filename.concat (Sys.getcwd()) file - else file + if not (Filename.is_relative file) then file + else Location.rewrite_absolute_path + (Filename.concat (Sys.getcwd()) file) (* Create a bytecode executable file *) @@ -569,10 +567,10 @@ let link ppf objfiles output_name = else "stdlib.cma" :: (objfiles @ ["std_exit.cmo"]) in let tolink = List.fold_right scan_file objfiles [] in let missing_modules = - IdentSet.filter (fun id -> not (Ident.is_predef_exn id)) !missing_globals + Ident.Set.filter (fun id -> not (Ident.is_predef_exn id)) !missing_globals in begin - match IdentSet.elements missing_modules with + match Ident.Set.elements missing_modules with | [] -> () | id :: _ -> raise (Error (Required_module_unavailable (Ident.name id))) end; @@ -707,7 +705,7 @@ let reset () = lib_ccobjs := []; lib_ccopts := []; lib_dllibs := []; - missing_globals := IdentSet.empty; + missing_globals := Ident.Set.empty; Consistbl.clear crc_interfaces; implementations_defined := []; debug_info := []; diff --git a/bytecomp/emitcode.ml b/bytecomp/emitcode.ml index 3c7f848a..aed2666c 100644 --- a/bytecomp/emitcode.ml +++ b/bytecomp/emitcode.ml @@ -168,8 +168,10 @@ let record_event ev = let path = ev.ev_loc.Location.loc_start.Lexing.pos_fname in let abspath = Location.absolute_path path in debug_dirs := StringSet.add (Filename.dirname abspath) !debug_dirs; - if Filename.is_relative path then - debug_dirs := StringSet.add (Sys.getcwd ()) !debug_dirs; + if Filename.is_relative path then begin + let cwd = Location.rewrite_absolute_path (Sys.getcwd ()) in + debug_dirs := StringSet.add cwd !debug_dirs; + end; ev.ev_pos <- !out_position; events := ev :: !events @@ -185,12 +187,12 @@ let init () = (* Emission of one instruction *) let emit_comp = function -| Ceq -> out opEQ | Cneq -> out opNEQ +| Ceq -> out opEQ | Cne -> out opNEQ | Clt -> out opLTINT | Cle -> out opLEINT | Cgt -> out opGTINT | Cge -> out opGEINT and emit_branch_comp = function -| Ceq -> out opBEQ | Cneq -> out opBNEQ +| Ceq -> out opBEQ | Cne -> out opBNEQ | Clt -> out opBLTINT | Cle -> out opBLEINT | Cgt -> out opBGTINT | Cge -> out opBGEINT @@ -262,7 +264,8 @@ let emit_instr = function | Kgetvectitem -> out opGETVECTITEM | Ksetvectitem -> out opSETVECTITEM | Kgetstringchar -> out opGETSTRINGCHAR - | Ksetstringchar -> out opSETSTRINGCHAR + | Kgetbyteschar -> out opGETBYTESCHAR + | Ksetbyteschar -> out opSETBYTESCHAR | Kbranch lbl -> out opBRANCH; out_label lbl | Kbranchif lbl -> out opBRANCHIF; out_label lbl | Kbranchifnot lbl -> out opBRANCHIFNOT; out_label lbl @@ -304,6 +307,11 @@ let emit_instr = function (* Emission of a list of instructions. Include some peephole optimization. *) +let remerge_events ev1 = function + | Kevent ev2 :: c -> + Kevent (Bytegen.merge_events ev1 ev2) :: c + | c -> Kevent ev1 :: c + let rec emit = function [] -> () (* Peephole optimizations *) @@ -316,7 +324,7 @@ let rec emit = function emit rem | Kpush::Kconst k::Kintcomp c::Kbranchifnot lbl::rem when is_immed_const k -> - emit_branch_comp (negate_comparison c) ; + emit_branch_comp (negate_integer_comparison c) ; out_const k ; out_label lbl ; emit rem @@ -372,13 +380,13 @@ let rec emit = function out opPUSHGETGLOBAL; slot_for_literal sc end; emit c - | Kpush :: (Kevent {ev_kind = Event_before} as ev) :: + | Kpush :: (Kevent ({ev_kind = Event_before} as ev)) :: (Kgetglobal _ as instr1) :: (Kgetfield _ as instr2) :: c -> - emit (Kpush :: instr1 :: instr2 :: ev :: c) - | Kpush :: (Kevent {ev_kind = Event_before} as ev) :: + emit (Kpush :: instr1 :: instr2 :: remerge_events ev c) + | Kpush :: (Kevent ({ev_kind = Event_before} as ev)) :: (Kacc _ | Kenvacc _ | Koffsetclosure _ | Kgetglobal _ | Kconst _ as instr):: c -> - emit (Kpush :: instr :: ev :: c) + emit (Kpush :: instr :: remerge_events ev c) | Kgetglobal id :: Kgetfield n :: c -> out opGETGLOBALFIELD; slot_for_getglobal id; out_int n; emit c (* Default case *) diff --git a/bytecomp/instruct.ml b/bytecomp/instruct.ml index 0360a6d3..d7dae7fc 100644 --- a/bytecomp/instruct.ml +++ b/bytecomp/instruct.ml @@ -78,7 +78,8 @@ type instruction = | Kgetvectitem | Ksetvectitem | Kgetstringchar - | Ksetstringchar + | Kgetbyteschar + | Ksetbyteschar | Kbranch of label | Kbranchif of label | Kbranchifnot of label @@ -93,7 +94,7 @@ type instruction = | Kccall of string * int | Knegint | Kaddint | Ksubint | Kmulint | Kdivint | Kmodint | Kandint | Korint | Kxorint | Klslint | Klsrint | Kasrint - | Kintcomp of comparison + | Kintcomp of integer_comparison | Koffsetint of int | Koffsetref of int | Kisint diff --git a/bytecomp/instruct.mli b/bytecomp/instruct.mli index e49edefd..f52f322d 100644 --- a/bytecomp/instruct.mli +++ b/bytecomp/instruct.mli @@ -98,7 +98,8 @@ type instruction = | Kgetvectitem | Ksetvectitem | Kgetstringchar - | Ksetstringchar + | Kgetbyteschar + | Ksetbyteschar | Kbranch of label | Kbranchif of label | Kbranchifnot of label @@ -113,7 +114,7 @@ type instruction = | Kccall of string * int | Knegint | Kaddint | Ksubint | Kmulint | Kdivint | Kmodint | Kandint | Korint | Kxorint | Klslint | Klsrint | Kasrint - | Kintcomp of comparison + | Kintcomp of integer_comparison | Koffsetint of int | Koffsetref of int | Kisint diff --git a/bytecomp/lambda.ml b/bytecomp/lambda.ml index d6f91ef0..4b396af1 100644 --- a/bytecomp/lambda.ml +++ b/bytecomp/lambda.ml @@ -27,13 +27,6 @@ type compile_time_constant = | Ostype_cygwin | Backend_type -type loc_kind = - | Loc_FILE - | Loc_LINE - | Loc_MODULE - | Loc_LOC - | Loc_POS - type immediate_or_pointer = | Immediate | Pointer @@ -54,7 +47,6 @@ type primitive = | Pignore | Prevapply | Pdirapply - | Ploc of loc_kind (* Globals *) | Pgetglobal of Ident.t | Psetglobal of Ident.t @@ -68,7 +60,6 @@ type primitive = | Psetfloatfield of int * initialization_or_assignment | Pduprecord of Types.record_representation * int (* Force lazy values *) - | Plazyforce (* External call *) | Pccall of Primitive.description (* Exceptions *) @@ -80,14 +71,14 @@ type primitive = | Pdivint of is_safe | Pmodint of is_safe | Pandint | Porint | Pxorint | Plslint | Plsrint | Pasrint - | Pintcomp of comparison + | Pintcomp of integer_comparison | Poffsetint of int | Poffsetref of int (* Float operations *) | Pintoffloat | Pfloatofint | Pnegfloat | Pabsfloat | Paddfloat | Psubfloat | Pmulfloat | Pdivfloat - | Pfloatcomp of comparison + | Pfloatcomp of float_comparison (* String operations *) | Pstringlength | Pstringrefu | Pstringrefs | Pbyteslength | Pbytesrefu | Pbytessetu | Pbytesrefs | Pbytessets @@ -103,8 +94,6 @@ type primitive = | Pisint (* Test if the (integer) argument is outside an interval *) | Pisout - (* Bitvect operations *) - | Pbittest (* Operations on boxed integers (Nativeint.t, Int32.t, Int64.t) *) | Pbintofint of boxed_integer | Pintofbint of boxed_integer @@ -121,7 +110,7 @@ type primitive = | Plslbint of boxed_integer | Plsrbint of boxed_integer | Pasrbint of boxed_integer - | Pbintcomp of boxed_integer * comparison + | Pbintcomp of boxed_integer * integer_comparison (* Operations on big arrays: (unsafe, #dimensions, kind, layout) *) | Pbigarrayref of bool * int * bigarray_kind * bigarray_layout | Pbigarrayset of bool * int * bigarray_kind * bigarray_layout @@ -131,9 +120,12 @@ type primitive = | Pstring_load_16 of bool | Pstring_load_32 of bool | Pstring_load_64 of bool - | Pstring_set_16 of bool - | Pstring_set_32 of bool - | Pstring_set_64 of bool + | Pbytes_load_16 of bool + | Pbytes_load_32 of bool + | Pbytes_load_64 of bool + | Pbytes_set_16 of bool + | Pbytes_set_32 of bool + | Pbytes_set_64 of bool (* load/set 16,32,64 bits from a (char, int8_unsigned_elt, c_layout) Bigarray.Array1.t : (unsafe) *) | Pbigstring_load_16 of bool @@ -152,8 +144,11 @@ type primitive = (* Inhibition of optimisation *) | Popaque -and comparison = - Ceq | Cneq | Clt | Cgt | Cle | Cge +and integer_comparison = + Ceq | Cne | Clt | Cgt | Cle | Cge + +and float_comparison = + CFeq | CFneq | CFlt | CFnlt | CFgt | CFngt | CFle | CFnle | CFge | CFnge and value_kind = Pgenval | Pfloatval | Pboxedintval of boxed_integer | Pintval @@ -408,7 +403,7 @@ let iter_opt f = function | None -> () | Some e -> f e -let iter f = function +let iter_head_constructor f = function Lvar _ | Lconst _ -> () | Lapply{ap_func = fn; ap_args = args} -> @@ -454,40 +449,83 @@ let iter f = function | Lifused (_v, e) -> f e +let rec free_variables = function + | Lvar id -> Ident.Set.singleton id + | Lconst _ -> Ident.Set.empty + | Lapply{ap_func = fn; ap_args = args} -> + free_variables_list (free_variables fn) args + | Lfunction{body; params} -> + Ident.Set.diff (free_variables body) + (Ident.Set.of_list params) + | Llet(_str, _k, id, arg, body) -> + Ident.Set.union + (free_variables arg) + (Ident.Set.remove id (free_variables body)) + | Lletrec(decl, body) -> + let set = free_variables_list (free_variables body) (List.map snd decl) in + Ident.Set.diff set (Ident.Set.of_list (List.map fst decl)) + | Lprim(_p, args, _loc) -> + free_variables_list Ident.Set.empty args + | Lswitch(arg, sw,_) -> + let set = + free_variables_list + (free_variables_list (free_variables arg) + (List.map snd sw.sw_consts)) + (List.map snd sw.sw_blocks) + in + begin match sw.sw_failaction with + | None -> set + | Some failaction -> Ident.Set.union set (free_variables failaction) + end + | Lstringswitch (arg,cases,default,_) -> + let set = + free_variables_list (free_variables arg) + (List.map snd cases) + in + begin match default with + | None -> set + | Some default -> Ident.Set.union set (free_variables default) + end + | Lstaticraise (_,args) -> + free_variables_list Ident.Set.empty args + | Lstaticcatch(body, (_, params), handler) -> + Ident.Set.union + (Ident.Set.diff + (free_variables handler) + (Ident.Set.of_list params)) + (free_variables body) + | Ltrywith(body, param, handler) -> + Ident.Set.union + (Ident.Set.remove + param + (free_variables handler)) + (free_variables body) + | Lifthenelse(e1, e2, e3) -> + Ident.Set.union + (Ident.Set.union (free_variables e1) (free_variables e2)) + (free_variables e3) + | Lsequence(e1, e2) -> + Ident.Set.union (free_variables e1) (free_variables e2) + | Lwhile(e1, e2) -> + Ident.Set.union (free_variables e1) (free_variables e2) + | Lfor(v, lo, hi, _dir, body) -> + let set = Ident.Set.union (free_variables lo) (free_variables hi) in + Ident.Set.union set (Ident.Set.remove v (free_variables body)) + | Lassign(id, e) -> + Ident.Set.add id (free_variables e) + | Lsend (_k, met, obj, args, _) -> + free_variables_list + (Ident.Set.union (free_variables met) (free_variables obj)) + args + | Levent (lam, _evt) -> + free_variables lam + | Lifused (_v, e) -> + (* Shouldn't v be considered a free variable ? *) + free_variables e -module IdentSet = Set.Make(Ident) - -let free_ids get l = - let fv = ref IdentSet.empty in - let rec free l = - iter free l; - fv := List.fold_right IdentSet.add (get l) !fv; - match l with - Lfunction{params} -> - List.iter (fun param -> fv := IdentSet.remove param !fv) params - | Llet(_str, _k, id, _arg, _body) -> - fv := IdentSet.remove id !fv - | Lletrec(decl, _body) -> - List.iter (fun (id, _exp) -> fv := IdentSet.remove id !fv) decl - | Lstaticcatch(_e1, (_,vars), _e2) -> - List.iter (fun id -> fv := IdentSet.remove id !fv) vars - | Ltrywith(_e1, exn, _e2) -> - fv := IdentSet.remove exn !fv - | Lfor(v, _e1, _e2, _dir, _e3) -> - fv := IdentSet.remove v !fv - | Lassign(id, _e) -> - fv := IdentSet.add id !fv - | Lvar _ | Lconst _ | Lapply _ - | Lprim _ | Lswitch _ | Lstringswitch _ | Lstaticraise _ - | Lifthenelse _ | Lsequence _ | Lwhile _ - | Lsend _ | Levent _ | Lifused _ -> () - in free l; !fv - -let free_variables l = - free_ids (function Lvar id -> [id] | _ -> []) l - -let free_methods l = - free_ids (function Lsend(Self, Lvar meth, _, _, _) -> [meth] | _ -> []) l +and free_variables_list set exprs = + List.fold_left (fun set expr -> Ident.Set.union (free_variables expr) set) + set exprs (* Check if an action has a "when" guard *) let raise_count = ref 0 @@ -496,12 +534,6 @@ let next_raise_count () = incr raise_count ; !raise_count -let negative_raise_count = ref 0 - -let next_negative_raise_count () = - decr negative_raise_count ; - !negative_raise_count - (* Anticipated staticraise, for guards *) let staticfail = Lstaticraise (0,[]) @@ -555,52 +587,69 @@ let rec make_sequence fn = function let lam = fn x in Lsequence(lam, make_sequence fn rem) (* Apply a substitution to a lambda-term. - Assumes that the bound variables of the lambda-term do not - belong to the domain of the substitution. Assumes that the image of the substitution is out of reach of the bound variables of the lambda-term (no capture). *) -let subst_lambda s lam = - let rec subst = function - Lvar id as l -> - begin try Ident.find_same id s with Not_found -> l end +let rec subst s lam = + let remove_list l s = + List.fold_left (fun s id -> Ident.Map.remove id s) s l + in + let module M = Ident.Map in + match lam with + | Lvar id as l -> + begin try Ident.Map.find id s with Not_found -> l end | Lconst _ as l -> l | Lapply ap -> - Lapply{ap with ap_func = subst ap.ap_func; - ap_args = List.map subst ap.ap_args} + Lapply{ap with ap_func = subst s ap.ap_func; + ap_args = subst_list s ap.ap_args} | Lfunction{kind; params; body; attr; loc} -> - Lfunction{kind; params; body = subst body; attr; loc} - | Llet(str, k, id, arg, body) -> Llet(str, k, id, subst arg, subst body) - | Lletrec(decl, body) -> Lletrec(List.map subst_decl decl, subst body) - | Lprim(p, args, loc) -> Lprim(p, List.map subst args, loc) + let s = List.fold_right Ident.Map.remove params s in + Lfunction{kind; params; body = subst s body; attr; loc} + | Llet(str, k, id, arg, body) -> + Llet(str, k, id, subst s arg, subst (Ident.Map.remove id s) body) + | Lletrec(decl, body) -> + let s = + List.fold_left (fun s (id, _) -> Ident.Map.remove id s) + s decl + in + Lletrec(List.map (subst_decl s) decl, subst s body) + | Lprim(p, args, loc) -> Lprim(p, subst_list s args, loc) | Lswitch(arg, sw, loc) -> - Lswitch(subst arg, - {sw with sw_consts = List.map subst_case sw.sw_consts; - sw_blocks = List.map subst_case sw.sw_blocks; - sw_failaction = subst_opt sw.sw_failaction; }, + Lswitch(subst s arg, + {sw with sw_consts = List.map (subst_case s) sw.sw_consts; + sw_blocks = List.map (subst_case s) sw.sw_blocks; + sw_failaction = subst_opt s sw.sw_failaction; }, loc) | Lstringswitch (arg,cases,default,loc) -> Lstringswitch - (subst arg,List.map subst_strcase cases,subst_opt default,loc) - | Lstaticraise (i,args) -> Lstaticraise (i, List.map subst args) - | Lstaticcatch(e1, io, e2) -> Lstaticcatch(subst e1, io, subst e2) - | Ltrywith(e1, exn, e2) -> Ltrywith(subst e1, exn, subst e2) - | Lifthenelse(e1, e2, e3) -> Lifthenelse(subst e1, subst e2, subst e3) - | Lsequence(e1, e2) -> Lsequence(subst e1, subst e2) - | Lwhile(e1, e2) -> Lwhile(subst e1, subst e2) - | Lfor(v, e1, e2, dir, e3) -> Lfor(v, subst e1, subst e2, dir, subst e3) - | Lassign(id, e) -> Lassign(id, subst e) + (subst s arg,List.map (subst_strcase s) cases,subst_opt s default,loc) + | Lstaticraise (i,args) -> Lstaticraise (i, subst_list s args) + | Lstaticcatch(body, (id, params), handler) -> + Lstaticcatch(subst s body, (id, params), + subst (remove_list params s) handler) + | Ltrywith(body, exn, handler) -> + Ltrywith(subst s body, exn, subst (Ident.Map.remove exn s) handler) + | Lifthenelse(e1, e2, e3) -> Lifthenelse(subst s e1, subst s e2, subst s e3) + | Lsequence(e1, e2) -> Lsequence(subst s e1, subst s e2) + | Lwhile(e1, e2) -> Lwhile(subst s e1, subst s e2) + | Lfor(v, lo, hi, dir, body) -> + Lfor(v, subst s lo, subst s hi, dir, + subst (Ident.Map.remove v s) body) + | Lassign(id, e) -> + assert(not (Ident.Map.mem id s)); + Lassign(id, subst s e) | Lsend (k, met, obj, args, loc) -> - Lsend (k, subst met, subst obj, List.map subst args, loc) - | Levent (lam, evt) -> Levent (subst lam, evt) - | Lifused (v, e) -> Lifused (v, subst e) - and subst_decl (id, exp) = (id, subst exp) - and subst_case (key, case) = (key, subst case) - and subst_strcase (key, case) = (key, subst case) - and subst_opt = function - | None -> None - | Some e -> Some (subst e) - in subst lam + Lsend (k, subst s met, subst s obj, subst_list s args, loc) + | Levent (lam, evt) -> Levent (subst s lam, evt) + | Lifused (v, e) -> Lifused (v, subst s e) +and subst_list s l = List.map (subst s) l +and subst_decl s (id, exp) = (id, subst s exp) +and subst_case s (key, case) = (key, subst s case) +and subst_strcase s (key, case) = (key, subst s case) +and subst_opt s = function + | None -> None + | Some e -> Some (subst s e) + let rec map f lam = let lam = @@ -672,46 +721,51 @@ let bind str var exp body = Lvar var' when Ident.same var var' -> body | _ -> Llet(str, Pgenval, var, exp, body) -and commute_comparison = function -| Ceq -> Ceq| Cneq -> Cneq -| Clt -> Cgt | Cle -> Cge -| Cgt -> Clt | Cge -> Cle - -and negate_comparison = function -| Ceq -> Cneq| Cneq -> Ceq -| Clt -> Cge | Cle -> Cgt -| Cgt -> Cle | Cge -> Clt +let negate_integer_comparison = function + | Ceq -> Cne + | Cne -> Ceq + | Clt -> Cge + | Cle -> Cgt + | Cgt -> Cle + | Cge -> Clt + +let swap_integer_comparison = function + | Ceq -> Ceq + | Cne -> Cne + | Clt -> Cgt + | Cle -> Cge + | Cgt -> Clt + | Cge -> Cle + +let negate_float_comparison = function + | CFeq -> CFneq + | CFneq -> CFeq + | CFlt -> CFnlt + | CFnlt -> CFlt + | CFgt -> CFngt + | CFngt -> CFgt + | CFle -> CFnle + | CFnle -> CFle + | CFge -> CFnge + | CFnge -> CFge + +let swap_float_comparison = function + | CFeq -> CFeq + | CFneq -> CFneq + | CFlt -> CFgt + | CFnlt -> CFngt + | CFle -> CFge + | CFnle -> CFnge + | CFgt -> CFlt + | CFngt -> CFnlt + | CFge -> CFle + | CFnge -> CFnle let raise_kind = function | Raise_regular -> "raise" | Raise_reraise -> "reraise" | Raise_notrace -> "raise_notrace" -let lam_of_loc kind loc = - let loc_start = loc.Location.loc_start in - let (file, lnum, cnum) = Location.get_pos_info loc_start in - let enum = loc.Location.loc_end.Lexing.pos_cnum - - loc_start.Lexing.pos_cnum + cnum in - match kind with - | Loc_POS -> - Lconst (Const_block (0, [ - Const_immstring file; - Const_base (Const_int lnum); - Const_base (Const_int cnum); - Const_base (Const_int enum); - ])) - | Loc_FILE -> Lconst (Const_immstring file) - | Loc_MODULE -> - let filename = Filename.basename file in - let name = Env.get_unit_name () in - let module_name = if name = "" then "//"^filename^"//" else name in - Lconst (Const_immstring module_name) - | Loc_LOC -> - let loc = Printf.sprintf "File %S, line %d, characters %d-%d" - file lnum cnum enum in - Lconst (Const_immstring loc) - | Loc_LINE -> Lconst (Const_base (Const_int lnum)) - let merge_inline_attributes attr1 attr2 = match attr1, attr2 with | Default_inline, _ -> Some attr2 diff --git a/bytecomp/lambda.mli b/bytecomp/lambda.mli index fef608d4..e82aa3e7 100644 --- a/bytecomp/lambda.mli +++ b/bytecomp/lambda.mli @@ -27,13 +27,6 @@ type compile_time_constant = | Ostype_cygwin | Backend_type -type loc_kind = - | Loc_FILE - | Loc_LINE - | Loc_MODULE - | Loc_LOC - | Loc_POS - type immediate_or_pointer = | Immediate | Pointer @@ -59,7 +52,6 @@ type primitive = | Pignore | Prevapply | Pdirapply - | Ploc of loc_kind (* Globals *) | Pgetglobal of Ident.t | Psetglobal of Ident.t @@ -72,8 +64,6 @@ type primitive = | Pfloatfield of int | Psetfloatfield of int * initialization_or_assignment | Pduprecord of Types.record_representation * int - (* Force lazy values *) - | Plazyforce (* External call *) | Pccall of Primitive.description (* Exceptions *) @@ -85,14 +75,14 @@ type primitive = | Pdivint of is_safe | Pmodint of is_safe | Pandint | Porint | Pxorint | Plslint | Plsrint | Pasrint - | Pintcomp of comparison + | Pintcomp of integer_comparison | Poffsetint of int | Poffsetref of int (* Float operations *) | Pintoffloat | Pfloatofint | Pnegfloat | Pabsfloat | Paddfloat | Psubfloat | Pmulfloat | Pdivfloat - | Pfloatcomp of comparison + | Pfloatcomp of float_comparison (* String operations *) | Pstringlength | Pstringrefu | Pstringrefs | Pbyteslength | Pbytesrefu | Pbytessetu | Pbytesrefs | Pbytessets @@ -111,8 +101,6 @@ type primitive = | Pisint (* Test if the (integer) argument is outside an interval *) | Pisout - (* Bitvect operations *) - | Pbittest (* Operations on boxed integers (Nativeint.t, Int32.t, Int64.t) *) | Pbintofint of boxed_integer | Pintofbint of boxed_integer @@ -129,7 +117,7 @@ type primitive = | Plslbint of boxed_integer | Plsrbint of boxed_integer | Pasrbint of boxed_integer - | Pbintcomp of boxed_integer * comparison + | Pbintcomp of boxed_integer * integer_comparison (* Operations on big arrays: (unsafe, #dimensions, kind, layout) *) | Pbigarrayref of bool * int * bigarray_kind * bigarray_layout | Pbigarrayset of bool * int * bigarray_kind * bigarray_layout @@ -139,9 +127,12 @@ type primitive = | Pstring_load_16 of bool | Pstring_load_32 of bool | Pstring_load_64 of bool - | Pstring_set_16 of bool - | Pstring_set_32 of bool - | Pstring_set_64 of bool + | Pbytes_load_16 of bool + | Pbytes_load_32 of bool + | Pbytes_load_64 of bool + | Pbytes_set_16 of bool + | Pbytes_set_32 of bool + | Pbytes_set_64 of bool (* load/set 16,32,64 bits from a (char, int8_unsigned_elt, c_layout) Bigarray.Array1.t : (unsafe) *) | Pbigstring_load_16 of bool @@ -160,8 +151,11 @@ type primitive = (* Inhibition of optimisation *) | Popaque -and comparison = - Ceq | Cneq | Clt | Cgt | Cle | Cge +and integer_comparison = + Ceq | Cne | Clt | Cgt | Cle | Cge + +and float_comparison = + CFeq | CFneq | CFlt | CFnlt | CFgt | CFngt | CFle | CFnle | CFge | CFnge and array_kind = Pgenarray | Paddrarray | Pintarray | Pfloatarray @@ -322,10 +316,12 @@ val lambda_unit: lambda val name_lambda: let_kind -> lambda -> (Ident.t -> lambda) -> lambda val name_lambda_list: lambda list -> (lambda list -> lambda) -> lambda -val iter: (lambda -> unit) -> lambda -> unit -module IdentSet: Set.S with type elt = Ident.t -val free_variables: lambda -> IdentSet.t -val free_methods: lambda -> IdentSet.t +val iter_head_constructor: (lambda -> unit) -> lambda -> unit +(** [iter_head_constructor f lam] apply [f] to only the first level of + sub expressions of [lam]. It does not recursively traverse the + expression. *) + +val free_variables: lambda -> Ident.Set.t val transl_normal_path: Path.t -> lambda (* Path.t is already normal *) val transl_path: ?loc:Location.t -> Env.t -> Path.t -> lambda @@ -338,12 +334,19 @@ val transl_class_path: ?loc:Location.t -> Env.t -> Path.t -> lambda val make_sequence: ('a -> lambda) -> 'a list -> lambda -val subst_lambda: lambda Ident.tbl -> lambda -> lambda +val subst: lambda Ident.Map.t -> lambda -> lambda +(** Apply a substitution to a lambda-term. + Assumes that the image of the substitution is out of reach + of the bound variables of the lambda-term (no capture). *) + val map : (lambda -> lambda) -> lambda -> lambda val bind : let_kind -> Ident.t -> lambda -> lambda -> lambda -val commute_comparison : comparison -> comparison -val negate_comparison : comparison -> comparison +val negate_integer_comparison : integer_comparison -> integer_comparison +val swap_integer_comparison : integer_comparison -> integer_comparison + +val negate_float_comparison : float_comparison -> float_comparison +val swap_float_comparison : float_comparison -> float_comparison val default_function_attribute : function_attribute val default_stub_attribute : function_attribute @@ -354,11 +357,6 @@ val default_stub_attribute : function_attribute (* Get a new static failure ident *) val next_raise_count : unit -> int -val next_negative_raise_count : unit -> int - (* Negative raise counts are used to compile 'match ... with - exception x -> ...'. This disabled some simplifications - performed by the Simplif module that assume that static raises - are in tail position in their handler. *) val staticfail : lambda (* Anticipated static failure *) @@ -367,7 +365,6 @@ val is_guarded: lambda -> bool val patch_guarded : lambda -> lambda -> lambda val raise_kind: raise_kind -> string -val lam_of_loc : loc_kind -> Location.t -> lambda val merge_inline_attributes : inline_attribute diff --git a/bytecomp/matching.ml b/bytecomp/matching.ml index 32e8043d..6ed69827 100644 --- a/bytecomp/matching.ml +++ b/bytecomp/matching.ml @@ -22,6 +22,7 @@ open Typedtree open Lambda open Parmatch open Printf +open Printpat let dbg = false @@ -60,6 +61,18 @@ let string_of_lam lam = Printlambda.lambda Format.str_formatter lam ; Format.flush_str_formatter () +let all_record_args lbls = match lbls with +| (_,{lbl_all=lbl_all},_)::_ -> + let t = + Array.map + (fun lbl -> mknoloc (Longident.Lident "?temp?"), lbl,omega) + lbl_all in + List.iter + (fun ((_, lbl,_) as x) -> t.(lbl.lbl_pos) <- x) + lbls ; + Array.to_list t +| _ -> fatal_error "Parmatch.all_record_args" + type matrix = pattern list list let add_omega_column pss = List.map (fun ps -> omega::ps) pss @@ -70,9 +83,9 @@ let pretty_ctx ctx = List.iter (fun {left=left ; right=right} -> prerr_string "LEFT:" ; - pretty_line left ; + pretty_line Format.err_formatter left ; prerr_string " RIGHT:" ; - pretty_line right ; + pretty_line Format.err_formatter right ; prerr_endline "") ctx @@ -163,7 +176,7 @@ let filter_matrix matcher pss = end | [] -> [] | _ -> - pretty_matrix pss ; + pretty_matrix Format.err_formatter pss ; fatal_error "Matching.filter_matrix" in filter_rec pss @@ -404,7 +417,7 @@ let pretty_cases cases = (fun (ps,_l) -> List.iter (fun p -> - Parmatch.top_pretty Format.str_formatter p ; + top_pretty Format.str_formatter p ; prerr_string " " ; prerr_string (Format.flush_str_formatter ())) ps ; @@ -421,7 +434,7 @@ let pretty_def def = List.iter (fun (pss,i) -> Printf.fprintf stderr "Matrix for %d\n" i ; - pretty_matrix pss) + pretty_matrix Format.err_formatter pss) def ; prerr_endline "+++++++++++++++++++++" @@ -441,7 +454,7 @@ let rec pretty_precompiled = function | PmOr x -> prerr_endline "++++ OR ++++" ; pretty_pm x.body ; - pretty_matrix x.or_matrix ; + pretty_matrix Format.err_formatter x.or_matrix ; List.iter (fun (_,i,_,pm) -> eprintf "++ Handler %d ++\n" i ; @@ -666,9 +679,9 @@ let default_compat p def = (* Or-pattern expansion, variables are a complication w.r.t. the article *) let rec extract_vars r p = match p.pat_desc with -| Tpat_var (id, _) -> IdentSet.add id r +| Tpat_var (id, _) -> Ident.Set.add id r | Tpat_alias (p, id,_ ) -> - extract_vars (IdentSet.add id r) p + extract_vars (Ident.Set.add id r) p | Tpat_tuple pats -> List.fold_left extract_vars r pats | Tpat_record (lpats,_) -> @@ -714,8 +727,8 @@ let rec explode_or_pat arg patl mk_action rem vars aliases = function let pm_free_variables {cases=cases} = List.fold_right - (fun (_,act) r -> IdentSet.union (free_variables act) r) - cases IdentSet.empty + (fun (_,act) r -> Ident.Set.union (free_variables act) r) + cases Ident.Set.empty (* Basic grouping predicates *) @@ -804,8 +817,8 @@ let insert_or_append p ps act ors no = if is_or q then begin if may_compat p q then if - IdentSet.is_empty (extract_vars IdentSet.empty p) && - IdentSet.is_empty (extract_vars IdentSet.empty q) && + Ident.Set.is_empty (extract_vars Ident.Set.empty p) && + Ident.Set.is_empty (extract_vars Ident.Set.empty q) && equiv_pat p q then (* attempt insert, for equivalent orpats with no variables *) let _, not_e = get_equiv q rem in @@ -1101,9 +1114,9 @@ and precompile_or argo cls ors args def k = match ors with args = (match args with _::r -> r | _ -> assert false) ; default = default_compat orp def} in let vars = - IdentSet.elements - (IdentSet.inter - (extract_vars IdentSet.empty orp) + Ident.Set.elements + (Ident.Set.inter + (extract_vars Ident.Set.empty orp) (pm_free_variables orpm)) in let or_num = next_raise_count () in let new_patl = Parmatch.omega_list patl in @@ -1807,10 +1820,10 @@ let share_actions_tree sw d = let d = match d with | None -> None - | Some d -> Some (store.Switch.act_store_shared d) in + | Some d -> Some (store.Switch.act_store_shared () d) in (* Store all other actions *) let sw = - List.map (fun (cst,act) -> cst,store.Switch.act_store act) sw in + List.map (fun (cst,act) -> cst,store.Switch.act_store () act) sw in (* Retrieve all actions, including potential default *) let acts = store.Switch.act_get_shared () in @@ -1888,7 +1901,7 @@ module SArg = struct type primitive = Lambda.primitive let eqint = Pintcomp Ceq - let neint = Pintcomp Cneq + let neint = Pintcomp Cne let leint = Pintcomp Cle let ltint = Pintcomp Clt let geint = Pintcomp Cge @@ -1934,14 +1947,14 @@ let share_actions_sw sw = | None -> None | Some fail -> (* Fail is translated to exit, whatever happens *) - Some (store.Switch.act_store_shared fail) in + Some (store.Switch.act_store_shared () fail) in let consts = List.map - (fun (i,e) -> i,store.Switch.act_store e) + (fun (i,e) -> i,store.Switch.act_store () e) sw.sw_consts and blocks = List.map - (fun (i,e) -> i,store.Switch.act_store e) + (fun (i,e) -> i,store.Switch.act_store () e) sw.sw_blocks in let acts = store.Switch.act_get_shared () in let hs,handle_shared = handle_shared () in @@ -2009,7 +2022,7 @@ let as_interval_canfail fail low high l = let do_store _tag act = - let i = store.act_store act in + let i = store.act_store () act in (* eprintf "STORE [%s] %i %s\n" tag i (string_of_lam act) ; *) @@ -2073,7 +2086,7 @@ let as_interval_nofail l = | [] -> [cur_low, cur_high, cur_act] | (i,act)::rem -> - let act_index = store.act_store act in + let act_index = store.act_store () act in if act_index = cur_act then i_rec cur_low i cur_act rem else @@ -2087,9 +2100,9 @@ let as_interval_nofail l = cases (cf. switch.ml, make_switch). Hence, this action will be shared *) if some_hole rem then - store.act_store_shared act + store.act_store_shared () act else - store.act_store act in + store.act_store () act in assert (act_index = 0) ; i_rec i i act_index rem | _ -> assert false in @@ -2241,22 +2254,22 @@ let combine_constant loc arg cst partial ctx def | Const_float _ -> make_test_sequence loc fail - (Pfloatcomp Cneq) (Pfloatcomp Clt) + (Pfloatcomp CFneq) (Pfloatcomp CFlt) arg const_lambda_list | Const_int32 _ -> make_test_sequence loc fail - (Pbintcomp(Pint32, Cneq)) (Pbintcomp(Pint32, Clt)) + (Pbintcomp(Pint32, Cne)) (Pbintcomp(Pint32, Clt)) arg const_lambda_list | Const_int64 _ -> make_test_sequence loc fail - (Pbintcomp(Pint64, Cneq)) (Pbintcomp(Pint64, Clt)) + (Pbintcomp(Pint64, Cne)) (Pbintcomp(Pint64, Clt)) arg const_lambda_list | Const_nativeint _ -> make_test_sequence loc fail - (Pbintcomp(Pnativeint, Cneq)) (Pbintcomp(Pnativeint, Clt)) + (Pbintcomp(Pnativeint, Cne)) (Pbintcomp(Pnativeint, Clt)) arg const_lambda_list in lambda1,jumps_union local_jumps total diff --git a/bytecomp/printinstr.ml b/bytecomp/printinstr.ml index 62bdfd22..6b3754cb 100644 --- a/bytecomp/printinstr.ml +++ b/bytecomp/printinstr.ml @@ -56,7 +56,8 @@ let instruction ppf = function | Kgetvectitem -> fprintf ppf "\tgetvectitem" | Ksetvectitem -> fprintf ppf "\tsetvectitem" | Kgetstringchar -> fprintf ppf "\tgetstringchar" - | Ksetstringchar -> fprintf ppf "\tsetstringchar" + | Kgetbyteschar -> fprintf ppf "\tgetbyteschar" + | Ksetbyteschar -> fprintf ppf "\tsetbyteschar" | Kbranch lbl -> fprintf ppf "\tbranch L%i" lbl | Kbranchif lbl -> fprintf ppf "\tbranchif L%i" lbl | Kbranchifnot lbl -> fprintf ppf "\tbranchifnot L%i" lbl @@ -87,7 +88,7 @@ let instruction ppf = function | Klsrint -> fprintf ppf "\tlsrint" | Kasrint -> fprintf ppf "\tasrint" | Kintcomp Ceq -> fprintf ppf "\teqint" - | Kintcomp Cneq -> fprintf ppf "\tneqint" + | Kintcomp Cne -> fprintf ppf "\tneqint" | Kintcomp Clt -> fprintf ppf "\tltint" | Kintcomp Cgt -> fprintf ppf "\tgtint" | Kintcomp Cle -> fprintf ppf "\tleint" diff --git a/bytecomp/printlambda.ml b/bytecomp/printlambda.ml index 54a64bee..f128db5e 100644 --- a/bytecomp/printlambda.ml +++ b/bytecomp/printlambda.ml @@ -109,13 +109,6 @@ let record_rep ppf r = | Record_extension -> fprintf ppf "ext" ;; -let string_of_loc_kind = function - | Loc_FILE -> "loc_FILE" - | Loc_LINE -> "loc_LINE" - | Loc_MODULE -> "loc_MODULE" - | Loc_POS -> "loc_POS" - | Loc_LOC -> "loc_LOC" - let block_shape ppf shape = match shape with | None | Some [] -> () | Some l when List.for_all ((=) Pgenval) l -> () @@ -128,6 +121,26 @@ let block_shape ppf shape = match shape with t; Format.fprintf ppf ")" +let integer_comparison ppf = function + | Ceq -> fprintf ppf "==" + | Cne -> fprintf ppf "!=" + | Clt -> fprintf ppf "<" + | Cle -> fprintf ppf "<=" + | Cgt -> fprintf ppf ">" + | Cge -> fprintf ppf ">=" + +let float_comparison ppf = function + | CFeq -> fprintf ppf "==." + | CFneq -> fprintf ppf "!=." + | CFlt -> fprintf ppf "<." + | CFnlt -> fprintf ppf "!<." + | CFle -> fprintf ppf "<=." + | CFnle -> fprintf ppf "!<=." + | CFgt -> fprintf ppf ">." + | CFngt -> fprintf ppf "!>." + | CFge -> fprintf ppf ">=." + | CFnge -> fprintf ppf "!>=." + let primitive ppf = function | Pidentity -> fprintf ppf "id" | Pbytes_to_string -> fprintf ppf "bytes_to_string" @@ -135,7 +148,6 @@ let primitive ppf = function | Pignore -> fprintf ppf "ignore" | Prevapply -> fprintf ppf "revapply" | Pdirapply -> fprintf ppf "dirapply" - | Ploc kind -> fprintf ppf "%s" (string_of_loc_kind kind) | Pgetglobal id -> fprintf ppf "global %a" Ident.print id | Psetglobal id -> fprintf ppf "setglobal %a" Ident.print id | Pmakeblock(tag, Immutable, shape) -> @@ -180,7 +192,6 @@ let primitive ppf = function in fprintf ppf "setfloatfield%s %i" init n | Pduprecord (rep, size) -> fprintf ppf "duprecord %a %i" record_rep rep size - | Plazyforce -> fprintf ppf "force" | Pccall p -> fprintf ppf "%s" p.prim_name | Praise k -> fprintf ppf "%s" (Lambda.raise_kind k) | Psequand -> fprintf ppf "&&" @@ -200,12 +211,7 @@ let primitive ppf = function | Plslint -> fprintf ppf "lsl" | Plsrint -> fprintf ppf "lsr" | Pasrint -> fprintf ppf "asr" - | Pintcomp(Ceq) -> fprintf ppf "==" - | Pintcomp(Cneq) -> fprintf ppf "!=" - | Pintcomp(Clt) -> fprintf ppf "<" - | Pintcomp(Cle) -> fprintf ppf "<=" - | Pintcomp(Cgt) -> fprintf ppf ">" - | Pintcomp(Cge) -> fprintf ppf ">=" + | Pintcomp(cmp) -> integer_comparison ppf cmp | Poffsetint n -> fprintf ppf "%i+" n | Poffsetref n -> fprintf ppf "+:=%i"n | Pintoffloat -> fprintf ppf "int_of_float" @@ -216,12 +222,7 @@ let primitive ppf = function | Psubfloat -> fprintf ppf "-." | Pmulfloat -> fprintf ppf "*." | Pdivfloat -> fprintf ppf "/." - | Pfloatcomp(Ceq) -> fprintf ppf "==." - | Pfloatcomp(Cneq) -> fprintf ppf "!=." - | Pfloatcomp(Clt) -> fprintf ppf "<." - | Pfloatcomp(Cle) -> fprintf ppf "<=." - | Pfloatcomp(Cgt) -> fprintf ppf ">." - | Pfloatcomp(Cge) -> fprintf ppf ">=." + | Pfloatcomp(cmp) -> float_comparison ppf cmp | Pstringlength -> fprintf ppf "string.length" | Pstringrefu -> fprintf ppf "string.unsafe_get" | Pstringrefs -> fprintf ppf "string.get" @@ -253,7 +254,6 @@ let primitive ppf = function fprintf ppf "sys.constant_%s" const_name | Pisint -> fprintf ppf "isint" | Pisout -> fprintf ppf "isout" - | Pbittest -> fprintf ppf "testbit" | Pbintofint bi -> print_boxed_integer "of_int" ppf bi | Pintofbint bi -> print_boxed_integer "to_int" ppf bi | Pcvtbint (bi1, bi2) -> print_boxed_integer_conversion ppf bi1 bi2 @@ -276,7 +276,7 @@ let primitive ppf = function | Plsrbint bi -> print_boxed_integer "lsr" ppf bi | Pasrbint bi -> print_boxed_integer "asr" ppf bi | Pbintcomp(bi, Ceq) -> print_boxed_integer "==" ppf bi - | Pbintcomp(bi, Cneq) -> print_boxed_integer "!=" ppf bi + | Pbintcomp(bi, Cne) -> print_boxed_integer "!=" ppf bi | Pbintcomp(bi, Clt) -> print_boxed_integer "<" ppf bi | Pbintcomp(bi, Cgt) -> print_boxed_integer ">" ppf bi | Pbintcomp(bi, Cle) -> print_boxed_integer "<=" ppf bi @@ -295,15 +295,24 @@ let primitive ppf = function | Pstring_load_64(unsafe) -> if unsafe then fprintf ppf "string.unsafe_get64" else fprintf ppf "string.get64" - | Pstring_set_16(unsafe) -> - if unsafe then fprintf ppf "string.unsafe_set16" - else fprintf ppf "string.set16" - | Pstring_set_32(unsafe) -> - if unsafe then fprintf ppf "string.unsafe_set32" - else fprintf ppf "string.set32" - | Pstring_set_64(unsafe) -> - if unsafe then fprintf ppf "string.unsafe_set64" - else fprintf ppf "string.set64" + | Pbytes_load_16(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_get16" + else fprintf ppf "bytes.get16" + | Pbytes_load_32(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_get32" + else fprintf ppf "bytes.get32" + | Pbytes_load_64(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_get64" + else fprintf ppf "bytes.get64" + | Pbytes_set_16(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_set16" + else fprintf ppf "bytes.set16" + | Pbytes_set_32(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_set32" + else fprintf ppf "bytes.set32" + | Pbytes_set_64(unsafe) -> + if unsafe then fprintf ppf "bytes.unsafe_set64" + else fprintf ppf "bytes.set64" | Pbigstring_load_16(unsafe) -> if unsafe then fprintf ppf "bigarray.array1.unsafe_get16" else fprintf ppf "bigarray.array1.get16" @@ -334,7 +343,6 @@ let name_of_primitive = function | Pignore -> "Pignore" | Prevapply -> "Prevapply" | Pdirapply -> "Pdirapply" - | Ploc _ -> "Ploc" | Pgetglobal _ -> "Pgetglobal" | Psetglobal _ -> "Psetglobal" | Pmakeblock _ -> "Pmakeblock" @@ -345,7 +353,6 @@ let name_of_primitive = function | Pfloatfield _ -> "Pfloatfield" | Psetfloatfield _ -> "Psetfloatfield" | Pduprecord _ -> "Pduprecord" - | Plazyforce -> "Plazyforce" | Pccall _ -> "Pccall" | Praise _ -> "Praise" | Psequand -> "Psequand" @@ -393,7 +400,6 @@ let name_of_primitive = function | Pctconst _ -> "Pctconst" | Pisint -> "Pisint" | Pisout -> "Pisout" - | Pbittest -> "Pbittest" | Pbintofint _ -> "Pbintofint" | Pintofbint _ -> "Pintofbint" | Pcvtbint _ -> "Pcvtbint" @@ -416,9 +422,12 @@ let name_of_primitive = function | Pstring_load_16 _ -> "Pstring_load_16" | Pstring_load_32 _ -> "Pstring_load_32" | Pstring_load_64 _ -> "Pstring_load_64" - | Pstring_set_16 _ -> "Pstring_set_16" - | Pstring_set_32 _ -> "Pstring_set_32" - | Pstring_set_64 _ -> "Pstring_set_64" + | Pbytes_load_16 _ -> "Pbytes_load_16" + | Pbytes_load_32 _ -> "Pbytes_load_32" + | Pbytes_load_64 _ -> "Pbytes_load_64" + | Pbytes_set_16 _ -> "Pbytes_set_16" + | Pbytes_set_32 _ -> "Pbytes_set_32" + | Pbytes_set_64 _ -> "Pbytes_set_64" | Pbigstring_load_16 _ -> "Pbigstring_load_16" | Pbigstring_load_32 _ -> "Pbigstring_load_32" | Pbigstring_load_64 _ -> "Pbigstring_load_64" diff --git a/bytecomp/semantics_of_primitives.ml b/bytecomp/semantics_of_primitives.ml index f963d867..b6b09e19 100644 --- a/bytecomp/semantics_of_primitives.ml +++ b/bytecomp/semantics_of_primitives.ml @@ -21,7 +21,9 @@ type coeffects = No_coeffects | Has_coeffects let for_primitive (prim : Lambda.primitive) = match prim with - | Pignore | Pidentity | Pbytes_to_string | Pbytes_of_string -> + | Pignore | Pidentity -> + No_effects, No_coeffects + | Pbytes_to_string | Pbytes_of_string -> No_effects, No_coeffects | Pmakeblock _ | Pmakearray (_, Mutable) -> Only_generative_effects, No_coeffects @@ -35,7 +37,6 @@ let for_primitive (prim : Lambda.primitive) = ( "caml_format_float" | "caml_format_int" | "caml_int32_format" | "caml_nativeint_format" | "caml_int64_format" ) } -> No_effects, No_coeffects - | Plazyforce | Pccall _ -> Arbitrary_effects, Has_coeffects | Praise _ -> Arbitrary_effects, No_coeffects | Pnot @@ -76,7 +77,6 @@ let for_primitive (prim : Lambda.primitive) = No_effects, Has_coeffects (* That old chestnut: [Obj.truncate]. *) | Pisint | Pisout - | Pbittest | Pbintofint _ | Pintofbint _ | Pcvtbint _ @@ -103,6 +103,9 @@ let for_primitive (prim : Lambda.primitive) = | Pstring_load_16 true | Pstring_load_32 true | Pstring_load_64 true + | Pbytes_load_16 true + | Pbytes_load_32 true + | Pbytes_load_64 true | Pbigarrayref (true, _, _, _) | Pbigstring_load_16 true | Pbigstring_load_32 true @@ -114,6 +117,9 @@ let for_primitive (prim : Lambda.primitive) = | Pstring_load_16 false | Pstring_load_32 false | Pstring_load_64 false + | Pbytes_load_16 false + | Pbytes_load_32 false + | Pbytes_load_64 false | Pbigarrayref (false, _, _, _) | Pbigstring_load_16 false | Pbigstring_load_32 false @@ -128,9 +134,9 @@ let for_primitive (prim : Lambda.primitive) = | Parraysets _ | Pbytessetu | Pbytessets - | Pstring_set_16 _ - | Pstring_set_32 _ - | Pstring_set_64 _ + | Pbytes_set_16 _ + | Pbytes_set_32 _ + | Pbytes_set_64 _ | Pbigarrayset _ | Pbigstring_set_16 _ | Pbigstring_set_32 _ @@ -143,9 +149,6 @@ let for_primitive (prim : Lambda.primitive) = | Pbbswap _ -> No_effects, No_coeffects | Pint_as_pointer -> No_effects, No_coeffects | Popaque -> Arbitrary_effects, Has_coeffects - | Ploc _ -> - (* Removed by [Translcore]. *) - No_effects, No_coeffects | Prevapply | Pdirapply -> (* Removed by [Simplif], but there is no reason to prevent using diff --git a/bytecomp/simplif.ml b/bytecomp/simplif.ml index f07fbc04..ea9513f9 100644 --- a/bytecomp/simplif.ml +++ b/bytecomp/simplif.ml @@ -31,7 +31,7 @@ let rec eliminate_ref id = function Lapply{ap with ap_func = eliminate_ref id ap.ap_func; ap_args = List.map (eliminate_ref id) ap.ap_args} | Lfunction _ as lam -> - if IdentSet.mem id (free_variables lam) + if Ident.Set.mem id (free_variables lam) then raise Real_reference else lam | Llet(str, kind, v, e1, e2) -> @@ -92,22 +92,31 @@ let rec eliminate_ref id = function (* Simplification of exits *) +type exit = { + mutable count: int; + mutable max_depth: int; +} + let simplify_exits lam = (* Count occurrences of (exit n ...) statements *) let exits = Hashtbl.create 17 in - let count_exit i = - try - !(Hashtbl.find exits i) - with - | Not_found -> 0 + let try_depth = ref 0 in - and incr_exit i = - try - incr (Hashtbl.find exits i) - with - | Not_found -> Hashtbl.add exits i (ref 1) in + let get_exit i = + try Hashtbl.find exits i + with Not_found -> {count = 0; max_depth = 0} + + and incr_exit i nb d = + match Hashtbl.find_opt exits i with + | Some r -> + r.count <- r.count + nb; + r.max_depth <- max r.max_depth d + | None -> + let r = {count = nb; max_depth = d} in + Hashtbl.add exits i r + in let rec count = function | (Lvar _| Lconst _) -> () @@ -133,25 +142,20 @@ let simplify_exits lam = | []|[_] -> count d | _ -> count d; count d (* default will get replicated *) end - | Lstaticraise (i,ls) -> incr_exit i ; List.iter count ls + | Lstaticraise (i,ls) -> incr_exit i 1 !try_depth; List.iter count ls | Lstaticcatch (l1,(i,[]),Lstaticraise (j,[])) -> (* i will be replaced by j in l1, so each occurrence of i in l1 increases j's ref count *) count l1 ; - let ic = count_exit i in - begin try - let r = Hashtbl.find exits j in r := !r + ic - with - | Not_found -> - Hashtbl.add exits j (ref ic) - end + let ic = get_exit i in + incr_exit j ic.count (max !try_depth ic.max_depth) | Lstaticcatch(l1, (i,_), l2) -> count l1; (* If l1 does not contain (exit i), l2 will be removed, so don't count its exits *) - if count_exit i > 0 then + if (get_exit i).count > 0 then count l2 - | Ltrywith(l1, _v, l2) -> count l1; count l2 + | Ltrywith(l1, _v, l2) -> incr try_depth; count l1; decr try_depth; count l2 | Lifthenelse(l1, l2, l3) -> count l1; count l2; count l3 | Lsequence(l1, l2) -> count l1; count l2 | Lwhile(l1, l2) -> count l1; count l2 @@ -176,6 +180,7 @@ let simplify_exits lam = end in count lam; + assert(!try_depth = 0); (* Second pass simplify ``catch body with (i ...) handler'' @@ -261,11 +266,11 @@ let simplify_exits lam = let ys = List.map Ident.rename xs in let env = List.fold_right2 - (fun x y t -> Ident.add x (Lvar y) t) - xs ys Ident.empty in + (fun x y t -> Ident.Map.add x (Lvar y) t) + xs ys Ident.Map.empty in List.fold_right2 (fun y l r -> Llet (Alias, Pgenval, y, l, r)) - ys ls (Lambda.subst_lambda env handler) + ys ls (Lambda.subst env handler) with | Not_found -> Lstaticraise (i,ls) end @@ -273,15 +278,23 @@ let simplify_exits lam = Hashtbl.add subst i ([],simplif l2) ; simplif l1 | Lstaticcatch (l1,(i,xs),l2) -> - begin match count_exit i with - | 0 -> simplif l1 - | 1 when i >= 0 -> - Hashtbl.add subst i (xs,simplif l2) ; - simplif l1 - | _ -> - Lstaticcatch (simplif l1, (i,xs), simplif l2) - end - | Ltrywith(l1, v, l2) -> Ltrywith(simplif l1, v, simplif l2) + let {count; max_depth} = get_exit i in + if count = 0 then + (* Discard staticcatch: not matching exit *) + simplif l1 + else if count = 1 && max_depth <= !try_depth then begin + (* Inline handler if there is a single occurrence and it is not + nested within an inner try..with *) + assert(max_depth = !try_depth); + Hashtbl.add subst i (xs,simplif l2); + simplif l1 + end else + Lstaticcatch (simplif l1, (i,xs), simplif l2) + | Ltrywith(l1, v, l2) -> + incr try_depth; + let l1 = simplif l1 in + decr try_depth; + Ltrywith(l1, v, simplif l2) | Lifthenelse(l1, l2, l3) -> Lifthenelse(simplif l1, simplif l2, simplif l3) | Lsequence(l1, l2) -> Lsequence(simplif l1, simplif l2) | Lwhile(l1, l2) -> Lwhile(simplif l1, simplif l2) @@ -569,7 +582,9 @@ let rec emit_tail_infos is_tail lambda = | Lletrec (bindings, body) -> List.iter (fun (_, lam) -> emit_tail_infos false lam) bindings; emit_tail_infos is_tail body - | Lprim ((Pidentity | Pbytes_to_string | Pbytes_of_string), [arg], _) -> + | Lprim (Pidentity, [arg], _) -> + emit_tail_infos is_tail arg + | Lprim ((Pbytes_to_string | Pbytes_of_string), [arg], _) -> emit_tail_infos is_tail arg | Lprim (Psequand, [arg1; arg2], _) | Lprim (Psequor, [arg1; arg2], _) -> @@ -648,7 +663,7 @@ let split_default_wrapper ~id:fun_id ~kind ~params ~body ~attr ~loc = (* Check that those *opt* identifiers don't appear in the remaining body. This should not appear, but let's be on the safe side. *) let fv = Lambda.free_variables body in - List.iter (fun (id, _) -> if IdentSet.mem id fv then raise Exit) map; + List.iter (fun (id, _) -> if Ident.Set.mem id fv then raise Exit) map; let inner_id = Ident.create (Ident.name fun_id ^ "_inner") in let map_param p = try List.assoc p map with Not_found -> p in @@ -667,10 +682,10 @@ let split_default_wrapper ~id:fun_id ~kind ~params ~body ~attr ~loc = let new_ids = List.map Ident.rename inner_params in let subst = List.fold_left2 (fun s id new_id -> - Ident.add id (Lvar new_id) s) - Ident.empty inner_params new_ids + Ident.Map.add id (Lvar new_id) s) + Ident.Map.empty inner_params new_ids in - let body = Lambda.subst_lambda subst body in + let body = Lambda.subst subst body in let inner_fun = Lfunction { kind = Curried; params = new_ids; body; attr; loc; } in diff --git a/bytecomp/switch.ml b/bytecomp/switch.ml index 2e373239..b03982dd 100644 --- a/bytecomp/switch.ml +++ b/bytecomp/switch.ml @@ -16,11 +16,11 @@ type 'a shared = Shared of 'a | Single of 'a -type 'a t_store = +type ('a, 'ctx) t_store = {act_get : unit -> 'a array ; act_get_shared : unit -> 'a shared array ; - act_store : 'a -> int ; - act_store_shared : 'a -> int ; } + act_store : 'ctx -> 'a -> int ; + act_store_shared : 'ctx -> 'a -> int ; } exception Not_simple @@ -31,7 +31,13 @@ module type Stored = sig val make_key : t -> key option end -module Store(A:Stored) = struct +module type CtxStored = sig + include Stored + type context + val make_key : context -> t -> key option +end + +module CtxStore(A:CtxStored) = struct module AMap = Map.Make(struct type t = A.key let compare = A.compare_key end) @@ -52,7 +58,7 @@ module Store(A:Stored) = struct st.next <- i+1 ; i in - let store mustshare act = match A.make_key act with + let store mustshare ctx act = match A.make_key ctx act with | Some key -> begin try let (shared,i) = AMap.find key st.map in @@ -86,6 +92,18 @@ module Store(A:Stored) = struct act_get = get; act_get_shared = get_shared; } end +module Store(A:Stored) = struct + module Me = + CtxStore + (struct + include A + type context = unit + let make_key () = A.make_key + end) + + let mk_store = Me.mk_store +end + module type S = diff --git a/bytecomp/switch.mli b/bytecomp/switch.mli index 2d0cfd7f..b4058c17 100644 --- a/bytecomp/switch.mli +++ b/bytecomp/switch.mli @@ -31,11 +31,11 @@ type 'a shared = Shared of 'a | Single of 'a -type 'a t_store = +type ('a, 'ctx) t_store = {act_get : unit -> 'a array ; act_get_shared : unit -> 'a shared array ; - act_store : 'a -> int ; - act_store_shared : 'a -> int ; } + act_store : 'ctx -> 'a -> int ; + act_store_shared : 'ctx -> 'a -> int ; } exception Not_simple @@ -46,9 +46,20 @@ module type Stored = sig val make_key : t -> key option end +module type CtxStored = sig + include Stored + type context + val make_key : context -> t -> key option +end + +module CtxStore(A:CtxStored) : + sig + val mk_store : unit -> (A.t, A.context) t_store + end + module Store(A:Stored) : sig - val mk_store : unit -> A.t t_store + val mk_store : unit -> (A.t, unit) t_store end (* Arguments to the Make functor *) @@ -106,13 +117,13 @@ module Make : (int * int) -> Arg.act -> (int * int * int) array -> - Arg.act t_store -> + (Arg.act, _) t_store -> Arg.act (* Output test sequence, sharing tracked *) val test_sequence : Arg.act -> (int * int * int) array -> - Arg.act t_store -> + (Arg.act, _) t_store -> Arg.act end diff --git a/bytecomp/translattribute.ml b/bytecomp/translattribute.ml index 68a0dc4a..8881dc77 100644 --- a/bytecomp/translattribute.ml +++ b/bytecomp/translattribute.ml @@ -188,11 +188,26 @@ let get_and_remove_inlined_attribute e = inlined, { e with exp_attributes } let get_and_remove_inlined_attribute_on_module e = - let attr, mod_attributes = - find_attribute is_inlined_attribute e.mod_attributes + let rec get_and_remove mod_expr = + let attr, mod_attributes = + find_attribute is_inlined_attribute mod_expr.mod_attributes + in + let attr = parse_inline_attribute attr in + let attr, mod_desc = + match mod_expr.Typedtree.mod_desc with + | Tmod_constraint (me, mt, mtc, mc) -> + let inner_attr, me = get_and_remove me in + let attr = + match attr with + | Always_inline | Never_inline | Unroll _ -> attr + | Default_inline -> inner_attr + in + attr, Tmod_constraint (me, mt, mtc, mc) + | md -> attr, md + in + attr, { mod_expr with mod_desc; mod_attributes } in - let inlined = parse_inline_attribute attr in - inlined, { e with mod_attributes } + get_and_remove e let get_and_remove_specialised_attribute e = let attr, exp_attributes = diff --git a/bytecomp/translclass.ml b/bytecomp/translclass.ml index d5ffd339..4f89faa9 100644 --- a/bytecomp/translclass.ml +++ b/bytecomp/translclass.ml @@ -402,8 +402,8 @@ let rec build_class_lets cl = let rec get_class_meths cl = match cl.cl_desc with Tcl_structure cl -> - Meths.fold (fun _ -> IdentSet.add) cl.cstr_meths IdentSet.empty - | Tcl_ident _ -> IdentSet.empty + Meths.fold (fun _ -> Ident.Set.add) cl.cstr_meths Ident.Set.empty + | Tcl_ident _ -> Ident.Set.empty | Tcl_fun (_, _, _, cl, _) | Tcl_let (_, _, _, cl) | Tcl_apply (cl, _) @@ -518,7 +518,7 @@ let const_path local = function | Lconst _ -> true | Lfunction {kind = Curried; body} -> let fv = free_variables body in - List.for_all (fun x -> not (IdentSet.mem x fv)) local + List.for_all (fun x -> not (Ident.Set.mem x fv)) local | p -> module_path p let rec builtin_meths self env env2 body = @@ -630,6 +630,33 @@ let prerr_ids msg ids = prerr_endline (String.concat " " (msg :: names)) *) +let free_methods l = + let fv = ref Ident.Set.empty in + let rec free l = + Lambda.iter_head_constructor free l; + match l with + | Lsend(Self, Lvar meth, _, _, _) -> + fv := Ident.Set.add meth !fv + | Lsend _ -> () + | Lfunction{params} -> + List.iter (fun param -> fv := Ident.Set.remove param !fv) params + | Llet(_str, _k, id, _arg, _body) -> + fv := Ident.Set.remove id !fv + | Lletrec(decl, _body) -> + List.iter (fun (id, _exp) -> fv := Ident.Set.remove id !fv) decl + | Lstaticcatch(_e1, (_,vars), _e2) -> + List.iter (fun id -> fv := Ident.Set.remove id !fv) vars + | Ltrywith(_e1, exn, _e2) -> + fv := Ident.Set.remove exn !fv + | Lfor(v, _e1, _e2, _dir, _e3) -> + fv := Ident.Set.remove v !fv + | Lassign _ + | Lvar _ | Lconst _ | Lapply _ + | Lprim _ | Lswitch _ | Lstringswitch _ | Lstaticraise _ + | Lifthenelse _ | Lsequence _ | Lwhile _ + | Levent _ | Lifused _ -> () + in free l; !fv + let transl_class ids cl_id pub_meths cl vflag = (* First check if it is not only a rebind *) let rebind = transl_class_rebind cl vflag in @@ -645,25 +672,25 @@ let transl_class ids cl_id pub_meths cl vflag = let meth_ids = get_class_meths cl in let subst env lam i0 new_ids' = let fv = free_variables lam in - (* prerr_ids "cl_id =" [cl_id]; prerr_ids "fv =" (IdentSet.elements fv); *) - let fv = List.fold_right IdentSet.remove !new_ids' fv in + (* prerr_ids "cl_id =" [cl_id]; prerr_ids "fv =" (Ident.Set.elements fv); *) + let fv = List.fold_right Ident.Set.remove !new_ids' fv in (* We need to handle method ids specially, as they do not appear in the typing environment (PR#3576, PR#4560) *) (* very hacky: we add and remove free method ids on the fly, depending on the visit order... *) method_ids := - IdentSet.diff (IdentSet.union (free_methods lam) !method_ids) meth_ids; - (* prerr_ids "meth_ids =" (IdentSet.elements meth_ids); - prerr_ids "method_ids =" (IdentSet.elements !method_ids); *) - let new_ids = List.fold_right IdentSet.add new_ids !method_ids in - let fv = IdentSet.inter fv new_ids in - new_ids' := !new_ids' @ IdentSet.elements fv; + Ident.Set.diff (Ident.Set.union (free_methods lam) !method_ids) meth_ids; + (* prerr_ids "meth_ids =" (Ident.Set.elements meth_ids); + prerr_ids "method_ids =" (Ident.Set.elements !method_ids); *) + let new_ids = List.fold_right Ident.Set.add new_ids !method_ids in + let fv = Ident.Set.inter fv new_ids in + new_ids' := !new_ids' @ Ident.Set.elements fv; (* prerr_ids "new_ids' =" !new_ids'; *) let i = ref (i0-1) in List.fold_left (fun subst id -> - incr i; Ident.add id (lfield env !i) subst) - Ident.empty !new_ids' + incr i; Ident.Map.add id (lfield env !i) subst) + Ident.Map.empty !new_ids' in let new_ids_meths = ref [] in let msubst arr = function @@ -671,7 +698,7 @@ let transl_class ids cl_id pub_meths cl vflag = let env = Ident.create "env" in let body' = if new_ids = [] then body else - subst_lambda (subst env body 0 new_ids_meths) body in + Lambda.subst (subst env body 0 new_ids_meths) body in begin try (* Doesn't seem to improve size for bytecode *) (* if not !Clflags.native_code then raise Not_found; *) @@ -679,7 +706,7 @@ let transl_class ids cl_id pub_meths cl vflag = builtin_meths [self] env env2 (lfunction args body') with Not_found -> [lfunction (self :: args) - (if not (IdentSet.mem env (free_variables body')) then body' else + (if not (Ident.Set.mem env (free_variables body')) then body' else Llet(Alias, Pgenval, env, Lprim(Pfield_computed, [Lvar self; Lvar env2], @@ -698,7 +725,7 @@ let transl_class ids cl_id pub_meths cl vflag = and subst_env envs l lam = if top then lam else (* must be called only once! *) - let lam = subst_lambda (subst env1 lam 1 new_ids_init) lam in + let lam = Lambda.subst (subst env1 lam 1 new_ids_init) lam in Llet(Alias, Pgenval, env1, (if l = [] then Lvar envs else lfield envs 0), Llet(Alias, Pgenval, env1', (if !new_ids_init = [] then Lvar env1 else lfield env1 0), @@ -748,7 +775,7 @@ let transl_class ids cl_id pub_meths cl vflag = params = [cla]; body = cl_init}) in Llet(Strict, Pgenval, class_init, cl_init, lam (free_variables cl_init)) and lbody fv = - if List.for_all (fun id -> not (IdentSet.mem id fv)) ids then + if List.for_all (fun id -> not (Ident.Set.mem id fv)) ids then mkappl (oo_prim "make_class",[transl_meth_list pub_meths; Lvar class_init]) else diff --git a/bytecomp/translcore.ml b/bytecomp/translcore.ml index 216601e0..fa1ddbeb 100644 --- a/bytecomp/translcore.ml +++ b/bytecomp/translcore.ml @@ -26,7 +26,6 @@ open Lambda type error = Free_super_var - | Unknown_builtin_primitive of string | Unreachable_reached exception Error of Location.t * error @@ -48,6 +47,9 @@ let prim_fresh_oo_id = Pccall (Primitive.simple ~name:"caml_fresh_oo_id" ~arity:1 ~alloc:false) let transl_extension_constructor env path ext = + let path = + Stdlib.Option.map (Printtyp.rewrite_double_underscore_paths env) path + in let name = match path, !Clflags.for_package with None, _ -> Ident.name ext.ext_id @@ -64,461 +66,6 @@ let transl_extension_constructor env path ext = | Text_rebind(path, _lid) -> transl_extension_path ~loc env path -(* Translation of primitives *) - -let comparisons_table = create_hashtable 11 [ - "%equal", - (Pccall(Primitive.simple ~name:"caml_equal" ~arity:2 ~alloc:true), - Pintcomp Ceq, - Pfloatcomp Ceq, - Pccall(Primitive.simple ~name:"caml_string_equal" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_equal" ~arity:2 - ~alloc:false), - Pbintcomp(Pnativeint, Ceq), - Pbintcomp(Pint32, Ceq), - Pbintcomp(Pint64, Ceq), - true); - "%notequal", - (Pccall(Primitive.simple ~name:"caml_notequal" ~arity:2 ~alloc:true), - Pintcomp Cneq, - Pfloatcomp Cneq, - Pccall(Primitive.simple ~name:"caml_string_notequal" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_notequal" ~arity:2 - ~alloc:false), - Pbintcomp(Pnativeint, Cneq), - Pbintcomp(Pint32, Cneq), - Pbintcomp(Pint64, Cneq), - true); - "%lessthan", - (Pccall(Primitive.simple ~name:"caml_lessthan" ~arity:2 ~alloc:true), - Pintcomp Clt, - Pfloatcomp Clt, - Pccall(Primitive.simple ~name:"caml_string_lessthan" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_lessthan" ~arity:2 - ~alloc:false), - Pbintcomp(Pnativeint, Clt), - Pbintcomp(Pint32, Clt), - Pbintcomp(Pint64, Clt), - false); - "%greaterthan", - (Pccall(Primitive.simple ~name:"caml_greaterthan" ~arity:2 ~alloc:true), - Pintcomp Cgt, - Pfloatcomp Cgt, - Pccall(Primitive.simple ~name:"caml_string_greaterthan" ~arity:2 - ~alloc: false), - Pccall(Primitive.simple ~name:"caml_bytes_greaterthan" ~arity:2 - ~alloc: false), - Pbintcomp(Pnativeint, Cgt), - Pbintcomp(Pint32, Cgt), - Pbintcomp(Pint64, Cgt), - false); - "%lessequal", - (Pccall(Primitive.simple ~name:"caml_lessequal" ~arity:2 ~alloc:true), - Pintcomp Cle, - Pfloatcomp Cle, - Pccall(Primitive.simple ~name:"caml_string_lessequal" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_lessequal" ~arity:2 - ~alloc:false), - Pbintcomp(Pnativeint, Cle), - Pbintcomp(Pint32, Cle), - Pbintcomp(Pint64, Cle), - false); - "%greaterequal", - (Pccall(Primitive.simple ~name:"caml_greaterequal" ~arity:2 ~alloc:true), - Pintcomp Cge, - Pfloatcomp Cge, - Pccall(Primitive.simple ~name:"caml_string_greaterequal" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_greaterequal" ~arity:2 - ~alloc:false), - Pbintcomp(Pnativeint, Cge), - Pbintcomp(Pint32, Cge), - Pbintcomp(Pint64, Cge), - false); - "%compare", - let unboxed_compare name native_repr = - Pccall( Primitive.make ~name ~alloc:false - ~native_name:(name^"_unboxed") - ~native_repr_args:[native_repr;native_repr] - ~native_repr_res:Untagged_int - ) in - (Pccall(Primitive.simple ~name:"caml_compare" ~arity:2 ~alloc:true), - (* Not unboxed since the comparison is done directly on tagged int *) - Pccall(Primitive.simple ~name:"caml_int_compare" ~arity:2 ~alloc:false), - unboxed_compare "caml_float_compare" Unboxed_float, - Pccall(Primitive.simple ~name:"caml_string_compare" ~arity:2 - ~alloc:false), - Pccall(Primitive.simple ~name:"caml_bytes_compare" ~arity:2 - ~alloc:false), - unboxed_compare "caml_nativeint_compare" (Unboxed_integer Pnativeint), - unboxed_compare "caml_int32_compare" (Unboxed_integer Pint32), - unboxed_compare "caml_int64_compare" (Unboxed_integer Pint64), - false) -] - -let gen_array_kind = - if Config.flat_float_array then Pgenarray else Paddrarray - -let primitives_table = create_hashtable 57 [ - "%identity", Pidentity; - "%bytes_to_string", Pbytes_to_string; - "%bytes_of_string", Pbytes_of_string; - "%ignore", Pignore; - "%revapply", Prevapply; - "%apply", Pdirapply; - "%loc_LOC", Ploc Loc_LOC; - "%loc_FILE", Ploc Loc_FILE; - "%loc_LINE", Ploc Loc_LINE; - "%loc_POS", Ploc Loc_POS; - "%loc_MODULE", Ploc Loc_MODULE; - "%field0", Pfield 0; - "%field1", Pfield 1; - "%setfield0", Psetfield(0, Pointer, Assignment); - "%makeblock", Pmakeblock(0, Immutable, None); - "%makemutable", Pmakeblock(0, Mutable, None); - "%raise", Praise Raise_regular; - "%reraise", Praise Raise_reraise; - "%raise_notrace", Praise Raise_notrace; - "%sequand", Psequand; - "%sequor", Psequor; - "%boolnot", Pnot; - "%big_endian", Pctconst Big_endian; - "%backend_type", Pctconst Backend_type; - "%word_size", Pctconst Word_size; - "%int_size", Pctconst Int_size; - "%max_wosize", Pctconst Max_wosize; - "%ostype_unix", Pctconst Ostype_unix; - "%ostype_win32", Pctconst Ostype_win32; - "%ostype_cygwin", Pctconst Ostype_cygwin; - "%negint", Pnegint; - "%succint", Poffsetint 1; - "%predint", Poffsetint(-1); - "%addint", Paddint; - "%subint", Psubint; - "%mulint", Pmulint; - "%divint", Pdivint Safe; - "%modint", Pmodint Safe; - "%andint", Pandint; - "%orint", Porint; - "%xorint", Pxorint; - "%lslint", Plslint; - "%lsrint", Plsrint; - "%asrint", Pasrint; - "%eq", Pintcomp Ceq; - "%noteq", Pintcomp Cneq; - "%ltint", Pintcomp Clt; - "%leint", Pintcomp Cle; - "%gtint", Pintcomp Cgt; - "%geint", Pintcomp Cge; - "%incr", Poffsetref(1); - "%decr", Poffsetref(-1); - "%intoffloat", Pintoffloat; - "%floatofint", Pfloatofint; - "%negfloat", Pnegfloat; - "%absfloat", Pabsfloat; - "%addfloat", Paddfloat; - "%subfloat", Psubfloat; - "%mulfloat", Pmulfloat; - "%divfloat", Pdivfloat; - "%eqfloat", Pfloatcomp Ceq; - "%noteqfloat", Pfloatcomp Cneq; - "%ltfloat", Pfloatcomp Clt; - "%lefloat", Pfloatcomp Cle; - "%gtfloat", Pfloatcomp Cgt; - "%gefloat", Pfloatcomp Cge; - "%string_length", Pstringlength; - "%string_safe_get", Pstringrefs; - "%string_safe_set", Pbytessets; - "%string_unsafe_get", Pstringrefu; - "%string_unsafe_set", Pbytessetu; - "%bytes_length", Pbyteslength; - "%bytes_safe_get", Pbytesrefs; - "%bytes_safe_set", Pbytessets; - "%bytes_unsafe_get", Pbytesrefu; - "%bytes_unsafe_set", Pbytessetu; - "%array_length", Parraylength gen_array_kind; - "%array_safe_get", Parrayrefs gen_array_kind; - "%array_safe_set", Parraysets gen_array_kind; - "%array_unsafe_get", Parrayrefu gen_array_kind; - "%array_unsafe_set", Parraysetu gen_array_kind; - "%obj_size", Parraylength gen_array_kind; - "%obj_field", Parrayrefu gen_array_kind; - "%obj_set_field", Parraysetu gen_array_kind; - "%floatarray_length", Parraylength Pfloatarray; - "%floatarray_safe_get", Parrayrefs Pfloatarray; - "%floatarray_safe_set", Parraysets Pfloatarray; - "%floatarray_unsafe_get", Parrayrefu Pfloatarray; - "%floatarray_unsafe_set", Parraysetu Pfloatarray; - "%obj_is_int", Pisint; - "%lazy_force", Plazyforce; - "%nativeint_of_int", Pbintofint Pnativeint; - "%nativeint_to_int", Pintofbint Pnativeint; - "%nativeint_neg", Pnegbint Pnativeint; - "%nativeint_add", Paddbint Pnativeint; - "%nativeint_sub", Psubbint Pnativeint; - "%nativeint_mul", Pmulbint Pnativeint; - "%nativeint_div", Pdivbint { size = Pnativeint; is_safe = Safe }; - "%nativeint_mod", Pmodbint { size = Pnativeint; is_safe = Safe }; - "%nativeint_and", Pandbint Pnativeint; - "%nativeint_or", Porbint Pnativeint; - "%nativeint_xor", Pxorbint Pnativeint; - "%nativeint_lsl", Plslbint Pnativeint; - "%nativeint_lsr", Plsrbint Pnativeint; - "%nativeint_asr", Pasrbint Pnativeint; - "%int32_of_int", Pbintofint Pint32; - "%int32_to_int", Pintofbint Pint32; - "%int32_neg", Pnegbint Pint32; - "%int32_add", Paddbint Pint32; - "%int32_sub", Psubbint Pint32; - "%int32_mul", Pmulbint Pint32; - "%int32_div", Pdivbint { size = Pint32; is_safe = Safe }; - "%int32_mod", Pmodbint { size = Pint32; is_safe = Safe }; - "%int32_and", Pandbint Pint32; - "%int32_or", Porbint Pint32; - "%int32_xor", Pxorbint Pint32; - "%int32_lsl", Plslbint Pint32; - "%int32_lsr", Plsrbint Pint32; - "%int32_asr", Pasrbint Pint32; - "%int64_of_int", Pbintofint Pint64; - "%int64_to_int", Pintofbint Pint64; - "%int64_neg", Pnegbint Pint64; - "%int64_add", Paddbint Pint64; - "%int64_sub", Psubbint Pint64; - "%int64_mul", Pmulbint Pint64; - "%int64_div", Pdivbint { size = Pint64; is_safe = Safe }; - "%int64_mod", Pmodbint { size = Pint64; is_safe = Safe }; - "%int64_and", Pandbint Pint64; - "%int64_or", Porbint Pint64; - "%int64_xor", Pxorbint Pint64; - "%int64_lsl", Plslbint Pint64; - "%int64_lsr", Plsrbint Pint64; - "%int64_asr", Pasrbint Pint64; - "%nativeint_of_int32", Pcvtbint(Pint32, Pnativeint); - "%nativeint_to_int32", Pcvtbint(Pnativeint, Pint32); - "%int64_of_int32", Pcvtbint(Pint32, Pint64); - "%int64_to_int32", Pcvtbint(Pint64, Pint32); - "%int64_of_nativeint", Pcvtbint(Pnativeint, Pint64); - "%int64_to_nativeint", Pcvtbint(Pint64, Pnativeint); - "%caml_ba_ref_1", - Pbigarrayref(false, 1, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_ref_2", - Pbigarrayref(false, 2, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_ref_3", - Pbigarrayref(false, 3, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_set_1", - Pbigarrayset(false, 1, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_set_2", - Pbigarrayset(false, 2, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_set_3", - Pbigarrayset(false, 3, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_ref_1", - Pbigarrayref(true, 1, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_ref_2", - Pbigarrayref(true, 2, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_ref_3", - Pbigarrayref(true, 3, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_set_1", - Pbigarrayset(true, 1, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_set_2", - Pbigarrayset(true, 2, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_unsafe_set_3", - Pbigarrayset(true, 3, Pbigarray_unknown, Pbigarray_unknown_layout); - "%caml_ba_dim_1", Pbigarraydim(1); - "%caml_ba_dim_2", Pbigarraydim(2); - "%caml_ba_dim_3", Pbigarraydim(3); - "%caml_string_get16", Pstring_load_16(false); - "%caml_string_get16u", Pstring_load_16(true); - "%caml_string_get32", Pstring_load_32(false); - "%caml_string_get32u", Pstring_load_32(true); - "%caml_string_get64", Pstring_load_64(false); - "%caml_string_get64u", Pstring_load_64(true); - "%caml_string_set16", Pstring_set_16(false); - "%caml_string_set16u", Pstring_set_16(true); - "%caml_string_set32", Pstring_set_32(false); - "%caml_string_set32u", Pstring_set_32(true); - "%caml_string_set64", Pstring_set_64(false); - "%caml_string_set64u", Pstring_set_64(true); - "%caml_bigstring_get16", Pbigstring_load_16(false); - "%caml_bigstring_get16u", Pbigstring_load_16(true); - "%caml_bigstring_get32", Pbigstring_load_32(false); - "%caml_bigstring_get32u", Pbigstring_load_32(true); - "%caml_bigstring_get64", Pbigstring_load_64(false); - "%caml_bigstring_get64u", Pbigstring_load_64(true); - "%caml_bigstring_set16", Pbigstring_set_16(false); - "%caml_bigstring_set16u", Pbigstring_set_16(true); - "%caml_bigstring_set32", Pbigstring_set_32(false); - "%caml_bigstring_set32u", Pbigstring_set_32(true); - "%caml_bigstring_set64", Pbigstring_set_64(false); - "%caml_bigstring_set64u", Pbigstring_set_64(true); - "%bswap16", Pbswap16; - "%bswap_int32", Pbbswap(Pint32); - "%bswap_int64", Pbbswap(Pint64); - "%bswap_native", Pbbswap(Pnativeint); - "%int_as_pointer", Pint_as_pointer; - "%opaque", Popaque; -] - -let find_primitive prim_name = - Hashtbl.find primitives_table prim_name - -let prim_restore_raw_backtrace = - Primitive.simple ~name:"caml_restore_raw_backtrace" ~arity:2 ~alloc:false - -let specialize_comparison table env ty = - let (gencomp, intcomp, floatcomp, stringcomp, bytescomp, - nativeintcomp, int32comp, int64comp, _) = table in - match () with - | () when is_base_type env ty Predef.path_int - || is_base_type env ty Predef.path_char - || (maybe_pointer_type env ty = Immediate) -> intcomp - | () when is_base_type env ty Predef.path_float -> floatcomp - | () when is_base_type env ty Predef.path_string -> stringcomp - | () when is_base_type env ty Predef.path_bytes -> bytescomp - | () when is_base_type env ty Predef.path_nativeint -> nativeintcomp - | () when is_base_type env ty Predef.path_int32 -> int32comp - | () when is_base_type env ty Predef.path_int64 -> int64comp - | () -> gencomp - -(* The following function computes the greatest lower bound in the - semilattice of array kinds: - gen - / \ - addr float - | - int - Note that the GLB is not guaranteed to exist, in which case we return - our first argument instead of raising a fatal error because, although - it cannot happen in a well-typed program, (ab)use of Obj.magic can - probably trigger it. -*) -let glb_array_type t1 t2 = - match t1, t2 with - | Pfloatarray, (Paddrarray | Pintarray) - | (Paddrarray | Pintarray), Pfloatarray -> t1 - - | Pgenarray, x | x, Pgenarray -> x - | Paddrarray, x | x, Paddrarray -> x - | Pintarray, Pintarray -> Pintarray - | Pfloatarray, Pfloatarray -> Pfloatarray - -(* Specialize a primitive from available type information, - raise Not_found if primitive is unknown *) - -let specialize_primitive p env ty ~has_constant_constructor = - try - let table = Hashtbl.find comparisons_table p.prim_name in - let (gencomp, intcomp, _, _, _, _, _, _, simplify_constant_constructor) = - table in - if has_constant_constructor && simplify_constant_constructor then - intcomp - else - match is_function_type env ty with - | Some (lhs,_rhs) -> specialize_comparison table env lhs - | None -> gencomp - with Not_found -> - let p = find_primitive p.prim_name in - (* Try strength reduction based on the type of the argument *) - let params = match is_function_type env ty with - | None -> [] - | Some (p1, rhs) -> match is_function_type env rhs with - | None -> [p1] - | Some (p2, _) -> [p1;p2] - in - match (p, params) with - (Psetfield(n, _, init), [_p1; p2]) -> - Psetfield(n, maybe_pointer_type env p2, init) - | (Parraylength t, [p]) -> - Parraylength(glb_array_type t (array_type_kind env p)) - | (Parrayrefu t, p1 :: _) -> - Parrayrefu(glb_array_type t (array_type_kind env p1)) - | (Parraysetu t, p1 :: _) -> - Parraysetu(glb_array_type t (array_type_kind env p1)) - | (Parrayrefs t, p1 :: _) -> - Parrayrefs(glb_array_type t (array_type_kind env p1)) - | (Parraysets t, p1 :: _) -> - Parraysets(glb_array_type t (array_type_kind env p1)) - | (Pbigarrayref(unsafe, n, Pbigarray_unknown, Pbigarray_unknown_layout), - p1 :: _) -> - let (k, l) = bigarray_type_kind_and_layout env p1 in - Pbigarrayref(unsafe, n, k, l) - | (Pbigarrayset(unsafe, n, Pbigarray_unknown, Pbigarray_unknown_layout), - p1 :: _) -> - let (k, l) = bigarray_type_kind_and_layout env p1 in - Pbigarrayset(unsafe, n, k, l) - | (Pmakeblock(tag, mut, None), fields) -> - let shape = List.map (Typeopt.value_kind env) fields in - Pmakeblock(tag, mut, Some shape) - | _ -> p - -(* Eta-expand a primitive *) - -let used_primitives = Hashtbl.create 7 -let add_used_primitive loc env path = - match path with - Some (Path.Pdot _ as path) -> - let path = Env.normalize_path (Some loc) env path in - let unit = Path.head path in - if Ident.global unit && not (Hashtbl.mem used_primitives path) - then Hashtbl.add used_primitives path loc - | _ -> () - -let transl_primitive loc p env ty path = - let prim = - try specialize_primitive p env ty ~has_constant_constructor:false - with Not_found -> - add_used_primitive loc env path; - Pccall p - in - match prim with - | Plazyforce -> - let parm = Ident.create "prim" in - Lfunction{kind = Curried; params = [parm]; - body = Matching.inline_lazy_force (Lvar parm) Location.none; - loc = loc; - attr = default_stub_attribute } - | Ploc kind -> - let lam = lam_of_loc kind loc in - begin match p.prim_arity with - | 0 -> lam - | 1 -> (* TODO: we should issue a warning ? *) - let param = Ident.create "prim" in - Lfunction{kind = Curried; params = [param]; - attr = default_stub_attribute; - loc = loc; - body = Lprim(Pmakeblock(0, Immutable, None), - [lam; Lvar param], loc)} - | _ -> assert false - end - | _ -> - let rec make_params n = - if n <= 0 then [] else Ident.create "prim" :: make_params (n-1) in - let params = make_params p.prim_arity in - Lfunction{ kind = Curried; params; - attr = default_stub_attribute; - loc = loc; - body = Lprim(prim, List.map (fun id -> Lvar id) params, loc) } - -let transl_primitive_application loc prim env ty path args = - let prim_name = prim.prim_name in - try - let has_constant_constructor = match args with - [_; {exp_desc = Texp_construct(_, {cstr_tag = Cstr_constant _}, _)}] - | [{exp_desc = Texp_construct(_, {cstr_tag = Cstr_constant _}, _)}; _] - | [_; {exp_desc = Texp_variant(_, None)}] - | [{exp_desc = Texp_variant(_, None)}; _] -> true - | _ -> false - in - specialize_primitive prim env ty ~has_constant_constructor - with Not_found -> - if String.length prim_name > 0 && prim_name.[0] = '%' then - raise(Error(loc, Unknown_builtin_primitive prim_name)); - add_used_primitive loc env path; - Pccall prim - (* To propagate structured constants *) exception Not_constant @@ -596,23 +143,9 @@ let rec push_defaults loc bindings cases partial = (* Insertion of debugging events *) -let event_before exp lam = match lam with -| Lstaticraise (_,_) -> lam -| _ -> - if !Clflags.debug && not !Clflags.native_code - then Levent(lam, {lev_loc = exp.exp_loc; - lev_kind = Lev_before; - lev_repr = None; - lev_env = Env.summary exp.exp_env}) - else lam +let event_before = Translprim.event_before -let event_after exp lam = - if !Clflags.debug && not !Clflags.native_code - then Levent(lam, {lev_loc = exp.exp_loc; - lev_kind = Lev_after exp.exp_type; - lev_repr = None; - lev_env = Env.summary exp.exp_env}) - else lam +let event_after = Translprim.event_after let event_function exp lam = if !Clflags.debug && not !Clflags.native_code then @@ -626,14 +159,6 @@ let event_function exp lam = else lam None -let primitive_is_ccall = function - (* Determine if a primitive is a Pccall or will be turned later into - a C function call that may raise an exception *) - | Pccall _ | Pstringrefs | Pbytesrefs | Pbytessets | Parrayrefs _ | - Parraysets _ | Pbigarrayref _ | Pbigarrayset _ | Pduprecord _ | Pdirapply | - Prevapply -> true - | _ -> false - (* Assertions *) let assert_failed exp = @@ -655,8 +180,6 @@ let rec cut n l = (* Translation of expressions *) -let try_ids = Hashtbl.create 8 - let rec transl_exp e = List.iter (Translattribute.check_attribute e) e.exp_attributes; let eval_once = @@ -670,25 +193,8 @@ let rec transl_exp e = and transl_exp0 e = match e.exp_desc with - Texp_ident(path, _, {val_kind = Val_prim p}) -> - let public_send = p.prim_name = "%send" in - if public_send || p.prim_name = "%sendself" then - let kind = if public_send then Public else Self in - let obj = Ident.create "obj" and meth = Ident.create "meth" in - Lfunction{kind = Curried; params = [obj; meth]; - attr = default_stub_attribute; - loc = e.exp_loc; - body = Lsend(kind, Lvar meth, Lvar obj, [], e.exp_loc)} - else if p.prim_name = "%sendcache" then - let obj = Ident.create "obj" and meth = Ident.create "meth" in - let cache = Ident.create "cache" and pos = Ident.create "pos" in - Lfunction{kind = Curried; params = [obj; meth; cache; pos]; - attr = default_stub_attribute; - loc = e.exp_loc; - body = Lsend(Cached, Lvar meth, Lvar obj, - [Lvar cache; Lvar pos], e.exp_loc)} - else - transl_primitive e.exp_loc p e.exp_env e.exp_type (Some path) + | Texp_ident(path, _, {val_kind = Val_prim p}) -> + Translprim.transl_primitive e.exp_loc p e.exp_env e.exp_type (Some path) | Texp_ident(_, _, {val_kind = Val_anc _}) -> raise(Error(e.exp_loc, Free_super_var)) | Texp_ident(path, _, {val_kind = Val_reg | Val_self _}) -> @@ -718,89 +224,32 @@ and transl_exp0 e = exp_type = prim_type } as funct, oargs) when List.length oargs >= p.prim_arity && List.for_all (fun (_, arg) -> arg <> None) oargs -> - let args, args' = cut p.prim_arity oargs in - let wrap f = - if args' = [] - then event_after e f - else - let should_be_tailcall, funct = - Translattribute.get_tailcall_attribute funct - in - let inlined, funct = - Translattribute.get_and_remove_inlined_attribute funct - in - let specialised, funct = - Translattribute.get_and_remove_specialised_attribute funct - in - let e = { e with exp_desc = Texp_apply(funct, oargs) } in - event_after e - (transl_apply ~should_be_tailcall ~inlined ~specialised - f args' e.exp_loc) + let argl, extra_args = cut p.prim_arity oargs in + let arg_exps = + List.map (function _, Some x -> x | _ -> assert false) argl in - let wrap0 f = - if args' = [] then f else wrap f in - let args = - List.map (function _, Some x -> x | _ -> assert false) args in - let argl = transl_list args in - let public_send = p.prim_name = "%send" - || not !Clflags.native_code && p.prim_name = "%sendcache"in - if public_send || p.prim_name = "%sendself" then - let kind = if public_send then Public else Self in - let obj = List.hd argl in - wrap (Lsend (kind, List.nth argl 1, obj, [], e.exp_loc)) - else if p.prim_name = "%sendcache" then - match argl with [obj; meth; cache; pos] -> - wrap (Lsend(Cached, meth, obj, [cache; pos], e.exp_loc)) - | _ -> assert false - else if p.prim_name = "%raise_with_backtrace" then begin - let texn1 = List.hd args (* Should not fail by typing *) in - let texn2,bt = match argl with - | [a;b] -> a,b - | _ -> assert false (* idem *) - in - let vexn = Ident.create "exn" in - Llet(Strict, Pgenval, vexn, texn2, - event_before e begin - Lsequence( - wrap (Lprim (Pccall prim_restore_raw_backtrace, - [Lvar vexn;bt], - e.exp_loc)), - wrap0 (Lprim(Praise Raise_reraise, - [event_after texn1 (Lvar vexn)], - e.exp_loc)) - ) - end - ) - end + let args = transl_list arg_exps in + let prim_exp = if extra_args = [] then Some e else None in + let lam = + Translprim.transl_primitive_application + e.exp_loc p e.exp_env prim_type path + prim_exp args arg_exps + in + if extra_args = [] then lam else begin - let prim = transl_primitive_application - e.exp_loc p e.exp_env prim_type (Some path) args in - match (prim, args) with - (Praise k, [arg1]) -> - let targ = List.hd argl in - let k = - match k, targ with - | Raise_regular, Lvar id - when Hashtbl.mem try_ids id -> - Raise_reraise - | _ -> - k - in - wrap0 (Lprim(Praise k, [event_after arg1 targ], e.exp_loc)) - | (Ploc kind, []) -> - lam_of_loc kind e.exp_loc - | (Ploc kind, [arg1]) -> - let lam = lam_of_loc kind arg1.exp_loc in - Lprim(Pmakeblock(0, Immutable, None), lam :: argl, e.exp_loc) - | (Ploc _, _) -> assert false - | (_, _) -> - begin match (prim, argl) with - | (Plazyforce, [a]) -> - wrap (Matching.inline_lazy_force a e.exp_loc) - | (Plazyforce, _) -> assert false - |_ -> let p = Lprim(prim, argl, e.exp_loc) in - if primitive_is_ccall prim then wrap p else wrap0 p - end + let should_be_tailcall, funct = + Translattribute.get_tailcall_attribute funct + in + let inlined, funct = + Translattribute.get_and_remove_inlined_attribute funct + in + let specialised, funct = + Translattribute.get_and_remove_specialised_attribute funct + in + let e = { e with exp_desc = Texp_apply(funct, oargs) } in + event_after e + (transl_apply ~should_be_tailcall ~inlined ~specialised + lam extra_args e.exp_loc) end | Texp_apply(funct, oargs) -> let should_be_tailcall, funct = @@ -1019,11 +468,13 @@ and transl_exp0 e = do *) begin match Typeopt.classify_lazy_argument e with | `Constant_or_function -> - (* a constant expr of type <> float gets compiled as itself *) + (* A constant expr (of type <> float if [Config.flat_float_array] is + true) gets compiled as itself. *) transl_exp e - | `Float -> + | `Float_that_cannot_be_shortcut -> (* We don't need to wrap with Popaque: this forward - block will never be shortcutted since it points to a float. *) + block will never be shortcutted since it points to a float + and Config.flat_float_array is true. *) Lprim(Pmakeblock(Obj.forward_tag, Immutable, None), [transl_exp e], e.exp_loc) | `Identifier `Forward_value -> @@ -1086,15 +537,19 @@ and transl_cases cases = List.map transl_case cases and transl_case_try {c_lhs; c_guard; c_rhs} = - match c_lhs.pat_desc with - | Tpat_var (id, _) - | Tpat_alias (_, id, _) -> - Hashtbl.replace try_ids id (); - Misc.try_finally - (fun () -> c_lhs, transl_guard c_guard c_rhs) - (fun () -> Hashtbl.remove try_ids id) - | _ -> - c_lhs, transl_guard c_guard c_rhs + let rec iter_exn_names f pat = + match pat.pat_desc with + | Tpat_var (id, _) -> f id + | Tpat_alias (p, id, _) -> + f id; + iter_exn_names f p + | _ -> () + in + iter_exn_names Translprim.add_exception_ident c_lhs; + Misc.try_finally + (fun () -> c_lhs, transl_guard c_guard c_rhs) + (fun () -> + iter_exn_names Translprim.remove_exception_ident c_lhs) and transl_cases_try cases = let cases = @@ -1203,12 +658,18 @@ and transl_function loc untuplify_fn repr partial param cases = Matching.for_function loc repr (Lvar param) (transl_cases cases) partial) -and transl_let rec_flag pat_expr_list body = +(* + Notice: transl_let consumes (ie compiles) its pat_expr_list argument, + and returns a function that will take the body of the lambda-let construct. + This complication allows choosing any compilation order for the + bindings and body of let constructs. +*) +and transl_let rec_flag pat_expr_list = match rec_flag with Nonrecursive -> let rec transl = function [] -> - body + fun body -> body | {vb_pat=pat; vb_expr=expr; vb_attributes=attr; vb_loc} :: rem -> let lam = transl_exp expr in let lam = @@ -1217,7 +678,8 @@ and transl_let rec_flag pat_expr_list body = let lam = Translattribute.add_specialise_attribute lam vb_loc attr in - Matching.for_let pat.pat_loc lam pat (transl rem) + let mk_body = transl rem in + fun body -> Matching.for_let pat.pat_loc lam pat (mk_body body) in transl pat_expr_list | Recursive -> let idlist = @@ -1238,7 +700,8 @@ and transl_let rec_flag pat_expr_list body = vb_attributes in (id, lam) in - Lletrec(List.map2 transl_case pat_expr_list idlist, body) + let lam_bds = List.map2 transl_case pat_expr_list idlist in + fun body -> Lletrec(lam_bds, body) and transl_setinstvar loc self var expr = Lprim(Psetfield_computed (maybe_pointer expr, Assignment), @@ -1347,7 +810,7 @@ and transl_match e arg pat_expr_list exn_pat_expr_list partial = and cases = transl_cases pat_expr_list and exn_cases = transl_cases_try exn_pat_expr_list in let static_catch body val_ids handler = - let static_exception_id = next_negative_raise_count () in + let static_exception_id = next_raise_count () in Lstaticcatch (Ltrywith (Lstaticraise (static_exception_id, body), id, Matching.for_trywith (Lvar id) exn_cases), @@ -1391,8 +854,6 @@ let report_error ppf = function | Free_super_var -> fprintf ppf "Ancestor names can only be used to select inherited methods" - | Unknown_builtin_primitive prim_name -> - fprintf ppf "Unknown builtin primitive \"%s\"" prim_name | Unreachable_reached -> fprintf ppf "Unreachable expression was reached" diff --git a/bytecomp/translcore.mli b/bytecomp/translcore.mli index 75c26f8d..e27eb20a 100644 --- a/bytecomp/translcore.mli +++ b/bytecomp/translcore.mli @@ -27,17 +27,12 @@ val transl_apply: ?should_be_tailcall:bool -> lambda -> (arg_label * expression option) list -> Location.t -> lambda val transl_let: rec_flag -> value_binding list -> lambda -> lambda -val transl_primitive: Location.t -> Primitive.description -> Env.t - -> Types.type_expr -> Path.t option -> lambda val transl_extension_constructor: Env.t -> Path.t option -> extension_constructor -> lambda -val used_primitives: (Path.t, Location.t) Hashtbl.t - type error = Free_super_var - | Unknown_builtin_primitive of string | Unreachable_reached exception Error of Location.t * error diff --git a/bytecomp/translmod.ml b/bytecomp/translmod.ml index 31557eed..63cdf699 100644 --- a/bytecomp/translmod.ml +++ b/bytecomp/translmod.ml @@ -28,7 +28,7 @@ open Translcore open Translclass type error = - Circular_dependency of Ident.t + Circular_dependency of Ident.t list | Conflicting_inline_attributes exception Error of Location.t * error @@ -78,7 +78,7 @@ let rec apply_coercion loc strict restr arg = let carg = apply_coercion loc Alias cc_arg (Lvar param) in apply_coercion_result loc strict arg [param] [carg] cc_res | Tcoerce_primitive { pc_loc; pc_desc; pc_env; pc_type; } -> - transl_primitive pc_loc pc_desc pc_env pc_type None + Translprim.transl_primitive pc_loc pc_desc pc_env pc_type None | Tcoerce_alias (path, cc) -> name_lambda strict arg (fun _ -> apply_coercion loc Alias cc (transl_normal_path path)) @@ -112,19 +112,19 @@ and apply_coercion_result loc strict funct params args cc_res = and wrap_id_pos_list loc id_pos_list get_field lam = let fv = free_variables lam in (*Format.eprintf "%a@." Printlambda.lambda lam; - IdentSet.iter (fun id -> Format.eprintf "%a " Ident.print id) fv; + Ident.Set.iter (fun id -> Format.eprintf "%a " Ident.print id) fv; Format.eprintf "@.";*) let (lam,s) = List.fold_left (fun (lam,s) (id',pos,c) -> - if IdentSet.mem id' fv then + if Ident.Set.mem id' fv then let id'' = Ident.create (Ident.name id') in (Llet(Alias, Pgenval, id'', apply_coercion loc Alias c (get_field pos),lam), - Ident.add id' (Lvar id'') s) + Ident.Map.add id' (Lvar id'') s) else (lam,s)) - (lam, Ident.empty) id_pos_list + (lam, Ident.Map.empty) id_pos_list in - if s == Ident.empty then lam else subst_lambda s lam + if s == Ident.Map.empty then lam else Lambda.subst s lam (* Compose two coercions @@ -199,9 +199,10 @@ let undefined_location loc = let init_shape modl = let rec init_shape_mod env mty = match Mtype.scrape env mty with - Mty_ident _ -> + Mty_ident _ + | Mty_alias (Mta_present, _) -> raise Not_found - | Mty_alias _ -> + | Mty_alias (Mta_absent, _) -> Const_block (1, [Const_pointer 0]) | Mty_signature sg -> Const_block(0, [Const_block(0, init_shape_struct env sg)]) @@ -247,7 +248,20 @@ let init_shape modl = (* Reorder bindings to honor dependencies. *) -type binding_status = Undefined | Inprogress | Defined +type binding_status = + | Undefined + | Inprogress of int option (** parent node *) + | Defined + +let extract_unsafe_cycle id status cycle_start = + let rec collect stop l i = match status.(i) with + | Inprogress None | Undefined | Defined -> assert false + | Inprogress Some i when i = stop -> id.(i) :: l + | Inprogress Some i -> collect stop (id.(i)::l) i in + collect cycle_start [id.(cycle_start)] cycle_start +(* This yields [cycle_start; ...; cycle_start]. The start of the cycle + is duplicated to make the cycle more visible in the corresponding error + message. *) let reorder_rec_bindings bindings = let id = Array.of_list (List.map (fun (id,_,_,_) -> id) bindings) @@ -258,23 +272,26 @@ let reorder_rec_bindings bindings = let num_bindings = Array.length id in let status = Array.make num_bindings Undefined in let res = ref [] in - let rec emit_binding i = + let rec emit_binding parent i = match status.(i) with Defined -> () - | Inprogress -> raise(Error(loc.(i), Circular_dependency id.(i))) + | Inprogress _ -> + status.(i) <- Inprogress parent; + let cycle = extract_unsafe_cycle id status i in + raise(Error(loc.(i), Circular_dependency cycle)) | Undefined -> if init.(i) = None then begin - status.(i) <- Inprogress; + status.(i) <- Inprogress parent; for j = 0 to num_bindings - 1 do - if IdentSet.mem id.(j) fv.(i) then emit_binding j + if Ident.Set.mem id.(j) fv.(i) then emit_binding (Some i) j done end; res := (id.(i), init.(i), rhs.(i)) :: !res; status.(i) <- Defined in for i = 0 to num_bindings - 1 do match status.(i) with - Undefined -> emit_binding i - | Inprogress -> assert false + Undefined -> emit_binding None i + | Inprogress _ -> assert false | Defined -> () done; List.rev !res @@ -456,6 +473,9 @@ and transl_module cc rootpath mexp = and transl_struct loc fields cc rootpath str = transl_structure loc fields cc rootpath str.str_final_env str.str_items +(* The function transl_structure is called by the bytecode compiler. + Some effort is made to compile in top to bottom order, in order to display + warning by increasing locations. *) and transl_structure loc fields cc rootpath final_env = function [] -> let body, size = @@ -472,19 +492,19 @@ and transl_structure loc fields cc rootpath final_env = function Format.eprintf "@]@.";*) let v = Array.of_list (List.rev fields) in let get_field pos = Lvar v.(pos) - and ids = List.fold_right IdentSet.add fields IdentSet.empty in + and ids = List.fold_right Ident.Set.add fields Ident.Set.empty in let lam = Lprim(Pmakeblock(0, Immutable, None), List.map (fun (pos, cc) -> match cc with Tcoerce_primitive p -> - transl_primitive p.pc_loc + Translprim.transl_primitive p.pc_loc p.pc_desc p.pc_env p.pc_type None | _ -> apply_coercion loc Strict cc (get_field pos)) pos_cc_list, loc) and id_pos_list = - List.filter (fun (id,_,_) -> not (IdentSet.mem id ids)) + List.filter (fun (id,_,_) -> not (Ident.Set.mem id ids)) id_pos_list in wrap_id_pos_list loc id_pos_list get_field lam, @@ -512,11 +532,14 @@ and transl_structure loc fields cc rootpath final_env = function in Lsequence(transl_exp expr, body), size | Tstr_value(rec_flag, pat_expr_list) -> + (* Translate bindings first *) + let mk_lam_let = transl_let rec_flag pat_expr_list in let ext_fields = rev_let_bound_idents pat_expr_list @ fields in + (* Then, translate remainder of struct *) let body, size = transl_structure loc ext_fields cc rootpath final_env rem in - transl_let rec_flag pat_expr_list body, size + mk_lam_let body, size | Tstr_primitive descr -> record_primitive descr.val_val; transl_structure loc fields cc rootpath final_env rem @@ -540,9 +563,7 @@ and transl_structure loc fields cc rootpath final_env = function size | Tstr_module mb -> let id = mb.mb_id in - let body, size = - transl_structure loc (id :: fields) cc rootpath final_env rem - in + (* Translate module first *) let module_body = transl_module Tcoerce_none (field_path rootpath id) mb.mb_expr in @@ -550,6 +571,10 @@ and transl_structure loc fields cc rootpath final_env = function Translattribute.add_inline_attribute module_body mb.mb_loc mb.mb_attributes in + (* Translate remainder second *) + let body, size = + transl_structure loc (id :: fields) cc rootpath final_env rem + in let module_body = Levent (module_body, { lev_loc = mb.mb_loc; @@ -632,7 +657,7 @@ let _ = let scan_used_globals lam = let globals = ref Ident.Set.empty in let rec scan lam = - Lambda.iter scan lam; + Lambda.iter_head_constructor scan lam; match lam with Lprim ((Pgetglobal id | Psetglobal id), _, _) -> globals := Ident.Set.add id !globals @@ -649,15 +674,16 @@ let required_globals ~flambda body = Ident.Set.add id req in let required = - Hashtbl.fold - (fun path _ -> add_global (Path.head path)) used_primitives + List.fold_left + (fun acc path -> add_global (Path.head path) acc) (if flambda then globals else Ident.Set.empty) + (Translprim.get_used_primitives ()) in let required = List.fold_right add_global (Env.get_required_globals ()) required in Env.reset_required_globals (); - Hashtbl.clear used_primitives; + Translprim.clear_used_primitives (); required (* Compile an implementation *) @@ -665,7 +691,7 @@ let required_globals ~flambda body = let transl_implementation_flambda module_name (str, cc) = reset_labels (); primitive_declarations := []; - Hashtbl.clear used_primitives; + Translprim.clear_used_primitives (); let module_id = Ident.create_persistent module_name in let body, size = Translobj.transl_label_init @@ -792,12 +818,12 @@ and all_idents = function "map" is a table from defined idents to (pos in global block, coercion). "prim" is a list of (pos in global block, primitive declaration). *) -let transl_store_subst = ref Ident.empty +let transl_store_subst = ref Ident.Map.empty (** In the native toplevel, this reference is threaded through successive calls of transl_store_structure *) let nat_toplevel_name id = - try match Ident.find_same id !transl_store_subst with + try match Ident.Map.find id !transl_store_subst with | Lprim(Pfield pos, [Lprim(Pgetglobal glob, [], _)], _) -> (glob,pos) | _ -> raise Not_found with Not_found -> @@ -808,7 +834,7 @@ let field_of_str loc str = fun (pos, cc) -> match cc with | Tcoerce_primitive { pc_loc; pc_desc; pc_env; pc_type; } -> - transl_primitive pc_loc pc_desc pc_env pc_type None + Translprim.transl_primitive pc_loc pc_desc pc_env pc_type None | _ -> apply_coercion loc Strict cc (Lvar ids.(pos)) @@ -820,14 +846,14 @@ let transl_store_structure glob map prims str = | item :: rem -> match item.str_desc with | Tstr_eval (expr, _attrs) -> - Lsequence(subst_lambda subst (transl_exp expr), + Lsequence(Lambda.subst subst (transl_exp expr), transl_store rootpath subst rem) | Tstr_value(rec_flag, pat_expr_list) -> let ids = let_bound_idents pat_expr_list in let lam = transl_let rec_flag pat_expr_list (store_idents Location.none ids) in - Lsequence(subst_lambda subst lam, + Lsequence(Lambda.subst subst lam, transl_store rootpath (add_idents false ids subst) rem) | Tstr_primitive descr -> record_primitive descr.val_val; @@ -842,13 +868,13 @@ let transl_store_structure glob map prims str = transl_type_extension item.str_env rootpath tyext (store_idents Location.none ids) in - Lsequence(subst_lambda subst lam, + Lsequence(Lambda.subst subst lam, transl_store rootpath (add_idents false ids subst) rem) | Tstr_exception ext -> let id = ext.ext_id in let path = field_path rootpath id in let lam = transl_extension_constructor item.str_env path ext in - Lsequence(Llet(Strict, Pgenval, id, subst_lambda subst lam, + Lsequence(Llet(Strict, Pgenval, id, Lambda.subst subst lam, store_ident ext.ext_loc id), transl_store rootpath (add_ident false id subst) rem) | Tstr_module{mb_id=id;mb_loc=loc; @@ -863,7 +889,7 @@ let transl_store_structure glob map prims str = let subst = !transl_store_subst in Lsequence(lam, Llet(Strict, Pgenval, id, - subst_lambda subst + Lambda.subst subst (Lprim(Pmakeblock(0, Immutable, None), List.map (fun id -> Lvar id) (defined_idents str.str_items), loc)), @@ -891,7 +917,7 @@ let transl_store_structure glob map prims str = let field = field_of_str loc str in Lsequence(lam, Llet(Strict, Pgenval, id, - subst_lambda subst + Lambda.subst subst (Lprim(Pmakeblock(0, Immutable, None), List.map field map, loc)), Lsequence(store_ident loc id, @@ -910,14 +936,14 @@ let transl_store_structure glob map prims str = the compilation unit (add_ident true returns subst unchanged). If not, we can use the value from the global (add_ident true adds id -> Pgetglobal... to subst). *) - Llet(Strict, Pgenval, id, subst_lambda subst lam, + Llet(Strict, Pgenval, id, Lambda.subst subst lam, Lsequence(store_ident loc id, transl_store rootpath (add_ident true id subst) rem)) | Tstr_recmodule bindings -> let ids = List.map (fun mb -> mb.mb_id) bindings in compile_recmodule (fun id modl _loc -> - subst_lambda subst + Lambda.subst subst (transl_module Tcoerce_none (field_path rootpath id) modl)) bindings @@ -928,7 +954,7 @@ let transl_store_structure glob map prims str = let lam = Lletrec(class_bindings, store_idents Location.none ids) in - Lsequence(subst_lambda subst lam, + Lsequence(Lambda.subst subst lam, transl_store rootpath (add_idents false ids subst) rem) | Tstr_include{ @@ -959,7 +985,7 @@ let transl_store_structure glob map prims str = | [], [] -> transl_store rootpath (add_idents true ids0 subst) rem | id :: ids, arg :: args -> - Llet(Alias, Pgenval, id, subst_lambda subst (field arg), + Llet(Alias, Pgenval, id, Lambda.subst subst (field arg), Lsequence(store_ident loc id, loop ids args)) | _ -> assert false @@ -980,7 +1006,7 @@ let transl_store_structure glob map prims str = store_idents (pos + 1) idl)) in Llet(Strict, Pgenval, mid, - subst_lambda subst (transl_module Tcoerce_none None modl), + Lambda.subst subst (transl_module Tcoerce_none None modl), store_idents 0 ids) | Tstr_modtype _ | Tstr_open _ @@ -1006,7 +1032,7 @@ let transl_store_structure glob map prims str = let (pos, cc) = Ident.find_same id map in match cc with Tcoerce_none -> - Ident.add id + Ident.Map.add id (Lprim(Pfield pos, [Lprim(Pgetglobal glob, [], Location.none)], Location.none)) @@ -1022,7 +1048,7 @@ let transl_store_structure glob map prims str = and store_primitive (pos, prim) cont = Lsequence(Lprim(Psetfield(pos, Pointer, Root_initialization), [Lprim(Pgetglobal glob, [], Location.none); - transl_primitive Location.none + Translprim.transl_primitive Location.none prim.pc_desc prim.pc_env prim.pc_type None], Location.none), cont) @@ -1076,14 +1102,14 @@ let build_ident_map restr idlist more_ids = let transl_store_gen module_name ({ str_items = str }, restr) topl = reset_labels (); primitive_declarations := []; - Hashtbl.clear used_primitives; + Translprim.clear_used_primitives (); let module_id = Ident.create_persistent module_name in let (map, prims, size) = build_ident_map restr (defined_idents str) (more_idents str) in let f = function | [ { str_desc = Tstr_eval (expr, _attrs) } ] when topl -> assert (size = 0); - subst_lambda !transl_store_subst (transl_exp expr) + Lambda.subst !transl_store_subst (transl_exp expr) | str -> transl_store_structure module_id map prims str in transl_store_label_init module_id size f str (*size, transl_label_init (transl_store_structure module_id map prims str)*) @@ -1093,7 +1119,7 @@ let transl_store_phrases module_name str = let transl_store_implementation module_name (str, restr) = let s = !transl_store_subst in - transl_store_subst := Ident.empty; + transl_store_subst := Ident.Map.empty; let (i, code) = transl_store_gen module_name (str, restr) false in transl_store_subst := s; { Lambda.main_module_block_size = i; @@ -1143,7 +1169,7 @@ let toploop_setvalue id lam = let toploop_setvalue_id id = toploop_setvalue id (Lvar id) let close_toplevel_term (lam, ()) = - IdentSet.fold (fun id l -> Llet(Strict, Pgenval, id, + Ident.Set.fold (fun id l -> Llet(Strict, Pgenval, id, toploop_getvalue id, l)) (free_variables lam) lam @@ -1219,7 +1245,7 @@ let transl_toplevel_item_and_close itm = let transl_toplevel_definition str = reset_labels (); - Hashtbl.clear used_primitives; + Translprim.clear_used_primitives (); make_sequence transl_toplevel_item_and_close str.str_items (* Compile the initialization code for a packed library *) @@ -1315,12 +1341,18 @@ let transl_store_package component_names target_name coercion = open Format +let print_cycle ppf = + Format.pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf "@ -> ") + Printtyp.ident ppf + let report_error ppf = function - Circular_dependency id -> + Circular_dependency cycle -> + let[@manual.ref "s-recursive-modules"] chapter, section = 8, 4 in fprintf ppf - "@[Cannot safely evaluate the definition@ \ - of the recursively-defined module %a@]" - Printtyp.ident id + "@[Cannot safely evaluate the definition of the following cycle@ \ + of recursively-defined modules:@ %a.@ \ + There are no safe modules in this cycle@ (see manual section %d.%d)@]" + print_cycle cycle chapter section | Conflicting_inline_attributes -> fprintf ppf "@[Conflicting ``inline'' attributes@]" @@ -1336,8 +1368,7 @@ let () = let reset () = primitive_declarations := []; - transl_store_subst := Ident.empty; - toploop_ident.Ident.flags <- 0; + transl_store_subst := Ident.Map.empty; aliased_idents := Ident.empty; Env.reset_required_globals (); - Hashtbl.clear used_primitives + Translprim.clear_used_primitives () diff --git a/bytecomp/translmod.mli b/bytecomp/translmod.mli index 1b86328d..3098e543 100644 --- a/bytecomp/translmod.mli +++ b/bytecomp/translmod.mli @@ -43,7 +43,7 @@ val nat_toplevel_name: Ident.t -> Ident.t * int val primitive_declarations: Primitive.description list ref type error = - Circular_dependency of Ident.t + Circular_dependency of Ident.t list | Conflicting_inline_attributes exception Error of Location.t * error diff --git a/bytecomp/translobj.ml b/bytecomp/translobj.ml index c3dd9793..dd55acf3 100644 --- a/bytecomp/translobj.ml +++ b/bytecomp/translobj.ml @@ -162,7 +162,7 @@ let transl_label_init f = let wrapping = ref false let top_env = ref Env.empty let classes = ref [] -let method_ids = ref IdentSet.empty +let method_ids = ref Ident.Set.empty let oo_add_class id = classes := id :: !classes; @@ -178,7 +178,7 @@ let oo_wrap env req f x = cache_required := req; top_env := env; classes := []; - method_ids := IdentSet.empty; + method_ids := Ident.Set.empty; let lambda = f x in let lambda = List.fold_left @@ -207,4 +207,4 @@ let reset () = wrapping := false; top_env := Env.empty; classes := []; - method_ids := IdentSet.empty + method_ids := Ident.Set.empty diff --git a/bytecomp/translobj.mli b/bytecomp/translobj.mli index d7426241..c27053e9 100644 --- a/bytecomp/translobj.mli +++ b/bytecomp/translobj.mli @@ -25,7 +25,7 @@ val transl_label_init: (unit -> lambda * 'a) -> lambda * 'a val transl_store_label_init: Ident.t -> int -> ('a -> lambda) -> 'a -> int * lambda -val method_ids: IdentSet.t ref (* reset when starting a new wrapper *) +val method_ids: Ident.Set.t ref (* reset when starting a new wrapper *) val oo_wrap: Env.t -> bool -> ('a -> lambda) -> 'a -> lambda val oo_add_class: Ident.t -> Env.t * bool diff --git a/bytecomp/translprim.ml b/bytecomp/translprim.ml new file mode 100644 index 00000000..25cc6154 --- /dev/null +++ b/bytecomp/translprim.ml @@ -0,0 +1,757 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Translation of primitives *) + +open Misc +open Asttypes +open Primitive +open Types +open Typedtree +open Typeopt +open Lambda + +type error = + | Unknown_builtin_primitive of string + | Wrong_arity_builtin_primitive of string + +exception Error of Location.t * error + +(* Insertion of debugging events *) + +let event_before exp lam = match lam with +| Lstaticraise (_,_) -> lam +| _ -> + if !Clflags.debug && not !Clflags.native_code + then Levent(lam, {lev_loc = exp.exp_loc; + lev_kind = Lev_before; + lev_repr = None; + lev_env = Env.summary exp.exp_env}) + else lam + +let event_after exp lam = + if !Clflags.debug && not !Clflags.native_code + then Levent(lam, {lev_loc = exp.exp_loc; + lev_kind = Lev_after exp.exp_type; + lev_repr = None; + lev_env = Env.summary exp.exp_env}) + else lam + +type comparison = + | Equal + | Not_equal + | Less_equal + | Less_than + | Greater_equal + | Greater_than + | Compare + +type comparison_kind = + | Compare_generic + | Compare_ints + | Compare_floats + | Compare_strings + | Compare_bytes + | Compare_nativeints + | Compare_int32s + | Compare_int64s + +type loc_kind = + | Loc_FILE + | Loc_LINE + | Loc_MODULE + | Loc_LOC + | Loc_POS + +type prim = + | Primitive of Lambda.primitive + | Comparison of comparison * comparison_kind + | Raise of Lambda.raise_kind + | Raise_with_backtrace + | Lazy_force + | Loc of loc_kind + | Send + | Send_self + | Send_cache + +let used_primitives = Hashtbl.create 7 +let add_used_primitive loc env path = + match path with + Some (Path.Pdot _ as path) -> + let path = Env.normalize_path (Some loc) env path in + let unit = Path.head path in + if Ident.global unit && not (Hashtbl.mem used_primitives path) + then Hashtbl.add used_primitives path loc + | _ -> () + +let clear_used_primitives () = Hashtbl.clear used_primitives +let get_used_primitives () = + Hashtbl.fold (fun path _ acc -> path :: acc) used_primitives [] + +let gen_array_kind = + if Config.flat_float_array then Pgenarray else Paddrarray + +let primitives_table = create_hashtable 57 [ + "%identity", Primitive Pidentity; + "%bytes_to_string", Primitive Pbytes_to_string; + "%bytes_of_string", Primitive Pbytes_of_string; + "%ignore", Primitive Pignore; + "%revapply", Primitive Prevapply; + "%apply", Primitive Pdirapply; + "%loc_LOC", Loc Loc_LOC; + "%loc_FILE", Loc Loc_FILE; + "%loc_LINE", Loc Loc_LINE; + "%loc_POS", Loc Loc_POS; + "%loc_MODULE", Loc Loc_MODULE; + "%field0", Primitive (Pfield 0); + "%field1", Primitive (Pfield 1); + "%setfield0", Primitive (Psetfield(0, Pointer, Assignment)); + "%makeblock", Primitive (Pmakeblock(0, Immutable, None)); + "%makemutable", Primitive (Pmakeblock(0, Mutable, None)); + "%raise", Raise Raise_regular; + "%reraise", Raise Raise_reraise; + "%raise_notrace", Raise Raise_notrace; + "%raise_with_backtrace", Raise_with_backtrace; + "%sequand", Primitive Psequand; + "%sequor", Primitive Psequor; + "%boolnot", Primitive Pnot; + "%big_endian", Primitive (Pctconst Big_endian); + "%backend_type", Primitive (Pctconst Backend_type); + "%word_size", Primitive (Pctconst Word_size); + "%int_size", Primitive (Pctconst Int_size); + "%max_wosize", Primitive (Pctconst Max_wosize); + "%ostype_unix", Primitive (Pctconst Ostype_unix); + "%ostype_win32", Primitive (Pctconst Ostype_win32); + "%ostype_cygwin", Primitive (Pctconst Ostype_cygwin); + "%negint", Primitive Pnegint; + "%succint", Primitive (Poffsetint 1); + "%predint", Primitive (Poffsetint(-1)); + "%addint", Primitive Paddint; + "%subint", Primitive Psubint; + "%mulint", Primitive Pmulint; + "%divint", Primitive (Pdivint Safe); + "%modint", Primitive (Pmodint Safe); + "%andint", Primitive Pandint; + "%orint", Primitive Porint; + "%xorint", Primitive Pxorint; + "%lslint", Primitive Plslint; + "%lsrint", Primitive Plsrint; + "%asrint", Primitive Pasrint; + "%eq", Primitive (Pintcomp Ceq); + "%noteq", Primitive (Pintcomp Cne); + "%ltint", Primitive (Pintcomp Clt); + "%leint", Primitive (Pintcomp Cle); + "%gtint", Primitive (Pintcomp Cgt); + "%geint", Primitive (Pintcomp Cge); + "%incr", Primitive (Poffsetref(1)); + "%decr", Primitive (Poffsetref(-1)); + "%intoffloat", Primitive Pintoffloat; + "%floatofint", Primitive Pfloatofint; + "%negfloat", Primitive Pnegfloat; + "%absfloat", Primitive Pabsfloat; + "%addfloat", Primitive Paddfloat; + "%subfloat", Primitive Psubfloat; + "%mulfloat", Primitive Pmulfloat; + "%divfloat", Primitive Pdivfloat; + "%eqfloat", Primitive (Pfloatcomp CFeq); + "%noteqfloat", Primitive (Pfloatcomp CFneq); + "%ltfloat", Primitive (Pfloatcomp CFlt); + "%lefloat", Primitive (Pfloatcomp CFle); + "%gtfloat", Primitive (Pfloatcomp CFgt); + "%gefloat", Primitive (Pfloatcomp CFge); + "%string_length", Primitive Pstringlength; + "%string_safe_get", Primitive Pstringrefs; + "%string_safe_set", Primitive Pbytessets; + "%string_unsafe_get", Primitive Pstringrefu; + "%string_unsafe_set", Primitive Pbytessetu; + "%bytes_length", Primitive Pbyteslength; + "%bytes_safe_get", Primitive Pbytesrefs; + "%bytes_safe_set", Primitive Pbytessets; + "%bytes_unsafe_get", Primitive Pbytesrefu; + "%bytes_unsafe_set", Primitive Pbytessetu; + "%array_length", Primitive (Parraylength gen_array_kind); + "%array_safe_get", Primitive (Parrayrefs gen_array_kind); + "%array_safe_set", Primitive (Parraysets gen_array_kind); + "%array_unsafe_get", Primitive (Parrayrefu gen_array_kind); + "%array_unsafe_set", Primitive (Parraysetu gen_array_kind); + "%obj_size", Primitive (Parraylength gen_array_kind); + "%obj_field", Primitive (Parrayrefu gen_array_kind); + "%obj_set_field", Primitive (Parraysetu gen_array_kind); + "%floatarray_length", Primitive (Parraylength Pfloatarray); + "%floatarray_safe_get", Primitive (Parrayrefs Pfloatarray); + "%floatarray_safe_set", Primitive (Parraysets Pfloatarray); + "%floatarray_unsafe_get", Primitive (Parrayrefu Pfloatarray); + "%floatarray_unsafe_set", Primitive (Parraysetu Pfloatarray); + "%obj_is_int", Primitive Pisint; + "%lazy_force", Lazy_force; + "%nativeint_of_int", Primitive (Pbintofint Pnativeint); + "%nativeint_to_int", Primitive (Pintofbint Pnativeint); + "%nativeint_neg", Primitive (Pnegbint Pnativeint); + "%nativeint_add", Primitive (Paddbint Pnativeint); + "%nativeint_sub", Primitive (Psubbint Pnativeint); + "%nativeint_mul", Primitive (Pmulbint Pnativeint); + "%nativeint_div", Primitive (Pdivbint { size = Pnativeint; is_safe = Safe }); + "%nativeint_mod", Primitive (Pmodbint { size = Pnativeint; is_safe = Safe }); + "%nativeint_and", Primitive (Pandbint Pnativeint); + "%nativeint_or", Primitive (Porbint Pnativeint); + "%nativeint_xor", Primitive (Pxorbint Pnativeint); + "%nativeint_lsl", Primitive (Plslbint Pnativeint); + "%nativeint_lsr", Primitive (Plsrbint Pnativeint); + "%nativeint_asr", Primitive (Pasrbint Pnativeint); + "%int32_of_int", Primitive (Pbintofint Pint32); + "%int32_to_int", Primitive (Pintofbint Pint32); + "%int32_neg", Primitive (Pnegbint Pint32); + "%int32_add", Primitive (Paddbint Pint32); + "%int32_sub", Primitive (Psubbint Pint32); + "%int32_mul", Primitive (Pmulbint Pint32); + "%int32_div", Primitive (Pdivbint { size = Pint32; is_safe = Safe }); + "%int32_mod", Primitive (Pmodbint { size = Pint32; is_safe = Safe }); + "%int32_and", Primitive (Pandbint Pint32); + "%int32_or", Primitive (Porbint Pint32); + "%int32_xor", Primitive (Pxorbint Pint32); + "%int32_lsl", Primitive (Plslbint Pint32); + "%int32_lsr", Primitive (Plsrbint Pint32); + "%int32_asr", Primitive (Pasrbint Pint32); + "%int64_of_int", Primitive (Pbintofint Pint64); + "%int64_to_int", Primitive (Pintofbint Pint64); + "%int64_neg", Primitive (Pnegbint Pint64); + "%int64_add", Primitive (Paddbint Pint64); + "%int64_sub", Primitive (Psubbint Pint64); + "%int64_mul", Primitive (Pmulbint Pint64); + "%int64_div", Primitive (Pdivbint { size = Pint64; is_safe = Safe }); + "%int64_mod", Primitive (Pmodbint { size = Pint64; is_safe = Safe }); + "%int64_and", Primitive (Pandbint Pint64); + "%int64_or", Primitive (Porbint Pint64); + "%int64_xor", Primitive (Pxorbint Pint64); + "%int64_lsl", Primitive (Plslbint Pint64); + "%int64_lsr", Primitive (Plsrbint Pint64); + "%int64_asr", Primitive (Pasrbint Pint64); + "%nativeint_of_int32", Primitive (Pcvtbint(Pint32, Pnativeint)); + "%nativeint_to_int32", Primitive (Pcvtbint(Pnativeint, Pint32)); + "%int64_of_int32", Primitive (Pcvtbint(Pint32, Pint64)); + "%int64_to_int32", Primitive (Pcvtbint(Pint64, Pint32)); + "%int64_of_nativeint", Primitive (Pcvtbint(Pnativeint, Pint64)); + "%int64_to_nativeint", Primitive (Pcvtbint(Pint64, Pnativeint)); + "%caml_ba_ref_1", + Primitive + (Pbigarrayref(false, 1, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_ref_2", + Primitive + (Pbigarrayref(false, 2, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_ref_3", + Primitive + (Pbigarrayref(false, 3, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_set_1", + Primitive + (Pbigarrayset(false, 1, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_set_2", + Primitive + (Pbigarrayset(false, 2, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_set_3", + Primitive + (Pbigarrayset(false, 3, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_ref_1", + Primitive + (Pbigarrayref(true, 1, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_ref_2", + Primitive + (Pbigarrayref(true, 2, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_ref_3", + Primitive + (Pbigarrayref(true, 3, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_set_1", + Primitive + (Pbigarrayset(true, 1, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_set_2", + Primitive + (Pbigarrayset(true, 2, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_unsafe_set_3", + Primitive + (Pbigarrayset(true, 3, Pbigarray_unknown, Pbigarray_unknown_layout)); + "%caml_ba_dim_1", Primitive (Pbigarraydim(1)); + "%caml_ba_dim_2", Primitive (Pbigarraydim(2)); + "%caml_ba_dim_3", Primitive (Pbigarraydim(3)); + "%caml_string_get16", Primitive (Pstring_load_16(false)); + "%caml_string_get16u", Primitive (Pstring_load_16(true)); + "%caml_string_get32", Primitive (Pstring_load_32(false)); + "%caml_string_get32u", Primitive (Pstring_load_32(true)); + "%caml_string_get64", Primitive (Pstring_load_64(false)); + "%caml_string_get64u", Primitive (Pstring_load_64(true)); + "%caml_string_set16", Primitive (Pbytes_set_16(false)); + "%caml_string_set16u", Primitive (Pbytes_set_16(true)); + "%caml_string_set32", Primitive (Pbytes_set_32(false)); + "%caml_string_set32u", Primitive (Pbytes_set_32(true)); + "%caml_string_set64", Primitive (Pbytes_set_64(false)); + "%caml_string_set64u", Primitive (Pbytes_set_64(true)); + "%caml_bytes_get16", Primitive (Pbytes_load_16(false)); + "%caml_bytes_get16u", Primitive (Pbytes_load_16(true)); + "%caml_bytes_get32", Primitive (Pbytes_load_32(false)); + "%caml_bytes_get32u", Primitive (Pbytes_load_32(true)); + "%caml_bytes_get64", Primitive (Pbytes_load_64(false)); + "%caml_bytes_get64u", Primitive (Pbytes_load_64(true)); + "%caml_bytes_set16", Primitive (Pbytes_set_16(false)); + "%caml_bytes_set16u", Primitive (Pbytes_set_16(true)); + "%caml_bytes_set32", Primitive (Pbytes_set_32(false)); + "%caml_bytes_set32u", Primitive (Pbytes_set_32(true)); + "%caml_bytes_set64", Primitive (Pbytes_set_64(false)); + "%caml_bytes_set64u", Primitive (Pbytes_set_64(true)); + "%caml_bigstring_get16", Primitive (Pbigstring_load_16(false)); + "%caml_bigstring_get16u", Primitive (Pbigstring_load_16(true)); + "%caml_bigstring_get32", Primitive (Pbigstring_load_32(false)); + "%caml_bigstring_get32u", Primitive (Pbigstring_load_32(true)); + "%caml_bigstring_get64", Primitive (Pbigstring_load_64(false)); + "%caml_bigstring_get64u", Primitive (Pbigstring_load_64(true)); + "%caml_bigstring_set16", Primitive (Pbigstring_set_16(false)); + "%caml_bigstring_set16u", Primitive (Pbigstring_set_16(true)); + "%caml_bigstring_set32", Primitive (Pbigstring_set_32(false)); + "%caml_bigstring_set32u", Primitive (Pbigstring_set_32(true)); + "%caml_bigstring_set64", Primitive (Pbigstring_set_64(false)); + "%caml_bigstring_set64u", Primitive (Pbigstring_set_64(true)); + "%bswap16", Primitive Pbswap16; + "%bswap_int32", Primitive (Pbbswap(Pint32)); + "%bswap_int64", Primitive (Pbbswap(Pint64)); + "%bswap_native", Primitive (Pbbswap(Pnativeint)); + "%int_as_pointer", Primitive Pint_as_pointer; + "%opaque", Primitive Popaque; + "%send", Send; + "%sendself", Send_self; + "%sendcache", Send_cache; + "%equal", Comparison(Equal, Compare_generic); + "%notequal", Comparison(Not_equal, Compare_generic); + "%lessequal", Comparison(Less_equal, Compare_generic); + "%lessthan", Comparison(Less_than, Compare_generic); + "%greaterequal", Comparison(Greater_equal, Compare_generic); + "%greaterthan", Comparison(Greater_than, Compare_generic); + "%compare", Comparison(Compare, Compare_generic); +] + +let lookup_primitive loc p env path = + match Hashtbl.find primitives_table p.prim_name with + | prim -> prim + | exception Not_found -> + if String.length p.prim_name > 0 && p.prim_name.[0] = '%' then + raise(Error(loc, Unknown_builtin_primitive p.prim_name)); + add_used_primitive loc env path; + Primitive (Pccall p) + +let simplify_constant_constructor = function + | Equal -> true + | Not_equal -> true + | Less_equal -> false + | Less_than -> false + | Greater_equal -> false + | Greater_than -> false + | Compare -> false + +(* The following function computes the greatest lower bound in the + semilattice of array kinds: + gen + / \ + addr float + | + int + Note that the GLB is not guaranteed to exist, in which case we return + our first argument instead of raising a fatal error because, although + it cannot happen in a well-typed program, (ab)use of Obj.magic can + probably trigger it. +*) +let glb_array_type t1 t2 = + match t1, t2 with + | Pfloatarray, (Paddrarray | Pintarray) + | (Paddrarray | Pintarray), Pfloatarray -> t1 + + | Pgenarray, x | x, Pgenarray -> x + | Paddrarray, x | x, Paddrarray -> x + | Pintarray, Pintarray -> Pintarray + | Pfloatarray, Pfloatarray -> Pfloatarray + +(* Specialize a primitive from available type information. *) + +let specialize_primitive env ty ~has_constant_constructor prim = + let param_tys = + match is_function_type env ty with + | None -> [] + | Some (p1, rhs) -> + match is_function_type env rhs with + | None -> [p1] + | Some (p2, _) -> [p1;p2] + in + match prim, param_tys with + | Primitive (Psetfield(n, Pointer, init)), [_; p2] -> begin + match maybe_pointer_type env p2 with + | Pointer -> None + | Immediate -> Some (Primitive (Psetfield(n, Immediate, init))) + end + | Primitive (Parraylength t), [p] -> begin + let array_type = glb_array_type t (array_type_kind env p) in + if t = array_type then None + else Some (Primitive (Parraylength array_type)) + end + | Primitive (Parrayrefu t), p1 :: _ -> begin + let array_type = glb_array_type t (array_type_kind env p1) in + if t = array_type then None + else Some (Primitive (Parrayrefu array_type)) + end + | Primitive (Parraysetu t), p1 :: _ -> begin + let array_type = glb_array_type t (array_type_kind env p1) in + if t = array_type then None + else Some (Primitive (Parraysetu array_type)) + end + | Primitive (Parrayrefs t), p1 :: _ -> begin + let array_type = glb_array_type t (array_type_kind env p1) in + if t = array_type then None + else Some (Primitive (Parrayrefs array_type)) + end + | Primitive (Parraysets t), p1 :: _ -> begin + let array_type = glb_array_type t (array_type_kind env p1) in + if t = array_type then None + else Some (Primitive (Parraysets array_type)) + end + | Primitive (Pbigarrayref(unsafe, n, Pbigarray_unknown, + Pbigarray_unknown_layout)), p1 :: _ -> begin + let (k, l) = bigarray_type_kind_and_layout env p1 in + match k, l with + | Pbigarray_unknown, Pbigarray_unknown_layout -> None + | _, _ -> Some (Primitive (Pbigarrayref(unsafe, n, k, l))) + end + | Primitive (Pbigarrayset(unsafe, n, Pbigarray_unknown, + Pbigarray_unknown_layout)), p1 :: _ -> begin + let (k, l) = bigarray_type_kind_and_layout env p1 in + match k, l with + | Pbigarray_unknown, Pbigarray_unknown_layout -> None + | _, _ -> Some (Primitive (Pbigarrayset(unsafe, n, k, l))) + end + | Primitive (Pmakeblock(tag, mut, None)), fields -> begin + let shape = List.map (Typeopt.value_kind env) fields in + let useful = List.exists (fun knd -> knd <> Pgenval) shape in + if useful then Some (Primitive (Pmakeblock(tag, mut, Some shape))) + else None + end + | Comparison(comp, Compare_generic), p1 :: _ -> + if (has_constant_constructor + && simplify_constant_constructor comp) then begin + Some (Comparison(comp, Compare_ints)) + end else if (is_base_type env p1 Predef.path_int + || is_base_type env p1 Predef.path_char + || (maybe_pointer_type env p1 = Immediate)) then begin + Some (Comparison(comp, Compare_ints)) + end else if is_base_type env p1 Predef.path_float then begin + Some (Comparison(comp, Compare_floats)) + end else if is_base_type env p1 Predef.path_string then begin + Some (Comparison(comp, Compare_strings)) + end else if is_base_type env p1 Predef.path_bytes then begin + Some (Comparison(comp, Compare_bytes)) + end else if is_base_type env p1 Predef.path_nativeint then begin + Some (Comparison(comp, Compare_nativeints)) + end else if is_base_type env p1 Predef.path_int32 then begin + Some (Comparison(comp, Compare_int32s)) + end else if is_base_type env p1 Predef.path_int64 then begin + Some (Comparison(comp, Compare_int64s)) + end else begin + None + end + | _ -> None + +let unboxed_compare name native_repr = + Primitive.make ~name ~alloc:false ~native_name:(name^"_unboxed") + ~native_repr_args:[native_repr;native_repr] ~native_repr_res:Untagged_int + +let caml_equal = + Primitive.simple ~name:"caml_equal" ~arity:2 ~alloc:true +let caml_string_equal = + Primitive.simple ~name:"caml_string_equal" ~arity:2 ~alloc:false +let caml_bytes_equal = + Primitive.simple ~name:"caml_bytes_equal" ~arity:2 ~alloc:false +let caml_notequal = + Primitive.simple ~name:"caml_notequal" ~arity:2 ~alloc:true +let caml_string_notequal = + Primitive.simple ~name:"caml_string_notequal" ~arity:2 ~alloc:false +let caml_bytes_notequal = + Primitive.simple ~name:"caml_bytes_notequal" ~arity:2 ~alloc:false +let caml_lessequal = + Primitive.simple ~name:"caml_lessequal" ~arity:2 ~alloc:true +let caml_string_lessequal = + Primitive.simple ~name:"caml_string_lessequal" ~arity:2 ~alloc:false +let caml_bytes_lessequal = + Primitive.simple ~name:"caml_bytes_lessequal" ~arity:2 ~alloc:false +let caml_lessthan = + Primitive.simple ~name:"caml_lessthan" ~arity:2 ~alloc:true +let caml_string_lessthan = + Primitive.simple ~name:"caml_string_lessthan" ~arity:2 ~alloc:false +let caml_bytes_lessthan = + Primitive.simple ~name:"caml_bytes_lessthan" ~arity:2 ~alloc:false +let caml_greaterequal = + Primitive.simple ~name:"caml_greaterequal" ~arity:2 ~alloc:true +let caml_string_greaterequal = + Primitive.simple ~name:"caml_string_greaterequal" ~arity:2 ~alloc:false +let caml_bytes_greaterequal = + Primitive.simple ~name:"caml_bytes_greaterequal" ~arity:2 ~alloc:false +let caml_greaterthan = + Primitive.simple ~name:"caml_greaterthan" ~arity:2 ~alloc:true +let caml_string_greaterthan = + Primitive.simple ~name:"caml_string_greaterthan" ~arity:2 ~alloc: false +let caml_bytes_greaterthan = + Primitive.simple ~name:"caml_bytes_greaterthan" ~arity:2 ~alloc: false +let caml_compare = + Primitive.simple ~name:"caml_compare" ~arity:2 ~alloc:true +let caml_int_compare = + (* Not unboxed since the comparison is done directly on tagged int *) + Primitive.simple ~name:"caml_int_compare" ~arity:2 ~alloc:false +let caml_float_compare = + unboxed_compare "caml_float_compare" Unboxed_float +let caml_string_compare = + Primitive.simple ~name:"caml_string_compare" ~arity:2 ~alloc:false +let caml_bytes_compare = + Primitive.simple ~name:"caml_bytes_compare" ~arity:2 ~alloc:false +let caml_nativeint_compare = + unboxed_compare "caml_nativeint_compare" (Unboxed_integer Pnativeint) +let caml_int32_compare = + unboxed_compare "caml_int32_compare" (Unboxed_integer Pint32) +let caml_int64_compare = + unboxed_compare "caml_int64_compare" (Unboxed_integer Pint64) + +let comparison_primitive comparison comparison_kind = + match comparison, comparison_kind with + | Equal, Compare_generic -> Pccall caml_equal + | Equal, Compare_ints -> Pintcomp Ceq + | Equal, Compare_floats -> Pfloatcomp CFeq + | Equal, Compare_strings -> Pccall caml_string_equal + | Equal, Compare_bytes -> Pccall caml_bytes_equal + | Equal, Compare_nativeints -> Pbintcomp(Pnativeint, Ceq) + | Equal, Compare_int32s -> Pbintcomp(Pint32, Ceq) + | Equal, Compare_int64s -> Pbintcomp(Pint64, Ceq) + | Not_equal, Compare_generic -> Pccall caml_notequal + | Not_equal, Compare_ints -> Pintcomp Cne + | Not_equal, Compare_floats -> Pfloatcomp CFneq + | Not_equal, Compare_strings -> Pccall caml_string_notequal + | Not_equal, Compare_bytes -> Pccall caml_bytes_notequal + | Not_equal, Compare_nativeints -> Pbintcomp(Pnativeint, Cne) + | Not_equal, Compare_int32s -> Pbintcomp(Pint32, Cne) + | Not_equal, Compare_int64s -> Pbintcomp(Pint64, Cne) + | Less_equal, Compare_generic -> Pccall caml_lessequal + | Less_equal, Compare_ints -> Pintcomp Cle + | Less_equal, Compare_floats -> Pfloatcomp CFle + | Less_equal, Compare_strings -> Pccall caml_string_lessequal + | Less_equal, Compare_bytes -> Pccall caml_bytes_lessequal + | Less_equal, Compare_nativeints -> Pbintcomp(Pnativeint, Cle) + | Less_equal, Compare_int32s -> Pbintcomp(Pint32, Cle) + | Less_equal, Compare_int64s -> Pbintcomp(Pint64, Cle) + | Less_than, Compare_generic -> Pccall caml_lessthan + | Less_than, Compare_ints -> Pintcomp Clt + | Less_than, Compare_floats -> Pfloatcomp CFlt + | Less_than, Compare_strings -> Pccall caml_string_lessthan + | Less_than, Compare_bytes -> Pccall caml_bytes_lessthan + | Less_than, Compare_nativeints -> Pbintcomp(Pnativeint, Clt) + | Less_than, Compare_int32s -> Pbintcomp(Pint32, Clt) + | Less_than, Compare_int64s -> Pbintcomp(Pint64, Clt) + | Greater_equal, Compare_generic -> Pccall caml_greaterequal + | Greater_equal, Compare_ints -> Pintcomp Cge + | Greater_equal, Compare_floats -> Pfloatcomp CFge + | Greater_equal, Compare_strings -> Pccall caml_string_greaterequal + | Greater_equal, Compare_bytes -> Pccall caml_bytes_greaterequal + | Greater_equal, Compare_nativeints -> Pbintcomp(Pnativeint, Cge) + | Greater_equal, Compare_int32s -> Pbintcomp(Pint32, Cge) + | Greater_equal, Compare_int64s -> Pbintcomp(Pint64, Cge) + | Greater_than, Compare_generic -> Pccall caml_greaterthan + | Greater_than, Compare_ints -> Pintcomp Cgt + | Greater_than, Compare_floats -> Pfloatcomp CFgt + | Greater_than, Compare_strings -> Pccall caml_string_greaterthan + | Greater_than, Compare_bytes -> Pccall caml_bytes_greaterthan + | Greater_than, Compare_nativeints -> Pbintcomp(Pnativeint, Cgt) + | Greater_than, Compare_int32s -> Pbintcomp(Pint32, Cgt) + | Greater_than, Compare_int64s -> Pbintcomp(Pint64, Cgt) + | Compare, Compare_generic -> Pccall caml_compare + | Compare, Compare_ints -> Pccall caml_int_compare + | Compare, Compare_floats -> Pccall caml_float_compare + | Compare, Compare_strings -> Pccall caml_string_compare + | Compare, Compare_bytes -> Pccall caml_bytes_compare + | Compare, Compare_nativeints -> Pccall caml_nativeint_compare + | Compare, Compare_int32s -> Pccall caml_int32_compare + | Compare, Compare_int64s -> Pccall caml_int64_compare + +let lambda_of_loc kind loc = + let loc_start = loc.Location.loc_start in + let (file, lnum, cnum) = Location.get_pos_info loc_start in + let enum = loc.Location.loc_end.Lexing.pos_cnum - + loc_start.Lexing.pos_cnum + cnum in + match kind with + | Loc_POS -> + Lconst (Const_block (0, [ + Const_immstring file; + Const_base (Const_int lnum); + Const_base (Const_int cnum); + Const_base (Const_int enum); + ])) + | Loc_FILE -> Lconst (Const_immstring file) + | Loc_MODULE -> + let filename = Filename.basename file in + let name = Env.get_unit_name () in + let module_name = if name = "" then "//"^filename^"//" else name in + Lconst (Const_immstring module_name) + | Loc_LOC -> + let loc = Printf.sprintf "File %S, line %d, characters %d-%d" + file lnum cnum enum in + Lconst (Const_immstring loc) + | Loc_LINE -> Lconst (Const_base (Const_int lnum)) + +let caml_restore_raw_backtrace = + Primitive.simple ~name:"caml_restore_raw_backtrace" ~arity:2 ~alloc:false + +let try_ids = Hashtbl.create 8 + +let add_exception_ident id = + Hashtbl.replace try_ids id () + +let remove_exception_ident id = + Hashtbl.remove try_ids id + +let lambda_of_prim prim_name prim loc args arg_exps = + match prim, args with + | Primitive prim, args -> + Lprim(prim, args, loc) + | Comparison(comp, knd), args -> + let prim = comparison_primitive comp knd in + Lprim(prim, args, loc) + | Raise kind, [arg] -> + let kind = + match kind, arg with + | Raise_regular, Lvar argv when Hashtbl.mem try_ids argv -> + Raise_reraise + | _, _ -> + kind + in + let arg = + match arg_exps with + | None -> arg + | Some [arg_exp] -> event_after arg_exp arg + | Some _ -> assert false + in + Lprim(Praise kind, [arg], loc) + | Raise_with_backtrace, [exn; bt] -> + let vexn = Ident.create "exn" in + let raise_arg = + match arg_exps with + | None -> Lvar vexn + | Some [exn_exp; _] -> event_after exn_exp (Lvar vexn) + | Some _ -> assert false + in + Llet(Strict, Pgenval, vexn, exn, + Lsequence(Lprim(Pccall caml_restore_raw_backtrace, + [Lvar vexn; bt], + loc), + Lprim(Praise Raise_reraise, [raise_arg], loc))) + | Lazy_force, [arg] -> + Matching.inline_lazy_force arg Location.none + | Loc kind, [] -> + lambda_of_loc kind loc + | Loc kind, [arg] -> + let lam = lambda_of_loc kind loc in + Lprim(Pmakeblock(0, Immutable, None), [lam; arg], loc) + | Send, [obj; meth] -> + Lsend(Public, meth, obj, [], loc) + | Send_self, [obj; meth] -> + Lsend(Self, meth, obj, [], loc) + | Send_cache, [obj; meth; cache; pos] -> + Lsend(Cached, meth, obj, [cache; pos], loc) + | (Raise _ | Raise_with_backtrace + | Lazy_force | Loc _ + | Send | Send_self | Send_cache), _ -> + raise(Error(loc, Wrong_arity_builtin_primitive prim_name)) + +(* Eta-expand a primitive *) + +let transl_primitive loc p env ty path = + let prim = lookup_primitive loc p env path in + let has_constant_constructor = false in + let prim = + match specialize_primitive env ty ~has_constant_constructor prim with + | None -> prim + | Some prim -> prim + in + let rec make_params n = + if n <= 0 then [] else Ident.create "prim" :: make_params (n-1) + in + let params = make_params p.prim_arity in + let args = List.map (fun id -> Lvar id) params in + let body = lambda_of_prim p.prim_name prim loc args None in + match params with + | [] -> body + | _ -> + Lfunction{ kind = Curried; params; + attr = default_stub_attribute; + loc = loc; + body = body; } + +(* Determine if a primitive is a Pccall or will be turned later into + a C function call that may raise an exception *) +let primitive_is_ccall = function + | Pccall _ | Pstringrefs | Pbytesrefs | Pbytessets | Parrayrefs _ | + Parraysets _ | Pbigarrayref _ | Pbigarrayset _ | Pduprecord _ | Pdirapply | + Prevapply -> true + | _ -> false + +(* Determine if a primitive should be surrounded by an "after" debug event *) +let primitive_needs_event_after = function + | Primitive prim -> primitive_is_ccall prim + | Comparison(comp, knd) -> + primitive_is_ccall (comparison_primitive comp knd) + | Lazy_force | Send | Send_self | Send_cache -> true + | Raise _ | Raise_with_backtrace | Loc _ -> false + +let transl_primitive_application loc p env ty path exp args arg_exps = + let prim = lookup_primitive loc p env (Some path) in + let has_constant_constructor = + match arg_exps with + | [_; {exp_desc = Texp_construct(_, {cstr_tag = Cstr_constant _}, _)}] + | [{exp_desc = Texp_construct(_, {cstr_tag = Cstr_constant _}, _)}; _] + | [_; {exp_desc = Texp_variant(_, None)}] + | [{exp_desc = Texp_variant(_, None)}; _] -> true + | _ -> false + in + let prim = + match specialize_primitive env ty ~has_constant_constructor prim with + | None -> prim + | Some prim -> prim + in + let lam = lambda_of_prim p.prim_name prim loc args (Some arg_exps) in + let lam = + if primitive_needs_event_after prim then begin + match exp with + | None -> lam + | Some exp -> event_after exp lam + end else begin + lam + end + in + lam + +(* Error report *) + +open Format + +let report_error ppf = function + | Unknown_builtin_primitive prim_name -> + fprintf ppf "Unknown builtin primitive \"%s\"" prim_name + | Wrong_arity_builtin_primitive prim_name -> + fprintf ppf "Wrong arity for builtin primitive \"%s\"" prim_name + +let () = + Location.register_error_of_exn + (function + | Error (loc, err) -> + Some (Location.error_of_printer loc report_error err) + | _ -> + None + ) diff --git a/bytecomp/translprim.mli b/bytecomp/translprim.mli new file mode 100644 index 00000000..d8941656 --- /dev/null +++ b/bytecomp/translprim.mli @@ -0,0 +1,49 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Insertion of debugging events *) + +val event_before : Typedtree.expression -> Lambda.lambda -> Lambda.lambda + +val event_after : Typedtree.expression -> Lambda.lambda -> Lambda.lambda + +(* Translation of primitives *) + +val add_exception_ident : Ident.t -> unit +val remove_exception_ident : Ident.t -> unit + +val clear_used_primitives : unit -> unit +val get_used_primitives: unit -> Path.t list + +val transl_primitive : + Location.t -> Primitive.description -> Env.t -> + Types.type_expr -> Path.t option -> Lambda.lambda + +val transl_primitive_application : + Location.t -> Primitive.description -> Env.t -> + Types.type_expr -> Path.t -> Typedtree.expression option -> + Lambda.lambda list -> Typedtree.expression list -> Lambda.lambda + +(* Errors *) + +type error = + | Unknown_builtin_primitive of string + | Wrong_arity_builtin_primitive of string + +exception Error of Location.t * error + +open Format + +val report_error : formatter -> error -> unit diff --git a/byterun/.depend b/byterun/.depend index 21a592ad..c0f81615 100644 --- a/byterun/.depend +++ b/byterun/.depend @@ -8,7 +8,7 @@ alloc.$(O): alloc.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ array.$(O): array.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/signals.h \ - caml/spacetime.h + caml/spacetime.h caml/io.h caml/stack.h backtrace.$(O): backtrace.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/backtrace.h \ @@ -22,7 +22,8 @@ backtrace_prim.$(O): backtrace_prim.c caml/config.h caml/m.h caml/s.h \ bigarray.$(O): bigarray.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/bigarray.h caml/custom.h caml/fail.h \ caml/intext.h caml/io.h caml/hash.h caml/memory.h caml/gc.h \ - caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h + caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ + caml/signals.h callback.$(O): callback.c caml/callback.h caml/mlvalues.h caml/config.h \ caml/m.h caml/s.h caml/misc.h caml/fail.h caml/memory.h caml/gc.h \ caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ @@ -37,7 +38,7 @@ compare.$(O): compare.c caml/custom.h caml/mlvalues.h caml/config.h caml/m.h \ custom.$(O): custom.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/custom.h caml/fail.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ - caml/address_class.h + caml/address_class.h caml/signals.h debugger.$(O): debugger.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/debugger.h caml/osdeps.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ @@ -139,7 +140,7 @@ misc.$(O): misc.c caml/config.h caml/m.h caml/s.h caml/misc.h caml/memory.h \ obj.$(O): obj.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/gc.h caml/interp.h caml/major_gc.h \ caml/freelist.h caml/memory.h caml/minor_gc.h caml/address_class.h \ - caml/prims.h caml/spacetime.h + caml/prims.h caml/spacetime.h caml/io.h caml/stack.h parsing.$(O): parsing.c caml/config.h caml/m.h caml/s.h caml/mlvalues.h \ caml/misc.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/alloc.h @@ -189,8 +190,6 @@ sys.$(O): sys.c caml/config.h caml/m.h caml/s.h caml/alloc.h caml/misc.h \ caml/osdeps.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/signals.h caml/stacks.h \ caml/sys.h caml/version.h caml/callback.h caml/startup_aux.h -terminfo.$(O): terminfo.c caml/config.h caml/m.h caml/s.h caml/alloc.h \ - caml/misc.h caml/mlvalues.h caml/fail.h caml/io.h unix.$(O): unix.c caml/config.h caml/m.h caml/s.h caml/fail.h caml/misc.h \ caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/osdeps.h \ @@ -209,7 +208,7 @@ alloc.d.$(O): alloc.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ array.d.$(O): array.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/signals.h \ - caml/spacetime.h + caml/spacetime.h caml/io.h caml/stack.h backtrace.d.$(O): backtrace.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/backtrace.h \ @@ -223,7 +222,8 @@ backtrace_prim.d.$(O): backtrace_prim.c caml/config.h caml/m.h caml/s.h \ bigarray.d.$(O): bigarray.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/bigarray.h caml/custom.h caml/fail.h \ caml/intext.h caml/io.h caml/hash.h caml/memory.h caml/gc.h \ - caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h + caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ + caml/signals.h callback.d.$(O): callback.c caml/callback.h caml/mlvalues.h caml/config.h \ caml/m.h caml/s.h caml/misc.h caml/fail.h caml/memory.h caml/gc.h \ caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ @@ -238,7 +238,7 @@ compare.d.$(O): compare.c caml/custom.h caml/mlvalues.h caml/config.h caml/m.h \ custom.d.$(O): custom.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/custom.h caml/fail.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ - caml/address_class.h + caml/address_class.h caml/signals.h debugger.d.$(O): debugger.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/debugger.h caml/osdeps.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ @@ -343,7 +343,7 @@ misc.d.$(O): misc.c caml/config.h caml/m.h caml/s.h caml/misc.h caml/memory.h \ obj.d.$(O): obj.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/gc.h caml/interp.h caml/major_gc.h \ caml/freelist.h caml/memory.h caml/minor_gc.h caml/address_class.h \ - caml/prims.h caml/spacetime.h + caml/prims.h caml/spacetime.h caml/io.h caml/stack.h parsing.d.$(O): parsing.c caml/config.h caml/m.h caml/s.h caml/mlvalues.h \ caml/misc.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/alloc.h @@ -393,8 +393,6 @@ sys.d.$(O): sys.c caml/config.h caml/m.h caml/s.h caml/alloc.h caml/misc.h \ caml/osdeps.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/signals.h caml/stacks.h \ caml/sys.h caml/version.h caml/callback.h caml/startup_aux.h -terminfo.d.$(O): terminfo.c caml/config.h caml/m.h caml/s.h caml/alloc.h \ - caml/misc.h caml/mlvalues.h caml/fail.h caml/io.h unix.d.$(O): unix.c caml/config.h caml/m.h caml/s.h caml/fail.h caml/misc.h \ caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/osdeps.h \ @@ -413,7 +411,7 @@ alloc.i.$(O): alloc.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ array.i.$(O): array.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/signals.h \ - caml/spacetime.h + caml/spacetime.h caml/io.h caml/stack.h backtrace.i.$(O): backtrace.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/backtrace.h \ @@ -427,7 +425,8 @@ backtrace_prim.i.$(O): backtrace_prim.c caml/config.h caml/m.h caml/s.h \ bigarray.i.$(O): bigarray.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/bigarray.h caml/custom.h caml/fail.h \ caml/intext.h caml/io.h caml/hash.h caml/memory.h caml/gc.h \ - caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h + caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ + caml/signals.h callback.i.$(O): callback.c caml/callback.h caml/mlvalues.h caml/config.h \ caml/m.h caml/s.h caml/misc.h caml/fail.h caml/memory.h caml/gc.h \ caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ @@ -442,7 +441,7 @@ compare.i.$(O): compare.c caml/custom.h caml/mlvalues.h caml/config.h caml/m.h \ custom.i.$(O): custom.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/custom.h caml/fail.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ - caml/address_class.h + caml/address_class.h caml/signals.h debugger.i.$(O): debugger.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/debugger.h caml/osdeps.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ @@ -544,7 +543,7 @@ misc.i.$(O): misc.c caml/config.h caml/m.h caml/s.h caml/misc.h caml/memory.h \ obj.i.$(O): obj.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/gc.h caml/interp.h caml/major_gc.h \ caml/freelist.h caml/memory.h caml/minor_gc.h caml/address_class.h \ - caml/prims.h caml/spacetime.h + caml/prims.h caml/spacetime.h caml/io.h caml/stack.h parsing.i.$(O): parsing.c caml/config.h caml/m.h caml/s.h caml/mlvalues.h \ caml/misc.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/alloc.h @@ -594,8 +593,6 @@ sys.i.$(O): sys.c caml/config.h caml/m.h caml/s.h caml/alloc.h caml/misc.h \ caml/osdeps.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/signals.h caml/stacks.h \ caml/sys.h caml/version.h caml/callback.h caml/startup_aux.h -terminfo.i.$(O): terminfo.c caml/config.h caml/m.h caml/s.h caml/alloc.h \ - caml/misc.h caml/mlvalues.h caml/fail.h caml/io.h unix.i.$(O): unix.c caml/config.h caml/m.h caml/s.h caml/fail.h caml/misc.h \ caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/osdeps.h \ @@ -614,7 +611,7 @@ alloc.pic.$(O): alloc.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h array.pic.$(O): array.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/signals.h \ - caml/spacetime.h + caml/spacetime.h caml/io.h caml/stack.h backtrace.pic.$(O): backtrace.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/backtrace.h \ @@ -628,7 +625,8 @@ backtrace_prim.pic.$(O): backtrace_prim.c caml/config.h caml/m.h caml/s.h \ bigarray.pic.$(O): bigarray.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/bigarray.h caml/custom.h caml/fail.h \ caml/intext.h caml/io.h caml/hash.h caml/memory.h caml/gc.h \ - caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h + caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ + caml/signals.h callback.pic.$(O): callback.c caml/callback.h caml/mlvalues.h caml/config.h \ caml/m.h caml/s.h caml/misc.h caml/fail.h caml/memory.h caml/gc.h \ caml/major_gc.h caml/freelist.h caml/minor_gc.h caml/address_class.h \ @@ -643,7 +641,7 @@ compare.pic.$(O): compare.c caml/custom.h caml/mlvalues.h caml/config.h caml/m.h custom.pic.$(O): custom.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/custom.h caml/fail.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ - caml/address_class.h + caml/address_class.h caml/signals.h debugger.pic.$(O): debugger.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \ caml/s.h caml/mlvalues.h caml/debugger.h caml/osdeps.h caml/memory.h \ caml/gc.h caml/major_gc.h caml/freelist.h caml/minor_gc.h \ @@ -745,7 +743,7 @@ misc.pic.$(O): misc.c caml/config.h caml/m.h caml/s.h caml/misc.h caml/memory.h obj.pic.$(O): obj.c caml/alloc.h caml/misc.h caml/config.h caml/m.h caml/s.h \ caml/mlvalues.h caml/fail.h caml/gc.h caml/interp.h caml/major_gc.h \ caml/freelist.h caml/memory.h caml/minor_gc.h caml/address_class.h \ - caml/prims.h caml/spacetime.h + caml/prims.h caml/spacetime.h caml/io.h caml/stack.h parsing.pic.$(O): parsing.c caml/config.h caml/m.h caml/s.h caml/mlvalues.h \ caml/misc.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/alloc.h @@ -795,8 +793,6 @@ sys.pic.$(O): sys.c caml/config.h caml/m.h caml/s.h caml/alloc.h caml/misc.h \ caml/osdeps.h caml/memory.h caml/gc.h caml/major_gc.h caml/freelist.h \ caml/minor_gc.h caml/address_class.h caml/signals.h caml/stacks.h \ caml/sys.h caml/version.h caml/callback.h caml/startup_aux.h -terminfo.pic.$(O): terminfo.c caml/config.h caml/m.h caml/s.h caml/alloc.h \ - caml/misc.h caml/mlvalues.h caml/fail.h caml/io.h unix.pic.$(O): unix.c caml/config.h caml/m.h caml/s.h caml/fail.h caml/misc.h \ caml/mlvalues.h caml/memory.h caml/gc.h caml/major_gc.h \ caml/freelist.h caml/minor_gc.h caml/address_class.h caml/osdeps.h \ diff --git a/byterun/Makefile b/byterun/Makefile index 9b92a589..25b7e2c3 100644 --- a/byterun/Makefile +++ b/byterun/Makefile @@ -14,10 +14,7 @@ #************************************************************************** include ../config/Makefile - -INSTALL_BINDIR=$(DESTDIR)$(BINDIR) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) -INSTALL_INCDIR=$(INSTALL_LIBDIR)/caml +include ../Makefile.common # The PROGRAMS (resp. LIBRARIES) variable list the files to build and # install as programs in $(INSTALL_BINDIR) (resp. libraries in @@ -25,6 +22,7 @@ INSTALL_INCDIR=$(INSTALL_LIBDIR)/caml PROGRAMS = ocamlrun$(EXE) LIBRARIES = ld.conf libcamlrun.$(A) +DYNLIBRARIES= ifeq "$(RUNTIMED)" "true" PROGRAMS += ocamlrund$(EXE) @@ -38,7 +36,8 @@ endif ifeq "$(UNIX_OR_WIN32)" "unix" ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true" -LIBRARIES += libcamlrun_pic.$(A) libcamlrun_shared.$(SO) +LIBRARIES += libcamlrun_pic.$(A) +DYNLIBRARIES += libcamlrun_shared.$(SO) endif endif @@ -89,15 +88,16 @@ endif PRIMS=\ alloc.c array.c compare.c extern.c floats.c gc_ctrl.c hash.c \ intern.c interp.c ints.c io.c lexing.c md5.c meta.c obj.c parsing.c \ - signals.c str.c sys.c terminfo.c callback.c weak.c finalise.c stacks.c \ - dynlink.c backtrace_prim.c backtrace.c spacetime.c afl.c + signals.c str.c sys.c callback.c weak.c finalise.c stacks.c \ + dynlink.c backtrace_prim.c backtrace.c spacetime.c afl.c \ + bigarray.c OBJS=$(addsuffix .$(O), \ interp misc stacks fix_code startup_aux startup \ freelist major_gc minor_gc memory alloc roots globroots \ fail signals signals_byt printexc backtrace_prim backtrace \ compare ints floats str array io extern intern \ - hash sys meta parsing gc_ctrl terminfo md5 obj \ + hash sys meta parsing gc_ctrl md5 obj \ lexing callback debugger weak compact finalise custom \ dynlink spacetime afl $(UNIX_OR_WIN32) bigarray main) @@ -106,18 +106,23 @@ IOBJS=$(OBJS:.$(O)=.i.$(O)) PICOBJS=$(OBJS:.$(O)=.pic.$(O)) .PHONY: all -all: $(LIBRARIES) $(PROGRAMS) +all: $(LIBRARIES) $(DYNLIBRARIES) $(PROGRAMS) ld.conf: ../config/Makefile echo "$(STUBLIBDIR)" > $@ echo "$(LIBDIR)" >> $@ +INSTALL_INCDIR=$(INSTALL_LIBDIR)/caml + .PHONY: install install: - cp $(PROGRAMS) "$(INSTALL_BINDIR)" - cp $(LIBRARIES) "$(INSTALL_LIBDIR)" + $(INSTALL_PROG) $(PROGRAMS) "$(INSTALL_BINDIR)" + $(INSTALL_DATA) $(LIBRARIES) "$(INSTALL_LIBDIR)" + if test -n "$(DYNLIBRARIES)"; then \ + $(INSTALL_PROG) $(DYNLIBRARIES) "$(INSTALL_LIBDIR)"; \ + fi mkdir -p "$(INSTALL_INCDIR)" - cp caml/*.h "$(INSTALL_INCDIR)" + $(INSTALL_DATA) caml/*.h "$(INSTALL_INCDIR)" # If primitives contain duplicated lines (e.g. because the code is defined # like @@ -156,24 +161,25 @@ prims.c : primitives echo ' 0 };') > prims.c caml/opnames.h : caml/instruct.h + cat $^ | tr -d '\r' | \ sed -e '/\/\*/d' \ -e '/^#/d' \ -e 's/enum /char * names_of_/' \ -e 's/{$$/[] = {/' \ - -e 's/\([[:upper:]][[:upper:]_0-9]*\)/"\1"/g' caml/instruct.h \ - > caml/opnames.h + -e 's/\([[:upper:]][[:upper:]_0-9]*\)/"\1"/g' > $@ # caml/jumptbl.h is required only if you have GCC 2.0 or later caml/jumptbl.h : caml/instruct.h + cat $^ | tr -d '\r' | \ sed -n -e '/^ /s/ \([A-Z]\)/ \&\&lbl_\1/gp' \ - -e '/^}/q' caml/instruct.h > caml/jumptbl.h + -e '/^}/q' > $@ caml/version.h : ../VERSION ../tools/make-version-header.sh ../tools/make-version-header.sh ../VERSION > caml/version.h .PHONY: clean clean: - rm -f $(LIBRARIES) $(PROGRAMS) *.$(O) *.$(A) *.$(SO) + rm -f $(LIBRARIES) $(DYNLIBRARIES) $(PROGRAMS) *.$(O) *.$(A) *.$(SO) rm -f primitives prims.c caml/opnames.h caml/jumptbl.h rm -f caml/version.h diff --git a/byterun/alloc.c b/byterun/alloc.c index e49fabd0..8924dbc0 100644 --- a/byterun/alloc.c +++ b/byterun/alloc.c @@ -159,7 +159,7 @@ CAMLexport value caml_alloc_array(value (*funct)(char const *), } /* [len] is a number of floats */ -CAMLprim value caml_alloc_float_array(mlsize_t len) +value caml_alloc_float_array(mlsize_t len) { #ifdef FLAT_FLOAT_ARRAY mlsize_t wosize = len * Double_wosize; diff --git a/byterun/bigarray.c b/byterun/bigarray.c index a8991d0e..3e376799 100644 --- a/byterun/bigarray.c +++ b/byterun/bigarray.c @@ -13,18 +13,11 @@ /* */ /**************************************************************************/ -/* This file is an intermediate step in making the bigarray library - (in otherlibs/bigarray) a part of the standard library. - This file defines the basic allocation functions for bigarrays, - as well as the comparison, hashing and marshaling methods for - bigarrays. The other bigarray primitives are still defined - in otherlibs/bigarray. Memory-mapping a file as a bigarray - is being migrated to otherlibs/unix and otherlibs/win32unix. */ - #define CAML_INTERNALS #include #include +#include #include "caml/alloc.h" #include "caml/bigarray.h" #include "caml/custom.h" @@ -33,6 +26,12 @@ #include "caml/hash.h" #include "caml/memory.h" #include "caml/mlvalues.h" +#include "caml/signals.h" + +#define int8 caml_ba_int8 +#define uint8 caml_ba_uint8 +#define int16 caml_ba_int16 +#define uint16 caml_ba_uint16 /* Compute the number of elements of a big array */ @@ -440,22 +439,31 @@ static void caml_ba_deserialize_longarray(void * dest, intnat num_elts) CAMLexport uintnat caml_ba_deserialize(void * dst) { struct caml_ba_array * b = dst; - int i, elt_size; - uintnat num_elts; + int i; + uintnat num_elts, size; /* Read back header information */ b->num_dims = caml_deserialize_uint_4(); + if (b->num_dims < 0 || b->num_dims > CAML_BA_MAX_NUM_DIMS) + caml_deserialize_error("input_value: wrong number of bigarray dimensions"); b->flags = caml_deserialize_uint_4() | CAML_BA_MANAGED; b->proxy = NULL; for (i = 0; i < b->num_dims; i++) b->dim[i] = caml_deserialize_uint_4(); - /* Compute total number of elements */ - num_elts = caml_ba_num_elts(b); - /* Determine element size in bytes */ + /* Compute total number of elements. Watch out for overflows (MPR#7765). */ + num_elts = 1; + for (i = 0; i < b->num_dims; i++) { + if (caml_umul_overflow(num_elts, b->dim[i], &num_elts)) + caml_deserialize_error("input_value: size overflow for bigarray"); + } + /* Determine array size in bytes. Watch out for overflows (MPR#7765). */ if ((b->flags & CAML_BA_KIND_MASK) > CAML_BA_CHAR) caml_deserialize_error("input_value: bad bigarray kind"); - elt_size = caml_ba_element_size[b->flags & CAML_BA_KIND_MASK]; + if (caml_umul_overflow(num_elts, + caml_ba_element_size[b->flags & CAML_BA_KIND_MASK], + &size)) + caml_deserialize_error("input_value: size overflow for bigarray"); /* Allocate room for data */ - b->data = malloc(elt_size * num_elts); + b->data = malloc(size); if (b->data == NULL) caml_deserialize_error("input_value: out of memory for bigarray"); /* Read data */ @@ -484,3 +492,732 @@ CAMLexport uintnat caml_ba_deserialize(void * dst) /* PR#5516: use C99's flexible array types if possible */ return SIZEOF_BA_ARRAY + b->num_dims * sizeof(intnat); } + +/* Allocate a bigarray from OCaml */ + +CAMLprim value caml_ba_create(value vkind, value vlayout, value vdim) +{ + intnat dim[CAML_BA_MAX_NUM_DIMS]; + mlsize_t num_dims; + int i, flags; + + num_dims = Wosize_val(vdim); + /* here num_dims is unsigned (mlsize_t) so no need to check (num_dims >= 0) */ + if (num_dims > CAML_BA_MAX_NUM_DIMS) + caml_invalid_argument("Bigarray.create: bad number of dimensions"); + for (i = 0; i < num_dims; i++) { + dim[i] = Long_val(Field(vdim, i)); + if (dim[i] < 0) + caml_invalid_argument("Bigarray.create: negative dimension"); + } + flags = Caml_ba_kind_val(vkind) | Caml_ba_layout_val(vlayout); + return caml_ba_alloc(flags, num_dims, NULL, dim); +} + +/* Given a big array and a vector of indices, check that the indices + are within the bounds and return the offset of the corresponding + array element in the data part of the array. */ + +static long caml_ba_offset(struct caml_ba_array * b, intnat * index) +{ + intnat offset; + int i; + + offset = 0; + if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { + /* C-style layout: row major, indices start at 0 */ + for (i = 0; i < b->num_dims; i++) { + if ((uintnat) index[i] >= (uintnat) b->dim[i]) + caml_array_bound_error(); + offset = offset * b->dim[i] + index[i]; + } + } else { + /* Fortran-style layout: column major, indices start at 1 */ + for (i = b->num_dims - 1; i >= 0; i--) { + if ((uintnat) (index[i] - 1) >= (uintnat) b->dim[i]) + caml_array_bound_error(); + offset = offset * b->dim[i] + (index[i] - 1); + } + } + return offset; +} + +/* Helper function to allocate a record of two double floats */ + +static value copy_two_doubles(double d0, double d1) +{ + value res = caml_alloc_small(2 * Double_wosize, Double_array_tag); + Store_double_field(res, 0, d0); + Store_double_field(res, 1, d1); + return res; +} + +/* Generic code to read from a big array */ + +value caml_ba_get_N(value vb, value * vind, int nind) +{ + struct caml_ba_array * b = Caml_ba_array_val(vb); + intnat index[CAML_BA_MAX_NUM_DIMS]; + int i; + intnat offset; + + /* Check number of indices = number of dimensions of array + (maybe not necessary if ML typing guarantees this) */ + if (nind != b->num_dims) + caml_invalid_argument("Bigarray.get: wrong number of indices"); + /* Compute offset and check bounds */ + for (i = 0; i < b->num_dims; i++) index[i] = Long_val(vind[i]); + offset = caml_ba_offset(b, index); + /* Perform read */ + switch ((b->flags) & CAML_BA_KIND_MASK) { + default: + CAMLassert(0); + case CAML_BA_FLOAT32: + return caml_copy_double(((float *) b->data)[offset]); + case CAML_BA_FLOAT64: + return caml_copy_double(((double *) b->data)[offset]); + case CAML_BA_SINT8: + return Val_int(((int8 *) b->data)[offset]); + case CAML_BA_UINT8: + return Val_int(((uint8 *) b->data)[offset]); + case CAML_BA_SINT16: + return Val_int(((int16 *) b->data)[offset]); + case CAML_BA_UINT16: + return Val_int(((uint16 *) b->data)[offset]); + case CAML_BA_INT32: + return caml_copy_int32(((int32_t *) b->data)[offset]); + case CAML_BA_INT64: + return caml_copy_int64(((int64_t *) b->data)[offset]); + case CAML_BA_NATIVE_INT: + return caml_copy_nativeint(((intnat *) b->data)[offset]); + case CAML_BA_CAML_INT: + return Val_long(((intnat *) b->data)[offset]); + case CAML_BA_COMPLEX32: + { float * p = ((float *) b->data) + offset * 2; + return copy_two_doubles(p[0], p[1]); } + case CAML_BA_COMPLEX64: + { double * p = ((double *) b->data) + offset * 2; + return copy_two_doubles(p[0], p[1]); } + case CAML_BA_CHAR: + return Val_int(((unsigned char *) b->data)[offset]); + } +} + +CAMLprim value caml_ba_get_1(value vb, value vind1) +{ + return caml_ba_get_N(vb, &vind1, 1); +} + +CAMLprim value caml_ba_get_2(value vb, value vind1, value vind2) +{ + value vind[2]; + vind[0] = vind1; vind[1] = vind2; + return caml_ba_get_N(vb, vind, 2); +} + +CAMLprim value caml_ba_get_3(value vb, value vind1, value vind2, value vind3) +{ + value vind[3]; + vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; + return caml_ba_get_N(vb, vind, 3); +} + +CAMLprim value caml_ba_get_generic(value vb, value vind) +{ + return caml_ba_get_N(vb, &Field(vind, 0), Wosize_val(vind)); +} + + +CAMLprim value caml_ba_uint8_get16(value vb, value vind) +{ + intnat res; + unsigned char b1, b2; + intnat idx = Long_val(vind); + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 1) caml_array_bound_error(); + b1 = ((unsigned char*) b->data)[idx]; + b2 = ((unsigned char*) b->data)[idx+1]; +#ifdef ARCH_BIG_ENDIAN + res = b1 << 8 | b2; +#else + res = b2 << 8 | b1; +#endif + return Val_int(res); +} + +CAMLprim value caml_ba_uint8_get32(value vb, value vind) +{ + intnat res; + unsigned char b1, b2, b3, b4; + intnat idx = Long_val(vind); + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 3) caml_array_bound_error(); + b1 = ((unsigned char*) b->data)[idx]; + b2 = ((unsigned char*) b->data)[idx+1]; + b3 = ((unsigned char*) b->data)[idx+2]; + b4 = ((unsigned char*) b->data)[idx+3]; +#ifdef ARCH_BIG_ENDIAN + res = b1 << 24 | b2 << 16 | b3 << 8 | b4; +#else + res = b4 << 24 | b3 << 16 | b2 << 8 | b1; +#endif + return caml_copy_int32(res); +} + +CAMLprim value caml_ba_uint8_get64(value vb, value vind) +{ + uint64_t res; + unsigned char b1, b2, b3, b4, b5, b6, b7, b8; + intnat idx = Long_val(vind); + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 7) caml_array_bound_error(); + b1 = ((unsigned char*) b->data)[idx]; + b2 = ((unsigned char*) b->data)[idx+1]; + b3 = ((unsigned char*) b->data)[idx+2]; + b4 = ((unsigned char*) b->data)[idx+3]; + b5 = ((unsigned char*) b->data)[idx+4]; + b6 = ((unsigned char*) b->data)[idx+5]; + b7 = ((unsigned char*) b->data)[idx+6]; + b8 = ((unsigned char*) b->data)[idx+7]; +#ifdef ARCH_BIG_ENDIAN + res = (uint64_t) b1 << 56 | (uint64_t) b2 << 48 + | (uint64_t) b3 << 40 | (uint64_t) b4 << 32 + | (uint64_t) b5 << 24 | (uint64_t) b6 << 16 + | (uint64_t) b7 << 8 | (uint64_t) b8; +#else + res = (uint64_t) b8 << 56 | (uint64_t) b7 << 48 + | (uint64_t) b6 << 40 | (uint64_t) b5 << 32 + | (uint64_t) b4 << 24 | (uint64_t) b3 << 16 + | (uint64_t) b2 << 8 | (uint64_t) b1; +#endif + return caml_copy_int64(res); +} + +/* Generic write to a big array */ + +static value caml_ba_set_aux(value vb, value * vind, intnat nind, value newval) +{ + struct caml_ba_array * b = Caml_ba_array_val(vb); + intnat index[CAML_BA_MAX_NUM_DIMS]; + int i; + intnat offset; + + /* Check number of indices = number of dimensions of array + (maybe not necessary if ML typing guarantees this) */ + if (nind != b->num_dims) + caml_invalid_argument("Bigarray.set: wrong number of indices"); + /* Compute offset and check bounds */ + for (i = 0; i < b->num_dims; i++) index[i] = Long_val(vind[i]); + offset = caml_ba_offset(b, index); + /* Perform write */ + switch (b->flags & CAML_BA_KIND_MASK) { + default: + CAMLassert(0); + case CAML_BA_FLOAT32: + ((float *) b->data)[offset] = Double_val(newval); break; + case CAML_BA_FLOAT64: + ((double *) b->data)[offset] = Double_val(newval); break; + case CAML_BA_CHAR: + case CAML_BA_SINT8: + case CAML_BA_UINT8: + ((int8 *) b->data)[offset] = Int_val(newval); break; + case CAML_BA_SINT16: + case CAML_BA_UINT16: + ((int16 *) b->data)[offset] = Int_val(newval); break; + case CAML_BA_INT32: + ((int32_t *) b->data)[offset] = Int32_val(newval); break; + case CAML_BA_INT64: + ((int64_t *) b->data)[offset] = Int64_val(newval); break; + case CAML_BA_NATIVE_INT: + ((intnat *) b->data)[offset] = Nativeint_val(newval); break; + case CAML_BA_CAML_INT: + ((intnat *) b->data)[offset] = Long_val(newval); break; + case CAML_BA_COMPLEX32: + { float * p = ((float *) b->data) + offset * 2; + p[0] = Double_field(newval, 0); + p[1] = Double_field(newval, 1); + break; } + case CAML_BA_COMPLEX64: + { double * p = ((double *) b->data) + offset * 2; + p[0] = Double_field(newval, 0); + p[1] = Double_field(newval, 1); + break; } + } + return Val_unit; +} + +CAMLprim value caml_ba_set_1(value vb, value vind1, value newval) +{ + return caml_ba_set_aux(vb, &vind1, 1, newval); +} + +CAMLprim value caml_ba_set_2(value vb, value vind1, value vind2, value newval) +{ + value vind[2]; + vind[0] = vind1; vind[1] = vind2; + return caml_ba_set_aux(vb, vind, 2, newval); +} + +CAMLprim value caml_ba_set_3(value vb, value vind1, value vind2, value vind3, + value newval) +{ + value vind[3]; + vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; + return caml_ba_set_aux(vb, vind, 3, newval); +} + +value caml_ba_set_N(value vb, value * vind, int nargs) +{ + return caml_ba_set_aux(vb, vind, nargs - 1, vind[nargs - 1]); +} + +CAMLprim value caml_ba_set_generic(value vb, value vind, value newval) +{ + return caml_ba_set_aux(vb, &Field(vind, 0), Wosize_val(vind), newval); +} + +CAMLprim value caml_ba_uint8_set16(value vb, value vind, value newval) +{ + unsigned char b1, b2; + intnat val; + intnat idx = Long_val(vind); + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 1) caml_array_bound_error(); + val = Long_val(newval); +#ifdef ARCH_BIG_ENDIAN + b1 = 0xFF & val >> 8; + b2 = 0xFF & val; +#else + b2 = 0xFF & val >> 8; + b1 = 0xFF & val; +#endif + ((unsigned char*) b->data)[idx] = b1; + ((unsigned char*) b->data)[idx+1] = b2; + return Val_unit; +} + +CAMLprim value caml_ba_uint8_set32(value vb, value vind, value newval) +{ + unsigned char b1, b2, b3, b4; + intnat idx = Long_val(vind); + intnat val; + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 3) caml_array_bound_error(); + val = Int32_val(newval); +#ifdef ARCH_BIG_ENDIAN + b1 = 0xFF & val >> 24; + b2 = 0xFF & val >> 16; + b3 = 0xFF & val >> 8; + b4 = 0xFF & val; +#else + b4 = 0xFF & val >> 24; + b3 = 0xFF & val >> 16; + b2 = 0xFF & val >> 8; + b1 = 0xFF & val; +#endif + ((unsigned char*) b->data)[idx] = b1; + ((unsigned char*) b->data)[idx+1] = b2; + ((unsigned char*) b->data)[idx+2] = b3; + ((unsigned char*) b->data)[idx+3] = b4; + return Val_unit; +} + +CAMLprim value caml_ba_uint8_set64(value vb, value vind, value newval) +{ + unsigned char b1, b2, b3, b4, b5, b6, b7, b8; + intnat idx = Long_val(vind); + int64_t val; + struct caml_ba_array * b = Caml_ba_array_val(vb); + if (idx < 0 || idx >= b->dim[0] - 7) caml_array_bound_error(); + val = Int64_val(newval); +#ifdef ARCH_BIG_ENDIAN + b1 = 0xFF & val >> 56; + b2 = 0xFF & val >> 48; + b3 = 0xFF & val >> 40; + b4 = 0xFF & val >> 32; + b5 = 0xFF & val >> 24; + b6 = 0xFF & val >> 16; + b7 = 0xFF & val >> 8; + b8 = 0xFF & val; +#else + b8 = 0xFF & val >> 56; + b7 = 0xFF & val >> 48; + b6 = 0xFF & val >> 40; + b5 = 0xFF & val >> 32; + b4 = 0xFF & val >> 24; + b3 = 0xFF & val >> 16; + b2 = 0xFF & val >> 8; + b1 = 0xFF & val; +#endif + ((unsigned char*) b->data)[idx] = b1; + ((unsigned char*) b->data)[idx+1] = b2; + ((unsigned char*) b->data)[idx+2] = b3; + ((unsigned char*) b->data)[idx+3] = b4; + ((unsigned char*) b->data)[idx+4] = b5; + ((unsigned char*) b->data)[idx+5] = b6; + ((unsigned char*) b->data)[idx+6] = b7; + ((unsigned char*) b->data)[idx+7] = b8; + return Val_unit; +} + +/* Return the number of dimensions of a big array */ + +CAMLprim value caml_ba_num_dims(value vb) +{ + struct caml_ba_array * b = Caml_ba_array_val(vb); + return Val_long(b->num_dims); +} + +/* Return the n-th dimension of a big array */ + +CAMLprim value caml_ba_dim(value vb, value vn) +{ + struct caml_ba_array * b = Caml_ba_array_val(vb); + intnat n = Long_val(vn); + if (n < 0 || n >= b->num_dims) caml_invalid_argument("Bigarray.dim"); + return Val_long(b->dim[n]); +} + +CAMLprim value caml_ba_dim_1(value vb) +{ + return caml_ba_dim(vb, Val_int(0)); +} + +CAMLprim value caml_ba_dim_2(value vb) +{ + return caml_ba_dim(vb, Val_int(1)); +} + +CAMLprim value caml_ba_dim_3(value vb) +{ + return caml_ba_dim(vb, Val_int(2)); +} + +/* Return the kind of a big array */ + +CAMLprim value caml_ba_kind(value vb) +{ + return Val_caml_ba_kind(Caml_ba_array_val(vb)->flags & CAML_BA_KIND_MASK); +} + +/* Return the layout of a big array */ + +CAMLprim value caml_ba_layout(value vb) +{ + int layout = Caml_ba_array_val(vb)->flags & CAML_BA_LAYOUT_MASK; + return Val_caml_ba_layout(layout); +} + +/* Create / update proxy to indicate that b2 is a sub-array of b1 */ + +static void caml_ba_update_proxy(struct caml_ba_array * b1, + struct caml_ba_array * b2) +{ + struct caml_ba_proxy * proxy; + /* Nothing to do for un-managed arrays */ + if ((b1->flags & CAML_BA_MANAGED_MASK) == CAML_BA_EXTERNAL) return; + if (b1->proxy != NULL) { + /* If b1 is already a proxy for a larger array, increment refcount of + proxy */ + b2->proxy = b1->proxy; + ++ b1->proxy->refcount; + } else { + /* Otherwise, create proxy and attach it to both b1 and b2 */ + proxy = malloc(sizeof(struct caml_ba_proxy)); + if (proxy == NULL) caml_raise_out_of_memory(); + proxy->refcount = 2; /* original array + sub array */ + proxy->data = b1->data; + proxy->size = + b1->flags & CAML_BA_MAPPED_FILE ? caml_ba_byte_size(b1) : 0; + b1->proxy = proxy; + b2->proxy = proxy; + } +} + +/* Slicing */ + +CAMLprim value caml_ba_slice(value vb, value vind) +{ + CAMLparam2 (vb, vind); + #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) + CAMLlocal1 (res); + intnat index[CAML_BA_MAX_NUM_DIMS]; + int num_inds, i; + intnat offset; + intnat * sub_dims; + char * sub_data; + + /* Check number of indices <= number of dimensions of array */ + num_inds = Wosize_val(vind); + if (num_inds > b->num_dims) + caml_invalid_argument("Bigarray.slice: too many indices"); + /* Compute offset and check bounds */ + if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { + /* We slice from the left */ + for (i = 0; i < num_inds; i++) index[i] = Long_val(Field(vind, i)); + for (/*nothing*/; i < b->num_dims; i++) index[i] = 0; + offset = caml_ba_offset(b, index); + sub_dims = b->dim + num_inds; + } else { + /* We slice from the right */ + for (i = 0; i < num_inds; i++) + index[b->num_dims - num_inds + i] = Long_val(Field(vind, i)); + for (i = 0; i < b->num_dims - num_inds; i++) index[i] = 1; + offset = caml_ba_offset(b, index); + sub_dims = b->dim; + } + sub_data = + (char *) b->data + + offset * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK]; + /* Allocate an OCaml bigarray to hold the result */ + res = caml_ba_alloc(b->flags, b->num_dims - num_inds, sub_data, sub_dims); + /* Create or update proxy in case of managed bigarray */ + caml_ba_update_proxy(b, Caml_ba_array_val(res)); + /* Return result */ + CAMLreturn (res); + + #undef b +} + +/* Changing the layout of an array (memory is shared) */ + +CAMLprim value caml_ba_change_layout(value vb, value vlayout) +{ + CAMLparam2 (vb, vlayout); + CAMLlocal1 (res); + #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) + /* if the layout is different, change the flags and reverse the dimensions */ + if (Caml_ba_layout_val(vlayout) != (b->flags & CAML_BA_LAYOUT_MASK)) { + /* change the flags to reflect the new layout */ + int flags = (b->flags & (CAML_BA_KIND_MASK | CAML_BA_MANAGED_MASK)) + | Caml_ba_layout_val(vlayout); + /* reverse the dimensions */ + intnat new_dim[CAML_BA_MAX_NUM_DIMS]; + unsigned int i; + for(i = 0; i < b->num_dims; i++) new_dim[i] = b->dim[b->num_dims - i - 1]; + res = caml_ba_alloc(flags, b->num_dims, b->data, new_dim); + caml_ba_update_proxy(b, Caml_ba_array_val(res)); + CAMLreturn(res); + } else { + /* otherwise, do nothing */ + CAMLreturn(vb); + } + #undef b +} + + +/* Extracting a sub-array of same number of dimensions */ + +CAMLprim value caml_ba_sub(value vb, value vofs, value vlen) +{ + CAMLparam3 (vb, vofs, vlen); + CAMLlocal1 (res); + #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) + intnat ofs = Long_val(vofs); + intnat len = Long_val(vlen); + int i, changed_dim; + intnat mul; + char * sub_data; + + /* Compute offset and check bounds */ + if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { + /* We reduce the first dimension */ + mul = 1; + for (i = 1; i < b->num_dims; i++) mul *= b->dim[i]; + changed_dim = 0; + } else { + /* We reduce the last dimension */ + mul = 1; + for (i = 0; i < b->num_dims - 1; i++) mul *= b->dim[i]; + changed_dim = b->num_dims - 1; + ofs--; /* Fortran arrays start at 1 */ + } + if (ofs < 0 || len < 0 || ofs + len > b->dim[changed_dim]) + caml_invalid_argument("Bigarray.sub: bad sub-array"); + sub_data = + (char *) b->data + + ofs * mul * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK]; + /* Allocate an OCaml bigarray to hold the result */ + res = caml_ba_alloc(b->flags, b->num_dims, sub_data, b->dim); + /* Doctor the changed dimension */ + Caml_ba_array_val(res)->dim[changed_dim] = len; + /* Create or update proxy in case of managed bigarray */ + caml_ba_update_proxy(b, Caml_ba_array_val(res)); + /* Return result */ + CAMLreturn (res); + + #undef b +} + +/* Copying a big array into another one */ + +#define LEAVE_RUNTIME_OP_CUTOFF 4096 +#define is_mmapped(ba) ((ba)->flags & CAML_BA_MAPPED_FILE) + +CAMLprim value caml_ba_blit(value vsrc, value vdst) +{ + CAMLparam2(vsrc, vdst); + struct caml_ba_array * src = Caml_ba_array_val(vsrc); + struct caml_ba_array * dst = Caml_ba_array_val(vdst); + void *src_data = src->data; + void *dst_data = dst->data; + int i; + intnat num_bytes; + int leave_runtime; + + /* Check same numbers of dimensions and same dimensions */ + if (src->num_dims != dst->num_dims) goto blit_error; + for (i = 0; i < src->num_dims; i++) + if (src->dim[i] != dst->dim[i]) goto blit_error; + /* Compute number of bytes in array data */ + num_bytes = + caml_ba_num_elts(src) + * caml_ba_element_size[src->flags & CAML_BA_KIND_MASK]; + leave_runtime = + ( + (num_bytes >= LEAVE_RUNTIME_OP_CUTOFF*sizeof(long)) + || is_mmapped(src) + || is_mmapped(dst) + ); + /* Do the copying */ + if (leave_runtime) caml_enter_blocking_section(); + memmove (dst_data, src_data, num_bytes); + if (leave_runtime) caml_leave_blocking_section(); + CAMLreturn (Val_unit); + blit_error: + caml_invalid_argument("Bigarray.blit: dimension mismatch"); + CAMLreturn (Val_unit); /* not reached */ +} + +/* Filling a big array with a given value */ + +#define FILL_GEN_LOOP(n_ops, loop) do{ \ + int leave_runtime = ((n_ops >= LEAVE_RUNTIME_OP_CUTOFF) || is_mmapped(b)); \ + if (leave_runtime) caml_enter_blocking_section(); \ + loop; \ + if (leave_runtime) caml_leave_blocking_section(); \ +}while(0) + +#define FILL_SCALAR_LOOP \ + FILL_GEN_LOOP(num_elts, \ + for (p = data; num_elts > 0; p++, num_elts--) *p = init) + +#define FILL_COMPLEX_LOOP \ + FILL_GEN_LOOP(num_elts + num_elts, \ + for (p = data; num_elts > 0; num_elts--) { *p++ = init0; *p++ = init1; }) + +CAMLprim value caml_ba_fill(value vb, value vinit) +{ + CAMLparam1(vb); + struct caml_ba_array * b = Caml_ba_array_val(vb); + void *data = b->data; + intnat num_elts = caml_ba_num_elts(b); + + switch (b->flags & CAML_BA_KIND_MASK) { + default: + CAMLassert(0); + case CAML_BA_FLOAT32: { + float init = Double_val(vinit); + float * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_FLOAT64: { + double init = Double_val(vinit); + double * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_CHAR: + case CAML_BA_SINT8: + case CAML_BA_UINT8: { + int init = Int_val(vinit); + unsigned char * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_SINT16: + case CAML_BA_UINT16: { + int init = Int_val(vinit); + int16 * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_INT32: { + int32_t init = Int32_val(vinit); + int32_t * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_INT64: { + int64_t init = Int64_val(vinit); + int64_t * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_NATIVE_INT: { + intnat init = Nativeint_val(vinit); + intnat * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_CAML_INT: { + intnat init = Long_val(vinit); + intnat * p; + FILL_SCALAR_LOOP; + break; + } + case CAML_BA_COMPLEX32: { + float init0 = Double_field(vinit, 0); + float init1 = Double_field(vinit, 1); + float * p; + FILL_COMPLEX_LOOP; + break; + } + case CAML_BA_COMPLEX64: { + double init0 = Double_field(vinit, 0); + double init1 = Double_field(vinit, 1); + double * p; + FILL_COMPLEX_LOOP; + break; + } + } + CAMLreturn (Val_unit); +} + +/* Reshape an array: change dimensions and number of dimensions, preserving + array contents */ + +CAMLprim value caml_ba_reshape(value vb, value vdim) +{ + CAMLparam2 (vb, vdim); + CAMLlocal1 (res); +#define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) + intnat dim[CAML_BA_MAX_NUM_DIMS]; + mlsize_t num_dims; + uintnat num_elts; + int i; + + num_dims = Wosize_val(vdim); + /* here num_dims is unsigned (mlsize_t) so no need to check (num_dims >= 0) */ + if (num_dims > CAML_BA_MAX_NUM_DIMS) + caml_invalid_argument("Bigarray.reshape: bad number of dimensions"); + num_elts = 1; + for (i = 0; i < num_dims; i++) { + dim[i] = Long_val(Field(vdim, i)); + if (dim[i] < 0) + caml_invalid_argument("Bigarray.reshape: negative dimension"); + num_elts *= dim[i]; + } + /* Check that sizes agree */ + if (num_elts != caml_ba_num_elts(b)) + caml_invalid_argument("Bigarray.reshape: size mismatch"); + /* Create bigarray with same data and new dimensions */ + res = caml_ba_alloc(b->flags, num_dims, b->data, dim); + /* Create or update proxy in case of managed bigarray */ + caml_ba_update_proxy(b, Caml_ba_array_val(res)); + /* Return result */ + CAMLreturn (res); + +#undef b +} diff --git a/byterun/caml/config.h b/byterun/caml/config.h index cee3e8bf..0dba12ad 100644 --- a/byterun/caml/config.h +++ b/byterun/caml/config.h @@ -29,6 +29,8 @@ #include "compatibility.h" #endif +#include + #ifdef HAS_STDINT_H #include #endif diff --git a/byterun/caml/exec.h b/byterun/caml/exec.h index f39747ac..38ab7ae8 100644 --- a/byterun/caml/exec.h +++ b/byterun/caml/exec.h @@ -58,7 +58,7 @@ struct exec_trailer { /* Magic number for this release */ -#define EXEC_MAGIC "Caml1999X011" +#define EXEC_MAGIC "Caml1999X023" #endif /* CAML_INTERNALS */ diff --git a/byterun/caml/instruct.h b/byterun/caml/instruct.h index 73798333..5c10df4f 100644 --- a/byterun/caml/instruct.h +++ b/byterun/caml/instruct.h @@ -41,7 +41,7 @@ enum instructions { GETFIELD0, GETFIELD1, GETFIELD2, GETFIELD3, GETFIELD, GETFLOATFIELD, SETFIELD0, SETFIELD1, SETFIELD2, SETFIELD3, SETFIELD, SETFLOATFIELD, VECTLENGTH, GETVECTITEM, SETVECTITEM, - GETSTRINGCHAR, SETSTRINGCHAR, + GETBYTESCHAR, SETBYTESCHAR, BRANCH, BRANCHIF, BRANCHIFNOT, SWITCH, BOOLNOT, PUSHTRAP, POPTRAP, RAISE, CHECK_SIGNALS, @@ -60,6 +60,7 @@ enum instructions { STOP, EVENT, BREAK, RERAISE, RAISE_NOTRACE, + GETSTRINGCHAR, FIRST_UNIMPLEMENTED_OP}; #endif /* CAML_INTERNALS */ diff --git a/byterun/caml/intext.h b/byterun/caml/intext.h index 673c6fc0..f67c98b5 100644 --- a/byterun/caml/intext.h +++ b/byterun/caml/intext.h @@ -196,7 +196,7 @@ struct code_fragment { CAMLextern struct code_fragment * caml_extern_find_code(char *addr); -struct ext_table caml_code_fragments_table; +extern struct ext_table caml_code_fragments_table; #endif /* CAML_INTERNALS */ diff --git a/byterun/caml/major_gc.h b/byterun/caml/major_gc.h index a6c42d9e..813f8a78 100644 --- a/byterun/caml/major_gc.h +++ b/byterun/caml/major_gc.h @@ -64,9 +64,9 @@ extern uintnat total_heap_size; extern char *caml_gc_sweep_hp; extern int caml_major_window; -double caml_major_ring[Max_major_window]; -int caml_major_ring_index; -double caml_major_work_credit; +extern double caml_major_ring[Max_major_window]; +extern int caml_major_ring_index; +extern double caml_major_work_credit; extern double caml_gc_clock; /* [caml_major_gc_hook] is called just between the end of the mark diff --git a/byterun/caml/minor_gc.h b/byterun/caml/minor_gc.h index e0820752..6c48c761 100644 --- a/byterun/caml/minor_gc.h +++ b/byterun/caml/minor_gc.h @@ -26,6 +26,7 @@ CAMLextern value *caml_young_ptr, *caml_young_limit; CAMLextern value *caml_young_trigger; extern asize_t caml_minor_heap_wsz; extern int caml_in_minor_collection; +extern double caml_extra_heap_resources_minor; #define CAML_TABLE_STRUCT(t) { \ t *base; \ diff --git a/byterun/caml/misc.h b/byterun/caml/misc.h index d9a7b768..8244de93 100644 --- a/byterun/caml/misc.h +++ b/byterun/caml/misc.h @@ -180,10 +180,8 @@ typedef wchar_t char_os; #define rename_os caml_win32_rename #define chdir_os _wchdir #define getcwd_os _wgetcwd -#define getenv_os _wgetenv #define system_os _wsystem #define rmdir_os _wrmdir -#define utime_os _wutime #define putenv_os _wputenv #define chmod_os _wchmod #define execv_os _wexecv @@ -214,10 +212,8 @@ typedef char char_os; #define rename_os rename #define chdir_os chdir #define getcwd_os getcwd -#define getenv_os getenv #define system_os system #define rmdir_os rmdir -#define utime_os utime #define putenv_os putenv #define chmod_os chmod #define execv_os execv @@ -252,7 +248,7 @@ typedef char char_os; #define CAML_SYS_UNLINK(filename) unlink_os(filename) #define CAML_SYS_RENAME(old_name,new_name) rename_os(old_name, new_name) #define CAML_SYS_CHDIR(dirname) chdir_os(dirname) -#define CAML_SYS_GETENV(varname) getenv_os(varname) +#define CAML_SYS_GETENV(varname) getenv(varname) #define CAML_SYS_SYSTEM(command) system_os(command) #define CAML_SYS_READ_DIRECTORY(dirname,tbl) caml_read_directory(dirname,tbl) @@ -306,7 +302,7 @@ extern intnat (*caml_cplugins_prim)(int,intnat,intnat,intnat); #define CAML_SYS_CHDIR(dirname) \ CAML_SYS_PRIM_1(CAML_CPLUGINS_CHDIR,chdir_os,dirname) #define CAML_SYS_GETENV(varname) \ - CAML_SYS_STRING_PRIM_1(CAML_CPLUGINS_GETENV,getenv_os,varname) + CAML_SYS_STRING_PRIM_1(CAML_CPLUGINS_GETENV,getenv,varname) #define CAML_SYS_SYSTEM(command) \ CAML_SYS_PRIM_1(CAML_CPLUGINS_SYSTEM,system_os,command) #define CAML_SYS_READ_DIRECTORY(dirname,tbl) \ diff --git a/byterun/caml/osdeps.h b/byterun/caml/osdeps.h index bc75a7de..b65503d8 100644 --- a/byterun/caml/osdeps.h +++ b/byterun/caml/osdeps.h @@ -98,6 +98,11 @@ extern char_os * caml_executable_name(void); */ extern char_os *caml_secure_getenv(char_os const *var); +/* If [fd] refers to a terminal or console, return the number of rows + (lines) that it displays. Otherwise, or if the number of rows + cannot be determined, return -1. */ +extern int caml_num_rows_fd(int fd); + #ifdef _WIN32 extern int caml_win32_rename(const wchar_t *, const wchar_t *); @@ -106,6 +111,8 @@ extern void caml_probe_win32_version(void); extern void caml_setup_win32_terminal(void); extern void caml_restore_win32_terminal(void); +extern wchar_t *caml_win32_getenv(wchar_t const *); + /* Windows Unicode support */ extern int win_multi_byte_to_wide_char(const char* s, int slen, wchar_t *out, int outlen); @@ -136,6 +143,8 @@ extern char* caml_stat_strdup_of_utf16(const wchar_t *s); */ extern value caml_copy_string_of_utf16(const wchar_t *s); +extern int caml_win32_isatty(int fd); + #endif /* _WIN32 */ #endif /* CAML_INTERNALS */ diff --git a/byterun/caml/spacetime.h b/byterun/caml/spacetime.h index df1193e2..5bcc9232 100644 --- a/byterun/caml/spacetime.h +++ b/byterun/caml/spacetime.h @@ -15,11 +15,9 @@ #ifndef CAML_SPACETIME_H #define CAML_SPACETIME_H -#ifdef NATIVE_CODE - -#include "caml/io.h" -#include "caml/misc.h" -#include "caml/stack.h" +#include "io.h" +#include "misc.h" +#include "stack.h" /* Runtime support for Spacetime profiling. * This header file is not intended for the casual user. @@ -202,7 +200,4 @@ extern void caml_spacetime_automatic_snapshot (void); #define Get_my_profinfo_with_cached_backtrace(profinfo, size) \ profinfo = (uintnat) 0; -#endif /* NATIVE_CODE */ - - #endif diff --git a/byterun/custom.c b/byterun/custom.c index f68eac95..b6a5c4e3 100644 --- a/byterun/custom.c +++ b/byterun/custom.c @@ -22,6 +22,7 @@ #include "caml/fail.h" #include "caml/memory.h" #include "caml/mlvalues.h" +#include "caml/signals.h" /* [size] is a number of bytes */ CAMLexport value caml_alloc_custom(struct custom_operations * ops, @@ -30,7 +31,8 @@ CAMLexport value caml_alloc_custom(struct custom_operations * ops, mlsize_t max) { mlsize_t wosize; - value result; + CAMLparam0(); + CAMLlocal1(result); wosize = 1 + (size + sizeof(value) - 1) / sizeof(value); if (wosize <= Max_young_wosize) { @@ -39,6 +41,16 @@ CAMLexport value caml_alloc_custom(struct custom_operations * ops, if (ops->finalize != NULL || mem != 0) { /* Remember that the block needs processing after minor GC. */ add_to_custom_table (&caml_custom_table, result, mem, max); + /* Keep track of extra resources held by custom block in + minor heap. */ + if (mem != 0) { + if (max == 0) max = 1; + caml_extra_heap_resources_minor += (double) mem / (double) max; + if (caml_extra_heap_resources_minor > 1.0) { + caml_request_minor_gc (); + caml_gc_dispatch (); + } + } } } else { result = caml_alloc_shr(wosize, Custom_tag); @@ -46,7 +58,7 @@ CAMLexport value caml_alloc_custom(struct custom_operations * ops, caml_adjust_gc_speed(mem, max); result = caml_check_urgent_gc(result); } - return result; + CAMLreturn(result); } struct custom_operations_list { diff --git a/byterun/debugger.c b/byterun/debugger.c index 71536774..1c416cd6 100644 --- a/byterun/debugger.c +++ b/byterun/debugger.c @@ -165,6 +165,7 @@ void caml_debugger_init(void) { char * address; char_os * a; + size_t a_len; char * port, * p; struct hostent * host; int n; @@ -194,11 +195,16 @@ void caml_debugger_init(void) /* Unix domain */ sock_domain = PF_UNIX; sock_addr.s_unix.sun_family = AF_UNIX; + a_len = strlen(address); + if (a_len >= sizeof(sock_addr.s_unix.sun_path)) { + caml_fatal_error("Debug socket path length exceeds maximum permitted length"); + } strncpy(sock_addr.s_unix.sun_path, address, - sizeof(sock_addr.s_unix.sun_path)); + sizeof(sock_addr.s_unix.sun_path) - 1); + sock_addr.s_unix.sun_path[sizeof(sock_addr.s_unix.sun_path) - 1] = '\0'; sock_addr_len = ((char *)&(sock_addr.s_unix.sun_path) - (char *)&(sock_addr.s_unix)) - + strlen(address); + + a_len; #else caml_fatal_error("Unix sockets not supported"); #endif diff --git a/byterun/extern.c b/byterun/extern.c index adebc910..db7163cd 100644 --- a/byterun/extern.c +++ b/byterun/extern.c @@ -694,7 +694,7 @@ CAMLprim value caml_output_value(value vchan, value v, value flags) CAMLreturn (Val_unit); } -CAMLprim value caml_output_value_to_string(value v, value flags) +CAMLprim value caml_output_value_to_bytes(value v, value flags) { char header[32]; int header_len; @@ -722,6 +722,11 @@ CAMLprim value caml_output_value_to_string(value v, value flags) return res; } +CAMLprim value caml_output_value_to_string(value v, value flags) +{ + return caml_output_value_to_bytes(v,flags); +} + CAMLexport intnat caml_output_value_to_block(value v, value flags, char * buf, intnat len) { diff --git a/byterun/finalise.c b/byterun/finalise.c index 9a41ff78..d34913fb 100644 --- a/byterun/finalise.c +++ b/byterun/finalise.c @@ -314,7 +314,7 @@ static void generic_final_minor_update (struct finalisable * final) CAMLassert (Is_block (final->table[i].val)); CAMLassert (Is_in_heap_or_young (final->table[i].val)); CAMLassert (Tag_val (final->table[i].val) != Forward_tag); - if(Is_young(final->table[j].val) && Hd_val(final->table[i].val) != 0){ + if(Is_young(final->table[i].val) && Hd_val(final->table[i].val) != 0){ /** dead */ to_do_tl->item[k] = final->table[i]; /* The finalisation function is called with unit not with the value */ diff --git a/byterun/fix_code.c b/byterun/fix_code.c index 68f97c99..ec2f08cc 100644 --- a/byterun/fix_code.c +++ b/byterun/fix_code.c @@ -38,6 +38,7 @@ code_t caml_start_code; asize_t caml_code_size; unsigned char * caml_saved_code; +struct ext_table caml_code_fragments_table; /* Read the main bytecode block from a file */ diff --git a/byterun/floats.c b/byterun/floats.c index fe313c59..4d2494cf 100644 --- a/byterun/floats.c +++ b/byterun/floats.c @@ -226,7 +226,19 @@ static int caml_float_of_hex(const char * s, double * res) if (*s == 0) return -1; /* nothing after exponent mark */ e = strtol(s, &p, 10); if (*p != 0) return -1; /* ill-formed exponent */ - if (e < INT_MIN || e > INT_MAX) return -1; /* unreasonable exponent */ + /* Handle exponents larger than int by returning 0/∞ directly. + Mind that INT_MIN/INT_MAX are included in the test so as to capture + the overflow case of strtol on Win64 — long and int have the same + size there. */ + if (e <= INT_MIN) { + *res = 0.; + return 0; + } + else if (e >= INT_MAX) { + *res = m == 0 ? 0. : HUGE_VAL; + return 0; + } + /* regular exponent value */ exp = e; s = p; /* stop at next loop iteration */ break; @@ -261,8 +273,17 @@ static int caml_float_of_hex(const char * s, double * res) on several architectures. */ f = (double) (int64_t) m; /* Adjust exponent to take decimal point and extra digits into account */ - if (dec_point >= 0) exp = exp + (dec_point - n_bits); - exp = exp + x_bits; + { + int adj = x_bits; + if (dec_point >= 0) adj = adj + (dec_point - n_bits); + /* saturated addition exp + adj */ + if (adj > 0 && exp > INT_MAX - adj) + exp = INT_MAX; + else if (adj < 0 && exp < INT_MIN - adj) + exp = INT_MIN; + else + exp = exp + adj; + } /* Apply exponent if needed */ if (exp != 0) f = ldexp(f, exp); /* Done! */ diff --git a/byterun/freelist.c b/byterun/freelist.c index 26c1d9c4..915eb9f9 100644 --- a/byterun/freelist.c +++ b/byterun/freelist.c @@ -534,9 +534,13 @@ header_t *caml_fl_merge_block (value bp) */ void caml_fl_add_blocks (value bp) { + value cur = bp; CAMLassert (fl_last != Val_NULL); CAMLassert (Next (fl_last) == Val_NULL); - caml_fl_cur_wsz += Whsize_bp (bp); + do { + caml_fl_cur_wsz += Whsize_bp (cur); + cur = Field(cur, 0); + } while (cur != Val_NULL); if (bp > fl_last){ Next (fl_last) = bp; @@ -547,7 +551,7 @@ void caml_fl_add_blocks (value bp) flp [flp_size++] = fl_last; } }else{ - value cur, prev; + value prev; prev = Fl_head; cur = Next (prev); diff --git a/byterun/intern.c b/byterun/intern.c index ba78846f..565ed10d 100644 --- a/byterun/intern.c +++ b/byterun/intern.c @@ -777,7 +777,7 @@ CAMLprim value caml_input_value_to_outside_heap(value vchan) CAMLreturn (res); } -CAMLexport value caml_input_val_from_string(value str, intnat ofs) +CAMLexport value caml_input_val_from_bytes(value str, intnat ofs) { CAMLparam1 (str); CAMLlocal1 (obj); @@ -801,7 +801,12 @@ CAMLexport value caml_input_val_from_string(value str, intnat ofs) CAMLprim value caml_input_value_from_string(value str, value ofs) { - return caml_input_val_from_string(str, Long_val(ofs)); + return caml_input_val_from_bytes(str, Long_val(ofs)); +} + +CAMLprim value caml_input_value_from_bytes(value str, value ofs) +{ + return caml_input_val_from_bytes(str, Long_val(ofs)); } static value input_val_from_block(struct marshal_header * h) diff --git a/byterun/interp.c b/byterun/interp.c index 76e600c9..0b74df3d 100644 --- a/byterun/interp.c +++ b/byterun/interp.c @@ -778,13 +778,13 @@ value caml_interprete(code_t prog, asize_t prog_size) sp += 2; Next; -/* String operations */ - +/* Bytes/String operations */ Instruct(GETSTRINGCHAR): + Instruct(GETBYTESCHAR): accu = Val_int(Byte_u(accu, Long_val(sp[0]))); sp += 1; Next; - Instruct(SETSTRINGCHAR): + Instruct(SETBYTESCHAR): Byte_u(accu, Long_val(sp[0])) = Int_val(sp[1]); sp += 2; accu = Val_unit; @@ -1002,10 +1002,9 @@ value caml_interprete(code_t prog, asize_t prog_size) Instruct(LSLINT): accu = (value)((((intnat) accu - 1) << Long_val(*sp++)) + 1); Next; Instruct(LSRINT): - accu = (value)((((uintnat) accu - 1) >> Long_val(*sp++)) | 1); - Next; + accu = (value)((((uintnat) accu) >> Long_val(*sp++)) | 1); Next; Instruct(ASRINT): - accu = (value)((((intnat) accu - 1) >> Long_val(*sp++)) | 1); Next; + accu = (value)((((intnat) accu) >> Long_val(*sp++)) | 1); Next; #define Integer_comparison(typ,opname,tst) \ Instruct(opname): \ diff --git a/byterun/ints.c b/byterun/ints.c index a104a0ee..76ae11d4 100644 --- a/byterun/ints.c +++ b/byterun/ints.c @@ -687,7 +687,7 @@ static uintnat nativeint_deserialize(void * dst) default: caml_deserialize_error("input_value: ill-formed native integer"); } - return sizeof(long); + return sizeof(intnat); } CAMLexport struct custom_operations caml_nativeint_ops = { diff --git a/byterun/io.c b/byterun/io.c index 3d956019..d124b56a 100644 --- a/byterun/io.c +++ b/byterun/io.c @@ -821,3 +821,8 @@ CAMLprim value caml_ml_input_scan_line(value vchannel) Unlock(channel); CAMLreturn (Val_long(res)); } + +CAMLprim value caml_terminfo_rows(value vchannel) +{ + return Val_int(caml_num_rows_fd(Channel(vchannel)->fd)); +} diff --git a/byterun/memory.c b/byterun/memory.c index 69a81611..f92b23c4 100644 --- a/byterun/memory.c +++ b/byterun/memory.c @@ -728,10 +728,19 @@ struct pool_block { #endif struct pool_block *next; struct pool_block *prev; - union max_align data[1]; /* not allocated, used for alignment purposes */ + /* Use C99's flexible array types if possible */ +#if (__STDC_VERSION__ >= 199901L) + union max_align data[]; /* not allocated, used for alignment purposes */ +#else + union max_align data[1]; +#endif }; +#if (__STDC_VERSION__ >= 199901L) +#define SIZEOF_POOL_BLOCK sizeof(struct pool_block) +#else #define SIZEOF_POOL_BLOCK offsetof(struct pool_block, data) +#endif static struct pool_block *pool = NULL; diff --git a/byterun/minor_gc.c b/byterun/minor_gc.c index b59b055d..6aa5ed72 100644 --- a/byterun/minor_gc.c +++ b/byterun/minor_gc.c @@ -77,6 +77,8 @@ CAMLexport struct caml_custom_table int caml_in_minor_collection = 0; +double caml_extra_heap_resources_minor = 0; + /* [sz] and [rsv] are numbers of entries */ static void alloc_generic_table (struct generic_table *tbl, asize_t sz, asize_t rsv, asize_t element_size) @@ -394,6 +396,7 @@ void caml_empty_minor_heap (void) clear_table ((struct generic_table *) &caml_ref_table); clear_table ((struct generic_table *) &caml_ephe_ref_table); clear_table ((struct generic_table *) &caml_custom_table); + caml_extra_heap_resources_minor = 0; caml_gc_message (0x02, ">"); caml_in_minor_collection = 0; caml_final_empty_young (); diff --git a/byterun/signals.c b/byterun/signals.c index e092e8d0..15addf1b 100644 --- a/byterun/signals.c +++ b/byterun/signals.c @@ -144,12 +144,12 @@ void caml_execute_signal(int signal_number, int in_signal_handler) void* saved_spacetime_trie_node_ptr; #endif #ifdef POSIX_SIGNALS - sigset_t sigs; + sigset_t nsigs, sigs; /* Block the signal before executing the handler, and record in sigs the original signal mask */ - sigemptyset(&sigs); - sigaddset(&sigs, signal_number); - sigprocmask(SIG_BLOCK, &sigs, &sigs); + sigemptyset(&nsigs); + sigaddset(&nsigs, signal_number); + sigprocmask(SIG_BLOCK, &nsigs, &sigs); #endif #if defined(NATIVE_CODE) && defined(WITH_SPACETIME) /* We record the signal handler's execution separately, in the same diff --git a/byterun/str.c b/byterun/str.c index 2eeceb55..8e07cb03 100644 --- a/byterun/str.c +++ b/byterun/str.c @@ -126,6 +126,11 @@ CAMLprim value caml_string_get16(value str, value index) return Val_int(res); } +CAMLprim value caml_bytes_get16(value str, value index) +{ + return caml_string_get16(str,index); +} + CAMLprim value caml_string_get32(value str, value index) { intnat res; @@ -144,6 +149,11 @@ CAMLprim value caml_string_get32(value str, value index) return caml_copy_int32(res); } +CAMLprim value caml_bytes_get32(value str, value index) +{ + return caml_string_get32(str,index); +} + CAMLprim value caml_string_get64(value str, value index) { uint64_t res; @@ -172,7 +182,12 @@ CAMLprim value caml_string_get64(value str, value index) return caml_copy_int64(res); } -CAMLprim value caml_string_set16(value str, value index, value newval) +CAMLprim value caml_bytes_get64(value str, value index) +{ + return caml_string_get64(str,index); +} + +CAMLprim value caml_bytes_set16(value str, value index, value newval) { unsigned char b1, b2; intnat val; @@ -191,7 +206,7 @@ CAMLprim value caml_string_set16(value str, value index, value newval) return Val_unit; } -CAMLprim value caml_string_set32(value str, value index, value newval) +CAMLprim value caml_bytes_set32(value str, value index, value newval) { unsigned char b1, b2, b3, b4; intnat val; @@ -216,7 +231,7 @@ CAMLprim value caml_string_set32(value str, value index, value newval) return Val_unit; } -CAMLprim value caml_string_set64(value str, value index, value newval) +CAMLprim value caml_bytes_set64(value str, value index, value newval) { unsigned char b1, b2, b3, b4, b5, b6, b7, b8; int64_t val; @@ -372,12 +387,6 @@ CAMLprim value caml_fill_string(value s, value offset, value len, value init) return caml_fill_bytes (s, offset, len, init); } -CAMLprim value caml_bitvect_test(value bv, value n) -{ - intnat pos = Long_val(n); - return Val_int(Byte_u(bv, pos >> 3) & (1 << (pos & 7))); -} - CAMLexport value caml_alloc_sprintf(const char * format, ...) { va_list args; @@ -453,3 +462,13 @@ CAMLexport value caml_alloc_sprintf(const char * format, ...) return res; #endif } + +CAMLprim value caml_string_of_bytes(value bv) +{ + return bv; +} + +CAMLprim value caml_bytes_of_string(value bv) +{ + return bv; +} diff --git a/byterun/sys.c b/byterun/sys.c index a46b6be4..a428fd73 100644 --- a/byterun/sys.c +++ b/byterun/sys.c @@ -27,7 +27,6 @@ #include #include #ifdef _WIN32 -#include /* for isatty */ #include /* for _wchdir and _wgetcwd */ #else #include @@ -333,25 +332,43 @@ CAMLprim value caml_sys_getcwd(value unit) CAMLprim value caml_sys_unsafe_getenv(value var) { char_os * res, * p; + value val; if (! caml_string_is_c_safe(var)) caml_raise_not_found(); p = caml_stat_strdup_to_os(String_val(var)); +#ifdef _WIN32 + res = caml_win32_getenv(p); +#else res = CAML_SYS_GETENV(p); +#endif caml_stat_free(p); if (res == 0) caml_raise_not_found(); - return caml_copy_string_of_os(res); + val = caml_copy_string_of_os(res); +#ifdef _WIN32 + caml_stat_free(res); +#endif + return val; } CAMLprim value caml_sys_getenv(value var) { char_os * res, * p; + value val; if (! caml_string_is_c_safe(var)) caml_raise_not_found(); p = caml_stat_strdup_to_os(String_val(var)); +#ifdef _WIN32 + res = caml_win32_getenv(p); +#else res = caml_secure_getenv(p); +#endif caml_stat_free(p); if (res == 0) caml_raise_not_found(); - return caml_copy_string_of_os(res); + val = caml_copy_string_of_os(res); +#ifdef _WIN32 + caml_stat_free(res); +#endif + return val; } char_os * caml_exe_name; @@ -619,8 +636,7 @@ CAMLprim value caml_sys_isatty(value chan) fd = (Channel(chan))->fd; #ifdef _WIN32 - ret = Val_bool(_isatty(fd)); - /* https://msdn.microsoft.com/en-us/library/f4s0ddew.aspx */ + ret = Val_bool(caml_win32_isatty(fd)); #else ret = Val_bool(isatty(fd)); #endif diff --git a/byterun/terminfo.c b/byterun/terminfo.c deleted file mode 100644 index 3f3401ee..00000000 --- a/byterun/terminfo.c +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -#define CAML_INTERNALS - -/* Read and output terminal commands */ - -#include "caml/config.h" -#include "caml/alloc.h" -#include "caml/fail.h" -#include "caml/io.h" -#include "caml/mlvalues.h" - -#define Uninitialised (Val_int(0)) -#define Bad_term (Val_int(1)) -#define Good_term_tag 0 - -#if defined (HAS_TERMCAP) && !defined (NATIVE_CODE) - -extern int tgetent (char * buffer, char * name); -extern char * tgetstr (char * id, char ** area); -extern int tgetnum (char * id); -extern int tputs (char * str, int count, int (*outchar)(int c)); - -static struct channel *chan; -static char area [1024]; -static char *area_p = area; -static int num_lines; -static char *up = NULL; -static char *down = NULL; -static char *standout = NULL; -static char *standend = NULL; - -CAMLprim value caml_terminfo_setup (value vchan) -{ - value result; - static char buffer[1024]; - char *term; - - chan = Channel (vchan); - - term = getenv ("TERM"); - if (term == NULL) return Bad_term; - if (tgetent(buffer, term) != 1) return Bad_term; - - num_lines = tgetnum ("li"); - up = tgetstr ("up", &area_p); - down = tgetstr ("do", &area_p); - standout = tgetstr ("us", &area_p); - standend = tgetstr ("ue", &area_p); - if (standout == NULL || standend == NULL){ - standout = tgetstr ("so", &area_p); - standend = tgetstr ("se", &area_p); - } - CAMLassert (area_p <= area + 1024); - if (num_lines == -1 || up == NULL || down == NULL - || standout == NULL || standend == NULL){ - return Bad_term; - } - result = caml_alloc_small (1, Good_term_tag); - Field (result, 0) = Val_int (num_lines); - return result; -} - -static int terminfo_putc (int c) -{ - caml_putch (chan, c); - return c; -} - -CAMLprim value caml_terminfo_backup (value lines) -{ - int i; - - for (i = 0; i < Int_val (lines); i++){ - tputs (up, 1, terminfo_putc); - } - return Val_unit; -} - -CAMLprim value caml_terminfo_standout (value start) -{ - tputs (Bool_val (start) ? standout : standend, 1, terminfo_putc); - return Val_unit; -} - -CAMLprim value caml_terminfo_resume (value lines) -{ - int i; - - for (i = 0; i < Int_val (lines); i++){ - tputs (down, 1, terminfo_putc); - } - return Val_unit; -} - -#else /* defined (HAS_TERMCAP) && !defined (NATIVE_CODE) */ - -CAMLexport value caml_terminfo_setup (value vchan) -{ - return Bad_term; -} - -CAMLexport value caml_terminfo_backup (value lines) -{ - caml_invalid_argument("Terminfo.backup"); - return Val_unit; -} - -CAMLexport value caml_terminfo_standout (value start) -{ - caml_invalid_argument("Terminfo.standout"); - return Val_unit; -} - -CAMLexport value caml_terminfo_resume (value lines) -{ - caml_invalid_argument("Terminfo.resume"); - return Val_unit; -} - -#endif /* defined (HAS_TERMCAP) && !defined (NATIVE_CODE) */ diff --git a/byterun/unix.c b/byterun/unix.c index 59882e06..da139195 100644 --- a/byterun/unix.c +++ b/byterun/unix.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "caml/config.h" #ifdef SUPPORT_DYNAMIC_LINKING @@ -161,12 +162,14 @@ caml_stat_string caml_search_in_path(struct ext_table * path, const char * name) static int cygwin_file_exists(const char * name) { - int fd; + int fd, ret; + struct stat st; /* Cannot use stat() here because it adds ".exe" implicitly */ fd = open(name, O_RDONLY); if (fd == -1) return 0; + ret = fstat(fd, &st); close(fd); - return 1; + return ret == 0 && S_ISREG(st.st_mode); } static caml_stat_string cygwin_search_exe_in_path(struct ext_table * path, const char * name) @@ -426,3 +429,19 @@ char *caml_secure_getenv (char const *var) return NULL; #endif } + +int caml_num_rows_fd(int fd) +{ +#ifdef TIOCGWINSZ + struct winsize w; + w.ws_row = -1; + if (ioctl(fd, TIOCGWINSZ, &w) == 0) + return w.ws_row; + else + return -1; +#else + return -1; +#endif +} + + diff --git a/byterun/weak.c b/byterun/weak.c index 2f309f44..f430ef8f 100644 --- a/byterun/weak.c +++ b/byterun/weak.c @@ -68,8 +68,9 @@ CAMLprim value caml_ephe_create (value len) mlsize_t size, i; value res; - size = Long_val (len) + 1 /* weak_list */ + 1 /* the value */; - if (size <= 0 || size > Max_wosize) caml_invalid_argument ("Weak.create"); + size = Long_val (len) + CAML_EPHE_FIRST_KEY; + if (size < CAML_EPHE_FIRST_KEY || size > Max_wosize) + caml_invalid_argument ("Weak.create"); res = caml_alloc_shr (size, Abstract_tag); for (i = 1; i < size; i++) Field (res, i) = caml_ephe_none; Field (res, CAML_EPHE_LINK_OFFSET) = caml_ephe_list_head; @@ -119,7 +120,7 @@ CAMLprim value caml_weak_create (value len) that is going to disappear is dead and so should trigger a cleaning */ static void do_check_key_clean(value ar, mlsize_t offset){ - CAMLassert ( offset >= 2); + CAMLassert (offset >= CAML_EPHE_FIRST_KEY); if (caml_gc_phase == Phase_clean){ value elt = Field (ar, offset); if (elt != caml_ephe_none && Is_Dead_during_clean(elt)){ @@ -161,9 +162,9 @@ static void do_set (value ar, mlsize_t offset, value v) CAMLprim value caml_ephe_set_key (value ar, value n, value el) { - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLassert (Is_in_heap (ar)); - if (offset < 2 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.set"); } do_check_key_clean(ar,offset); @@ -173,9 +174,9 @@ CAMLprim value caml_ephe_set_key (value ar, value n, value el) CAMLprim value caml_ephe_unset_key (value ar, value n) { - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLassert (Is_in_heap (ar)); - if (offset < 2 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.set"); } do_check_key_clean(ar,offset); @@ -185,9 +186,9 @@ CAMLprim value caml_ephe_unset_key (value ar, value n) value caml_ephe_set_key_option (value ar, value n, value el) { - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLassert (Is_in_heap (ar)); - if (offset < 2 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.set"); } do_check_key_clean(ar,offset); @@ -212,7 +213,7 @@ CAMLprim value caml_ephe_set_data (value ar, value el) cleaned we always need to check it. */ caml_ephe_clean(ar); }; - do_set (ar, 1, el); + do_set (ar, CAML_EPHE_DATA_OFFSET, el); return Val_unit; } @@ -226,10 +227,10 @@ CAMLprim value caml_ephe_unset_data (value ar) CAMLprim value caml_ephe_get_key (value ar, value n) { CAMLparam2 (ar, n); - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLlocal2 (res, elt); CAMLassert (Is_in_heap (ar)); - if (offset < 2 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.get_key"); } if (is_ephe_key_none(ar, offset)){ @@ -252,10 +253,9 @@ CAMLprim value caml_weak_get (value ar, value n){ CAMLprim value caml_ephe_get_data (value ar) { CAMLparam1 (ar); - mlsize_t offset = 1; CAMLlocal2 (res, elt); CAMLassert (Is_in_heap (ar)); - elt = Field (ar, offset); + elt = Field (ar, CAML_EPHE_DATA_OFFSET); if(caml_gc_phase == Phase_clean) caml_ephe_clean(ar); if (elt == caml_ephe_none){ res = None_val; @@ -272,11 +272,11 @@ CAMLprim value caml_ephe_get_data (value ar) CAMLprim value caml_ephe_get_key_copy (value ar, value n) { CAMLparam2 (ar, n); - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLlocal2 (res, elt); value v; /* Caution: this is NOT a local root. */ CAMLassert (Is_in_heap (ar)); - if (offset < 1 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.get_copy"); } @@ -319,7 +319,7 @@ CAMLprim value caml_weak_get_copy (value ar, value n){ CAMLprim value caml_ephe_get_data_copy (value ar) { CAMLparam1 (ar); - mlsize_t offset = 1; + mlsize_t offset = CAML_EPHE_DATA_OFFSET; CAMLlocal2 (res, elt); value v; /* Caution: this is NOT a local root. */ CAMLassert (Is_in_heap (ar)); @@ -360,9 +360,9 @@ CAMLprim value caml_ephe_get_data_copy (value ar) CAMLprim value caml_ephe_check_key (value ar, value n) { - mlsize_t offset = Long_val (n) + 2; + mlsize_t offset = Long_val (n) + CAML_EPHE_FIRST_KEY; CAMLassert (Is_in_heap (ar)); - if (offset < 2 || offset >= Wosize_val (ar)){ + if (offset < CAML_EPHE_FIRST_KEY || offset >= Wosize_val (ar)){ caml_invalid_argument ("Weak.check"); } return Val_bool (!is_ephe_key_none(ar, offset)); @@ -382,16 +382,16 @@ CAMLprim value caml_ephe_check_data (value ar) CAMLprim value caml_ephe_blit_key (value ars, value ofs, value ard, value ofd, value len) { - mlsize_t offset_s = Long_val (ofs) + 2; - mlsize_t offset_d = Long_val (ofd) + 2; + mlsize_t offset_s = Long_val (ofs) + CAML_EPHE_FIRST_KEY; + mlsize_t offset_d = Long_val (ofd) + CAML_EPHE_FIRST_KEY; mlsize_t length = Long_val (len); long i; CAMLassert (Is_in_heap (ars)); CAMLassert (Is_in_heap (ard)); - if (offset_s < 1 || offset_s + length > Wosize_val (ars)){ + if (offset_s < CAML_EPHE_FIRST_KEY || offset_s + length > Wosize_val (ars)){ caml_invalid_argument ("Weak.blit"); } - if (offset_d < 1 || offset_d + length > Wosize_val (ard)){ + if (offset_d < CAML_EPHE_FIRST_KEY || offset_d + length > Wosize_val (ard)){ caml_invalid_argument ("Weak.blit"); } if (caml_gc_phase == Phase_clean){ diff --git a/byterun/win32.c b/byterun/win32.c index 264ee201..1ce8ad5e 100644 --- a/byterun/win32.c +++ b/byterun/win32.c @@ -17,6 +17,11 @@ /* Win32-specific stuff */ +/* FILE_INFO_BY_HANDLE_CLASS and FILE_NAME_INFO are only available from Windows + Vista onwards */ +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 + #define WIN32_LEAN_AND_MEAN #include #include @@ -51,12 +56,6 @@ #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #endif -/* Very old Microsoft headers don't include intptr_t */ -#if defined(_MSC_VER) && !defined(_UINTPTR_T_DEFINED) -typedef unsigned int uintptr_t; -#define _UINTPTR_T_DEFINED -#endif - unsigned short caml_win32_major = 0; unsigned short caml_win32_minor = 0; unsigned short caml_win32_build = 0; @@ -294,8 +293,6 @@ static volatile sighandler ctrl_handler_action = SIG_DFL; static BOOL WINAPI ctrl_handler(DWORD event) { - int saved_mode; - /* Only ctrl-C and ctrl-Break are handled */ if (event != CTRL_C_EVENT && event != CTRL_BREAK_EVENT) return FALSE; /* Default behavior is to exit, which we get by not handling the event */ @@ -367,7 +364,7 @@ static void expand_argument(wchar_t * arg) static void expand_pattern(wchar_t * pat) { wchar_t * prefix, * p, * name; - int handle; + intptr_t handle; struct _wfinddata_t ffblk; size_t i; @@ -380,7 +377,7 @@ static void expand_pattern(wchar_t * pat) /* We need to stop at the first directory or drive boundary, because the * _findata_t structure contains the filename, not the leading directory. */ for (i = wcslen(prefix); i > 0; i--) { - char c = prefix[i - 1]; + wchar_t c = prefix[i - 1]; if (c == L'\\' || c == L'/' || c == L':') { prefix[i] = 0; break; } } /* No separator was found, it's a filename pattern without a leading directory. */ @@ -416,11 +413,7 @@ int caml_read_directory(wchar_t * dirname, struct ext_table * contents) { size_t dirnamelen; wchar_t * template; -#if _MSC_VER <= 1200 - int h; -#else intptr_t h; -#endif struct _wfinddata_t fileinfo; dirnamelen = wcslen(dirname); @@ -731,7 +724,51 @@ int caml_snprintf(char * buf, size_t size, const char * format, ...) wchar_t *caml_secure_getenv (wchar_t const *var) { /* Win32 doesn't have a notion of setuid bit, so getenv is safe. */ - return CAML_SYS_GETENV (var); + return _wgetenv(var); +} + +/* caml_win32_getenv is used to implement Sys.getenv and Unix.getenv in such a + way that they get direct access to the Win32 environment rather than to the + copy that is cached by the C runtime system. The result of caml_win32_getenv + is dynamically allocated and must be explicitly deallocated. + + In contrast, the OCaml runtime system still calls _wgetenv from the C runtime + system, via caml_secure_getenv. The result is statically allocated and needs + no deallocation. */ +CAMLexport wchar_t *caml_win32_getenv(wchar_t const *lpName) +{ + wchar_t * lpBuffer; + DWORD nSize = 256, res; + + lpBuffer = caml_stat_alloc_noexc(nSize * sizeof(wchar_t)); + + if (lpBuffer == NULL) + return NULL; + + res = GetEnvironmentVariable(lpName, lpBuffer, nSize); + + if (res == 0) { + caml_stat_free(lpBuffer); + return NULL; + } + + if (res < nSize) + return lpBuffer; + + nSize = res; + lpBuffer = caml_stat_resize_noexc(lpBuffer, nSize * sizeof(wchar_t)); + + if (lpBuffer == NULL) + return NULL; + + res = GetEnvironmentVariable(lpName, lpBuffer, nSize); + + if (res == 0 || res >= nSize) { + caml_stat_free(lpBuffer); + return NULL; + } + + return lpBuffer; } /* The rename() implementation in MSVC's CRT is based on MoveFile() @@ -914,3 +951,69 @@ void caml_restore_win32_terminal(void) if (startup_codepage != 0) SetConsoleOutputCP(startup_codepage); } + +/* Detect if a named pipe corresponds to a Cygwin/MSYS pty: see + https://github.com/mirror/newlib-cygwin/blob/00e9bf2/winsup/cygwin/dtable.cc#L932 +*/ +typedef +BOOL (WINAPI *tGetFileInformationByHandleEx)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, + LPVOID, DWORD); + +static int caml_win32_is_cygwin_pty(HANDLE hFile) +{ + char buffer[1024]; + FILE_NAME_INFO * nameinfo = (FILE_NAME_INFO *) buffer; + static tGetFileInformationByHandleEx pGetFileInformationByHandleEx = INVALID_HANDLE_VALUE; + + if (pGetFileInformationByHandleEx == INVALID_HANDLE_VALUE) + pGetFileInformationByHandleEx = + (tGetFileInformationByHandleEx)GetProcAddress(GetModuleHandle(L"KERNEL32.DLL"), + "GetFileInformationByHandleEx"); + + if (pGetFileInformationByHandleEx == NULL) + return 0; + + /* Get pipe name. GetFileInformationByHandleEx does not NULL-terminate the string, so reduce + the buffer size to allow for adding one. */ + if (! pGetFileInformationByHandleEx(hFile, FileNameInfo, buffer, sizeof(buffer) - sizeof(WCHAR))) + return 0; + + nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; + + /* check if this could be a msys pty pipe ('msys-XXXX-ptyN-XX') + or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX') */ + if ((wcsstr(nameinfo->FileName, L"msys-") || + wcsstr(nameinfo->FileName, L"cygwin-")) && wcsstr(nameinfo->FileName, L"-pty")) + return 1; + + return 0; +} + +CAMLexport int caml_win32_isatty(int fd) +{ + DWORD lpMode; + HANDLE hFile = (HANDLE)_get_osfhandle(fd); + + if (hFile == INVALID_HANDLE_VALUE) + return 0; + + switch (GetFileType(hFile)) { + case FILE_TYPE_CHAR: + /* Both console handles and the NUL device are FILE_TYPE_CHAR. The NUL + device returns FALSE for a GetConsoleMode call. _isatty incorrectly + only uses GetFileType (see GPR#1321). */ + return GetConsoleMode(hFile, &lpMode); + case FILE_TYPE_PIPE: + /* Cygwin PTYs are implemented using named pipes */ + return caml_win32_is_cygwin_pty(hFile); + default: + break; + } + + return 0; +} + +int caml_num_rows_fd(int fd) +{ + return -1; +} diff --git a/config/Makefile-templ b/config/Makefile-templ index 4797a0dd..34af691e 100644 --- a/config/Makefile-templ +++ b/config/Makefile-templ @@ -172,14 +172,13 @@ RANLIBCMD=ranlib # Currently available: # unix Unix system calls # str Regular expressions and high-level string processing -# num Arbitrary-precision rational arithmetic # threads Lightweight concurrent processes # systhreads Same as threads, requires POSIX threads # graph Portable drawing primitives for X11 # dynlink Dynamic linking of bytecode # bigarray Large, multidimensional numerical arrays -OTHERLIBRARIES=unix str num threads graph dynlink bigarray +OTHERLIBRARIES=unix str threads graph dynlink bigarray ### Link-time options to ocamlc or ocamlopt for linking with POSIX threads # Needed for the "systhreads" package diff --git a/config/Makefile.mingw b/config/Makefile.mingw index 3fafb0fc..3f1eb9b4 100644 --- a/config/Makefile.mingw +++ b/config/Makefile.mingw @@ -96,6 +96,7 @@ UNIX_OR_WIN32=win32 UNIXLIB=win32unix GRAPHLIB=win32graph FLAMBDA=false +WITH_FLAMBDA_INVARIANTS=false WITH_SPACETIME=false ENABLE_CALL_COUNTS=false WITH_PROFINFO=false @@ -106,6 +107,7 @@ FORCE_SAFE_STRING=false DEFAULT_SAFE_STRING=true WINDOWS_UNICODE=1 AFL_INSTRUMENT=false +AWK=gawk ########## Configuration for the bytecode compiler @@ -133,7 +135,7 @@ FLEXLINK_CMD=flexlink FLEXDLL_CHAIN=mingw # FLEXLINK_FLAGS must be safe to insert in an OCaml string # (see ocamlmklibconfig.ml in tools/Makefile) -FLEXLINK_FLAGS=-chain $(FLEXDLL_CHAIN) -stack 16777216 -link -static-libgcc +FLEXLINK_FLAGS=-chain $(FLEXDLL_CHAIN) -stack 16777216 FLEXLINK=$(FLEXLINK_CMD) $(FLEXLINK_FLAGS) FLEXDIR:=$(shell $(FLEXLINK) -where 2>/dev/null) ifeq ($(FLEXDIR),) @@ -156,10 +158,10 @@ MKEXE_BOOT=$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUTEXE)$(1) $(2) MKEXE_ANSI=$(FLEXLINK) -exe ### How to build a static library -MKLIB=rm -f $(1); $(TOOLPREF)ar rc $(1) $(2); $(RANLIB) $(1) +MKLIB=rm -f $(1) && $(TOOLPREF)ar rcs $(1) $(2) #ml let mklib out files opts = -#ml Printf.sprintf "rm -f %s && %sar rcs %s %s %s" -#ml out toolpref opts out files;; +#ml Printf.sprintf "%sar rcs %s %s %s" +#ml toolpref opts out files;; ### Canonicalize the name of a system library SYSLIB=-l$(1) diff --git a/config/Makefile.mingw64 b/config/Makefile.mingw64 index 0466e63c..df605a9f 100644 --- a/config/Makefile.mingw64 +++ b/config/Makefile.mingw64 @@ -96,6 +96,7 @@ UNIX_OR_WIN32=win32 UNIXLIB=win32unix GRAPHLIB=win32graph FLAMBDA=false +WITH_FLAMBDA_INVARIANTS=false WITH_PROFINFO=false WITH_SPACETIME=false ENABLE_CALL_COUNTS=false @@ -106,6 +107,7 @@ FORCE_SAFE_STRING=false DEFAULT_SAFE_STRING=true WINDOWS_UNICODE=1 AFL_INSTRUMENT=false +AWK=gawk ########## Configuration for the bytecode compiler @@ -156,10 +158,10 @@ MKEXE_BOOT=$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUTEXE)$(1) $(2) MKEXE_ANSI=$(FLEXLINK) -exe ### How to build a static library -MKLIB=rm -f $(1); $(TOOLPREF)ar rc $(1) $(2); $(RANLIB) $(1) +MKLIB=rm -f $(1) && $(TOOLPREF)ar rcs $(1) $(2) #ml let mklib out files opts = -#ml Printf.sprintf "rm -f %s && %sar rcs %s %s %s" -#ml out toolpref opts out files;; +#ml Printf.sprintf "%sar rcs %s %s %s" +#ml toolpref opts out files;; ### Canonicalize the name of a system library SYSLIB=-l$(1) diff --git a/config/Makefile.msvc b/config/Makefile.msvc index 9f623684..743d3687 100644 --- a/config/Makefile.msvc +++ b/config/Makefile.msvc @@ -89,6 +89,7 @@ UNIX_OR_WIN32=win32 UNIXLIB=win32unix GRAPHLIB=win32graph FLAMBDA=false +WITH_FLAMBDA_INVARIANTS=false WITH_PROFINFO=false WITH_SPACETIME=false ENABLE_CALL_COUNTS=false @@ -99,6 +100,7 @@ FORCE_SAFE_STRING=false DEFAULT_SAFE_STRING=true WINDOWS_UNICODE=1 AFL_INSTRUMENT=false +AWK=gawk ########## Configuration for the bytecode compiler diff --git a/config/Makefile.msvc64 b/config/Makefile.msvc64 index f7b52033..67bf16a2 100644 --- a/config/Makefile.msvc64 +++ b/config/Makefile.msvc64 @@ -88,6 +88,7 @@ UNIX_OR_WIN32=win32 UNIXLIB=win32unix GRAPHLIB=win32graph FLAMBDA=false +WITH_FLAMBDA_INVARIANTS=false WITH_PROFINFO=false WITH_SPACETIME=false ENABLE_CALL_COUNTS=false @@ -98,6 +99,7 @@ FORCE_SAFE_STRING=false DEFAULT_SAFE_STRING=true WINDOWS_UNICODE=1 AFL_INSTRUMENT=false +AWK=gawk ########## Configuration for the bytecode compiler diff --git a/config/s-nt.h b/config/s-nt.h index c8de2cab..ab4046b3 100644 --- a/config/s-nt.h +++ b/config/s-nt.h @@ -17,7 +17,7 @@ #define OCAML_OS_TYPE "Win32" -#ifdef __MINGW32__ +#if defined(__MINGW32__) || _MSC_VER >= 1600 #define HAS_STDINT_H #endif #undef BSD_SIGNALS diff --git a/config/s-templ.h b/config/s-templ.h index 6eb971d2..1df4eb31 100644 --- a/config/s-templ.h +++ b/config/s-templ.h @@ -40,13 +40,6 @@ /* Define HAS_SIGSETMASK if you have sigsetmask(), as in BSD. */ -#define HAS_TERMCAP - -/* Define HAS_TERMCAP if you have the termcap functions to read the - terminal database, e.g. tgetent(), tgetstr(), tgetnum(), tputs(). - Also add the required libraries (e.g. -lcurses -ltermcap) to $(CCLIBS) - in ../Makefile.config */ - #define SUPPORT_DYNAMIC_LINKING /* Define SUPPORT_DYNAMIC_LINKING if dynamic loading of C stub code diff --git a/configure b/configure index 20339655..1316b3c1 100755 --- a/configure +++ b/configure @@ -33,7 +33,6 @@ cpp='cpp' asoption='' asppoption='' cclibs='' -curseslibs='' mathlib='-lm' dllib='' x11_include_dir='' @@ -46,9 +45,7 @@ graph_wanted=yes pthread_wanted=yes dl_defs='' verbose=false -with_curses=yes -debugruntime=false -with_instrumented_runtime=false +debugruntime=true with_sharedlibs=true partialld="ld -r" with_debugger=ocamldebugger @@ -70,6 +67,10 @@ max_testsuite_dir_retries=0 with_cplugins=false with_fpic=false flat_float_array=true +with_flambda_invariants=false + +# we distinguish '' (not set) from 'true' (explicitly set by the user) +with_instrumented_runtime='' # Try to turn internationalization off, can cause config.guess to malfunction! unset LANG @@ -152,7 +153,7 @@ while : ; do -lib*) cclibs="$2 $cclibs"; shift;; -no-curses|--no-curses) - with_curses=no;; + ;; # Ignored for backward compatibility -no-shared-libs|--no-shared-libs) with_sharedlibs=false;; -x11include*|--x11include*) @@ -173,9 +174,13 @@ while : ; do -verbose|--verbose) verbose=true;; -with-debug-runtime|--with-debug-runtime) - debugruntime=true;; + debugruntime=true;; # default + -no-debug-runtime|--no-debug-runtime) + debugruntime=false;; -with-instrumented-runtime|--with-instrumented-runtime) with_instrumented_runtime=true;; + -no-instrumented-runtime|--no-instrumented-runtime) + with_instrumented_runtime=false;; -no-debugger|--no-debugger) with_debugger="";; -no-ocamldoc|--no-ocamldoc) @@ -206,6 +211,8 @@ while : ; do native_compiler=false;; -flambda|--flambda) flambda=true;; + -with-flambda-invariants|--with-flambda-invariants) + with_flambda_invariants=true;; -with-cplugins|--with-cplugins) with_cplugins=true;; -no-cplugins|--no-cplugins) @@ -544,7 +551,6 @@ case "$cc,$target" in exe=".exe" ostype="Cygwin";; *,*-*-mingw*) - dllccompopt="-DCAML_DLL" if $with_sharedlibs; then case "$target" in i686-*-*) flexlink_chain="mingw";; @@ -974,7 +980,9 @@ case "$target" in powerpc-*-openbsd*) arch=power; model=ppc; system=bsd_elf;; s390x*-*-linux*) arch=s390x; model=z10; system=elf;; armv6*-*-linux-gnueabihf) arch=arm; model=armv6; system=linux_eabihf;; - arm*-*-linux-gnueabihf) arch=arm; system=linux_eabihf;; + armv7*-*-linux-gnueabihf) arch=arm; model=armv7; system=linux_eabihf;; + armv8*-*-linux-gnueabihf) arch=arm; model=armv8; system=linux_eabihf;; + armv8*-*-linux-gnueabi) arch=arm; model=armv8; system=linux_eabi;; armv7*-*-linux-gnueabi) arch=arm; model=armv7; system=linux_eabi;; armv6t2*-*-linux-gnueabi) arch=arm; model=armv6t2; system=linux_eabi;; armv6*-*-linux-gnueabi) arch=arm; model=armv6; system=linux_eabi;; @@ -1191,35 +1199,30 @@ if sh ./hasgot -i unistd.h issetugid; then echo "#define HAS_ISSETUGID" >> s.h fi -# For the terminfo module - -if test "$with_curses" = "yes"; then - for libs in "" "-lcurses" "-ltermcap" "-lcurses -ltermcap" "-lncurses"; do - if sh ./hasgot $libs tgetent tgetstr tgetnum tputs; then - inf "termcap functions found (with libraries '$libs')" - echo "#define HAS_TERMCAP" >> s.h - curseslibs="${libs}" - break - fi - done -fi - # For instrumented runtime # (clock_gettime needs -lrt for glibc before 2.17) -if $with_instrumented_runtime; then - with_instrumented_runtime=false #enabled it only if found +if test "$with_instrumented_runtime" != "false"; then + instrumented_runtime_support="nonsupported" for libs in "" "-lrt"; do if sh ./hasgot $libs clock_gettime; then inf "clock_gettime functions found (with libraries '$libs')" instrumented_runtime_libs="${libs}" - with_instrumented_runtime=true; + instrumented_runtime_support="supported"; break fi done - if ! $with_instrumented_runtime; then - err "clock_gettime functions not found. " \ - "Instrumented runtime can't be built." - fi + case "$with_instrumented_runtime,$instrumented_runtime_support" in + *,supported) + with_instrumented_runtime=true;; + true,nonsupported) + with_instrumented_runtime=false; + err "clock_gettime functions not found. " \ + "Instrumented runtime can't be built.";; + ,nonsupported) + with_instrumented_runtime=false; + inf "clock_gettime functions not found. " \ + "Instrumented runtime can't be built.";; + esac fi # Configuration for the libraries @@ -1783,6 +1786,8 @@ if test "$x11_include" = "not found"; then \ /usr/lib/i386-linux-gnu \ /usr/lib/x86_64-linux-gnu \ + \ + /usr/lib/`echo $target | sed -e "s/-[^-]*//"` \ ; \ do if test -f $dir/libX11.a || \ @@ -1793,7 +1798,6 @@ if test "$x11_include" = "not found"; then if test $dir = /usr/lib; then x11_link="-lX11" else - x11_libs="-L$dir" case "$target" in *-*-freebsd*|*-*-dragonfly*) x11_link="-L$dir -lX11";; *-kfreebsd*-gnu) x11_link="-L$dir -lX11";; @@ -1806,7 +1810,7 @@ if test "$x11_include" = "not found"; then done fi -if test "x11_include" != "not found"; then +if test "$x11_include" != "not found"; then if test "$x11_include" = "-I/usr/include"; then x11_include="" fi @@ -2057,8 +2061,7 @@ config CPPFLAGS "$common_cppflags $internal_cppflags" config OCAMLC_CFLAGS "$common_cflags $sharedcccompopts" config OCAMLC_CPPFLAGS "$common_cppflags" config LDFLAGS "$ldflags" -config BYTECCLIBS "$cclibs $dllib $curseslibs $pthread_link \ - $instrumented_runtime_libs" +config BYTECCLIBS "$cclibs $dllib $pthread_link $instrumented_runtime_libs" config RPATH "$rpath" config EXE "$exe" config EMPTY "" @@ -2072,9 +2075,9 @@ SYSLIB=-l\$(1) #ml let syslib x = "-l"^x;; ### How to build a static library -MKLIB=${TOOLPREF}ar rc \$(1) \$(2); ${TOOLPREF}ranlib \$(1) +MKLIB=rm -f \$(1) && ${TOOLPREF}ar rc \$(1) \$(2) && ${TOOLPREF}ranlib \$(1) #ml let mklib out files opts = (* "" *) -#ml Printf.sprintf "${TOOLPREF}ar rc %s %s %s; ${TOOLPREF}ranlib %s" +#ml Printf.sprintf "${TOOLPREF}ar rc %s %s %s && ${TOOLPREF}ranlib %s" #ml out opts files out;; EOF config ARCH "$arch" @@ -2132,12 +2135,14 @@ if [ "$ostype" = Cygwin ]; then config DIFF "diff -q --strip-trailing-cr" fi config FLAMBDA "$flambda" +config WITH_FLAMBDA_INVARIANTS "$with_flambda_invariants" config FORCE_SAFE_STRING "$force_safe_string" config DEFAULT_SAFE_STRING "$default_safe_string" config WINDOWS_UNICODE "0" config AFL_INSTRUMENT "$afl_instrument" config MAX_TESTSUITE_DIR_RETRIES "$max_testsuite_dir_retries" config FLAT_FLOAT_ARRAY "$flat_float_array" +config AWK "awk" rm -f tst hasgot.c @@ -2158,8 +2163,7 @@ inf " manual pages.............. $mandir (with extension .$programs_man_s inf "Configuration for the bytecode compiler:" inf " C compiler used........... $cc" inf " options for compiling..... $common_cflags" -inf " options for linking....... $ldflags $cclibs $dllib" \ - "$curseslibs $pthread_link" +inf " options for linking....... $ldflags $cclibs $dllib $pthread_link" if $shared_libraries_supported; then inf " shared libraries are supported" inf " options for compiling..... $sharedcccompopts $common_cflags" @@ -2203,7 +2207,7 @@ else fi if $with_spacetime; then inf " spacetime profiling....... yes" - if test "$with_spacetime_call_counts" = "true"; then + if test "$enable_call_counts" = "true"; then inf " ... with call counts.... yes" else inf " ... with call counts.... no" @@ -2251,6 +2255,11 @@ else fi if test "$flambda" = "true"; then inf " using flambda middle-end . yes" + if test "$with_flambda_invariants" = "true"; then + inf " ... with flambda invariants checks . yes" + else + inf " ... with flambda invariants checks . no" + fi else inf " using flambda middle-end . no" fi diff --git a/debugger/.depend b/debugger/.depend index 86b18ab6..5e1310c4 100644 --- a/debugger/.depend +++ b/debugger/.depend @@ -1,7 +1,9 @@ -breakpoints.cmo : symbols.cmi pos.cmi ../bytecomp/instruct.cmi exec.cmi \ - debugcom.cmi checkpoints.cmi breakpoints.cmi -breakpoints.cmx : symbols.cmx pos.cmx ../bytecomp/instruct.cmx exec.cmx \ - debugcom.cmx checkpoints.cmx breakpoints.cmi +breakpoints.cmo : symbols.cmi pos.cmi parameters.cmi \ + ../bytecomp/instruct.cmi exec.cmi debugcom.cmi checkpoints.cmi \ + breakpoints.cmi +breakpoints.cmx : symbols.cmx pos.cmx parameters.cmx \ + ../bytecomp/instruct.cmx exec.cmx debugcom.cmx checkpoints.cmx \ + breakpoints.cmi breakpoints.cmi : ../bytecomp/instruct.cmi checkpoints.cmo : primitives.cmi int64ops.cmi debugcom.cmi checkpoints.cmi checkpoints.cmx : primitives.cmx int64ops.cmx debugcom.cmx checkpoints.cmi @@ -67,9 +69,9 @@ history.cmx : primitives.cmx int64ops.cmx debugger_config.cmx \ checkpoints.cmx history.cmi history.cmi : input_handling.cmo : $(UNIXDIR)/unix.cmi primitives.cmi \ - input_handling.cmi + parameters.cmi input_handling.cmi input_handling.cmx : $(UNIXDIR)/unix.cmx primitives.cmx \ - input_handling.cmi + parameters.cmx input_handling.cmi input_handling.cmi : primitives.cmi int64ops.cmo : int64ops.cmi int64ops.cmx : int64ops.cmi @@ -78,28 +80,28 @@ lexer.cmo : parser.cmi lexer.cmi lexer.cmx : parser.cmx lexer.cmi lexer.cmi : parser.cmi loadprinter.cmo : ../typing/types.cmi ../bytecomp/symtable.cmi printval.cmi \ - ../typing/printtyp.cmi ../typing/path.cmi ../utils/misc.cmi \ - ../parsing/longident.cmi ../parsing/location.cmi ../typing/ident.cmi \ - ../typing/env.cmi ../typing/ctype.cmi ../utils/config.cmi \ - ../driver/compdynlink.cmi loadprinter.cmi + ../typing/printtyp.cmi ../typing/path.cmi parameters.cmi \ + ../utils/misc.cmi ../parsing/longident.cmi ../parsing/location.cmi \ + ../typing/ident.cmi ../typing/env.cmi ../typing/ctype.cmi \ + ../utils/config.cmi ../driver/compdynlink.cmi loadprinter.cmi loadprinter.cmx : ../typing/types.cmx ../bytecomp/symtable.cmx printval.cmx \ - ../typing/printtyp.cmx ../typing/path.cmx ../utils/misc.cmx \ - ../parsing/longident.cmx ../parsing/location.cmx ../typing/ident.cmx \ - ../typing/env.cmx ../typing/ctype.cmx ../utils/config.cmx \ - ../driver/compdynlink.cmi loadprinter.cmi + ../typing/printtyp.cmx ../typing/path.cmx parameters.cmx \ + ../utils/misc.cmx ../parsing/longident.cmx ../parsing/location.cmx \ + ../typing/ident.cmx ../typing/env.cmx ../typing/ctype.cmx \ + ../utils/config.cmx ../driver/compdynlink.cmi loadprinter.cmi loadprinter.cmi : ../parsing/longident.cmi ../driver/compdynlink.cmi main.cmo : unix_tools.cmi $(UNIXDIR)/unix.cmi time_travel.cmi \ show_information.cmi question.cmi program_management.cmi primitives.cmi \ - parameters.cmi ../utils/misc.cmi input_handling.cmi frames.cmi exec.cmi \ - ../typing/env.cmi debugger_config.cmi ../utils/config.cmi \ - command_line.cmi ../typing/cmi_format.cmi ../utils/clflags.cmi \ - checkpoints.cmi + parameters.cmi ../utils/misc.cmi loadprinter.cmi input_handling.cmi \ + frames.cmi exec.cmi ../typing/env.cmi debugger_config.cmi \ + ../utils/config.cmi command_line.cmi ../typing/cmi_format.cmi \ + ../utils/clflags.cmi checkpoints.cmi main.cmx : unix_tools.cmx $(UNIXDIR)/unix.cmx time_travel.cmx \ show_information.cmx question.cmx program_management.cmx primitives.cmx \ - parameters.cmx ../utils/misc.cmx input_handling.cmx frames.cmx exec.cmx \ - ../typing/env.cmx debugger_config.cmx ../utils/config.cmx \ - command_line.cmx ../typing/cmi_format.cmx ../utils/clflags.cmx \ - checkpoints.cmx + parameters.cmx ../utils/misc.cmx loadprinter.cmx input_handling.cmx \ + frames.cmx exec.cmx ../typing/env.cmx debugger_config.cmx \ + ../utils/config.cmx command_line.cmx ../typing/cmi_format.cmx \ + ../utils/clflags.cmx checkpoints.cmx parameters.cmo : primitives.cmi ../typing/envaux.cmi debugger_config.cmi \ ../utils/config.cmi parameters.cmi parameters.cmx : primitives.cmx ../typing/envaux.cmx debugger_config.cmx \ diff --git a/debugger/Makefile b/debugger/Makefile index 2c130dd1..571e91bb 100644 --- a/debugger/Makefile +++ b/debugger/Makefile @@ -14,6 +14,8 @@ #************************************************************************** include ../config/Makefile +include ../Makefile.common + UNIXDIR=../otherlibs/$(UNIXLIB) CAMLRUN ?= ../boot/ocamlrun CAMLYACC ?= ../boot/ocamlyacc @@ -27,8 +29,6 @@ CAMLLEX=$(CAMLRUN) ../boot/ocamllex CAMLDEP=$(CAMLRUN) ../tools/ocamldep DEPFLAGS=$(INCLUDES) -INSTALL_BINDIR=$(DESTDIR)$(BINDIR) - INCLUDES=\ -I ../utils -I ../parsing -I ../typing -I ../bytecomp -I ../toplevel \ -I ../driver -I $(UNIXDIR) @@ -39,6 +39,7 @@ OTHEROBJS=\ ../utils/identifiable.cmo ../utils/numbers.cmo \ ../utils/arg_helper.cmo ../utils/clflags.cmo \ ../utils/consistbl.cmo ../utils/warnings.cmo \ + ../utils/build_path_prefix_map.cmo \ ../utils/terminfo.cmo \ ../parsing/location.cmo ../parsing/longident.cmo ../parsing/docstrings.cmo \ ../parsing/syntaxerr.cmo \ @@ -96,7 +97,7 @@ ocamldebug$(EXE): $(OBJS) $(OTHEROBJS) $(CAMLC) $(LINKFLAGS) -o ocamldebug$(EXE) -linkall $(OTHEROBJS) $(OBJS) install: - cp ocamldebug$(EXE) "$(INSTALL_BINDIR)/ocamldebug$(EXE)" + $(INSTALL_PROG) ocamldebug$(EXE) "$(INSTALL_BINDIR)/ocamldebug$(EXE)" clean:: rm -f ocamldebug$(EXE) diff --git a/debugger/breakpoints.ml b/debugger/breakpoints.ml index 5d5b6ced..62e8ecfb 100644 --- a/debugger/breakpoints.ml +++ b/debugger/breakpoints.ml @@ -170,9 +170,11 @@ let rec new_breakpoint = incr breakpoint_number; insert_position event.ev_pos; breakpoints := (!breakpoint_number, event) :: !breakpoints); - printf "Breakpoint %d at %d: %s" !breakpoint_number event.ev_pos - (Pos.get_desc event); - print_newline () + if !Parameters.breakpoint then begin + printf "Breakpoint %d at %d: %s" !breakpoint_number event.ev_pos + (Pos.get_desc event); + print_newline () + end (* Remove a breakpoint from lists. *) let remove_breakpoint number = @@ -183,9 +185,11 @@ let remove_breakpoint number = (function () -> breakpoints := List.remove_assoc number !breakpoints; remove_position pos; - printf "Removed breakpoint %d at %d: %s" number ev.ev_pos - (Pos.get_desc ev); - print_newline () + if !Parameters.breakpoint then begin + printf "Removed breakpoint %d at %d: %s" number ev.ev_pos + (Pos.get_desc ev); + print_newline () + end ) with Not_found -> diff --git a/debugger/input_handling.ml b/debugger/input_handling.ml index 91f4cc50..e69c5f4b 100644 --- a/debugger/input_handling.ml +++ b/debugger/input_handling.ml @@ -108,7 +108,7 @@ let stop_user_input () = (* Resume reading user input. *) let resume_user_input () = if not (List.mem_assoc !user_channel.io_fd !active_files) then begin - if !interactif then begin + if !interactif && !Parameters.prompt then begin print_string !current_prompt; flush Pervasives.stdout end; diff --git a/debugger/loadprinter.ml b/debugger/loadprinter.ml index 54a2c167..b657331b 100644 --- a/debugger/loadprinter.ml +++ b/debugger/loadprinter.ml @@ -106,11 +106,9 @@ let eval_path path = (* since 4.00, "topdirs.cmi" is not in the same directory as the standard library, so we load it beforehand as it cannot be found in the search path. *) -let () = - let compiler_libs = - Filename.concat Config.standard_library "compiler-libs" in +let init () = let topdirs = - Filename.concat compiler_libs "topdirs.cmi" in + Filename.concat !Parameters.topdirs_path "topdirs.cmi" in ignore (Env.read_signature "Topdirs" topdirs) let match_printer_type desc typename = @@ -124,7 +122,7 @@ let match_printer_type desc typename = let ty_arg = Ctype.newvar() in Ctype.unify Env.empty (Ctype.newconstr printer_type [ty_arg]) - (Ctype.instance Env.empty desc.val_type); + (Ctype.instance desc.val_type); Ctype.end_def(); Ctype.generalize ty_arg; ty_arg diff --git a/debugger/loadprinter.mli b/debugger/loadprinter.mli index c645e8d2..81e4814e 100644 --- a/debugger/loadprinter.mli +++ b/debugger/loadprinter.mli @@ -17,6 +17,8 @@ open Format +val init : unit -> unit + val loadfile : formatter -> string -> unit val install_printer : formatter -> Longident.t -> unit val remove_printer : Longident.t -> unit diff --git a/debugger/main.ml b/debugger/main.ml index 4f2b830f..87027596 100644 --- a/debugger/main.ml +++ b/debugger/main.ml @@ -152,6 +152,8 @@ let add_include d = Misc.expand_directory Config.standard_library d :: !default_load_path let set_socket s = socket_name := s +let set_topdirs_path s = + topdirs_path := s let set_checkpoints n = checkpoint_max_count := n let set_directory dir = @@ -182,6 +184,16 @@ let speclist = [ " Print version and exit"; "-vnum", Arg.Unit print_version_num, " Print version number and exit"; + "-no-version", Arg.Clear Parameters.version, + " Do not print version at startup"; + "-no-prompt", Arg.Clear Parameters.prompt, + " Suppress all prompts"; + "-no-time", Arg.Clear Parameters.time, + " Do not print times"; + "-no-breakpoint-message", Arg.Clear Parameters.breakpoint, + " Do not print message at breakpoint setup and removal"; + "-topdirs-path", Arg.String set_topdirs_path, + " Set path to the directory containing topdirs.cmi"; ] let function_placeholder () = @@ -211,7 +223,9 @@ let main () = arguments := !arguments ^ " " ^ (Filename.quote Sys.argv.(j)) done end; - printf "\tOCaml Debugger version %s@.@." Config.version; + if !Parameters.version + then printf "\tOCaml Debugger version %s@.@." Config.version; + Loadprinter.init(); Config.load_path := !default_load_path; Clflags.recursive_types := true; (* Allow recursive types. *) toplevel_loop (); (* Toplevel. *) diff --git a/debugger/parameters.ml b/debugger/parameters.ml index a4d647c4..ea11698a 100644 --- a/debugger/parameters.ml +++ b/debugger/parameters.ml @@ -27,6 +27,13 @@ let arguments = ref "" let default_load_path = ref [ Filename.current_dir_name; Config.standard_library ] +let breakpoint = ref true +let prompt = ref true +let time = ref true +let version = ref true + +let topdirs_path = ref (Filename.concat Config.standard_library "compiler-libs") + let add_path dir = load_path := dir :: except dir !load_path; Envaux.reset_cache() diff --git a/debugger/parameters.mli b/debugger/parameters.mli index 388fb94d..d680e7f1 100644 --- a/debugger/parameters.mli +++ b/debugger/parameters.mli @@ -20,6 +20,11 @@ val program_name : string ref val socket_name : string ref val arguments : string ref val default_load_path : string list ref +val breakpoint : bool ref +val prompt : bool ref +val time : bool ref +val version : bool ref +val topdirs_path : string ref val add_path : string -> unit val add_path_for : string -> string -> unit diff --git a/debugger/show_information.ml b/debugger/show_information.ml index 30d7774e..29fe1fb6 100644 --- a/debugger/show_information.ml +++ b/debugger/show_information.ml @@ -28,20 +28,23 @@ open Parameters (* Display information about the current event. *) let show_current_event ppf = - fprintf ppf "Time: %Li" (current_time ()); - (match current_pc () with - | Some pc -> - fprintf ppf " - pc: %i" pc - | _ -> ()); + if !Parameters.time then begin + fprintf ppf "Time: %Li" (current_time ()); + (match current_pc () with + | Some pc -> + fprintf ppf " - pc: %i" pc + | _ -> ()); + end; update_current_event (); reset_frame (); match current_report () with | None -> - fprintf ppf "@.Beginning of program.@."; + if !Parameters.time then fprintf ppf "@."; + fprintf ppf "Beginning of program.@."; show_no_point () | Some {rep_type = (Event | Breakpoint); rep_program_pointer = pc} -> let ev = get_current_event () in - fprintf ppf " - module %s@." ev.ev_module; + if !Parameters.time then fprintf ppf " - module %s@." ev.ev_module; (match breakpoints_at_pc pc with | [] -> () @@ -55,17 +58,20 @@ let show_current_event ppf = (List.sort compare breakpoints)); show_point ev true | Some {rep_type = Exited} -> - fprintf ppf "@.Program exit.@."; + if !Parameters.time then fprintf ppf "@."; + fprintf ppf "Program exit.@."; show_no_point () | Some {rep_type = Uncaught_exc} -> + if !Parameters.time then fprintf ppf "@."; fprintf ppf - "@.Program end.@.\ + "Program end.@.\ @[Uncaught exception:@ %a@]@." Printval.print_exception (Debugcom.Remote_value.accu ()); show_no_point () | Some {rep_type = Trap_barrier} -> (* Trap_barrier not visible outside *) (* of module `time_travel'. *) + if !Parameters.time then fprintf ppf "@."; Misc.fatal_error "Show_information.show_current_event" (* Display short information about one frame. *) diff --git a/debugger/symbols.ml b/debugger/symbols.ml index 31124974..2318c10f 100644 --- a/debugger/symbols.ml +++ b/debugger/symbols.ml @@ -167,7 +167,10 @@ let find_event ev char = else bsearch (pivot + 1) hi end in - bsearch 0 (Array.length ev - 1) + if Array.length ev = 0 then + raise Not_found + else + bsearch 0 (Array.length ev - 1) (* Return first event after the given position. *) (* Raise [Not_found] if module is unknown or no event is found. *) diff --git a/driver/compenv.ml b/driver/compenv.ml index 194fa617..704a65f5 100644 --- a/driver/compenv.ml +++ b/driver/compenv.ml @@ -101,19 +101,30 @@ type filename = string type readenv_position = Before_args | Before_compile of filename | Before_link -(* Syntax of OCAMLPARAM: (name=VALUE,)* _ (,name=VALUE)* - where VALUE should not contain ',' *) +(* Syntax of OCAMLPARAM: SEP?(name=VALUE SEP)* _ (SEP name=VALUE)* + where VALUE should not contain SEP, and SEP is ',' if unspecified, + or ':', '|', ';', ' ' or ',' *) exception SyntaxError of string let parse_args s = - let args = String.split_on_char ',' s in + let args = + let len = String.length s in + if len = 0 then [] + else + (* allow first char to specify an alternative separator in ":|; ," *) + match s.[0] with + | ( ':' | '|' | ';' | ' ' | ',' ) as c -> + List.tl (String.split_on_char c s) + | _ -> String.split_on_char ',' s + in let rec iter is_after args before after = match args with [] -> if not is_after then raise (SyntaxError "no '_' separator found") else - (List.rev before, List.rev after) + (List.rev before, List.rev after) + | "" :: tail -> iter is_after tail before after | "_" :: _ when is_after -> raise (SyntaxError "too many '_' separators") | "_" :: tail -> iter true tail before after | arg :: tail -> @@ -329,6 +340,8 @@ let read_one_param ppf position name v = set "flambda-verbose" [ dump_flambda_verbose ] v | "flambda-invariants" -> set "flambda-invariants" [ flambda_invariant_checks ] v + | "linscan" -> + set "linscan" [ use_linscan ] v (* color output *) | "color" -> @@ -358,7 +371,9 @@ let read_one_param ppf position name v = ccobjs := Misc.rev_split_words v @ !ccobjs end - | "ccopts" -> + | "ccopt" + | "ccopts" + -> begin match position with | Before_link | Before_compile _ -> diff --git a/driver/compile.ml b/driver/compile.ml index 98ac5be4..75a2470f 100644 --- a/driver/compile.ml +++ b/driver/compile.ml @@ -41,7 +41,7 @@ let interface ppf sourcefile outputprefix = if !Clflags.dump_typedtree then fprintf ppf "%a@." Printtyped.interface tsg; let sg = tsg.sig_type in if !Clflags.print_types then - Printtyp.wrap_printing_env initial_env (fun () -> + Printtyp.wrap_printing_env ~error:false initial_env (fun () -> fprintf std_formatter "%a@." Printtyp.signature (Typemod.simplify_signature sg)); ignore (Includemod.signatures initial_env sg sg); diff --git a/driver/compmisc.ml b/driver/compmisc.ml index a0839f34..b1bed14b 100644 --- a/driver/compmisc.ml +++ b/driver/compmisc.ml @@ -43,27 +43,19 @@ let init_path ?(dir="") native = (* Note: do not do init_path() in initial_env, this breaks toplevel initialization (PR#1775) *) -let open_implicit_module m env = - let open Asttypes in - let lid = {loc = Location.in_file "command line"; - txt = Longident.parse m } in - snd (Typemod.type_open_ Override env lid.loc lid) - let initial_env () = Ident.reinit(); - let initial = - if Config.safe_string then Env.initial_safe_string - else if !Clflags.unsafe_string then Env.initial_unsafe_string - else Env.initial_safe_string - in - let env = - if !Clflags.nopervasives then initial else - open_implicit_module "Pervasives" initial + let initially_opened_module = + if !Clflags.nopervasives then + None + else + Some "Stdlib" in - List.fold_left (fun env m -> - open_implicit_module m env - ) env (!implicit_modules @ List.rev !Clflags.open_modules) - + Typemod.initial_env + ~loc:(Location.in_file "command line") + ~safe_string:(Config.safe_string || not !Clflags.unsafe_string) + ~initially_opened_module + ~open_implicit_modules:(!implicit_modules @ List.rev !Clflags.open_modules) let read_color_env ppf = try diff --git a/driver/main.ml b/driver/main.ml index 110ea3cf..5fc9387b 100644 --- a/driver/main.ml +++ b/driver/main.ml @@ -111,6 +111,8 @@ module Options = Main_args.Make_bytecomp_options (struct let _where = print_standard_library let _verbose = set verbose let _nopervasives = set nopervasives + let _dno_unique_ids = unset unique_ids + let _dunique_ids = set unique_ids let _dsource = set dump_source let _dparsetree = set dump_parsetree let _dtypedtree = set dump_typedtree diff --git a/driver/main_args.ml b/driver/main_args.ml index 757c7ac5..47e427eb 100644 --- a/driver/main_args.ml +++ b/driver/main_args.ml @@ -457,7 +457,7 @@ let mk_strict_sequence f = let mk_thread f = "-thread", Arg.Unit f, - " Generate code that supports the system threads library" + " (deprecated) same as -I +threads" ;; let mk_dtimings f = @@ -613,6 +613,14 @@ let mk_drawlambda f = "-drawlambda", Arg.Unit f, " (undocumented)" ;; +let mk_dno_unique_ids f = + "-dno-unique-ids", Arg.Unit f, " (undocumented)" +;; + +let mk_dunique_ids f = + "-dunique-ids", Arg.Unit f, " (undocumented)" +;; + let mk_dsource f = "-dsource", Arg.Unit f, " (undocumented)" ;; @@ -637,6 +645,11 @@ let mk_drawflambda f = "-drawflambda", Arg.Unit f, " Print Flambda terms after closure conversion" ;; +let mk_dflambda_invariants f = + "-dflambda-invariants", Arg.Unit f, " Check Flambda invariants \ + around each pass" +;; + let mk_dflambda_no_invariants f = "-dflambda-no-invariants", Arg.Unit f, " Do not Check Flambda invariants \ around each pass" @@ -809,6 +822,8 @@ module type Common_options = sig val _warn_error : string -> unit val _warn_help : unit -> unit + val _dno_unique_ids : unit -> unit + val _dunique_ids : unit -> unit val _dsource : unit -> unit val _dparsetree : unit -> unit val _dtypedtree : unit -> unit @@ -931,6 +946,7 @@ module type Optcommon_options = sig val _clambda_checks : unit -> unit val _dflambda : unit -> unit val _drawflambda : unit -> unit + val _dflambda_invariants : unit -> unit val _dflambda_no_invariants : unit -> unit val _dflambda_let : int -> unit val _dflambda_verbose : unit -> unit @@ -1082,6 +1098,8 @@ struct mk_nopervasives F._nopervasives; mk_use_prims F._use_prims; + mk_dno_unique_ids F._dno_unique_ids; + mk_dunique_ids F._dunique_ids; mk_dsource F._dsource; mk_dparsetree F._dparsetree; mk_dtypedtree F._dtypedtree; @@ -1139,6 +1157,8 @@ struct mk_warn_help F._warn_help; mk__ F.anonymous; + mk_dno_unique_ids F._dno_unique_ids; + mk_dunique_ids F._dunique_ids; mk_dsource F._dsource; mk_dparsetree F._dparsetree; mk_dtypedtree F._dtypedtree; @@ -1254,6 +1274,8 @@ struct mk__ F.anonymous; mk_nopervasives F._nopervasives; + mk_dno_unique_ids F._dno_unique_ids; + mk_dunique_ids F._dunique_ids; mk_dsource F._dsource; mk_dparsetree F._dparsetree; mk_dtypedtree F._dtypedtree; @@ -1263,6 +1285,7 @@ struct mk_dclambda F._dclambda; mk_dflambda F._dflambda; mk_drawflambda F._drawflambda; + mk_dflambda_invariants F._dflambda_invariants; mk_dflambda_no_invariants F._dflambda_no_invariants; mk_dflambda_let F._dflambda_let; mk_dflambda_verbose F._dflambda_verbose; diff --git a/driver/main_args.mli b/driver/main_args.mli index 3d6db535..4777f6b4 100644 --- a/driver/main_args.mli +++ b/driver/main_args.mli @@ -49,6 +49,8 @@ module type Common_options = sig val _warn_error : string -> unit val _warn_help : unit -> unit + val _dno_unique_ids : unit -> unit + val _dunique_ids : unit -> unit val _dsource : unit -> unit val _dparsetree : unit -> unit val _dtypedtree : unit -> unit @@ -171,6 +173,7 @@ module type Optcommon_options = sig val _clambda_checks : unit -> unit val _dflambda : unit -> unit val _drawflambda : unit -> unit + val _dflambda_invariants : unit -> unit val _dflambda_no_invariants : unit -> unit val _dflambda_let : int -> unit val _dflambda_verbose : unit -> unit diff --git a/driver/makedepend.ml b/driver/makedepend.ml index 6b888a0c..32d6e9d7 100644 --- a/driver/makedepend.ml +++ b/driver/makedepend.ml @@ -464,7 +464,8 @@ let sort_files_by_dependencies files = if !worklist <> [] then begin Format.fprintf Format.err_formatter - "@[Warning: cycle in dependencies. End of list is not sorted.@]@."; + "@[%t: cycle in dependencies. End of list is not sorted.@]@." + Location.print_error_prefix; let sorted_deps = let li = ref [] in Hashtbl.iter (fun _ file_deps -> li := file_deps :: !li) h; @@ -478,6 +479,7 @@ let sort_files_by_dependencies files = ) !deps; Format.fprintf Format.err_formatter "@]@."; Printf.printf "%s " file) sorted_deps; + error_occurred := true end; Printf.printf "\n%!"; () diff --git a/driver/optcompile.ml b/driver/optcompile.ml index c450b5f6..d5b64c0f 100644 --- a/driver/optcompile.ml +++ b/driver/optcompile.ml @@ -41,7 +41,7 @@ let interface ppf sourcefile outputprefix = if !Clflags.dump_typedtree then fprintf ppf "%a@." Printtyped.interface tsg; let sg = tsg.sig_type in if !Clflags.print_types then - Printtyp.wrap_printing_env initial_env (fun () -> + Printtyp.wrap_printing_env ~error:false initial_env (fun () -> fprintf std_formatter "%a@." Printtyp.signature (Typemod.simplify_signature sg)); ignore (Includemod.signatures initial_env sg sg); diff --git a/driver/optmain.ml b/driver/optmain.ml index 33fc848d..44b49304 100644 --- a/driver/optmain.ml +++ b/driver/optmain.ml @@ -195,6 +195,8 @@ module Options = Main_args.Make_optcomp_options (struct let _where () = print_standard_library () let _nopervasives = set nopervasives + let _dno_unique_ids = clear unique_ids + let _dunique_ids = set unique_ids let _dsource = set dump_source let _dparsetree = set dump_parsetree let _dtypedtree = set dump_typedtree @@ -208,6 +210,7 @@ module Options = Main_args.Make_optcomp_options (struct let _dflambda_verbose () = set dump_flambda (); set dump_flambda_verbose () + let _dflambda_invariants = set flambda_invariant_checks let _dflambda_no_invariants = clear flambda_invariant_checks let _dcmm = set dump_cmm let _dsel = set dump_selection diff --git a/emacs/Makefile b/emacs/Makefile index 93b2d7d7..dcb7a958 100644 --- a/emacs/Makefile +++ b/emacs/Makefile @@ -13,6 +13,7 @@ #************************************************************************** include ../config/Makefile +include ../Makefile.common # Files to install FILES= caml-font.el caml-hilit.el caml.el camldebug.el \ @@ -64,7 +65,7 @@ install-el: simple-install: @echo "Installing in $(EMACSDIR)..." if test -d $(EMACSDIR); then : ; else mkdir -p $(EMACSDIR); fi - cp $(FILES) $(EMACSDIR) + $(INSTALL_DATA) $(FILES) $(EMACSDIR) if [ -z "$(NOCOMPILE)" ]; then \ cd $(EMACSDIR); $(EMACS) --batch --eval '$(COMPILECMD)'; \ fi @@ -74,7 +75,7 @@ ocamltags: ocamltags.in chmod a+x ocamltags install-ocamltags: ocamltags - cp ocamltags $(SCRIPTDIR)/ocamltags + $(INSTALL_DATA) ocamltags $(SCRIPTDIR)/ocamltags # This is for testing purposes compile-only: diff --git a/emacs/caml-font-old.el b/emacs/caml-font-old.el index 674beb68..fb39c223 100644 --- a/emacs/caml-font-old.el +++ b/emacs/caml-font-old.el @@ -42,7 +42,7 @@ (setq font-lock-variable-name-face 'DarkGoldenRod) (setq font-lock-type-face 'DarkOliveGreen) (setq font-lock-reference-face 'CadetBlue))) - ; extra faces for documention + ; extra faces for documentation (make-face 'Stop) (set-face-foreground 'Stop "White") (set-face-background 'Stop "Red") diff --git a/emacs/caml-font.el b/emacs/caml-font.el index ac339744..91c6fce9 100644 --- a/emacs/caml-font.el +++ b/emacs/caml-font.el @@ -62,7 +62,7 @@ "when" "while" "with") 'words)) . font-lock-constant-face) - ("\\" + ("\\<\\(raise\\|failwith\\|invalid_arg\\)\\>" . font-lock-comment-face) ;labels (and open) ("\\(\\([~?]\\|\\<\\)[a-z][a-zA-Z0-9_']*:\\)[^:=]" diff --git a/emacs/caml-help.el b/emacs/caml-help.el index 6b1abc65..9e3a221b 100644 --- a/emacs/caml-help.el +++ b/emacs/caml-help.el @@ -25,7 +25,7 @@ ;; This is a preliminary version. ;; ;; Possible improvements? -;; - dump some databaes: Info, Lib, ... +;; - dump some databases: Info, Lib, ... ;; - accept a search path for local libraries instead of current dir ;; (then distinguish between different modules lying in different ;; directories) @@ -33,8 +33,8 @@ ;; ;; Abstract over ;; - the viewing method and the database, so that the documentation for -;; and identifier could be search in -;; * info / html / man / mli's sources +;; an identifier could be +;; * searched in info / html / man / mli's sources ;; * viewed in Emacs or using an external previewer. ;; ;; Take all identifiers (labels, Constructors, exceptions, etc.) @@ -56,7 +56,7 @@ (defvar ocaml-lib-path 'lazy "Path list for ocaml lib sources (mli files). -`lazy' means ask ocaml to find it for your at first use.") +`lazy' means ask ocaml to find it for you at first use.") (defun ocaml-lib-path () "Compute if necessary and return the path for ocaml libs." (if (listp ocaml-lib-path) nil @@ -233,7 +233,7 @@ ocaml-visible-modules) (defun ocaml-open-module (arg) - "*Make module of name ARG visible whe ARG is a string. + "*Make module of name ARG visible when ARG is a string. When call interactively, make completion over known modules." (interactive "P") (if (not (stringp arg)) @@ -335,7 +335,7 @@ with an optional non-nil argument." (defun caml-complete (arg) "Does completion for OCaml identifiers qualified. -It attemps to recognize an qualified identifier Module . entry +It attemps to recognize a qualified identifier Module . entry around point using function \\[ocaml-qualified-identifier]. If Module is defined, it does completion for identifier in Module. @@ -647,14 +647,14 @@ current buffer using \\[ocaml-qualified-identifier]." (defun caml-help (arg) "Find documentation for OCaml qualified identifiers. -It attemps to recognize an qualified identifier of the form +It attempts to recognize a qualified identifier of the form ``Module . entry'' around point using function `ocaml-qualified-identifier'. If Module is undetermined it is temptatively guessed from the identifier name -and according to visible modules. If this is still unsucessful, the user is +and according to visible modules. If this is still unsuccessful, the user is then prompted for a Module name. -The documentation for Module is first seach in the info manual if available, +The documentation for Module is first searched in the info manual, if available, then in the ``module.mli'' source file. The entry is then searched in the documentation. @@ -666,7 +666,7 @@ Prefix arg 0 forces recompilation of visible modules (and their content) from the file content. Prefix arg 4 prompts for Module and identifier instead of guessing values -from the possition of point in the current buffer." +from the position of point in the current buffer." (interactive "p") (delete-overlay ocaml-help-ovl) (let ((module) (entry) (module-entry)) @@ -726,9 +726,9 @@ from the possition of point in the current buffer." (defvar ocaml-links nil "Local links in the current of last info node or interface file. -The car of the list is a key that indentifies the module to prevent +The car of the list is a key that identifies the module to prevent recompilation when next help command is relative to the same module. -The cdr is a list of elments, each of which is an string and a pair of +The cdr is a list of elements, each of which is a string and a pair of buffer positions." ) (make-variable-buffer-local 'ocaml-links) diff --git a/emacs/caml-types.el b/emacs/caml-types.el index cc5d9152..dc01af64 100644 --- a/emacs/caml-types.el +++ b/emacs/caml-types.el @@ -669,7 +669,7 @@ The function uses two overlays. (error (message "End of buffer!"))))) (setq speed (* speed speed))))) ;; main action, when the motion is inside the window - ;; or on orginal button down event + ;; or on original button down event ((or (caml-mouse-movement-p event) (equal original-event event)) (setq cnum (caml-event-point-end event)) @@ -732,7 +732,7 @@ The function uses two overlays. ;; However, it could also be a key stroke before mouse release. ;; Emacs does not allow to test whether mouse is up or down. ;; Not sure it is robust to loop for mouse release after an error - ;; occured, as is done for exploration. + ;; occurred, as is done for exploration. ;; So far, we just ignore next event. (Next line also be uncommenting.) (if event (caml-read-event))))) diff --git a/emacs/caml.el b/emacs/caml.el index def64b91..1945fbad 100644 --- a/emacs/caml.el +++ b/emacs/caml.el @@ -75,179 +75,179 @@ Priorities are assigned to `interesting' caml operators as follows: (make-variable-buffer-local 'caml-apply-extra-indent) (defvar caml-begin-indent 2 - "*How many spaces to indent from a begin keyword in caml mode.") + "*How many spaces to indent from a \"begin\" keyword in caml mode.") (make-variable-buffer-local 'caml-begin-indent) (defvar caml-class-indent 2 - "*How many spaces to indent from a class keyword in caml mode.") + "*How many spaces to indent from a \"class\" keyword in caml mode.") (make-variable-buffer-local 'caml-class-indent) (defvar caml-exception-indent 2 - "*How many spaces to indent from a exception keyword in caml mode.") + "*How many spaces to indent from an \"exception\" keyword in caml mode.") (make-variable-buffer-local 'caml-exception-indent) (defvar caml-for-indent 2 - "*How many spaces to indent from a for keyword in caml mode.") + "*How many spaces to indent from a \"for\" keyword in caml mode.") (make-variable-buffer-local 'caml-for-indent) (defvar caml-fun-indent 2 - "*How many spaces to indent from a fun keyword in caml mode.") + "*How many spaces to indent from a \"fun\" keyword in caml mode.") (make-variable-buffer-local 'caml-fun-indent) (defvar caml-function-indent 4 - "*How many spaces to indent from a function keyword in caml mode.") + "*How many spaces to indent from a \"function\" keyword in caml mode.") (make-variable-buffer-local 'caml-function-indent) (defvar caml-if-indent 2 - "*How many spaces to indent from a if keyword in caml mode.") + "*How many spaces to indent from an \"if\" keyword in caml mode.") (make-variable-buffer-local 'caml-if-indent) (defvar caml-if-else-indent 0 - "*How many spaces to indent from an if .. else line in caml mode.") + "*How many spaces to indent from an \"if .. else\" line in caml mode.") (make-variable-buffer-local 'caml-if-else-indent) (defvar caml-inherit-indent 2 - "*How many spaces to indent from a inherit keyword in caml mode.") + "*How many spaces to indent from an \"inherit\" keyword in caml mode.") (make-variable-buffer-local 'caml-inherit-indent) (defvar caml-initializer-indent 2 - "*How many spaces to indent from a initializer keyword in caml mode.") + "*How many spaces to indent from an \"initializer\" keyword in caml mode.") (make-variable-buffer-local 'caml-initializer-indent) (defvar caml-include-indent 2 - "*How many spaces to indent from a include keyword in caml mode.") + "*How many spaces to indent from an \"include\" keyword in caml mode.") (make-variable-buffer-local 'caml-include-indent) (defvar caml-let-indent 2 - "*How many spaces to indent from a let keyword in caml mode.") + "*How many spaces to indent from a \"let\" keyword in caml mode.") (make-variable-buffer-local 'caml-let-indent) (defvar caml-let-in-indent 0 - "*How many spaces to indent from a let .. in keyword in caml mode.") + "*How many spaces to indent from a \"let .. in\" keyword in caml mode.") (make-variable-buffer-local 'caml-let-in-indent) (defvar caml-match-indent 2 - "*How many spaces to indent from a match keyword in caml mode.") + "*How many spaces to indent from a \"match\" keyword in caml mode.") (make-variable-buffer-local 'caml-match-indent) (defvar caml-method-indent 2 - "*How many spaces to indent from a method keyword in caml mode.") + "*How many spaces to indent from a \"method\" keyword in caml mode.") (make-variable-buffer-local 'caml-method-indent) (defvar caml-module-indent 2 - "*How many spaces to indent from a module keyword in caml mode.") + "*How many spaces to indent from a \"module\" keyword in caml mode.") (make-variable-buffer-local 'caml-module-indent) (defvar caml-object-indent 2 - "*How many spaces to indent from a object keyword in caml mode.") + "*How many spaces to indent from an \"object\" keyword in caml mode.") (make-variable-buffer-local 'caml-object-indent) (defvar caml-of-indent 2 - "*How many spaces to indent from a of keyword in caml mode.") + "*How many spaces to indent from an \"of\" keyword in caml mode.") (make-variable-buffer-local 'caml-of-indent) (defvar caml-parser-indent 4 - "*How many spaces to indent from a parser keyword in caml mode.") + "*How many spaces to indent from a \"parser\" keyword in caml mode.") (make-variable-buffer-local 'caml-parser-indent) (defvar caml-sig-indent 2 - "*How many spaces to indent from a sig keyword in caml mode.") + "*How many spaces to indent from a \"sig\" keyword in caml mode.") (make-variable-buffer-local 'caml-sig-indent) (defvar caml-struct-indent 2 - "*How many spaces to indent from a struct keyword in caml mode.") + "*How many spaces to indent from a \"struct\" keyword in caml mode.") (make-variable-buffer-local 'caml-struct-indent) (defvar caml-try-indent 2 - "*How many spaces to indent from a try keyword in caml mode.") + "*How many spaces to indent from a \"try\" keyword in caml mode.") (make-variable-buffer-local 'caml-try-indent) (defvar caml-type-indent 4 - "*How many spaces to indent from a type keyword in caml mode.") + "*How many spaces to indent from a \"type\" keyword in caml mode.") (make-variable-buffer-local 'caml-type-indent) (defvar caml-val-indent 2 - "*How many spaces to indent from a val keyword in caml mode.") + "*How many spaces to indent from a \"val\" keyword in caml mode.") (make-variable-buffer-local 'caml-val-indent) (defvar caml-while-indent 2 - "*How many spaces to indent from a while keyword in caml mode.") + "*How many spaces to indent from a \"while\" keyword in caml mode.") (make-variable-buffer-local 'caml-while-indent) (defvar caml-::-indent 2 - "*How many spaces to indent from a :: operator in caml mode.") + "*How many spaces to indent from a \"::\" operator in caml mode.") (make-variable-buffer-local 'caml-::-indent) (defvar caml-@-indent 2 - "*How many spaces to indent from a @ operator in caml mode.") + "*How many spaces to indent from a \"@\" operator in caml mode.") (make-variable-buffer-local 'caml-@-indent) (defvar caml-:=-indent 2 - "*How many spaces to indent from a := operator in caml mode.") + "*How many spaces to indent from a \":=\" operator in caml mode.") (make-variable-buffer-local 'caml-:=-indent) (defvar caml-<--indent 2 - "*How many spaces to indent from a <- operator in caml mode.") + "*How many spaces to indent from a \"<-\" operator in caml mode.") (make-variable-buffer-local 'caml-<--indent) (defvar caml-->-indent 2 - "*How many spaces to indent from a -> operator in caml mode.") + "*How many spaces to indent from a \"->\" operator in caml mode.") (make-variable-buffer-local 'caml-->-indent) (defvar caml-lb-indent 2 - "*How many spaces to indent from a \[ operator in caml mode.") + "*How many spaces to indent from a \"\[\" operator in caml mode.") (make-variable-buffer-local 'caml-lb-indent) (defvar caml-lc-indent 2 - "*How many spaces to indent from a \{ operator in caml mode.") + "*How many spaces to indent from a \"\{\" operator in caml mode.") (make-variable-buffer-local 'caml-lc-indent) (defvar caml-lp-indent 1 - "*How many spaces to indent from a \( operator in caml mode.") + "*How many spaces to indent from a \"\(\" operator in caml mode.") (make-variable-buffer-local 'caml-lp-indent) (defvar caml-and-extra-indent nil - "*Extra indent for caml lines starting with the and keyword. + "*Extra indent for caml lines starting with the \"and\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-and-extra-indent) (defvar caml-do-extra-indent nil - "*Extra indent for caml lines starting with the do keyword. + "*Extra indent for caml lines starting with the \"do\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-do-extra-indent) (defvar caml-done-extra-indent nil - "*Extra indent for caml lines starting with the done keyword. + "*Extra indent for caml lines starting with the \"done\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-done-extra-indent) (defvar caml-else-extra-indent nil - "*Extra indent for caml lines starting with the else keyword. + "*Extra indent for caml lines starting with the \"else\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-else-extra-indent) (defvar caml-end-extra-indent nil - "*Extra indent for caml lines starting with the end keyword. + "*Extra indent for caml lines starting with the \"end\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-end-extra-indent) (defvar caml-in-extra-indent nil - "*Extra indent for caml lines starting with the in keyword. + "*Extra indent for caml lines starting with the \"in\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-in-extra-indent) (defvar caml-then-extra-indent nil - "*Extra indent for caml lines starting with the then keyword. + "*Extra indent for caml lines starting with the \"then\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-then-extra-indent) (defvar caml-to-extra-indent -1 - "*Extra indent for caml lines starting with the to keyword. + "*Extra indent for caml lines starting with the \"to\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-to-extra-indent) (defvar caml-with-extra-indent nil - "*Extra indent for caml lines starting with the with keyword. + "*Extra indent for caml lines starting with the \"with\" keyword. Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-with-extra-indent) @@ -261,7 +261,7 @@ Usually negative. nil is align on master.") (make-variable-buffer-local 'caml-|-extra-indent) (defvar caml-rb-extra-indent -2 - "*Extra indent for caml lines statring with ]. + "*Extra indent for caml lines starting with ]. Usually negative. nil is align on master.") (defvar caml-rc-extra-indent -2 @@ -275,13 +275,13 @@ Usually negative. nil is align on master.") (defvar caml-electric-indent t "*Non-nil means electrically indent lines starting with |, ] or }. -Many people find eletric keys irritating, so you can disable them if +Many people find electric keys irritating, so you can disable them if you are one.") (defvar caml-electric-close-vector t "*Non-nil means electrically insert a | before a vector-closing ]. -Many people find eletric keys irritating, so you can disable them if +Many people find electric keys irritating, so you can disable them if you are one. You should probably have this on, though, if you also have caml-electric-indent on, which see.") @@ -623,8 +623,8 @@ have caml-electric-indent on, which see.") (defun caml-eval-phrase (arg &optional min max) "Send the phrase containing the point to the CAML process. With prefix-arg send as many phrases as its numeric value, -If an error occurs during evalutaion, stop at this phrase and -repport the error. +If an error occurs during evaluation, stop at this phrase and +report the error. Return nil if noerror and position of error if any. @@ -1136,7 +1136,7 @@ to the end. (defun caml-in-comment-p () "Returns non-nil if point is inside a caml comment. -Returns nil for the parenthesis openning a comment." +Returns nil for the parenthesis opening a comment." ;;we look for comments differently than literals. there are two ;;reasons for this. first, caml has nested comments and it is not so ;;clear that parse-partial-sexp supports them; second, if proper @@ -1266,7 +1266,7 @@ Used to distinguish it from toplevel let construct.") "Look back for a caml keyword or operator matching KWOP-REGEXP. Second optional argument MIN-POS bounds the search. -Ignore occurences inside literals. If found, return a list of two +Ignore occurrences inside literals. If found, return a list of two values: the actual text of the keyword or operator, and a boolean indicating whether the keyword was one we looked for explicitly {non-nil}, or on the other hand one of the block-terminating @@ -1971,7 +1971,7 @@ with prefix arg, indent that many phrases starting with the current phrase." "Explore type annotations by mouse dragging." t) (autoload 'caml-help "caml-help" - "Show documentation for qualilifed OCaml identifier." t) + "Show documentation for qualified OCaml identifier." t) (autoload 'caml-complete "caml-help" "Does completion for documented qualified OCaml identifier." t) (autoload 'ocaml-open-module "caml-help" diff --git a/emacs/camldebug.el b/emacs/camldebug.el index 674cd320..8b59942f 100644 --- a/emacs/camldebug.el +++ b/emacs/camldebug.el @@ -99,7 +99,7 @@ The following commands are available: the last line referred to in the camldebug buffer. \\[camldebug-step], \\[camldebug-back] and \\[camldebug-next], in the camldebug -window,call camldebug to step, backstep or next and then update the other window +window, call camldebug to step, backstep or next and then update the other window with the current file and position. If you are in a source file, you may select a point to break diff --git a/emacs/inf-caml.el b/emacs/inf-caml.el index 05bf318f..3d2b2dc9 100644 --- a/emacs/inf-caml.el +++ b/emacs/inf-caml.el @@ -23,7 +23,7 @@ ;; User modifiable variables -;; Whether you want the output buffer to be diplayed when you send a phrase +;; Whether you want the output buffer to be displayed when you send a phrase (defvar caml-display-when-eval t "*If true, display the inferior caml buffer when evaluating expressions.") @@ -205,7 +205,7 @@ Input and output via buffer `*inferior-caml*'." (goto-char loc))) -;;; orgininal inf-caml.el ended here +;;; original inf-caml.el ended here ;; as eval-phrase, but ignores errors. @@ -225,16 +225,16 @@ should lies." beg)) (defvar caml-previous-output nil - "tells the beginning of output in the shell-output buffer, so that the -output can be retreived later, asynchronously.") + "Tells the beginning of output in the shell-output buffer, so that the +output can be retrieved later, asynchronously.") -;; enriched version of eval-phrase, to repport errors. +;; enriched version of eval-phrase, to report errors. (defun inferior-caml-eval-phrase (arg &optional min max) "Send the phrase containing the point to the CAML process. With prefix-arg send as many phrases as its numeric value, -If an error occurs during evalutaion, stop at this phrase and -repport the error. +If an error occurs during evaluation, stop at this phrase and +report the error. Return nil if noerror and position of error if any. diff --git a/lex/outputbis.ml b/lex/outputbis.ml index fc8dfac8..37ff25b0 100644 --- a/lex/outputbis.ml +++ b/lex/outputbis.ml @@ -19,89 +19,129 @@ open Printf open Lexgen open Common -let output_auto_defs oc has_refill = - output_string oc - "let __ocaml_lex_init_lexbuf lexbuf mem_size =\ -\n let pos = lexbuf.Lexing.lex_curr_pos in\ -\n lexbuf.Lexing.lex_mem <- Array.make mem_size (-1) ;\ -\n lexbuf.Lexing.lex_start_pos <- pos ;\ -\n lexbuf.Lexing.lex_last_pos <- pos ;\ -\n lexbuf.Lexing.lex_last_action <- -1\ -\n\n\ -" ; - - if has_refill then - output_string oc - "let rec __ocaml_lex_next_char lexbuf state k =\ -\n if lexbuf.Lexing.lex_curr_pos >= lexbuf.Lexing.lex_buffer_len then begin\ -\n if lexbuf.Lexing.lex_eof_reached then\ -\n state lexbuf k 256\ -\n else begin\ -\n __ocaml_lex_refill (fun lexbuf ->\ -\n lexbuf.Lexing.refill_buff lexbuf ;\ -\n __ocaml_lex_next_char lexbuf state k)\ -\n lexbuf\ -\n end\ -\n end else begin\ -\n let i = lexbuf.Lexing.lex_curr_pos in\ -\n let c = Bytes.get lexbuf.Lexing.lex_buffer i in\ -\n lexbuf.Lexing.lex_curr_pos <- i+1 ;\ -\n state lexbuf k (Char.code c)\ -\n end\ -\n\n" - else - output_string oc - "let rec __ocaml_lex_next_char lexbuf =\ -\n if lexbuf.Lexing.lex_curr_pos >= lexbuf.Lexing.lex_buffer_len then begin\ -\n if lexbuf.Lexing.lex_eof_reached then\ -\n 256\ -\n else begin\ -\n lexbuf.Lexing.refill_buff lexbuf ;\ -\n __ocaml_lex_next_char lexbuf\ -\n end\ -\n end else begin\ -\n let i = lexbuf.Lexing.lex_curr_pos in\ -\n let c = Bytes.get lexbuf.Lexing.lex_buffer i in\ -\n lexbuf.Lexing.lex_curr_pos <- i+1 ;\ -\n Char.code c\ -\n end\ -\n\n" - - -let output_pats oc pats = List.iter (fun p -> fprintf oc "|%d" p) pats - -let output_action oc has_refill mems r = - output_memory_actions " " oc mems ; +type ctx = { + oc: out_channel; + has_refill: bool; + goto_state: (ctx -> string -> int -> unit); + last_action: int option; +} + +let pr ctx = fprintf ctx.oc + +let output_auto_defs ctx = + if ctx.has_refill then begin + pr ctx "\n"; + pr ctx "let rec __ocaml_lex_refill_buf lexbuf _buf _len _curr _last _last_action state k =\n"; + pr ctx " if lexbuf.Lexing.lex_eof_reached then\n"; + pr ctx " state lexbuf _last_action _buf _len _curr _last k 256\n"; + pr ctx " else begin\n"; + pr ctx " lexbuf.Lexing.lex_curr_pos <- _curr;\n"; + pr ctx " lexbuf.Lexing.lex_last_pos <- _last;\n"; + pr ctx " __ocaml_lex_refill\n"; + pr ctx " (fun lexbuf ->\n"; + pr ctx " let _curr = lexbuf.Lexing.lex_curr_pos in\n"; + pr ctx " let _last = lexbuf.Lexing.lex_last_pos in\n"; + pr ctx " let _len = lexbuf.Lexing.lex_buffer_len in\n"; + pr ctx " let _buf = lexbuf.Lexing.lex_buffer in\n"; + pr ctx " if _curr < _len then\n"; + pr ctx " state lexbuf _last_action _buf _len (_curr + 1) _last k\n"; + pr ctx " (Char.code (Bytes.unsafe_get _buf _curr))\n"; + pr ctx " else\n"; + pr ctx " __ocaml_lex_refill_buf lexbuf _buf _len _curr _last _last_action\n"; + pr ctx " state k\n"; + pr ctx " )\n"; + pr ctx " lexbuf\n"; + pr ctx " end\n"; + pr ctx "\n"; + end else begin + pr ctx "\n"; + pr ctx "let rec __ocaml_lex_refill_buf lexbuf _buf _len _curr _last =\n"; + pr ctx " if lexbuf.Lexing.lex_eof_reached then\n"; + pr ctx " 256, _buf, _len, _curr, _last\n"; + pr ctx " else begin\n"; + pr ctx " lexbuf.Lexing.lex_curr_pos <- _curr;\n"; + pr ctx " lexbuf.Lexing.lex_last_pos <- _last;\n"; + pr ctx " lexbuf.Lexing.refill_buff lexbuf;\n"; + pr ctx " let _curr = lexbuf.Lexing.lex_curr_pos in\n"; + pr ctx " let _last = lexbuf.Lexing.lex_last_pos in\n"; + pr ctx " let _len = lexbuf.Lexing.lex_buffer_len in\n"; + pr ctx " let _buf = lexbuf.Lexing.lex_buffer in\n"; + pr ctx " if _curr < _len then\n"; + pr ctx " Char.code (Bytes.unsafe_get _buf _curr), _buf, _len, (_curr + 1), _last\n"; + pr ctx " else\n"; + pr ctx " __ocaml_lex_refill_buf lexbuf _buf _len _curr _last\n"; + pr ctx " end\n"; + pr ctx "\n"; + end + +let output_memory_actions pref oc = function + | [] -> () + | mvs -> + output_string oc pref; + output_string oc "(* " ; + fprintf oc "L=%d " (List.length mvs) ; + List.iter + (fun mv -> match mv with + | Copy (tgt, src) -> + fprintf oc "[%d] <- [%d] ;" tgt src + | Set tgt -> + fprintf oc "[%d] <- p ; " tgt) + mvs ; + output_string oc " *)\n" ; + List.iter + (fun mv -> match mv with + | Copy (tgt, src) -> + fprintf oc + "%s%a <- %a ;\n" + pref output_mem_access tgt output_mem_access src + | Set tgt -> + fprintf oc "%s%a <- _curr;\n" + pref output_mem_access tgt) + mvs + +let output_pats ctx = function + | [x] -> pr ctx "| %d" x + | pats -> List.iter (fun p -> pr ctx "|%d" p) pats + +let last_action ctx = + match ctx.last_action with + | None -> "_last_action" + | Some i -> Printf.sprintf "%i (* = last_action *)" i + +let output_action ctx pref mems r = + output_memory_actions pref ctx.oc mems; match r with | Backtrack -> - fprintf oc - " lexbuf.Lexing.lex_curr_pos <- lexbuf.Lexing.lex_last_pos ;\n" ; - if has_refill then - fprintf oc " k lexbuf lexbuf.Lexing.lex_last_action\n" - else - fprintf oc " lexbuf.Lexing.lex_last_action\n" + pr ctx "%slet _curr = _last in\n\ + %slexbuf.Lexing.lex_curr_pos <- _curr;\n\ + %slexbuf.Lexing.lex_last_pos <- _last;\n" + pref pref pref; + if ctx.has_refill then + pr ctx "%sk lexbuf %s\n" pref (last_action ctx) + else + pr ctx "%s%s\n" pref (last_action ctx) | Goto n -> - fprintf oc " __ocaml_lex_state%d lexbuf%s\n" n - (if has_refill then " k" else "") + ctx.goto_state ctx pref n -let output_pat oc i = +let output_pat ctx i = if i >= 256 then - fprintf oc "|eof" + pr ctx "|eof" else - fprintf oc "|'%s'" (Char.escaped (Char.chr i)) - -let output_clause oc has_refill pats mems r = - fprintf oc "(* " ; - List.iter (output_pat oc) pats ; - fprintf oc " *)\n" ; - fprintf oc " %a ->\n" output_pats pats ; - output_action oc has_refill mems r + pr ctx "|'%s'" (Char.escaped (Char.chr i)) -let output_default_clause oc has_refill mems r = - fprintf oc " | _ ->\n" ; output_action oc has_refill mems r +let output_clause ctx pref pats mems r = + pr ctx "%s(* " pref; + List.iter (output_pat ctx) pats; + pr ctx " *)\n%s" pref; + output_pats ctx pats; + pr ctx " ->\n"; + output_action ctx (" "^pref) mems r +let output_default_clause ctx pref mems r = + pr ctx "%s| _ ->\n" pref; + output_action ctx (" "^pref) mems r -let output_moves oc has_refill moves = +let output_moves ctx pref moves = let t = Hashtbl.create 17 in let add_move i (m,mems) = let mems,r = try Hashtbl.find t m with Not_found -> mems,[] in @@ -126,98 +166,187 @@ let output_moves oc has_refill moves = Hashtbl.iter (fun m (mems,pats) -> if m <> !most_frequent then - output_clause oc has_refill (List.rev pats) mems m) + output_clause ctx pref (List.rev pats) mems m) t ; - output_default_clause oc has_refill !most_mems !most_frequent + output_default_clause ctx pref !most_mems !most_frequent -let output_tag_actions pref oc mvs = - output_string oc "(*" ; +let output_tag_actions pref ctx mvs = + pr ctx "%s(*" pref; List.iter (fun i -> match i with - | SetTag (t,m) -> fprintf oc " t%d <- [%d] ;" t m - | EraseTag t -> fprintf oc " t%d <- -1 ;" t) + | SetTag (t,m) -> pr ctx " t%d <- [%d] ;" t m + | EraseTag t -> pr ctx " t%d <- -1 ;" t) mvs ; - output_string oc " *)\n" ; + pr ctx " *)\n" ; List.iter (fun i -> match i with | SetTag (t,m) -> - fprintf oc "%s%a <- %a ;\n" + pr ctx "%s%a <- %a ;\n" pref output_mem_access t output_mem_access m | EraseTag t -> - fprintf oc "%s%a <- -1 ;\n" + pr ctx "%s%a <- -1 ;\n" pref output_mem_access t) mvs -let output_trans pref oc has_refill i trans = - let entry = sprintf "__ocaml_lex_state%d" i in - fprintf oc "%s %s lexbuf %s= " pref entry - (if has_refill then "k " else ""); - match trans with +let output_trans_body pref ctx = function | Perform (n,mvs) -> - output_tag_actions " " oc mvs ; - fprintf oc " %s%d\n" - (if has_refill then "k lexbuf " else "") - n + output_tag_actions pref ctx mvs ; + pr ctx "%slexbuf.Lexing.lex_curr_pos <- _curr;\n" pref; + pr ctx "%slexbuf.Lexing.lex_last_pos <- _last;\n" pref; + pr ctx "%s%s%d\n" pref (if ctx.has_refill then "k lexbuf " else "") n | Shift (trans, move) -> - begin match trans with - | Remember (n,mvs) -> - output_tag_actions " " oc mvs ; - fprintf oc - " lexbuf.Lexing.lex_last_pos <- lexbuf.Lexing.lex_curr_pos ;\n" ; - fprintf oc " lexbuf.Lexing.lex_last_action <- %d ;\n" n; - | No_remember -> () - end; - if has_refill then - let next = entry ^ "_next" in - fprintf oc " __ocaml_lex_next_char lexbuf %s k\n" next; - fprintf oc "and %s lexbuf k = function " next - else - output_string oc "match __ocaml_lex_next_char lexbuf with\n"; - output_moves oc has_refill move - -let output_automata oc has_refill auto = - output_auto_defs oc has_refill; + let ctx = + match trans with + | Remember (n,mvs) -> + output_tag_actions pref ctx mvs ; + pr ctx "%slet _last = _curr in\n" pref; + begin match ctx.last_action with + | Some i when i = n -> + pr ctx "%s(* let _last_action = %d in*)\n" pref n; + ctx + | _ -> + pr ctx "%slet _last_action = %d in\n" pref n; + {ctx with last_action = Some n} + end + | No_remember -> + ctx + in + if ctx.has_refill then begin + (* TODO: bind this 'state' function at toplevel instead *) + pr ctx + "%slet state lexbuf _last_action _buf _len _curr _last k = function\n" + pref; + output_moves ctx pref move; + pr ctx "%sin\n\ + %sif _curr >= _len then\n\ + %s __ocaml_lex_refill_buf lexbuf _buf _len _curr _last _last_action state k\n\ + %selse\n\ + %s state lexbuf _last_action _buf _len (_curr + 1) _last k\n\ + %s (Char.code (Bytes.unsafe_get _buf _curr))\n" + pref pref pref pref pref pref + end + else begin + pr ctx "%slet next_char, _buf, _len, _curr, _last =\n\ + %s if _curr >= _len then\n\ + %s __ocaml_lex_refill_buf lexbuf _buf _len _curr _last\n\ + %s else\n\ + %s Char.code (Bytes.unsafe_get _buf _curr),\n\ + %s _buf, _len, (_curr + 1), _last\n\ + %sin\n\ + %sbegin match next_char with\n" + pref pref pref pref pref pref pref pref; + output_moves ctx (pref ^ " ") move; + pr ctx "%send\n" pref + end + +let output_automata ctx auto inline = + output_auto_defs ctx; let n = Array.length auto in - output_trans "let rec" oc has_refill 0 auto.(0) ; - for i = 1 to n-1 do - output_trans "\nand" oc has_refill i auto.(i) - done ; - output_char oc '\n' + let first = ref true in + for i = 0 to n-1 do + if not inline.(i) then begin + pr ctx + "%s __ocaml_lex_state%d lexbuf _last_action _buf _len _curr _last %s=\n" + (if !first then "let rec" else "\nand") + i + (if ctx.has_refill then "k " else ""); + output_trans_body " " ctx auto.(i); + first := false; + end + done; + pr ctx "\n\n" (* Output the entries *) -let output_entry ic oc has_refill tr e = - let init_num, init_moves = e.auto_initial_state in - fprintf oc "%s %alexbuf =\n __ocaml_lex_init_lexbuf lexbuf %d; %a" - e.auto_name output_args e.auto_args - e.auto_mem_size - (output_memory_actions " ") init_moves; - fprintf oc - (if has_refill - then "\n __ocaml_lex_state%d lexbuf (fun lexbuf __ocaml_lex_result ->" - else "\n let __ocaml_lex_result = __ocaml_lex_state%d lexbuf in") - init_num; - output_string oc "\ -\n lexbuf.Lexing.lex_start_p <- lexbuf.Lexing.lex_curr_p;\ -\n lexbuf.Lexing.lex_curr_p <- {lexbuf.Lexing.lex_curr_p with\ -\n Lexing.pos_cnum = lexbuf.Lexing.lex_abs_pos+lexbuf.Lexing.lex_curr_pos};\ -\n match __ocaml_lex_result with\n"; +let output_init ctx pref e init_moves = + if e.auto_mem_size > 0 then + pr ctx "%slexbuf.Lexing.lex_mem <- Array.make %d (-1);\n" + pref e.auto_mem_size; + pr ctx "%slet _curr = lexbuf.Lexing.lex_curr_pos in\n" pref; + pr ctx "%slet _last = _curr in\n" pref; + pr ctx "%slet _len = lexbuf.Lexing.lex_buffer_len in\n" pref; + pr ctx "%slet _buf = lexbuf.Lexing.lex_buffer in\n" pref; + pr ctx "%slet _last_action = -1 in\n" pref; + pr ctx "%slexbuf.Lexing.lex_start_pos <- _curr;\n" pref; + output_memory_actions pref ctx.oc init_moves + +let output_rules ic ctx pref tr e = + pr ctx "%sbegin\n" pref; + pr ctx "%s let _curr_p = lexbuf.Lexing.lex_curr_p in\n" pref; + pr ctx "%s if _curr_p != Lexing.dummy_pos then begin\n" pref; + pr ctx "%s lexbuf.Lexing.lex_start_p <- _curr_p;\n" pref; + pr ctx "%s lexbuf.Lexing.lex_curr_p <-\n" pref; + pr ctx "%s {_curr_p with Lexing.pos_cnum =\n" pref; + pr ctx "%s lexbuf.Lexing.lex_abs_pos+lexbuf.Lexing.lex_curr_pos}\n" pref; + pr ctx "%s end\n" pref; + pr ctx "%send;\n" pref; + pr ctx "%smatch __ocaml_lex_result with\n" pref; List.iter (fun (num, env, loc) -> - fprintf oc " | "; - fprintf oc "%d ->\n" num; - output_env ic oc tr env ; - copy_chunk ic oc tr loc true; - fprintf oc "\n") + pr ctx "%s| %d ->\n" pref num; + output_env ic ctx.oc tr env; + copy_chunk ic ctx.oc tr loc true; + pr ctx "\n") e.auto_actions; - fprintf oc " | _ -> raise (Failure \"lexing: empty token\")\n"; - if has_refill then - output_string oc " )\n\n" - else - output_string oc "\n\n" + pr ctx "%s| _ -> raise (Failure \"lexing: empty token\")\n" pref + +let output_entry ic ctx tr e = + let init_num, init_moves = e.auto_initial_state in + pr ctx "%s %alexbuf =\n" e.auto_name output_args e.auto_args; + + if ctx.has_refill then begin + pr ctx " let k lexbuf __ocaml_lex_result =\n"; + output_rules ic ctx " " tr e; + pr ctx " in\n"; + output_init ctx " " e init_moves; + ctx.goto_state ctx " " init_num + end else begin + pr ctx " let __ocaml_lex_result =\n"; + output_init ctx " " e init_moves; + ctx.goto_state ctx " " init_num; + pr ctx " in\n"; + output_rules ic ctx " " tr e + end; + pr ctx "\n\n" + + +(* Determine which states to inline *) +let choose_inlining entry_points transitions = + let counters = Array.make (Array.length transitions) 0 in + let count i = counters.(i) <- counters.(i) + 1 in + List.iter (fun e -> count (fst e.auto_initial_state)) entry_points; + Array.iter + (function + | Shift (_, a) -> + let tbl = Hashtbl.create 8 in + Array.iter + (function + | (Goto i, _) when not (Hashtbl.mem tbl i) -> + Hashtbl.add tbl i (); count i + | _ -> () + ) + a + | Perform _ -> () + ) + transitions; + Array.mapi + (fun i -> function + | Perform _ -> true + | Shift _ -> counters.(i) = 1 + ) + transitions + +let goto_state inline transitions ctx pref n = + if inline.(n) then + output_trans_body pref ctx transitions.(n) + else + pr ctx "%s__ocaml_lex_state%d lexbuf %s _buf _len _curr _last%s\n" + pref n + (last_action ctx) + (if ctx.has_refill then " k" else "") (* Main output function *) @@ -226,15 +355,24 @@ let output_lexdef ic oc tr header rh copy_chunk ic oc tr header false; let has_refill = output_refill_handler ic oc tr rh in - output_automata oc has_refill transitions; + let inline = choose_inlining entry_points transitions in + let ctx = + { + has_refill; + oc; + goto_state = goto_state inline transitions; + last_action = None; + } + in + output_automata ctx transitions inline; begin match entry_points with [] -> () | entry1 :: entries -> output_string oc "let rec "; - output_entry ic oc has_refill tr entry1; + output_entry ic ctx tr entry1; List.iter (fun e -> output_string oc "and "; - output_entry ic oc has_refill tr e) + output_entry ic ctx tr e) entries; output_string oc ";;\n\n"; end; diff --git a/man/ocaml.m b/man/ocaml.m index 3b20ada0..edfc2b6b 100644 --- a/man/ocaml.m +++ b/man/ocaml.m @@ -170,8 +170,7 @@ are supported. .B \-safe\-string Enforce the separation between types .BR string \ and\ bytes , -thereby making strings read-only. This will become the default in -a future version of OCaml. +thereby making strings read-only. This is the default. .TP .B \-short\-paths When a type is visible under several module-paths, use the shortest @@ -207,9 +206,9 @@ accesses an array or string outside of its bounds. .B \-unsafe\-string Identify the types .BR string \ and\ bytes , -thereby making strings writable. For reasons of backward compatibility, -this is the default setting for the moment, but this will change in a future -version of OCaml. +thereby making strings writable. +This is intended for compatibility with old source code and should not +be used with new software. .TP .B \-version Print version string and exit. diff --git a/man/ocamlc.m b/man/ocamlc.m index 532397e5..810e821a 100644 --- a/man/ocamlc.m +++ b/man/ocamlc.m @@ -611,8 +611,7 @@ suffix is supported and gives a debug version of the runtime. .B \-safe\-string Enforce the separation between types .BR string \ and\ bytes , -thereby making strings read-only. This will become the default in -a future version of OCaml. +thereby making strings read-only. This is the default. .TP .B \-short\-paths When a type is visible under several module-paths, use the shortest @@ -622,11 +621,6 @@ warning messages. .B \-strict\-sequence Force the left-hand part of each sequence to have type unit. .TP -.B \-thread -Compile or link multithreaded programs, in combination with the -system "threads" library described in -.IR The\ OCaml\ user's\ manual . -.TP .B \-unboxed\-types When a type is unboxable (i.e. a record with a single argument or a concrete datatype with a single constructor of one argument) it will @@ -650,9 +644,9 @@ accesses an array or string outside of its bounds. .B \-unsafe\-string Identify the types .BR string \ and\ bytes , -thereby making strings writable. For reasons of backward compatibility, -this is the default setting for the moment, but this will change in a future -version of OCaml. +thereby making strings writable. +This is intended for compatibility with old source code and should not +be used with new software. .TP .BI \-use\-runtime \ runtime\-name Generate a bytecode executable file that can be executed on the custom diff --git a/man/ocamlopt.m b/man/ocamlopt.m index f2a2b208..9bd34f4f 100644 --- a/man/ocamlopt.m +++ b/man/ocamlopt.m @@ -360,6 +360,12 @@ setting the option ensures that this module will always be linked if it is put in a library and this library is linked. .TP +.B \-linscan +Use linear scan register allocation. Compiling with this allocator is faster +than with the usual graph coloring allocator, sometimes quite drastically so for +long functions and modules. On the other hand, the generated code can be a bit +slower. +.TP .B \-no-alias-deps Do not record dependencies for module aliases. .TP @@ -554,8 +560,7 @@ is saved in the file .B \-safe\-string Enforce the separation between types .BR string \ and\ bytes , -thereby making strings read-only. This will become the default in -a future version of OCaml. +thereby making strings read-only. This is the default. .TP .B \-shared Build a plugin (usually .cmxs) that can be dynamically loaded with @@ -583,11 +588,6 @@ warning messages. .B \-strict\-sequence The left-hand part of a sequence must have type unit. .TP -.B \-thread -Compile or link multithreaded programs, in combination with the -system threads library described in -.IR "The OCaml user's manual" . -.TP .B \-unboxed\-types When a type is unboxable (i.e. a record with a single argument or a concrete datatype with a single constructor of one argument) it will @@ -618,9 +618,9 @@ exception. .B \-unsafe\-string Identify the types .BR string \ and\ bytes , -thereby making strings writable. For reasons of backward compatibility, -this is the default setting for the moment, but this will change in a future -version of OCaml. +thereby making strings writable. +This is intended for compatibility with old source code and should not +be used with new software. .TP .B \-v Print the version number of the compiler and the location of the diff --git a/manual/LICENSE-for-the-manual b/manual/LICENSE-for-the-manual new file mode 100644 index 00000000..c104a053 --- /dev/null +++ b/manual/LICENSE-for-the-manual @@ -0,0 +1,20 @@ +The present documentation is copyright Institut National de Recherche +en Informatique et en Automatique (INRIA). + +The OCaml documentation and user's manual may be reproduced and +distributed in whole or in part, subject to the following conditions: + +- The copyright notice above and this permission notice must be + preserved complete on all complete or partial copies. + +- Any translation or derivative work of the OCaml documentation and + user's manual must be approved by the authors in writing before + distribution. + +- If you distribute the OCaml documentation and user's manual in part, + instructions for obtaining the complete version of this manual must + be included, and a means for obtaining a complete version provided. + +- Small portions may be reproduced as illustrations for reviews or + quotes in other works without this permission notice if proper + citation is given. diff --git a/manual/Makefile b/manual/Makefile new file mode 100644 index 00000000..d866494d --- /dev/null +++ b/manual/Makefile @@ -0,0 +1,32 @@ +all: tools + cd manual; ${MAKE} all + ${MAKE} tests +# cd fpcl; ${MAKE} all + +clean: + cd manual; ${MAKE} clean + cd tools; ${MAKE} clean +# cd fpcl; ${MAKE} clean + +release: + cd manual; ${MAKE} release +# cd fpcl; ${MAKE} release + +.PHONY: tools +tools: + cd tools; ${MAKE} clean; ${MAKE} all + +# The pregen-etex target generates the latex files from the .etex +# files to ensure that this phase of the manual build process, which +# may execute OCaml fragments and expect certain outputs, is correct +pregen-etex: tools + cd manual; $(MAKE) etex-files + +# pregen builds both .etex files and the documentation of the standard library +pregen: tools + cd manual; $(MAKE) files + +# test the consistency of the manual and the compiler source +.PHONY:tests +tests: + ${MAKE} -C tests all diff --git a/manual/README.md b/manual/README.md new file mode 100644 index 00000000..26f818c0 --- /dev/null +++ b/manual/README.md @@ -0,0 +1,252 @@ +OCAML DOCUMENTATION +=================== + +Prerequisites +------------- + +- Any prerequisites required to build OCaml from sources. + +- The Unix editor 'ed', no longer installed by default on some systems. + +- A LaTeX installation. + +- The HeVeA LaTeX-to-HTML convertor (available in OPAM): + + +Note that you must make sure `hevea.sty` is installed into TeX properly. Your +package manager may not do this for you. Run `kpsewhich hevea.sty` to check. + + +Building +-------- + +0. Install the OCaml distribution. + +1. Run `make` in the manual. + +NB: If you already set `LD_LIBRARY_PATH` (OS X: `DYLD_LIBRARY_PATH`) + in your environment don't forget to add + `otherlibs/unix:otherlibs/str` to it in an absolute way. + +Outputs +------- + +In the manual: + +- The HTML Manual is in directory `htmlman`. The main file is `index.html`. + +- The plain text manual is in directory `textman` as file `manual.txt`. + +- The Info manual is in directory `infoman`. + +- The DVI manual is in directory `texstuff` as file `manual.dvi`. + +- The PDF manual is in directory `texstuff` as file `pdfmanual.pdf`. + +Source files +------------ +The manual is written in an extended dialect of latex and is split in many +source files. During the build process, the sources files are converted into +classical latex file using the tools available in `tools`. These files are +then converted to the different output formats using either latex or hevea. + +Each part of the manual corresponds to a specific directory, and each distinct +chapters (or sometimes sections) are mapped to a distinct `.etex` file: + +- Part I, Introduction to OCaml: `tutorials` + - The core language: `coreexamples.etex` + - The module system: `moduleexamples.etex` + - Objects in OCaml: `objectexamples.etex` + - Labels and variants: `lablexamples.etex` + - Advanced examples with classes and modules: `advexamples.etex` + +- Part II, The OCaml language: `refman` + This part is separated in two very distinct chapters; the + `OCaml language` chapter and the `Language extensions` chapter. + + - The OCaml language: `refman.etex` + This chapter consists in a technical description of the OCaml language. + Each section of this chapter is mapped to a separated latex file: + - `lex.etex`, `values.etex`, `names.etex`, `types.etex`, `const.etex`, + `patterns.etex`, `expr.etex`, `typedecl.etex`, `classes.etex`, + `modtypes.etex`, `compunit.etex` + + - Language extensions: `exten.etex` + This chapter contains a description of all recent features of the OCaml + language. + +- Part III, The OCaml tools: 'cmds' + - Batch compilation (ocamlc): `comp.etex` + - The toplevel system (ocaml): `top.etex` + - The runtime system (ocamlrun): `runtime.etex` + - Native-code compilation (ocamlopt): `native.etex` + - Lexer and parser generators (ocamllex, ocamlyacc): `lexyacc.etex` + - Dependency generator (ocamldep): `ocamldep.etex` + - The browser/editor (ocamlbrowser): `browser.etex` + - The documentation generator (ocamldoc): `ocamldoc.etex` + - The debugger (ocamldebug): `debugger.etex` + - Profiling (ocamlprof): `profil.etex` + - The ocamlbuild compilation manager: `ocamlbuild.etex` + - Interfacing C with OCaml: `intf-c.etex` + - Optimisation with Flambda: `flambda.etex` + - Memory profiling with Spacetime: `spacetime.etex` + - Fuzzing with afl-fuzz: `afl-fuzz.etex` + +Note that ocamlc,ocamlopt and the toplevel options overlap a lot. +Consequently, these options are described together in the file +`unified-options.etex` and then included from `comp.etex`, `native.etex`, +and `top.etex`. If you need to update this list of options, the top comment +of `unified-options.etex` contains the relevant information. + +- Part IV, The OCaml library: 'libref' + This parts contains an brief presentation of all libraries bundled with the + compilers and the api documentation generated for these libraries. + - The core library: `core.etex` + - The standard library: `stdlib.etex` + - The compiler front-end: `compilerlibs.etex` + - The unix library: Unix system calls: `libunix.etex` + - The legacy num library: this library has been removed from the core + distribution, see `libnum.etex` + - The str library: regular expressions and string processing: `libstr.etex` + - The threads library: `libthreads.etex` + - The graphics library: `libgraph.etex` + - The dynlink library: dynamic loading and linking of object files: + `libdynlink.etex` + - The bigarray library: `libbigarray.etex` + +Latex extensions +---------------- + +### Caml environments + +The tool `tool/caml-tex2` is used to generate the latex code for the examples +in the introduction and language extension parts of the manual. It implements +two pseudo-environments: `caml_example` and `caml_eval`. + +The pseudo-environment `caml_example` evaluates its contents using an ocaml +interpreter and then translates both the input code and the interpreter output +to latex code, e.g. +```latex +\begin{caml_example}{toplevel} +let f x = x;; +\end{caml_example} +``` +Note that the toplevel output can be suppressed by using a `*` suffix: +```latex +\begin{caml_example*}{verbatim} +let f x = x +\end{caml_example*} +``` + +The `{verbatim}` or `{toplevel}` argument of the environment corresponds +to the the mode of the example, two modes are available `toplevel` and +`verbatim`. +The `toplevel` mode mimics the appearance and behavior of the toplevel. +In particular, toplevel examples must end with a double semi-colon `;;`, +otherwise an error would be raised. +The `verbatim` does not require a final `;;` and is intended to be +a lighter mode for code examples. + +By default, `caml_tex2` raises an error and stops if the output of one +the `caml_example` environment contains an unexpected error or warning. +If such an error or warning is, in fact, expected, it is necessary to +indicate the expected output status to `caml_tex2` by adding either +an option to the `caml_example` environment: +```latex +\begin{caml_example}{toplevel}[error] +1 + 2. ;; +\end{caml_example} + or for warning +\begin{caml_example}[warning=8] +let f None = None;; +\end{caml_example} +``` +or an annotation to the concerned phrase: + +```latex +\begin{caml_example}{toplevel} +1 + 2. [@@expect error] ;; +let f None = None [@@expect warning 8];; +3 + 4 [@@expect ok];; +\end{caml_example} +``` + +It is also possible to elide a code fragment by annotating it with +an `[@ellipsis]` attribute + +```latex +\begin{caml_example}{toplevel} +let f: type a. a list -> int = List.length[@ellipsis] ;; +\end{caml_example} +``` +For module components, it might be easier to hide them by using +`[@@@ellipsis.start]` and `[@@@ellipsis.stop]`: +```latex +\begin{caml_example*}{verbatim} +module M = struct + [@@@ellipsis.start] + type t = T + let x = 0 + [@@@ellipsis.stop] + end +\end{caml_example*} +``` + +Another possibility to avoid displaying distracting code is to use +the `caml_eval` environment. This environment is a companion environment +to `caml_example` and can be used to evaluate OCaml expressions in the +toplevel without printing anything: +```latex +\begin{caml_eval} +let pi = 4. *. atan 1.;; +\end{caml_eval} +\begin{caml_example}{toplevel} +let f x = x +. pi;; +\end{caml_example} +``` +Beware that the detection code for these pseudo-environments is quite brittle +and the environments must start and end at the beginning of the line. + +### Quoting + +The tool `tools/texquote2` provides support for verbatim-like quotes using +`\"` delimiters. More precisely, outside of caml environments and verbatim +environments, `texquote2` translates double quotes `"text"` to +`\machine{escaped_text}`. + +### BNF grammar notation + +The tool `tools/transf` provides support for BNF grammar notations and special +quotes for non-terminal. When transf is used, the environment `syntax` can +be used to describe grammars using BNF notation: +```latex +\begin{syntax} +expr: + value-path + | constant + | '(' expr ')' + | 'begin' expr 'end' + | '(' expr ':' typexpr ')' + | expr {{',' expr}} + | constr expr + | "`"tag-name expr + | expr '::' expr + | '[' expr { ';' expr } [';'] ']' + | '[|' expr { ';' expr } [';'] '|]' + | '{' field [':' typexpr] '=' expr% + { ';' field [':' typexpr] '=' expr } [';'] '}' +\end{syntax} +``` +Notice that terminal symbols are quoted using `'` delimiters. +Moreover, outside of the syntax environment, `@`-quotes can be used +to introduce fragment of grammar: `@'(' module-expr ')'@`. As a consequence, +when this extension is used `@` characters must be escaped as `\@`. +This extension is used mainly in the language reference part of the manual. +and a more complete description of the notation used is available in the +first subsection of `refman/refman.etex`. + +Consistency tests +----------------- + +The `tests` folder contains consistency tests that checks that the manual +and the rest of the compiler sources stay synced. diff --git a/manual/manual/.gitignore b/manual/manual/.gitignore new file mode 100644 index 00000000..71605a70 --- /dev/null +++ b/manual/manual/.gitignore @@ -0,0 +1,8 @@ +allfiles.tex +biblio.tex +foreword.tex +version.tex +warnings.etex +warnings.tex +foreword.htex +manual.html diff --git a/manual/manual/Makefile b/manual/manual/Makefile new file mode 100644 index 00000000..9cc3d819 --- /dev/null +++ b/manual/manual/Makefile @@ -0,0 +1,143 @@ +# $Id$ + +FILES=allfiles.tex biblio.tex foreword.tex version.tex warnings-help.etex +TEXINPUTS=.:..:../refman:../library:../cmds:../tutorials:../../styles: +TEXFONTS=../../styles: +RELEASE=$$HOME/release/$${RELEASENAME} +HEVEA=hevea +HACHA=hacha +INFO=-fix -exec xxdate.exe -info -w 79 +HTML=-fix -exec xxdate.exe -O +TEXT=-fix -exec xxdate.exe -text -w 79 +SRC = $(abspath ../../) + +export LD_LIBRARY_PATH ?= $(SRC)/otherlibs/unix/:$(SRC)/otherlibs/str/ +export DYLD_LIBRARY_PATH ?= $(SRC)/otherlibs/unix/:$(SRC)/otherlibs/str/ +SET_LD_PATH=CAML_LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) + +OCAMLDOC=$(if $(wildcard $(SRC)/ocamldoc/ocamldoc.opt),\ + $(SRC)/ocamldoc/ocamldoc.opt,\ + $(SET_LD_PATH) $(SRC)/byterun/ocamlrun $(SRC)/ocamldoc/ocamldoc)\ + -hide Pervasives -nostdlib -initially-opened-module Pervasives + +manual: files + cd texstuff; \ + TEXINPUTS=$(TEXINPUTS) latex manual.tex + +index:: + cd texstuff && \ + sh ../../tools/fix_index.sh manual.idx && \ + makeindex manual.idx + cd texstuff; makeindex manual.kwd.idx + +pdfmanual: files + cd texstuff; \ + TEXINPUTS=$(TEXINPUTS) pdflatex pdfmanual.tex + +index:: + cd texstuff && \ + sh ../../tools/fix_index.sh pdfmanual.idx && \ + makeindex pdfmanual.idx + cd texstuff; makeindex pdfmanual.kwd.idx + + +# Copy and unprefix the standard library when needed +include $(SRC)/ocamldoc/Makefile.unprefix + +html: files $(STDLIB_CMIS) + cd htmlman; \ + mkdir -p libref ; \ + $(OCAMLDOC) -colorize-code -sort -html \ + -d libref \ + -I $(STDLIB_UNPREFIXED) \ + $(STDLIB_MLIS) ; \ + cp -f ../style.css libref ; \ + ${HEVEA} ${HTML} -I .. -I ../refman -I ../library -I ../cmds \ + -I ../tutorials -I ../../styles -I ../texstuff manual.hva \ + -e macros.tex ../manual.tex ; \ + ${HACHA} -tocter manual.html ; \ + +info: files + cd infoman; rm -f ocaml.info*; \ + ${HEVEA} ${INFO} -o ocaml.info.body -I .. -I ../refman -I ../library \ + -I ../cmds -I ../tutorials -I ../../styles -I ../texstuff \ + ../manual.inf -e macros.tex ../manual.tex + cat manual.info.header infoman/ocaml.info.body > infoman/ocaml.info + cd infoman; rm -f ocaml.info.tmp ocaml.info.body ; gzip -9 ocaml.info* + +text: files + cd textman; \ + ${HEVEA} ${TEXT} -I .. -I ../refman -I ../library -I ../cmds \ + -I ../tutorials -I ../../styles -I ../texstuff \ + ../manual.inf -e macros.tex ../manual.tex + +etex-files: $(FILES) + cd refman; $(MAKE) etex-files RELEASEDIR=$(SRC) + cd library; $(MAKE) etex-files RELEASEDIR=$(SRC) + cd cmds; $(MAKE) etex-files RELEASEDIR=$(SRC) + cd tutorials; $(MAKE) etex-files RELEASEDIR=$(SRC) + +files: $(FILES) + cd refman; $(MAKE) all RELEASEDIR=$(SRC) + cd library; $(MAKE) all RELEASEDIR=$(SRC) + cd cmds; $(MAKE) all RELEASEDIR=$(SRC) + cd tutorials; $(MAKE) all RELEASEDIR=$(SRC) + +all: + $(MAKE) manual pdfmanual RELEASEDIR=$(SRC) + $(MAKE) manual pdfmanual RELEASEDIR=$(SRC) + $(MAKE) index RELEASEDIR=$(SRC) + $(MAKE) manual pdfmanual RELEASEDIR=$(SRC) + $(MAKE) html text info RELEASEDIR=$(SRC) + +clean: + rm -f $(FILES) + cd refman; $(MAKE) clean + cd library; $(MAKE) clean + cd cmds; $(MAKE) clean + cd tutorials; $(MAKE) clean + -rm -f texstuff/* + cd htmlman; rm -rf libref index.html manual*.html *.haux *.hind + cd textman; rm -f manual.txt *.haux *.hind + cd infoman; rm -f ocaml.info ocaml.info-* *.haux *.hind + rm -f warnings-help.etex + +release: + gzip < texstuff/manual.dvi > $(RELEASE)refman.dvi.gz + dvips -o '!gzip > $(RELEASE)refman.ps.gz' texstuff/manual.dvi + cp htmlman/manual.html $(RELEASE)refman.html + rm -f htmlman/manual.{html,haux,hmanual*,htoc} + tar zcf $(RELEASE)refman-html.tar.gz htmlman/*.* htmlman/libref + zip -8 $(RELEASE)refman-html.zip htmlman/*.* htmlman/libref/*.* + cp texstuff/pdfmanual.pdf $(RELEASE)refman.pdf + cp textman/manual.txt $(RELEASE)refman.txt + tar cf - infoman/ocaml.info* | gzip > $(RELEASE)refman.info.tar.gz + +.SUFFIXES: +.SUFFIXES: .tex .etex .htex + + +.etex.tex: + ../tools/texquote2 < $*.etex > $*.tex + +version.tex: $(SRC)/VERSION + sed -n -e '1s/^\([0-9]*\.[0-9]*\).*$$/\\def\\ocamlversion{\1}/p' \ + $(SRC)/VERSION > version.tex + +warnings-help.etex: $(SRC)/utils/warnings.ml $(SRC)/ocamlc + (echo "% This file is generated from (ocamlc -warn-help)";\ + echo "% according to a rule in manual/manual/Makefile.";\ + echo "% In particular, the reference to documentation sections";\ + echo "% are inserted through the Makefile, which should be updated";\ + echo "% when a new warning is documented.";\ + echo "%";\ + $(SET_LD_PATH) $(SRC)/boot/ocamlrun $(SRC)/ocamlc -warn-help \ + | sed -e 's/^ *\([0-9A-Z][0-9]*\)\(.*\)/\\item[\1] \2/'\ + ) >$@ +# sed --inplace is not portable, emulate + for i in 52 57; do\ + sed\ + s'/\\item\['$$i'\]/\\item\['$$i' (see \\ref{ss:warn'$$i'})\]/'\ + $@ > $@.tmp;\ + mv $@.tmp $@;\ + done diff --git a/manual/manual/allfiles.etex b/manual/manual/allfiles.etex new file mode 100644 index 00000000..7380648f --- /dev/null +++ b/manual/manual/allfiles.etex @@ -0,0 +1,110 @@ +\makeindex{\jobname} +\makeindex{\jobname.kwd} + +\setlength{\emergencystretch}{50pt} % pour que TeX resolve les overfull hbox lui-meme + +\begin{document} + +\thispagestyle{empty} +\begin{maintitle} +~\vfill +\Huge The OCaml system \\ + release \ocamlversion \\[1cm] +\Large Documentation and user's manual \\[1cm] +\large Xavier Leroy, \\ + Damien Doligez, Alain Frisch, Jacques Garrigue, Didier Rémy and Jérôme Vouillon \\[1cm] + \today \\ + ~ +\vfill +\normalsize Copyright \copyright\ \number\year\ Institut National de + Recherche en Informatique et en Automatique +\end{maintitle} +\cleardoublepage +\setcounter{page}{1} + + +\begin{htmlonly} +\begin{quote} +\rule{}{} +This manual is also available in +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman.pdf}{PDF}. +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman.ps.gz}{Postscript}, +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman.dvi.gz}{DVI}, +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman.txt}{plain text}, +as a +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman-html.tar.gz}{bundle of HTML files}, +and as a +\ahref{http://caml.inria.fr/distrib/ocaml-\ocamlversion/ocaml-\ocamlversion-refman.info.tar.gz}{bundle of Emacs Info files}. +\rule{}{} +\end{quote} +\end{htmlonly} + +\tableofcontents + +\input{foreword.tex} + +\part{An introduction to OCaml} +\label{p:tutorials} +\input{coreexamples.tex} +\input{moduleexamples.tex} +\input{objectexamples.tex} +\input{lablexamples.tex} +\input{polymorphism.tex} +\input{advexamples.tex} + +\part{The OCaml language} +\label{p:refman} +\input{refman.tex} +\input{exten.tex} + +\part{The OCaml tools} +\label{p:commands} + +\input{comp.tex} +\input{top.tex} +\input{runtime.tex} +\input{native.tex} +\input{lexyacc.tex} +\input{depend.tex} +\input{browser.tex} +\input{ocamldoc.tex} +\input{debugger.tex} +\input{profil.tex} +\input{ocamlbuild.tex} +% \input emacs.tex +\input{intf-c.tex} +\input{flambda.tex} +\input{spacetime.tex} +\input{afl-fuzz.tex} +\input{plugins} + +\part{The OCaml library} +\label{p:library} +\input{core.tex} +\input{stdlib.tex} +\input{compilerlibs.tex} +\input{libunix.tex} +\input{libnum.tex} +\input{libstr.tex} +\input{libthreads.tex} +\input{libgraph.tex} +\input{libdynlink.tex} +\input{libbigarray.tex} + +\part{Appendix} +\label{p:appendix} + +\ifouthtml +\begin{links} +\item \ahref{libref/index_modules.html}{Index of modules} +\item \ahref{libref/index_module_types.html}{Index of module types} +\item \ahref{libref/index_types.html}{Index of types} +\item \ahref{libref/index_exceptions.html}{Index of exceptions} +\item \ahref{libref/index_values.html}{Index of values} +\end{links} +\else +\printindex{\jobname}{Index to the library} +\fi +\printindex{\jobname.kwd}{Index of keywords} + +\end{document} diff --git a/manual/manual/biblio.etex b/manual/manual/biblio.etex new file mode 100644 index 00000000..dd4c26dd --- /dev/null +++ b/manual/manual/biblio.etex @@ -0,0 +1,240 @@ +\chapter{Further reading} + +For the interested reader, we list below some references to books and +reports related (sometimes loosely) to Caml Light. + +\section{Programming in ML} + +The books below are programming courses taught in ML. Their main goal +is to teach programming, not to describe ML in full details --- though +most contain fairly good introductions to the ML language. Some of +those books use the Standard ML dialect instead of the Caml dialect, +so you will have to keep in mind the differences in syntax and in +semantics. + +\begin{itemize} + +\item Pierre Weis and Xavier Leroy. {\it Le langage Caml.} +InterÉditions, 1993. + +The natural companion to this manual, provided you read French. This +book is a step-by-step introduction to programming in Caml, and +presents many realistic examples of Caml programs. + +\item Guy Cousineau and Michel Mauny. {\it Approche fonctionnelle de +la programmation}. Ediscience, 1995. + +Another Caml programming course written in French, with many original +examples. + +\item Lawrence C.\ Paulson. {\it ML for the working programmer.} +Cambridge University Press, 1991. + +A good introduction to programming in Standard ML. Develops a +theorem prover as a complete example. Contains a presentation of +the module system of Standard ML. + +\item Jeffrey D.\ Ullman. {\it Elements of ML programming.} +Prentice Hall, 1993. + +Another good introduction to programming in Standard ML. No realistic +examples, but a very detailed presentation of the language constructs. + +\item Ryan Stansifer. {\em ML primer.} Prentice-Hall, 1992. + +A short, but nice introduction to programming in Standard ML. + +\item Thérèse Accart Hardin and Véronique Donzeau-Gouge Viguié. {\em +Concepts et outils de la programmation. Du fonctionnel à +l'impératif avec Caml et Ada.} InterÉditions, 1992. + +A first course in programming, that first introduces the main programming +notions in Caml, then shows them underlying Ada. Intended for +beginners; slow-paced for the others. + +\item Rachel Harrison. {\em Abstract Data Types in Standard ML}. +John Wiley \& Sons, 1993. + +A presentation of Standard ML from the standpoint of abstract data +types. Uses intensively the Standard ML module system. + +\item Harold Abelson and Gerald Jay Sussman. +{\em Structure and Interpretation of Computer Programs.} The MIT +press, 1985. (French translation: {\em Structure et interprétation +des programmes informatiques}, InterÉditions, 1989.) + +An outstanding course on programming, taught in Scheme, the modern +dialect of Lisp. Well worth reading, even if you are more interested +in ML than in Lisp. + +\end{itemize} + +\section{Descriptions of ML dialects} + +The books and reports below are descriptions of various programming +languages from the ML family. They assume some familiarity with ML. + +\begin{itemize} + +\item Xavier Leroy and Pierre Weis. {\em Manuel de référence du +langage Caml.} InterÉditions, 1993. + +The French edition of the present reference manual and user's manual. + +\item Robert Harper. {\em Introduction to Standard ML.} Technical +report ECS-LFCS-86-14, University of Edinburgh, 1986. + +An overview of Standard ML, including the module system. Terse, but +still readable. + +\item Robin Milner, Mads Tofte and Robert Harper. {\em The definition +of Standard ML.} The MIT press, 1990. + +A complete formal definition of Standard ML, in the framework of +structured operational semantics. This book is probably the most +mathematically precise definition of a programming language ever +written. It is heavy on formalism and extremely terse, so +even readers who are thoroughly familiar with ML will have +major difficulties with it. + +\item Robin Milner and Mads Tofte. {\em Commentary on Standard ML.} +The MIT Press, 1991. + +A commentary on the book above, that attempts to explain the most +delicate parts and motivate the design choices. Easier to read than the +Definition, but still rather involving. + +\item Guy Cousineau and Gérard Huet. {\em The CAML primer.} Technical +report~122, INRIA, 1990. + +A short description of the original Caml system, from which Caml Light +has evolved. Some familiarity with Lisp is assumed. + +\item Pierre Weis et al. {\em The CAML reference manual, version +2.6.1.} Technical report~121, INRIA, 1990. + +The manual for the original Caml system, from which Caml Light +has evolved. + +\item Michael J.\ Gordon, Arthur J.\ Milner and Christopher P.\ Wadsworth. +{\em Edinburgh LCF.} Lecture Notes in Computer Science +volume~78, Springer-Verlag, 1979. + +This is the first published description of the ML language, at the +time when it was nothing more than the control language for the LCF +system, a theorem prover. This book is now obsolete, since the ML +language has much evolved since then; but it is still of historical +interest. + +\item Paul Hudak, Simon Peyton-Jones and Philip Wadler. {\em +Report on the programming language Haskell, version 1.1.} Technical +report, Yale University, 1991. + +Haskell is a purely functional language with lazy semantics that +shares many important points with ML (full functionality, polymorphic +typing), but has interesting features of its own (dynamic overloading, +also called type classes). + +\end{itemize} + +\section{Implementing functional programming languages} + +The references below are intended for those who are curious to learn +how a language like Caml Light is compiled and implemented. + +\begin{itemize} + +\item Xavier Leroy. {\em The ZINC experiment: an economical +implementation of the ML language.} Technical report~117, INRIA, 1990. +(Available by anonymous FTP on "ftp.inria.fr".) + +A description of the ZINC implementation, the prototype ML +implementation that has evolved into Caml Light. Large parts of this +report still apply to the current Caml Light system, in particular the +description of the execution model and abstract machine. Other parts +are now obsolete. Yet this report still gives a complete overview of the +implementation techniques used in Caml Light. + +\item Simon Peyton-Jones. {\em The implementation of functional +programming languages.} Prentice-Hall, 1987. (French translation: +{\em Mise en \oe uvre des langages fonctionnels de programmation}, +Masson, 1990.) + +An excellent description of the implementation of purely functional +languages with lazy semantics, using the technique known as graph +reduction. The part of the book that deals with the transformation +from ML to enriched lambda-calculus directly applies to Caml Light. +You will find a good description of how pattern-matching is compiled +and how types are inferred. The remainder of the book does not apply +directly to Caml Light, since Caml Light is not purely functional (it +has side-effects), has strict semantics, and does not use graph +reduction at all. + +\item Andrew W.\ Appel. {\em Compiling with continuations.} Cambridge +University Press, 1992. + +A complete description of an optimizing compiler for Standard ML, +based on an intermediate representation called continuation-passing +style. Shows how many advanced program optimizations can be applied to +ML. Not directly relevant to the Caml Light system, since Caml Light +does not use continuation-passing style at all, and makes little +attempts at optimizing programs. + +\end{itemize} + +\section{Applications of ML} + +The following reports show ML at work in various, sometimes +unexpected, areas. + +\begin{itemize} + +\item Emmanuel Chailloux and Guy Cousineau. {\em The MLgraph primer.} +Technical report 92-15, École Normale Supérieure, 1992. (Available by +anonymous FTP on "ftp.ens.fr".) +%, répertoire "biblio", fichier +% "liens-92-15.A4.300dpi.ps.Z".) + +Describes a Caml Light library that produces Postscript pictures +through high-level drawing functions. + +\item Xavier Leroy. {\em Programmation du système Unix en Caml Light.} +Technical report~147, INRIA, 1992. (Available by anonymous FTP on +"ftp.inria.fr".) +%, répertoire "INRIA/publication", fichier "RT-0147.ps.Z".) + +A Unix systems programming course, demonstrating the use of the Caml +Light library that gives access to Unix system calls. + +\item John H.\ Reppy. {\em Concurrent programming with events --- The +concurrent ML manual.} Cornell University, 1990. +(Available by anonymous FTP on "research.att.com".) +%, répertoire "dist/ml", fichier "CML-0.9.8.tar.Z".) + +Concurrent ML extends Standard ML of New Jersey with concurrent +processes that communicate through channels and events. + +\item Jeannette M. Wing, Manuel Faehndrich, J.\ Gregory Morrisett and +Scottt Nettles. {\em Extensions to Standard ML to support +transactions.} Technical report CMU-CS-92-132, Carnegie-Mellon +University, 1992. (Available by anonymous FTP on +"reports.adm.cs.cmu.edu".) +% , répertoire "1992", fichier "CMU-CS-92-132.ps".) + +How to integrate the basic database operations to Standard ML. + +\item Emden R.\ Gansner and John H.\ Reppy. {\em eXene.} Bell Labs, +1991. (Available by anonymous FTP on "research.att.com".) +%, répertoire "dist/ml", fichier "eXene-0.4.tar.Z".) + +An interface between Standard ML of New Jersey and the X Windows +windowing system. + +%% \item Daniel de Rauglaudre. {\em X toolkit in Caml Light.} INRIA, +%% 1992. (Included in the Caml Light distribution.) +%% % Disponible par FTP anonyme sur +%% % "ftp.inria.fr", répertoire "lang/caml-light", fichier "rt5.tar.Z".) +%% +%% An interface between Caml Light and the X Windows windowing system. + +\end{itemize} diff --git a/manual/manual/cmds/.gitignore b/manual/manual/cmds/.gitignore new file mode 100644 index 00000000..0d45900b --- /dev/null +++ b/manual/manual/cmds/.gitignore @@ -0,0 +1,3 @@ +*.tex +*.htex +warnings.etex diff --git a/manual/manual/cmds/Makefile b/manual/manual/cmds/Makefile new file mode 100644 index 00000000..3ff916ed --- /dev/null +++ b/manual/manual/cmds/Makefile @@ -0,0 +1,60 @@ +FILES=comp.tex top.tex runtime.tex native.tex lexyacc.tex intf-c.tex \ + depend.tex profil.tex debugger.tex browser.tex ocamldoc.tex \ + warnings-help.tex ocamlbuild.tex flambda.tex spacetime.tex \ + afl-fuzz.tex plugins.tex unified-options.tex + +TOPDIR=../../.. +include $(TOPDIR)/Makefile.tools + +LD_PATH="$(TOPDIR)/otherlibs/str:$(TOPDIR)/otherlibs/unix" + +TRANSF=$(SET_LD_PATH) $(OCAMLRUN) ../../tools/transf +TEXQUOTE=../../tools/texquote2 +FORMAT=../../tools/format-intf + +CAMLLATEX=$(SET_LD_PATH) $(OCAMLRUN) ../../tools/caml-tex2 \ +-caml "TERM=norepeat $(OCAML)" -n 80 -v false + +WITH_TRANSF= top.tex intf-c.tex flambda.tex spacetime.tex \ + afl-fuzz.tex lexyacc.tex debugger.tex + +WITH_CAMLEXAMPLE = ocamldoc.tex + +etex-files: $(FILES) + +all: $(FILES) + +clean:: + rm -f $(FILES) + rm -f *~ #*# + +.SUFFIXES: +.SUFFIXES: .tex .etex + +.etex.tex: + @$(TEXQUOTE) < $*.etex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex + +$(WITH_TRANSF):%.tex:%.etex + @$(TRANSF) < $*.etex > $*.transf_error.tex \ + && mv $*.transf_error.tex $*.transf_gen.tex \ + && $(TEXQUOTE) < $*.transf_gen.tex > $*.texquote_error.tex \ + && mv $*.texquote_error.tex $*.tex \ + || printf "Failure when generating %s\n" $*.tex + + +$(WITH_CAMLEXAMPLE):%.tex:%.etex + @$(CAMLLATEX) -o $*.caml_tex_error.tex $*.etex \ + && mv $*.caml_tex_error.tex $*.gen.tex \ + && $(TRANSF) < $*.gen.tex > $*.transf_error.tex \ + && mv $*.transf_error.tex $*.gen.tex\ + && $(TEXQUOTE) < $*.gen.tex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex + +warnings-help.etex: ../warnings-help.etex + cp ../warnings-help.etex . + +clean:: + rm -f warnings-help.etex diff --git a/manual/manual/cmds/afl-fuzz.etex b/manual/manual/cmds/afl-fuzz.etex new file mode 100644 index 00000000..5e8a4beb --- /dev/null +++ b/manual/manual/cmds/afl-fuzz.etex @@ -0,0 +1,74 @@ +\chapter{Fuzzing with afl-fuzz} +\pdfchapterfold{-9}{Fuzzing with afl-fuzz} +%HEVEA\cutname{afl-fuzz.html} + +\section{Overview} + +American fuzzy lop (``afl-fuzz'') is a {\em fuzzer}, a tool for +testing software by providing randomly-generated inputs, searching for +those inputs which cause the program to crash. + +Unlike most fuzzers, afl-fuzz observes the internal behaviour of the +program being tested, and adjusts the test cases it generates to +trigger unexplored execution paths. As a result, test cases generated +by afl-fuzz cover more of the possible behaviours of the tested +program than other fuzzers. + +This requires that programs to be tested are instrumented to +communicate with afl-fuzz. The native-code compiler ``ocamlopt'' can +generate such instrumentation, allowing afl-fuzz to be used against +programs written in OCaml. + +For more information on afl-fuzz, see the website at +\ifouthtml +\ahref{http://lcamtuf.coredump.cx/afl/}{http://lcamtuf.coredump.cx/afl/}. +\else +{\tt http://lcamtuf.coredump.cx/afl/} +\fi + +\section{Generating instrumentation} + +The instrumentation that afl-fuzz requires is not generated by +default, and must be explicitly enabled, by passing the {\tt + -afl-instrument} option to {\tt ocamlopt}. + +To fuzz a large system without modifying build tools, OCaml's {\tt + configure} script also accepts the {\tt afl-instrument} option. If +OCaml is configured with {\tt afl-instrument}, then all programs +compiled by {\tt ocamlopt} will be instrumented. + +\subsection{Advanced options} + +In rare cases, it is useful to control the amount of instrumentation +generated. By passing the {\tt -afl-inst-ratio N} argument to {\tt + ocamlopt} with {\tt N} less than 100, instrumentation can be +generated for only N\% of branches. (See the afl-fuzz documentation on +the parameter {\tt AFL\_INST\_RATIO} for the precise effect of this). + +\section{Example} + +As an example, we fuzz-test the following program, {\tt readline.ml}: + +\begin{verbatim} +let _ = + let s = read_line () in + match Array.to_list (Array.init (String.length s) (String.get s)) with + ['s'; 'e'; 'c'; 'r'; 'e'; 't'; ' '; 'c'; 'o'; 'd'; 'e'] -> failwith "uh oh" + | _ -> () +\end{verbatim} + +There is a single input (the string ``secret code'') which causes this +program to crash, but finding it by blind random search is infeasible. + +Instead, we compile with afl-fuzz instrumentation enabled: +\begin{verbatim} +ocamlopt -afl-instrument readline.ml -o readline +\end{verbatim} +Next, we run the program under afl-fuzz: +\begin{verbatim} +mkdir input +echo asdf > input/testcase +mkdir output +afl-fuzz -i input -o output ./readline +\end{verbatim} +By inspecting instrumentation output, the fuzzer finds the crashing input quickly. diff --git a/manual/manual/cmds/browser.etex b/manual/manual/cmds/browser.etex new file mode 100644 index 00000000..5eb5a4ff --- /dev/null +++ b/manual/manual/cmds/browser.etex @@ -0,0 +1,7 @@ +\chapter{The browser/editor (ocamlbrowser)} \label{c:browser} +\pdfchapter{The browser/editor (ocamlbrowser)} +%HEVEA\cutname{browser.html} + +Since OCaml version 4.02, the OCamlBrowser tool and the Labltk library +are distributed separately from the OCaml compiler. The project is now +hosted at \url{https://forge.ocamlcore.org/projects/labltk/}. diff --git a/manual/manual/cmds/comp.etex b/manual/manual/cmds/comp.etex new file mode 100644 index 00000000..3e601014 --- /dev/null +++ b/manual/manual/cmds/comp.etex @@ -0,0 +1,512 @@ +\chapter{Batch compilation (ocamlc)} \label{c:camlc} +\pdfchapter{Batch compilation (ocamlc)} +%HEVEA\cutname{comp.html} + +This chapter describes the OCaml batch compiler "ocamlc", +which compiles OCaml source files to bytecode object files and links +these object files to produce standalone bytecode executable files. +These executable files are then run by the bytecode interpreter +"ocamlrun". + +\section{Overview of the compiler} + +The "ocamlc" command has a command-line interface similar to the one of +most C compilers. It accepts several types of arguments and processes them +sequentially, after all options have been processed: + +\begin{itemize} +\item +Arguments ending in ".mli" are taken to be source files for +compilation unit interfaces. Interfaces specify the names exported by +compilation units: they declare value names with their types, define +public data types, declare abstract data types, and so on. From the +file \var{x}".mli", the "ocamlc" compiler produces a compiled interface +in the file \var{x}".cmi". + +\item +Arguments ending in ".ml" are taken to be source files for compilation +unit implementations. Implementations provide definitions for the +names exported by the unit, and also contain expressions to be +evaluated for their side-effects. From the file \var{x}".ml", the "ocamlc" +compiler produces compiled object bytecode in the file \var{x}".cmo". + +If the interface file \var{x}".mli" exists, the implementation +\var{x}".ml" is checked against the corresponding compiled interface +\var{x}".cmi", which is assumed to exist. If no interface +\var{x}".mli" is provided, the compilation of \var{x}".ml" produces a +compiled interface file \var{x}".cmi" in addition to the compiled +object code file \var{x}".cmo". The file \var{x}".cmi" produced +corresponds to an interface that exports everything that is defined in +the implementation \var{x}".ml". + +\item +Arguments ending in ".cmo" are taken to be compiled object bytecode. These +files are linked together, along with the object files obtained +by compiling ".ml" arguments (if any), and the OCaml standard +library, to produce a standalone executable program. The order in +which ".cmo" and ".ml" arguments are presented on the command line is +relevant: compilation units are initialized in that order at +run-time, and it is a link-time error to use a component of a unit +before having initialized it. Hence, a given \var{x}".cmo" file must come +before all ".cmo" files that refer to the unit \var{x}. + +\item +Arguments ending in ".cma" are taken to be libraries of object bytecode. +A library of object bytecode packs in a single file a set of object +bytecode files (".cmo" files). Libraries are built with "ocamlc -a" +(see the description of the "-a" option below). The object files +contained in the library are linked as regular ".cmo" files (see +above), in the order specified when the ".cma" file was built. The +only difference is that if an object file contained in a library is +not referenced anywhere in the program, then it is not linked in. + +\item +Arguments ending in ".c" are passed to the C compiler, which generates +a ".o" object file (".obj" under Windows). This object file is linked +with the program if the "-custom" flag is set (see the description of +"-custom" below). + +\item +Arguments ending in ".o" or ".a" (".obj" or ".lib" under Windows) +are assumed to be C object files and libraries. They are passed to the +C linker when linking in "-custom" mode (see the description of +"-custom" below). + +\item +Arguments ending in ".so" (".dll" under Windows) +are assumed to be C shared libraries (DLLs). During linking, they are +searched for external C functions referenced from the OCaml code, +and their names are written in the generated bytecode executable. +The run-time system "ocamlrun" then loads them dynamically at program +start-up time. + +\end{itemize} + +The output of the linking phase is a file containing compiled bytecode +that can be executed by the OCaml bytecode interpreter: +the command named "ocamlrun". If "a.out" is the name of the file +produced by the linking phase, the command +\begin{alltt} + ocamlrun a.out \nth{arg}{1} \nth{arg}{2} \ldots \nth{arg}{n} +\end{alltt} +executes the compiled code contained in "a.out", passing it as +arguments the character strings \nth{arg}{1} to \nth{arg}{n}. +(See chapter~\ref{c:runtime} for more details.) + +On most systems, the file produced by the linking +phase can be run directly, as in: +\begin{alltt} + ./a.out \nth{arg}{1} \nth{arg}{2} \ldots \nth{arg}{n} +\end{alltt} +The produced file has the executable bit set, and it manages to launch +the bytecode interpreter by itself. + +\section{Options}\label{s:comp-options} + +The following command-line options are recognized by "ocamlc". +The options "-pack", "-a", "-c" and "-output-obj" are mutually exclusive. +% Define boolean variables used by the macros in unified-options.etex +\newif\ifcomp \comptrue +\newif\ifnat \natfalse +\newif\iftop \topfalse +% unified-options gathers all options across the native/bytecode +% compilers and toplevel +\input{unified-options.tex} + +\paragraph{Contextual control of command-line options} + +The compiler command line can be modified ``from the outside'' +with the following mechanisms. These are experimental +and subject to change. They should be used only for experimental and +development work, not in released packages. + +\begin{options} +\item["OCAMLPARAM" \rm(environment variable)] +A set of arguments that will be inserted before or after the arguments from +the command line. Arguments are specified in a comma-separated list +of "name=value" pairs. A "_" is used to specify the position of +the command line arguments, i.e. "a=x,_,b=y" means that "a=x" should be +executed before parsing the arguments, and "b=y" after. Finally, +an alternative separator can be specified as the +first character of the string, within the set ":|; ,". +\item["ocaml_compiler_internal_params" \rm(file in the stdlib directory)] +A mapping of file names to lists of arguments that +will be added to the command line (and "OCAMLPARAM") arguments. +\item["OCAML_FLEXLINK" \rm(environment variable)] +Alternative executable to use on native +Windows for "flexlink" instead of the +configured value. Primarily used for bootstrapping. +\end{options} + +\section{Modules and the file system} + +This short section is intended to clarify the relationship between the +names of the modules corresponding to compilation units and the names +of the files that contain their compiled interface and compiled +implementation. + +The compiler always derives the module name by taking the capitalized +base name of the source file (".ml" or ".mli" file). That is, it +strips the leading directory name, if any, as well as the ".ml" or +".mli" suffix; then, it set the first letter to uppercase, in order to +comply with the requirement that module names must be capitalized. +For instance, compiling the file "mylib/misc.ml" provides an +implementation for the module named "Misc". Other compilation units +may refer to components defined in "mylib/misc.ml" under the names +"Misc."\var{name}; they can also do "open Misc", then use unqualified +names \var{name}. + +The ".cmi" and ".cmo" files produced by the compiler have the same +base name as the source file. Hence, the compiled files always have +their base name equal (modulo capitalization of the first letter) to +the name of the module they describe (for ".cmi" files) or implement +(for ".cmo" files). + +When the compiler encounters a reference to a free module identifier +"Mod", it looks in the search path for a file named "Mod.cmi" or "mod.cmi" +and loads the compiled interface +contained in that file. As a consequence, renaming ".cmi" files is not +advised: the name of a ".cmi" file must always correspond to the name +of the compilation unit it implements. It is admissible to move them +to another directory, if their base name is preserved, and the correct +"-I" options are given to the compiler. The compiler will flag an +error if it loads a ".cmi" file that has been renamed. + +Compiled bytecode files (".cmo" files), on the other hand, can be +freely renamed once created. That's because the linker never attempts +to find by itself the ".cmo" file that implements a module with a +given name: it relies instead on the user providing the list of ".cmo" +files by hand. + +\section{Common errors} \label{s:comp-errors} + +This section describes and explains the most frequently encountered +error messages. + +\begin{options} + +\item[Cannot find file \var{filename}] +The named file could not be found in the current directory, nor in the +directories of the search path. The \var{filename} is either a +compiled interface file (".cmi" file), or a compiled bytecode file +(".cmo" file). If \var{filename} has the format \var{mod}".cmi", this +means you are trying to compile a file that references identifiers +from module \var{mod}, but you have not yet compiled an interface for +module \var{mod}. Fix: compile \var{mod}".mli" or \var{mod}".ml" +first, to create the compiled interface \var{mod}".cmi". + +If \var{filename} has the format \var{mod}".cmo", this +means you are trying to link a bytecode object file that does not +exist yet. Fix: compile \var{mod}".ml" first. + +If your program spans several directories, this error can also appear +because you haven't specified the directories to look into. Fix: add +the correct "-I" options to the command line. + +\item[Corrupted compiled interface \var{filename}] +The compiler produces this error when it tries to read a compiled +interface file (".cmi" file) that has the wrong structure. This means +something went wrong when this ".cmi" file was written: the disk was +full, the compiler was interrupted in the middle of the file creation, +and so on. This error can also appear if a ".cmi" file is modified after +its creation by the compiler. Fix: remove the corrupted ".cmi" file, +and rebuild it. + +\item[This expression has type \nth{t}{1}, but is used with type \nth{t}{2}] +This is by far the most common type error in programs. Type \nth{t}{1} is +the type inferred for the expression (the part of the program that is +displayed in the error message), by looking at the expression itself. +Type \nth{t}{2} is the type expected by the context of the expression; it +is deduced by looking at how the value of this expression is used in +the rest of the program. If the two types \nth{t}{1} and \nth{t}{2} are not +compatible, then the error above is produced. + +In some cases, it is hard to understand why the two types \nth{t}{1} and +\nth{t}{2} are incompatible. For instance, the compiler can report that +``expression of type "foo" cannot be used with type "foo"'', and it +really seems that the two types "foo" are compatible. This is not +always true. Two type constructors can have the same name, but +actually represent different types. This can happen if a type +constructor is redefined. Example: +\begin{verbatim} + type foo = A | B + let f = function A -> 0 | B -> 1 + type foo = C | D + f C +\end{verbatim} +This result in the error message ``expression "C" of type "foo" cannot +be used with type "foo"''. + +\item[The type of this expression, \var{t}, contains type variables + that cannot be generalized] +Type variables ("'a", "'b", \ldots) in a type \var{t} can be in either +of two states: generalized (which means that the type \var{t} is valid +for all possible instantiations of the variables) and not generalized +(which means that the type \var{t} is valid only for one instantiation +of the variables). In a "let" binding "let "\var{name}" = "\var{expr}, +the type-checker normally generalizes as many type variables as +possible in the type of \var{expr}. However, this leads to unsoundness +(a well-typed program can crash) in conjunction with polymorphic +mutable data structures. To avoid this, generalization is performed at +"let" bindings only if the bound expression \var{expr} belongs to the +class of ``syntactic values'', which includes constants, identifiers, +functions, tuples of syntactic values, etc. In all other cases (for +instance, \var{expr} is a function application), a polymorphic mutable +could have been created and generalization is therefore turned off for +all variables occurring in contravariant or non-variant branches of the +type. For instance, if the type of a non-value is "'a list" the +variable is generalizable ("list" is a covariant type constructor), +but not in "'a list -> 'a list" (the left branch of "->" is +contravariant) or "'a ref" ("ref" is non-variant). + +Non-generalized type variables in a type cause no difficulties inside +a given structure or compilation unit (the contents of a ".ml" file, +or an interactive session), but they cannot be allowed inside +signatures nor in compiled interfaces (".cmi" file), because they +could be used inconsistently later. Therefore, the compiler +flags an error when a structure or compilation unit defines a value +\var{name} whose type contains non-generalized type variables. There +are two ways to fix this error: +\begin{itemize} +\item Add a type constraint or a ".mli" file to give a monomorphic +type (without type variables) to \var{name}. For instance, instead of +writing +\begin{verbatim} + let sort_int_list = Sort.list (<) + (* inferred type 'a list -> 'a list, with 'a not generalized *) +\end{verbatim} +write +\begin{verbatim} + let sort_int_list = (Sort.list (<) : int list -> int list);; +\end{verbatim} +\item If you really need \var{name} to have a polymorphic type, turn +its defining expression into a function by adding an extra parameter. +For instance, instead of writing +\begin{verbatim} + let map_length = List.map Array.length + (* inferred type 'a array list -> int list, with 'a not generalized *) +\end{verbatim} +write +\begin{verbatim} + let map_length lv = List.map Array.length lv +\end{verbatim} +\end{itemize} + +\item[Reference to undefined global \var{mod}] +This error appears when trying to link an incomplete or incorrectly +ordered set of files. Either you have forgotten to provide an +implementation for the compilation unit named \var{mod} on the command line +(typically, the file named \var{mod}".cmo", or a library containing +that file). Fix: add the missing ".ml" or ".cmo" file to the command +line. Or, you have provided an implementation for the module named +\var{mod}, but it comes too late on the command line: the +implementation of \var{mod} must come before all bytecode object files +that reference \var{mod}. Fix: change the order of ".ml" and ".cmo" +files on the command line. + +Of course, you will always encounter this error if you have mutually +recursive functions across modules. That is, function "Mod1.f" calls +function "Mod2.g", and function "Mod2.g" calls function "Mod1.f". +In this case, no matter what permutations you perform on the command +line, the program will be rejected at link-time. Fixes: +\begin{itemize} +\item Put "f" and "g" in the same module. +\item Parameterize one function by the other. +That is, instead of having +\begin{verbatim} +mod1.ml: let f x = ... Mod2.g ... +mod2.ml: let g y = ... Mod1.f ... +\end{verbatim} +define +\begin{verbatim} +mod1.ml: let f g x = ... g ... +mod2.ml: let rec g y = ... Mod1.f g ... +\end{verbatim} +and link "mod1.cmo" before "mod2.cmo". +\item Use a reference to hold one of the two functions, as in : +\begin{verbatim} +mod1.ml: let forward_g = + ref((fun x -> failwith "forward_g") : ) + let f x = ... !forward_g ... +mod2.ml: let g y = ... Mod1.f ... + let _ = Mod1.forward_g := g +\end{verbatim} +\end{itemize} + +\item[The external function \var{f} is not available] +This error appears when trying to link code that calls external +functions written in C. As explained in +chapter~\ref{c:intf-c}, such code must be linked with C libraries that +implement the required \var{f} C function. If the C libraries in +question are not shared libraries (DLLs), the code must be linked in +``custom runtime'' mode. Fix: add the required C libraries to the +command line, and possibly the "-custom" option. + +\end{options} + +\section{Warning reference} \label{s:comp-warnings} + +This section describes and explains in detail some warnings: + +\subsection{Warning 9: missing fields in a record pattern} + + When pattern matching on records, it can be useful to match only few + fields of a record. Eliding fields can be done either implicitly + or explicitly by ending the record pattern with "; _". + However, implicit field elision is at odd with pattern matching + exhaustiveness checks. + Enabling warning 9 prioritizes exhaustiveness checks over the + convenience of implicit field elision and will warn on implicit + field elision in record patterns. In particular, this warning can + help to spot exhaustive record pattern that may need to be updated + after the addition of new fields to a record type. + +\begin{verbatim} +type 'a point = {x='a ;y='a} +let dx { x } = x (* implicit field elision: trigger warning 9 *) +let dy { y; _ } = y (* explicit field elision: do not trigger warning 9 *) +\end{verbatim} + +\subsection{Warning 52: fragile constant pattern} +\label{ss:warn52} + + Some constructors, such as the exception constructors "Failure" and + "Invalid_argument", take as parameter a "string" value holding + a text message intended for the user. + + These text messages are usually not stable over time: call sites + building these constructors may refine the message in a future + version to make it more explicit, etc. Therefore, it is dangerous to + match over the precise value of the message. For example, until + OCaml 4.02, "Array.iter2" would raise the exception +\begin{verbatim} + Invalid_argument "arrays must have the same length" +\end{verbatim} + Since 4.03 it raises the more helpful message +\begin{verbatim} + Invalid_argument "Array.iter2: arrays must have the same length" +\end{verbatim} + but this means that any code of the form +\begin{verbatim} + try ... + with Invalid_argument "arrays must have the same length" -> ... +\end{verbatim} + is now broken and may suffer from uncaught exceptions. + + Warning 52 is there to prevent users from writing such fragile code + in the first place. It does not occur on every matching on a literal + string, but only in the case in which library authors expressed + their intent to possibly change the constructor parameter value in + the future, by using the attribute "ocaml.warn_on_literal_pattern" + (see the manual section on builtin attributes in + \ref{ss:builtin-attributes}): +\begin{verbatim} + type t = + | Foo of string [@ocaml.warn_on_literal_pattern] + | Bar of string + + let no_warning = function + | Bar "specific value" -> 0 + | _ -> 1 + + let warning = function + | Foo "specific value" -> 0 + | _ -> 1 + +> | Foo "specific value" -> 0 +> ^^^^^^^^^^^^^^^^ +> Warning 52: Code should not depend on the actual values of +> this constructor's arguments. They are only for information +> and may change in future versions. (See manual section 8.5) +\end{verbatim} + + In particular, all built-in exceptions with a string argument have + this attribute set: "Invalid_argument", "Failure", "Sys_error" will + all raise this warning if you match for a specific string argument. + + If your code raises this warning, you should {\em not} change the + way you test for the specific string to avoid the warning (for + example using a string equality inside the right-hand-side instead + of a literal pattern), as your code would remain fragile. You should + instead enlarge the scope of the pattern by matching on all possible + values. + +\begin{verbatim} + +let warning = function + | Foo _ -> 0 + | _ -> 1 +\end{verbatim} + + This may require some care: if the scrutinee may return several + different cases of the same pattern, or raise distinct instances of + the same exception, you may need to modify your code to separate + those several cases. + + For example, +\begin{verbatim} +try (int_of_string count_str, bool_of_string choice_str) with + | Failure "int_of_string" -> (0, true) + | Failure "bool_of_string" -> (-1, false) +\end{verbatim} + should be rewritten into more atomic tests. For example, + using the "exception" patterns documented in Section~\ref{s:exception-match}, + one can write: +\begin{verbatim} +match int_of_string count_str with + | exception (Failure _) -> (0, true) + | count -> + begin match bool_of_string choice_str with + | exception (Failure _) -> (-1, false) + | choice -> (count, choice) + end +\end{verbatim} + +The only case where that transformation is not possible is if a given +function call may raise distinct exceptions with the same constructor +but different string values. In this case, you will have to check for +specific string values. This is dangerous API design and it should be +discouraged: it's better to define more precise exception constructors +than store useful information in strings. + +\subsection{Warning 57: Ambiguous or-pattern variables under guard} +\label{ss:warn57} + + The semantics of or-patterns in OCaml is specified with + a left-to-right bias: a value \var{v} matches the pattern \var{p} "|" \var{q} + if it matches \var{p} or \var{q}, but if it matches both, + the environment captured by the match is the environment captured by + \var{p}, never the one captured by \var{q}. + + While this property is generally intuitive, there is at least one specific + case where a different semantics might be expected. + Consider a pattern followed by a when-guard: + "|"~\var{p}~"when"~\var{g}~"->"~\var{e}, for example: +\begin{verbatim} + | ((Const x, _) | (_, Const x)) when is_neutral x -> branch +\end{verbatim} + The semantics is clear: + match the scrutinee against the pattern, if it matches, test the guard, + and if the guard passes, take the branch. + In particular, consider the input "(Const"~\var{a}", Const"~\var{b}")", where + \var{a} fails the test "is_neutral"~\var{a}, while \var{b} passes the test + "is_neutral"~\var{b}. With the left-to-right semantics, the clause above is + {\em not} taken by its input: matching "(Const"~\var{a}", Const"~\var{b}")" + against the or-pattern succeeds in the left branch, it returns the + environment \var{x}~"->"~\var{a}, and then the guard + "is_neutral"~\var{a} is tested and fails, the branch is not taken. + + However, another semantics may be considered more natural here: + any pair that has one side passing the test will take the branch. With this + semantics the previous code fragment would be equivalent to +\begin{verbatim} + | (Const x, _) when is_neutral x -> branch + | (_, Const x) when is_neutral x -> branch +\end{verbatim} + This is {\em not} the semantics adopted by OCaml. + + Warning 57 is dedicated to these confusing cases where the + specified left-to-right semantics is not equivalent to a non-deterministic + semantics (any branch can be taken) relatively to a specific guard. + More precisely, it warns when guard uses ``ambiguous'' variables, that are bound + to different parts of the scrutinees by different sides of a or-pattern. diff --git a/manual/manual/cmds/debugger.etex b/manual/manual/cmds/debugger.etex new file mode 100644 index 00000000..31a2ad65 --- /dev/null +++ b/manual/manual/cmds/debugger.etex @@ -0,0 +1,674 @@ +\chapter{The debugger (ocamldebug)} \label{c:debugger} +\pdfchapter{The debugger (ocamldebug)} +%HEVEA\cutname{debugger.html} + +This chapter describes the OCaml source-level replay debugger +"ocamldebug". + +\begin{unix} The debugger is available on Unix systems that provide +BSD sockets. +\end{unix} + +\begin{windows} The debugger is available under the Cygwin port of +OCaml, but not under the native Win32 ports. +\end{windows} + +\section{Compiling for debugging} + +Before the debugger can be used, the program must be compiled and +linked with the "-g" option: all ".cmo" and ".cma" files that are part +of the program should have been created with "ocamlc -g", and they +must be linked together with "ocamlc -g". + +Compiling with "-g" entails no penalty on the running time of +programs: object files and bytecode executable files are bigger and +take longer to produce, but the executable files run at +exactly the same speed as if they had been compiled without "-g". + +\section{Invocation} + +\subsection{Starting the debugger} + +The OCaml debugger is invoked by running the program +"ocamldebug" with the name of the bytecode executable file as first +argument: +\begin{alltt} + ocamldebug \optvar{options} \var{program} \optvar{arguments} +\end{alltt} +The arguments following \var{program} are optional, and are passed as +command-line arguments to the program being debugged. (See also the +"set arguments" command.) + +The following command-line options are recognized: +\begin{options} +\item["-c " \var{count}] +Set the maximum number of simultaneously live checkpoints to \var{count}. + +\item["-cd " \var{dir}] +Run the debugger program from the working directory \var{dir}, +instead of the current directory. (See also the "cd" command.) + +\item["-emacs"] +Tell the debugger it is executed under Emacs. (See +section~\ref{s:inf-debugger} for information on how to run the +debugger under Emacs.) + +\item["-I "\var{directory}] +Add \var{directory} to the list of directories searched for source +files and compiled files. (See also the "directory" command.) + +\item["-s "\var{socket}] +Use \var{socket} for communicating with the debugged program. See the +description of the command "set socket" (section~\ref{s:communication}) +for the format of \var{socket}. + +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-help" or "--help"] +Display a short usage summary and exit. +% +\end{options} + +\subsection{Initialization file} + +On start-up, the debugger will read commands from an initialization +file before giving control to the user. The default file is +".ocamldebug" in the current directory if it exists, otherwise +".ocamldebug" in the user's home directory. + +\subsection{Exiting the debugger} + +The command "quit" exits the debugger. You can also exit the debugger +by typing an end-of-file character (usually "ctrl-D"). + +Typing an interrupt character (usually "ctrl-C") will not exit the +debugger, but will terminate the action of any debugger command that is in +progress and return to the debugger command level. + +\section{Commands} \label{s:debugger-commands} + +A debugger command is a single line of input. It starts with a command +name, which is followed by arguments depending on this name. Examples: +\begin{verbatim} + run + goto 1000 + set arguments arg1 arg2 +\end{verbatim} + +A command name can be truncated as long as there is no ambiguity. For +instance, "go 1000" is understood as "goto 1000", since there are no +other commands whose name starts with "go". For the most frequently +used commands, ambiguous abbreviations are allowed. For instance, "r" +stands for "run" even though there are others commands starting with +"r". You can test the validity of an abbreviation using the "help" command. + +If the previous command has been successful, a blank line (typing just +"RET") will repeat it. + +\subsection{Getting help} + +The OCaml debugger has a simple on-line help system, which gives +a brief description of each command and variable. + +\begin{options} +\item["help"] +Print the list of commands. + +\item["help "\var{command}] +Give help about the command \var{command}. + +\item["help set "\var{variable}, "help show "\var{variable}] +Give help about the variable \var{variable}. The list of all debugger +variables can be obtained with "help set". + +\item["help info "\var{topic}] +Give help about \var{topic}. Use "help info" to get a list of known topics. +\end{options} + +\subsection{Accessing the debugger state} + +\begin{options} +\item["set "\var{variable} \var{value}] +Set the debugger variable \var{variable} to the value \var{value}. + +\item["show "\var{variable}] +Print the value of the debugger variable \var{variable}. + +\item["info "\var{subject}] +Give information about the given subject. +For instance, "info breakpoints" will print the list of all breakpoints. +\end{options} + +\section{Executing a program} + +\subsection{Events} + +Events are ``interesting'' locations in the source code, corresponding +to the beginning or end of evaluation of ``interesting'' +sub-expressions. Events are the unit of single-stepping (stepping goes +to the next or previous event encountered in the program execution). +Also, breakpoints can only be set at events. Thus, events play the +role of line numbers in debuggers for conventional languages. + +During program execution, a counter is incremented at each event +encountered. The value of this counter is referred as the {\em current +time}. Thanks to reverse execution, it is possible to jump back and +forth to any time of the execution. + +Here is where the debugger events (written \event) are located in +the source code: +\begin{itemize} +\item Following a function application: +\begin{alltt} +(f arg)\event +\end{alltt} +\item On entrance to a function: +\begin{alltt} +fun x y z -> \event ... +\end{alltt} +\item On each case of a pattern-matching definition (function, +"match"\ldots"with" construct, "try"\ldots"with" construct): +\begin{alltt} +function pat1 -> \event expr1 + | ... + | patN -> \event exprN +\end{alltt} +\item Between subexpressions of a sequence: +\begin{alltt} +expr1; \event expr2; \event ...; \event exprN +\end{alltt} +\item In the two branches of a conditional expression: +\begin{alltt} +if cond then \event expr1 else \event expr2 +\end{alltt} +\item At the beginning of each iteration of a loop: +\begin{alltt} +while cond do \event body done +for i = a to b do \event body done +\end{alltt} +\end{itemize} +Exceptions: A function application followed by a function return is replaced +by the compiler by a jump (tail-call optimization). In this case, no +event is put after the function application. +% Also, no event is put after a function application when the function +% is external (written in C). + +\subsection{Starting the debugged program} + +The debugger starts executing the debugged program only when needed. +This allows setting breakpoints or assigning debugger variables before +execution starts. There are several ways to start execution: +\begin{options} +\item["run"] Run the program until a breakpoint is hit, or the program +terminates. +\item["goto 0"] Load the program and stop on the first event. +\item["goto "\var{time}] Load the program and execute it until the +given time. Useful when you already know approximately at what time +the problem appears. Also useful to set breakpoints on function values +that have not been computed at time 0 (see section~\ref{s:breakpoints}). +\end{options} + +The execution of a program is affected by certain information it +receives when the debugger starts it, such as the command-line +arguments to the program and its working directory. The debugger +provides commands to specify this information ("set arguments" and "cd"). +These commands must be used before program execution starts. If you try +to change the arguments or the working directory after starting your +program, the debugger will kill the program (after asking for confirmation). + +\subsection{Running the program} + +The following commands execute the program forward or backward, +starting at the current time. The execution will stop either when +specified by the command or when a breakpoint is encountered. + +\begin{options} +\item["run"] Execute the program forward from current time. Stops at +next breakpoint or when the program terminates. +\item["reverse"] Execute the program backward from current time. +Mostly useful to go to the last breakpoint encountered before the +current time. +\item["step "\optvar{count}] Run the program and stop at the next +event. With an argument, do it \var{count} times. If \var{count} is 0, +run until the program terminates or a breakpoint is hit. +\item["backstep "\optvar{count}] Run the program backward and stop at +the previous event. With an argument, do it \var{count} times. +\item["next "\optvar{count}] Run the program and stop at the next +event, skipping over function calls. With an argument, do it +\var{count} times. +\item["previous "\optvar{count}] Run the program backward and stop at +the previous event, skipping over function calls. With an argument, do +it \var{count} times. +\item["finish"] Run the program until the current function returns. +\item["start"] Run the program backward and stop at the first event +before the current function invocation. +\end{options} + +\subsection{Time travel} + +You can jump directly to a given time, without stopping on +breakpoints, using the "goto" command. + +As you move through the program, the debugger maintains an history of +the successive times you stop at. The "last" command can be used to +revisit these times: each "last" command moves one step back through +the history. That is useful mainly to undo commands such as "step" +and "next". + +\begin{options} +\item["goto "\var{time}] +Jump to the given time. +\item["last "\optvar{count}] +Go back to the latest time recorded in the execution history. With an +argument, do it \var{count} times. +\item["set history "\var{size}] +Set the size of the execution history. +\end{options} + +\subsection{Killing the program} + +\begin{options} +\item["kill"] Kill the program being executed. This command is mainly +useful if you wish to recompile the program without leaving the debugger. +\end{options} + +\section{Breakpoints} \label{s:breakpoints} + +A breakpoint causes the program to stop whenever a certain point in +the program is reached. It can be set in several ways using the +"break" command. Breakpoints are assigned numbers when set, for +further reference. The most comfortable way to set breakpoints is +through the Emacs interface (see section~\ref{s:inf-debugger}). + +\begin{options} +\item["break"] +Set a breakpoint at the current position in the program execution. The +current position must be on an event (i.e., neither at the beginning, +nor at the end of the program). + +\item["break "\var{function}] +Set a breakpoint at the beginning of \var{function}. This works only +when the functional value of the identifier \var{function} has been +computed and assigned to the identifier. Hence this command cannot be +used at the very beginning of the program execution, when all +identifiers are still undefined; use "goto" \var{time} to advance +execution until the functional value is available. + +\item["break \@" \optvar{module} \var{line}] +Set a breakpoint in module \var{module} (or in the current module if +\var{module} is not given), at the first event of line \var{line}. + +\item["break \@" \optvar{module} \var{line} \var{column}] +Set a breakpoint in module \var{module} (or in the current module if +\var{module} is not given), at the event closest to line \var{line}, +column \var{column}. + +\item["break \@" \optvar{module} "#" \var{character}] +Set a breakpoint in module \var{module} at the event closest to +character number \var{character}. + +\item["break "\var{address}] +Set a breakpoint at the code address \var{address}. + +\item["delete "\optvar{breakpoint-numbers}] +Delete the specified breakpoints. Without argument, all breakpoints +are deleted (after asking for confirmation). + +\item["info breakpoints"] Print the list of all breakpoints. +\end{options} + +\section{The call stack} + +Each time the program performs a function application, it saves the +location of the application (the return address) in a block of data +called a stack frame. The frame also contains the local variables of +the caller function. All the frames are allocated in a region of +memory called the call stack. The command "backtrace" (or "bt") +displays parts of the call stack. + +At any time, one of the stack frames is ``selected'' by the debugger; several +debugger commands refer implicitly to the selected frame. In particular, +whenever you ask the debugger for the value of a local variable, the +value is found in the selected frame. The commands "frame", "up" and "down" +select whichever frame you are interested in. + +When the program stops, the debugger automatically selects the +currently executing frame and describes it briefly as the "frame" +command does. + +\begin{options} +\item["frame"] +Describe the currently selected stack frame. + +\item["frame" \var{frame-number}] +Select a stack frame by number and describe it. The frame currently +executing when the program stopped has number 0; its caller has number +1; and so on up the call stack. + +\item["backtrace "\optvar{count}, "bt "\optvar{count}] +Print the call stack. This is useful to see which sequence of function +calls led to the currently executing frame. With a positive argument, +print only the innermost \var{count} frames. +With a negative argument, print only the outermost -\var{count} frames. + +\item["up" \optvar{count}] +Select and display the stack frame just ``above'' the selected frame, +that is, the frame that called the selected frame. An argument says how +many frames to go up. + +\item["down "\optvar{count}] +Select and display the stack frame just ``below'' the selected frame, +that is, the frame that was called by the selected frame. An argument +says how many frames to go down. +\end{options} + +\section{Examining variable values} + +The debugger can print the current value of simple expressions. The +expressions can involve program variables: all the identifiers that +are in scope at the selected program point can be accessed. + +Expressions that can be printed are a subset of OCaml +expressions, as described by the following grammar: +\begin{syntax} +simple-expr: + lowercase-ident + | { capitalized-ident '.' } lowercase-ident + | '*' + | '$' integer + | simple-expr '.' lowercase-ident + | simple-expr '.(' integer ')' + | simple-expr '.[' integer ']' + | '!' simple-expr + | '(' simple-expr ')' +\end{syntax} +The first two cases refer to a value identifier, either unqualified or +qualified by the path to the structure that define it. +"*" refers to the result just computed (typically, the value of a +function application), and is valid only if the selected event is an +``after'' event (typically, a function application). +@'$' integer@ refer to a previously printed value. The remaining four +forms select part of an expression: respectively, a record field, an +array element, a string element, and the current contents of a +reference. + +\begin{options} +\item["print "\var{variables}] +Print the values of the given variables. "print" can be abbreviated as +"p". +\item["display "\var{variables}] +Same as "print", but limit the depth of printing to 1. Useful to +browse large data structures without printing them in full. +"display" can be abbreviated as "d". +\end{options} + +When printing a complex expression, a name of the form "$"\var{integer} +is automatically assigned to its value. Such names are also assigned +to parts of the value that cannot be printed because the maximal +printing depth is exceeded. Named values can be printed later on +with the commands "p $"\var{integer} or "d $"\var{integer}. +Named values are valid only as long as the program is stopped. They +are forgotten as soon as the program resumes execution. + +\begin{options} +\item["set print_depth" \var{d}] +Limit the printing of values to a maximal depth of \var{d}. +\item["set print_length" \var{l}] +Limit the printing of values to at most \var{l} nodes printed. +\end{options} + +\section{Controlling the debugger} + +\subsection{Setting the program name and arguments} + +\begin{options} +\item["set program" \var{file}] +Set the program name to \var{file}. +\item["set arguments" \var{arguments}] +Give \var{arguments} as command-line arguments for the program. +\end{options} + +A shell is used to pass the arguments to the debugged program. You can +therefore use wildcards, shell variables, and file redirections inside +the arguments. To debug programs that read from standard input, it is +recommended to redirect their input from a file (using +"set arguments < input-file"), otherwise input to the program and +input to the debugger are not properly separated, and inputs are not +properly replayed when running the program backwards. + +\subsection{How programs are loaded} + +The "loadingmode" variable controls how the program is executed. + +\begin{options} +\item["set loadingmode direct"] +The program is run directly by the debugger. This is the default mode. +\item["set loadingmode runtime"] +The debugger execute the OCaml runtime "ocamlrun" on the program. +Rarely useful; moreover it prevents the debugging of programs compiled +in ``custom runtime'' mode. +\item["set loadingmode manual"] +The user starts manually the program, when asked by the debugger. +Allows remote debugging (see section~\ref{s:communication}). +\end{options} + +\subsection{Search path for files} + +The debugger searches for source files and compiled interface files in +a list of directories, the search path. The search path initially +contains the current directory "." and the standard library directory. +The "directory" command adds directories to the path. + +Whenever the search path is modified, the debugger will clear any +information it may have cached about the files. + +\begin{options} +\item["directory" \var{directorynames}] +Add the given directories to the search path. These directories are +added at the front, and will therefore be searched first. + +\item["directory" \var{directorynames} "for" \var{modulename}] +Same as "directory" \var{directorynames}, but the given directories will be +searched only when looking for the source file of a module that has +been packed into \var{modulename}. + +\item["directory"] +Reset the search path. This requires confirmation. +\end{options} + +\subsection{Working directory} + +Each time a program is started in the debugger, it inherits its working +directory from the current working directory of the debugger. This +working directory is initially whatever it inherited from its parent +process (typically the shell), but you can specify a new working +directory in the debugger with the "cd" command or the "-cd" +command-line option. + +\begin{options} +\item["cd" \var{directory}] +Set the working directory for "ocamldebug" to \var{directory}. + +\item["pwd"] +Print the working directory for "ocamldebug". +\end{options} + +\subsection{Turning reverse execution on and off} + +In some cases, you may want to turn reverse execution off. This speeds +up the program execution, and is also sometimes useful for interactive +programs. + +Normally, the debugger takes checkpoints of the program state from +time to time. That is, it makes a copy of the current state of the +program (using the Unix system call "fork"). If the variable +\var{checkpoints} is set to "off", the debugger will not take any +checkpoints. + +\begin{options} +\item["set checkpoints" \var{on/off}] +Select whether the debugger makes checkpoints or not. +\end{options} + +\subsection{Communication between the debugger and the program} +\label{s:communication} + +The debugger communicate with the program being debugged through a +Unix socket. You may need to change the socket name, for example if +you need to run the debugger on a machine and your program on another. + +\begin{options} +\item["set socket" \var{socket}] +Use \var{socket} for communication with the program. \var{socket} can be +either a file name, or an Internet port specification +\var{host}:\var{port}, where \var{host} is a host name or an Internet +address in dot notation, and \var{port} is a port number on the host. +\end{options} + +On the debugged program side, the socket name is passed through the +"CAML_DEBUG_SOCKET" environment variable. + +\subsection{Fine-tuning the debugger} \label{s:fine-tuning} + +Several variables enables to fine-tune the debugger. Reasonable +defaults are provided, and you should normally not have to change them. + +\begin{options} +\item["set processcount" \var{count}] +Set the maximum number of checkpoints to \var{count}. More checkpoints +facilitate going far back in time, but use more memory and create more +Unix processes. +\end{options} + +As checkpointing is quite expensive, it must not be done too often. On +the other hand, backward execution is faster when checkpoints are +taken more often. In particular, backward single-stepping is more +responsive when many checkpoints have been taken just before the +current time. To fine-tune the checkpointing strategy, the debugger +does not take checkpoints at the same frequency for long displacements +(e.g. "run") and small ones (e.g. "step"). The two variables "bigstep" +and "smallstep" contain the number of events between two checkpoints +in each case. + +\begin{options} +\item["set bigstep" \var{count}] +Set the number of events between two checkpoints for long displacements. +\item["set smallstep" \var{count}] +Set the number of events between two checkpoints for small +displacements. +\end{options} + +The following commands display information on checkpoints and events: + +\begin{options} +\item["info checkpoints"] +Print a list of checkpoints. +\item["info events" \optvar{module}] +Print the list of events in the given module (the current module, by default). +\end{options} + +\subsection{User-defined printers} + +Just as in the toplevel system (section~\ref{s:toplevel-directives}), +the user can register functions for printing values of certain types. +For technical reasons, the debugger cannot call printing functions +that reside in the program being debugged. The code for the printing +functions must therefore be loaded explicitly in the debugger. + +\begin{options} +\item["load_printer \""\var{file-name}"\""] +Load in the debugger the indicated ".cmo" or ".cma" object file. The +file is loaded in an environment consisting only of the OCaml +standard library plus the definitions provided by object files +previously loaded using "load_printer". If this file depends on other +object files not yet loaded, the debugger automatically loads them if +it is able to find them in the search path. The loaded file does not +have direct access to the modules of the program being debugged. + +\item["install_printer "\var{printer-name}] +Register the function named \var{printer-name} (a +value path) as a printer for objects whose types match the argument +type of the function. That is, the debugger will call +\var{printer-name} when it has such an object to print. +The printing function \var{printer-name} must use the "Format" library +module to produce its output, otherwise its output will not be +correctly located in the values printed by the toplevel loop. + +The value path \var{printer-name} must refer to one of the functions +defined by the object files loaded using "load_printer". It cannot +reference the functions of the program being debugged. + +\item["remove_printer "\var{printer-name}] +Remove the named function from the table of value printers. +\end{options} + +\section{Miscellaneous commands} + +\begin{options} +\item["list" \optvar{module} \optvar{beginning} \optvar{end}] +List the source of module \var{module}, from line number +\var{beginning} to line number \var{end}. By default, 20 lines of the +current module are displayed, starting 10 lines before the current +position. +\item["source" \var{filename}] +Read debugger commands from the script \var{filename}. +\end{options} + +\section{Running the debugger under Emacs} \label{s:inf-debugger} + +The most user-friendly way to use the debugger is to run it under Emacs. +See the file "emacs/README" in the distribution for information on how +to load the Emacs Lisp files for OCaml support. + +The OCaml debugger is started under Emacs by the command "M-x +camldebug", with argument the name of the executable file +\var{progname} to debug. Communication with the debugger takes place +in an Emacs buffer named "*camldebug-"\var{progname}"*". The editing +and history facilities of Shell mode are available for interacting +with the debugger. + +In addition, Emacs displays the source files containing the current +event (the current position in the program execution) and highlights +the location of the event. This display is updated synchronously with +the debugger action. + +The following bindings for the most common debugger commands are +available in the "*camldebug-"\var{progname}"*" buffer: + +\begin{options} +\item["C-c C-s"] (command "step"): execute the program one step forward. +\item["C-c C-k"] (command "backstep"): execute the program one step backward. +\item["C-c C-n"] (command "next"): execute the program one step +forward, skipping over function calls. +\item[Middle mouse button] (command "display"): display named value. +"$"\var{n} under mouse cursor (support incremental browsing of large +data structures). +\item["C-c C-p"] (command "print"): print value of identifier at point. +\item["C-c C-d"] (command "display"): display value of identifier at point. +\item["C-c C-r"] (command "run"): execute the program forward to next +breakpoint. +\item["C-c C-v"] (command "reverse"): execute the program backward to +latest breakpoint. +\item["C-c C-l"] (command "last"): go back one step in the command history. +\item["C-c C-t"] (command "backtrace"): display backtrace of function calls. +\item["C-c C-f"] (command "finish"): run forward till the current +function returns. +\item["C-c <"] (command "up"): select the stack frame below the +current frame. +\item["C-c >"] (command "down"): select the stack frame above the +current frame. +\end{options} + +In all buffers in OCaml editing mode, the following debugger commands +are also available: + +\begin{options} +\item["C-x C-a C-b"] (command "break"): set a breakpoint at event closest +to point +\item["C-x C-a C-p"] (command "print"): print value of identifier at point +\item["C-x C-a C-d"] (command "display"): display value of identifier at point +\end{options} diff --git a/manual/manual/cmds/depend.etex b/manual/manual/cmds/depend.etex new file mode 100644 index 00000000..b5dadd58 --- /dev/null +++ b/manual/manual/cmds/depend.etex @@ -0,0 +1,222 @@ +\chapter{Dependency generator (ocamldep)} \label{c:camldep} +\pdfchapter{Dependency generator (ocamldep)} +%HEVEA\cutname{depend.html} + +The "ocamldep" command scans a set of OCaml source files +(".ml" and ".mli" files) for references to external compilation units, +and outputs dependency lines in a format suitable for the "make" +utility. This ensures that "make" will compile the source files in the +correct order, and recompile those files that need to when a source +file is modified. + +The typical usage is: +\begin{alltt} + ocamldep \var{options} *.mli *.ml > .depend +\end{alltt} +where "*.mli *.ml" expands to all source files in the current +directory and ".depend" is the file that should contain the +dependencies. (See below for a typical "Makefile".) + +Dependencies are generated both for compiling with the bytecode +compiler "ocamlc" and with the native-code compiler "ocamlopt". + +\section{Options} + +The following command-line options are recognized by "ocamldep". + +\begin{options} + +\item["-absname"] +Show absolute filenames in error messages. + +\item["-all"] +Generate dependencies on all required files, rather than assuming +implicit dependencies. + +\item["-allow-approx"] +Allow falling back on a lexer-based approximation when parsing fails. + +\item["-args" \var{filename}] + Read additional newline-terminated command line arguments from \var{filename}. + +\item["-args0" \var{filename}] + Read additional null character terminated command line arguments from \var{filename}. + +\item["-as-map"] +For the following files, do not include delayed dependencies for +module aliases. +This option assumes that they are compiled using options +"-no-alias-deps -w -49", and that those files or their interface are +passed with the "-map" option when computing dependencies for other +files. Note also that for dependencies to be correct in the +implementation of a map file, its interface should not coerce any of +the aliases it contains. + +\item["-debug-map"] +Dump the delayed dependency map for each map file. + +\item["-I" \var{directory}] +Add the given directory to the list of directories searched for +source files. If a source file "foo.ml" mentions an external +compilation unit "Bar", a dependency on that unit's interface +"bar.cmi" is generated only if the source for "bar" is found in the +current directory or in one of the directories specified with "-I". +Otherwise, "Bar" is assumed to be a module from the standard library, +and no dependencies are generated. For programs that span multiple +directories, it is recommended to pass "ocamldep" the same "-I" options +that are passed to the compiler. + +\item["-impl" \var{file}] +Process \var{file} as a ".ml" file. + +\item["-intf" \var{file}] +Process \var{file} as a ".mli" file. + +\item["-map" \var{file}] +Read an propagate the delayed dependencies for module aliases in +\var{file}, so that the following files will depend on the +exported aliased modules if they use them. See the example below. + +\item["-ml-synonym" \var{.ext}] +Consider the given extension (with leading dot) to be a synonym for .ml. + +\item["-mli-synonym" \var{.ext}] +Consider the given extension (with leading dot) to be a synonym for .mli. + +\item["-modules"] +Output raw dependencies of the form +\begin{verbatim} + filename: Module1 Module2 ... ModuleN +\end{verbatim} +where "Module1", \ldots, "ModuleN" are the names of the compilation +units referenced within the file "filename", but these names are not +resolved to source file names. Such raw dependencies cannot be used +by "make", but can be post-processed by other tools such as "Omake". + +\item["-native"] +Generate dependencies for a pure native-code program (no bytecode +version). When an implementation file (".ml" file) has no explicit +interface file (".mli" file), "ocamldep" generates dependencies on the +bytecode compiled file (".cmo" file) to reflect interface changes. +This can cause unnecessary bytecode recompilations for programs that +are compiled to native-code only. The flag "-native" causes +dependencies on native compiled files (".cmx") to be generated instead +of on ".cmo" files. (This flag makes no difference if all source files +have explicit ".mli" interface files.) + +\item["-one-line"] +Output one line per file, regardless of the length. + +\item["-open" \var{module}] +Assume that module \var{module} is opened before parsing each of the +following files. + +\item["-plugin" \var{plugin}] +Dynamically load the code of the given \var{plugin} +(a ".cmo", ".cma" or ".cmxs" file) in "ocamldep". \var{plugin} must exist in +the same kind of code as "ocamldep" ("ocamldep.byte" must load bytecode +plugins, while "ocamldep.opt" must load native code plugins), and +extension adaptation is done automatically for ".cma" files (to ".cmxs" files +if "ocamldep" is compiled in native code). + +\item["-pp" \var{command}] +Cause "ocamldep" to call the given \var{command} as a preprocessor +for each source file. + +\item["-ppx" \var{command}] +Pipe abstract syntax trees through preprocessor \var{command}. + +\item["-shared"] +Generate dependencies for native plugin files (.cmxs) in addition to +native compiled files (.cmx). + +\item["-slash"] +Under Windows, use a forward slash (/) as the path separator instead +of the usual backward slash ($\backslash$). Under Unix, this option does +nothing. + +\item["-sort"] +Sort files according to their dependencies. + +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-help" or "--help"] +Display a short usage summary and exit. +% +\end{options} + +\section{A typical Makefile} + +Here is a template "Makefile" for a OCaml program. + +\begin{verbatim} +OCAMLC=ocamlc +OCAMLOPT=ocamlopt +OCAMLDEP=ocamldep +INCLUDES= # all relevant -I options here +OCAMLFLAGS=$(INCLUDES) # add other options for ocamlc here +OCAMLOPTFLAGS=$(INCLUDES) # add other options for ocamlopt here + +# prog1 should be compiled to bytecode, and is composed of three +# units: mod1, mod2 and mod3. + +# The list of object files for prog1 +PROG1_OBJS=mod1.cmo mod2.cmo mod3.cmo + +prog1: $(PROG1_OBJS) + $(OCAMLC) -o prog1 $(OCAMLFLAGS) $(PROG1_OBJS) + +# prog2 should be compiled to native-code, and is composed of two +# units: mod4 and mod5. + +# The list of object files for prog2 +PROG2_OBJS=mod4.cmx mod5.cmx + +prog2: $(PROG2_OBJS) + $(OCAMLOPT) -o prog2 $(OCAMLFLAGS) $(PROG2_OBJS) + +# Common rules +.SUFFIXES: .ml .mli .cmo .cmi .cmx + +.ml.cmo: + $(OCAMLC) $(OCAMLFLAGS) -c $< + +.mli.cmi: + $(OCAMLC) $(OCAMLFLAGS) -c $< + +.ml.cmx: + $(OCAMLOPT) $(OCAMLOPTFLAGS) -c $< + +# Clean up +clean: + rm -f prog1 prog2 + rm -f *.cm[iox] + +# Dependencies +depend: + $(OCAMLDEP) $(INCLUDES) *.mli *.ml > .depend + +include .depend +\end{verbatim} + +If you use module aliases to give shorter names to modules, you need +to change the above definitions. Assuming that your map file is called +"mylib.mli", here are minimal modifications. +\begin{verbatim} +OCAMLFLAGS=$(INCLUDES) -open Mylib + +mylib.cmi: mylib.mli + $(OCAMLC) $(INCLUDES) -no-alias-deps -w -49 -c $< + +depend: + $(OCAMLDEP) $(INCLUDES) -map mylib.mli $(PROG1_OBJS:.cmo=.ml) > .depend +\end{verbatim} +Note that in this case you should not compute dependencies for +"mylib.mli" together with the other files, hence the need to pass +explicitly the list of files to process. +If "mylib.mli" itself has dependencies, you should compute them using +"-as-map". diff --git a/manual/manual/cmds/flambda.etex b/manual/manual/cmds/flambda.etex new file mode 100644 index 00000000..063029ec --- /dev/null +++ b/manual/manual/cmds/flambda.etex @@ -0,0 +1,1343 @@ +\chapter{Optimisation with Flambda} +\pdfchapterfold{-9}{Optimisation with Flambda} +%HEVEA\cutname{flambda.html} + +\section{Overview} + +{\em Flambda} is the term used to describe a series of optimisation passes +provided by the native code compilers as of OCaml 4.03. + +Flambda aims to make it easier to write idiomatic OCaml code without +incurring performance penalties. + +To use the Flambda optimisers it is necessary to pass the {\tt -flambda} +option to the OCaml {\tt configure} script. (There is no support for a +single compiler that can operate in both Flambda and non-Flambda modes.) +Code compiled with Flambda +cannot be linked into the same program as code compiled without Flambda. +Attempting to do this will result in a compiler error. + +Whether or not a particular {\tt ocamlopt} uses Flambda may be +determined by invoking it with the {\tt -config} option and looking +for any line starting with ``{\tt flambda:}''. If such a line is present +and says ``{\tt true}'', then Flambda is supported, otherwise it is not. + +Flambda provides full optimisation across different compilation units, +so long as the {\tt .cmx} files for the dependencies of the unit currently +being compiled are available. (A compilation unit corresponds to a +single {\tt .ml} source file.) However it does not yet act entirely as +a whole-program compiler: for example, elimination of dead code across +a complete set of compilation units is not supported. + +Optimisation with Flambda is not currently supported when generating +bytecode. + +Flambda should not in general affect the semantics of existing programs. +Two exceptions to this rule are: possible elimination of pure code +that is being benchmarked (see section\ \ref{inhibition}) and changes in +behaviour of code using unsafe operations (see section\ \ref{unsafe}). + +Flambda does not yet optimise array or string bounds checks. Neither +does it take hints for optimisation from any assertions written by the +user in the code. + +Consult the {\em Glossary} at the end of this chapter for definitions of +technical terms used below. + +\section{Command-line flags} + +The Flambda optimisers provide a variety of command-line flags that may +be used to control their behaviour. Detailed descriptions of each flag +are given in the referenced sections. Those sections also describe any +arguments which the particular flags take. + +Commonly-used options: +\begin{options} +\item[\machine{-O2}] Perform more optimisation than usual. Compilation +times may be lengthened. (This flag is an abbreviation for a certain +set of parameters described in section\ \ref{defaults}.) +\item[\machine{-O3}] Perform even more optimisation than usual, possibly +including unrolling of recursive functions. Compilation times may be +significantly lengthened. +\item[\machine{-Oclassic}] Make inlining decisions at the point of +definition of a function rather than at the call site(s). This mirrors +the behaviour of OCaml compilers not using Flambda. Compared to compilation +using the new Flambda inlining heuristics (for example at {\tt -O2}) it +produces +smaller {\tt .cmx} files, shorter compilation times and code that probably +runs rather slower. When using {\tt -Oclassic}, only the following options +described in this section are relevant: {\tt -inlining-report} and +{\tt -inline}. If any other of the options described in this section are +used, the behaviour is undefined and may cause an error in future versions +of the compiler. +\item[\machine{-inlining-report}] Emit {\tt .inlining} files (one per +round of optimisation) showing all of the inliner's decisions. +\end{options} + +Less commonly-used options: +\begin{options} +\item[\machine{-remove-unused-arguments}] Remove unused function arguments +even when the argument is not specialised. This may have a small +performance penalty. +See section\ \ref{remove-unused-args}. +\item[\machine{-unbox-closures}] Pass free variables via specialised arguments +rather than closures (an optimisation for reducing allocation). See +section\ \ref{unbox-closures}. This may have a small performance penalty. +\end{options} + +Advanced options, only needed for detailed tuning: +\begin{options} +\item[\machine{-inline}] The behaviour depends on whether {\tt -Oclassic} +is used. +\begin{itemize} +\item When not in {\tt -Oclassic} mode, {\tt -inline} limits the total +size of functions considered for inlining during any speculative inlining +search. (See section\ \ref{speculation}.) Note that +this parameter does +{\bf not} control the assessment as to whether any particular function may +be inlined. Raising it to excessive amounts will not necessarily cause +more functions to be inlined. +\item When in {\tt -Oclassic} mode, {\tt -inline} behaves as in +previous versions of the compiler: it is the maximum size of function to +be considered for inlining. See section\ \ref{classic}. +\end{itemize} +\item[\machine{-inline-toplevel}] The equivalent of {\tt -inline} but used +when speculative inlining starts at toplevel. See +section\ \ref{speculation}. +Not used in {\tt -Oclassic} mode. +\item[\machine{-inline-branch-factor}] Controls how the inliner assesses +whether a code path is likely to be hot or cold. See +section\ \ref{assessment-inlining}. +\item[\machine{-inline-alloc-cost}, + \machine{-inline-branch-cost}, + \machine{-inline-call-cost}] Controls how the inliner assesses the runtime + performance penalties associated with various operations. See + section\ \ref{assessment-inlining}. +\item[\machine{-inline-indirect-cost}, + \machine{-inline-prim-cost}] Likewise. +\item[\machine{-inline-lifting-benefit}] Controls inlining of functors +at toplevel. See section\ \ref{assessment-inlining}. +\item[\machine{-inline-max-depth}] The maximum depth of any +speculative inlining search. See section\ \ref{speculation}. +\item[\machine{-inline-max-unroll}] The maximum depth of any unrolling of +recursive functions during any speculative inlining search. +See section\ \ref{speculation}. +\item[\machine{-no-unbox-free-vars-of-closures}] % +Do not unbox closure variables. See section\ \ref{unbox-fvs}. +\item[\machine{-no-unbox-specialised-args}] % +Do not unbox arguments to which functions have been specialised. See +section\ \ref{unbox-spec-args}. +\item[\machine{-rounds}] How many rounds of optimisation to perform. +See section\ \ref{rounds}. +\item[\machine{-unbox-closures-factor}] Scaling factor for benefit +calculation when using {\tt -unbox-closures}. See +section\ \ref{unbox-closures}. +\end{options} + +\paragraph{Notes} +\begin{itemize} +\item The set of command line flags relating to optimisation should typically +be specified to be the same across an entire project. Flambda does not +currently record the requested flags in the {\tt .cmx} files. As such, +inlining of functions from previously-compiled units will subject their code +to the optimisation parameters of the unit currently being compiled, rather +than those specified when they were previously compiled. It is hoped to +rectify this deficiency in the future. + +\item Flambda-specific flags do not affect linking with the exception of +affecting the optimisation of code in the startup file (containing +generated functions such as currying helpers). Typically such optimisation +will not be significant, so eliding such flags at link time might be +reasonable. + +\item Flambda-specific flags are silently accepted even when the +{\tt -flambda} option was not provided to the {\tt configure} script. +(There is no means provided to change this behaviour.) +This is intended to make it more +straightforward to run benchmarks with and without the Flambda optimisers +in effect. +\item Some of the Flambda flags may be subject to change in future +releases. +\end{itemize} + +\subsection{Specification of optimisation parameters by round}\label{rounds} + +Flambda operates in {\em rounds}: one round consists of a certain sequence +of transformations that may then be repeated in order to achieve more +satisfactory results. The number of rounds can be set manually using the +{\tt -rounds} parameter (although this is not necessary when using +predefined optimisation levels such as with {\tt -O2} and {\tt -O3}). +For high optimisation the number of rounds might be set at 3 or 4. + +Command-line flags that may apply per round, for example those with +{\tt "-cost"} in the name, accept arguments of the form: +\begin{center} +{\em n}{\tt\ |\ }{\em round}{\tt =}{\em n}[{\tt,}...] +\end{center} +\begin{itemize} +\item If the first form is used, with a single integer specified, +the value will apply to all rounds. +\item If the second form is used, zero-based {\em round} integers specify +values which are to be used only for those rounds. +\end{itemize} + +The flags {\tt -Oclassic}, {\tt -O2} and {\tt -O3} are applied before all +other flags, meaning that certain parameters may be overridden without +having to specify every parameter usually invoked by the given optimisation +level. + +\section{Inlining} + +{\em Inlining} refers to the copying of the code of a function to a +place where the function is called. +The code of the function will be surrounded by bindings of its parameters +to the corresponding arguments. + +The aims of inlining are: +\begin{itemize} +\item to reduce the runtime overhead caused by function calls (including +setting up for such calls and returning afterwards); +\item to reduce instruction cache misses by expressing frequently-taken +paths through the program using fewer machine instructions; and +\item to reduce the amount of allocation (especially of closures). +\end{itemize} +These goals are often reached not just by inlining itself but also by +other optimisations that the compiler is able to perform as a result of +inlining. + +When a recursive call to a function (within the definition of that function +or another in the same mutually-recursive group) is inlined, the procedure is +also known as {\em unrolling}. This is somewhat akin to loop peeling. +For example, given the following code: +\begin{verbatim} +let rec fact x = + if x = 0 then + 1 + else + x * fact (x - 1) + +let n = fact 4 +\end{verbatim} +unrolling once at the call site {\tt fact 4} produces (with the body of +{\tt fact} unchanged): +\begin{verbatim} +let n = + if 4 = 0 then + 1 + else + 4 * fact (4 - 1) +\end{verbatim} +This simplifies to: +\begin{verbatim} +let n = 4 * fact 3 +\end{verbatim} + +%% CR pchambart: A specific section for unrolling might be worth (telling +%% when this is beneficial) + +Flambda provides significantly enhanced inlining capabilities relative to +previous versions of the compiler. + +\subsubsection{Aside: when inlining is performed} + +Inlining is performed together with all of the other Flambda optimisation +passes, that is to say, after closure conversion. This has three particular +advantages over a potentially more straightforward implementation prior to +closure conversion: +\begin{itemize} +\item It permits higher-order inlining, for example when a non-inlinable +function always returns the same function yet with different environments +of definition. Not all such cases are supported yet, but it is intended +that such support will be improved in future. +\item It is easier to integrate with cross-module optimisation, since +imported information about other modules is already in the correct +intermediate language. +\item It becomes more straightforward to optimise closure allocations since +the layout of closures does not have to be estimated in any way: it is +known. Similarly, +it becomes more straightforward to control which variables end up +in which closures, helping to avoid closure bloat. +\end{itemize} + +\subsection{Classic inlining heuristic}\label{classic} + +In {\tt -Oclassic} mode the behaviour of the Flambda inliner +mimics previous versions +of the compiler. (Code may still be subject to further optimisations not +performed by previous versions of the compiler: functors may be inlined, +constants are lifted and unused code is eliminated all as described elsewhere +in this chapter. See sections \ref{functors},\ \ref{lift-const} % +and\ \ref{remove-unused}. +At the definition site of a function, the body of the +function is measured. It will then be marked as eligible for inlining +(and hence inlined at every direct call site) if: +\begin{itemize} +\item the measured size (in unspecified units) is smaller than that of a +function call plus the argument of the {\tt -inline} command-line flag; and +\item the function is not recursive. +\end{itemize} + +Non-Flambda versions of the compiler cannot inline functions that +contain a definition of another function. However {\tt -Oclassic} does +permit this. Further, non-Flambda versions also cannot inline functions +that are only themselves exposed as a result of a previous pass of inlining, +but again this is permitted by {\tt -Oclassic}. +For example: +\begin{verbatim} +module M : sig + val i : int +end = struct + let f x = + let g y = x + y in + g + let h = f 3 + let i = h 4 (* h is correctly discovered to be g and inlined *) +end +\end{verbatim} + +All of this contrasts with the normal Flambda mode, that is to say +without {\tt -Oclassic}, where: +\begin{itemize} +\item the inlining decision is made at the {\bf call site}; and +\item recursive functions can be handled, by {\em specialisation} (see +below). +\end{itemize} +The Flambda mode is described in the next section. + +\subsection{Overview of ``Flambda'' inlining heuristics} + +The Flambda inlining heuristics, used whenever the compiler is configured +for Flambda and {\tt -Oclassic} was not specified, make inlining decisions +at call sites. This helps in situations where the context is important. +For example: +\begin{verbatim} +let f b x = + if b then + x + else + ... big expression ... + +let g x = f true x +\end{verbatim} +In this case, we would like to inline {\tt f} into {\tt g}, because a +conditional jump can be eliminated and the code size should reduce. If the +inlining decision has been made after the declaration of {\tt f} without +seeing the use, its size would have probably made it ineligible for +inlining; but at the call site, its final size can be known. Further, +this function should probably not be inlined systematically: if {\tt b} +is unknown, or indeed {\tt false}, there is little benefit to trade off +against a large increase in code size. In the existing non-Flambda inliner +this isn't a great problem because chains of inlining were cut off fairly +quickly. However it has led to excessive use of overly-large inlining +parameters such as {\tt -inline 10000}. + +In more detail, at each call site the following procedure is followed: +\begin{itemize} +\item Determine whether it is clear that inlining would be beneficial +without, for the moment, doing any inlining within the function itself. +(The exact assessment of {\em benefit} is described below.) If so, the +function is inlined. +\item If inlining the function is not clearly beneficial, then inlining +will be performed {\em speculatively} inside the function itself. The +search for speculative inlining possibilities is controlled by two +parameters: the {\em inlining threshold} and the {\em inlining depth}. +(These are described in more detail below.) +\begin{itemize} +\item If such speculation shows that performing some inlining inside the +function would be beneficial, then such inlining is performed and the +resulting function inlined at the original call site. +\item Otherwise, nothing happens. +\end{itemize} +\end{itemize} +Inlining within recursive functions of calls to other +functions in the same mutually-recursive group is kept in check by +an {\em unrolling depth}, described below. This ensures that functions are +not unrolled to excess. (Unrolling is only enabled +if {\tt -O3} optimisation level is selected and/or the +{\tt -inline-max-unroll} +flag is passed with an argument greater than zero.) + +\subsection{Handling of specific language constructs} + +\subsubsection{Functors}\label{functors} + +There is nothing particular about functors that inhibits inlining compared +to normal functions. To the inliner, these both look the same, except +that functors are marked as such. + +Applications of functors at toplevel are biased in favour of inlining. +(This bias may be adjusted: +see the documentation for {\tt -inline-lifting-benefit} below.) + +Applications of functors not at toplevel, for example in a local module +inside some other expression, are treated by the inliner identically to +normal function calls. + +\subsubsection{First-class modules} + +The inliner will be able to consider inlining a call to a function in a first +class module if it knows which particular function is going to be called. +The presence of the first-class module record that wraps the set of functions +in the module does not per se inhibit inlining. + +\subsubsection{Objects} + +Method calls to objects are not at present inlined by Flambda. + +\subsection{Inlining reports} + +If the {\tt -inlining-report} option is provided to the compiler then a file +will be emitted corresponding to each round of optimisation. For the +OCaml source file {\em basename}{\tt .ml} the files +are named {\em basename}{\tt .}{\em round}{\tt.inlining.org}, +with {\em round} a +zero-based integer. Inside the files, which are formatted as ``org mode'', +will be found English prose describing the decisions that the inliner took. + +\subsection{Assessment of inlining benefit}\label{assessment-inlining} + +Inlining typically +results in an increase in code size, which if left unchecked, may not only +lead to grossly large executables and excessive compilation times but also +a decrease in performance due to worse locality. As such, the +Flambda inliner trades off the change in code size against +the expected runtime performance benefit, with the benefit being computed +based on the number of operations that the compiler observes may be removed +as a result of inlining. + +For example given the following code: +\begin{verbatim} +let f b x = + if b then + x + else + ... big expression ... + +let g x = f true x +\end{verbatim} +it would be observed that inlining of {\tt f} would remove: +\begin{itemize} +\item one direct call; +\item one conditional branch. +\end{itemize} + +Formally, an estimate of runtime performance benefit is computed by +first summing +the cost of the operations that are known to be removed as a result of the +inlining and subsequent simplification of the inlined body. +The individual costs for the various kinds of operations may be adjusted +using the various {\tt -inline-...-cost} flags as follows. Costs are +specified as integers. All of these flags accept a single argument +describing such integers using the conventions +detailed in section\ \ref{rounds}. +\begin{options} +\item[\machine{-inline-alloc-cost}] The cost of an allocation. +\item[\machine{-inline-branch-cost}] The cost of a branch. +\item[\machine{-inline-call-cost}] The cost of a direct function call. +\item[\machine{-inline-indirect-cost}] The cost of an indirect function call. +\item[\machine{-inline-prim-cost}] The cost of a {\em primitive}. Primitives +encompass operations including arithmetic and memory access. +\end{options} +(Default values are described in section\ \ref{defaults} below.) + +The initial benefit value is then scaled by a factor that attempts to +compensate for the fact that the current point in the code, if under some +number of conditional branches, may be cold. (Flambda does not currently +compute hot and cold paths.) The factor---the estimated probability that +the inliner really is on a {\em hot} path---is calculated as +$\frac{1}{(1 + f)^{d}}$, where $f$ is set by +{\tt -inline-branch-factor} and $d$ is the nesting depth of branches +at the current point. As the inliner descends into more deeply-nested +branches, the benefit of inlining thus lessens. + +The resulting benefit value is known as the {\em estimated benefit}. + +The change in code size is also estimated: morally speaking it should be the +change in machine code size, but since that is not available to the inliner, +an approximation is used. + +If the estimated benefit exceeds the increase in code size then the inlined +version of the function will be kept. Otherwise the function will not be +inlined. + +Applications of functors at toplevel will be given +an additional benefit (which may be controlled by the +{\tt -inline-lifting-benefit} flag) to bias inlining in such situations +towards keeping the inlined version. + +\subsection{Control of speculation}\label{speculation} + +As described above, there are three parameters that restrict the search +for inlining opportunities during speculation: +\begin{itemize} +\item the {\em inlining threshold}; +\item the {\em inlining depth}; +\item the {\em unrolling depth}. +\end{itemize} +These parameters are ultimately bounded by the arguments provided to +the corresponding command-line flags (or their default values): +\begin{itemize} +\item {\tt -inline} (or, if the call site that triggered speculation is +at toplevel, {\tt -inline-toplevel}); +\item {\tt -inline-max-depth}; +\item {\tt -inline-max-unroll}. +\end{itemize} +{\bf Note in particular} that {\tt -inline} does not have the meaning that +it has in the previous compiler or in {\tt -Oclassic} mode. In both of those +situations {\tt -inline} was effectively some kind of basic assessment of +inlining benefit. However in Flambda inlining mode it corresponds to a +constraint on the search; the assessment of benefit is independent, as +described above. + +When speculation starts the inlining threshold starts at the value set +by {\tt -inline} (or {\tt -inline-toplevel} if appropriate, see above). +Upon making a speculative inlining decision the +threshold is reduced by the code size of the function being inlined. +If the threshold becomes exhausted, at or below zero, no further speculation +will be performed. + +The inlining depth starts at zero +and is increased by one every time the inliner +descends into another function. It is then decreased by one every time the +inliner leaves such function. If the depth exceeds the value set by +{\tt -inline-max-depth} then speculation stops. This parameter is intended +as a general backstop for situations where the inlining +threshold does not control the search sufficiently. + +The unrolling depth applies to calls within the same mutually-recursive +group of functions. Each time an inlining of such a call is performed +the depth is incremented by one when examining the resulting body. If the +depth reaches the limit set by {\tt -inline-max-unroll} then speculation +stops. + +\section{Specialisation}\label{specialisation} + +The inliner may discover a call site to a recursive function where +something is known about the arguments: for example, they may be equal to +some other variables currently in scope. In this situation it may be +beneficial to {\em specialise} the function to those arguments. This is +done by copying the declaration of the function (and any others involved +in any same mutually-recursive declaration) and noting the extra information +about the arguments. The arguments augmented by this information are known +as {\em specialised arguments}. In order to try to ensure that specialisation +is not performed uselessly, arguments are only specialised if it can be shown +that they are {\em invariant}: in other words, during the execution of the +recursive function(s) themselves, the arguments never change. + +Unless overridden by an attribute (see below), specialisation of a function +will not be attempted if: +\begin{itemize} +\item the compiler is in {\tt -Oclassic} mode; +\item the function is not obviously recursive; +\item the function is not closed. +\end{itemize} + +The compiler can prove invariance of function arguments across multiple +functions within a recursive group (although this has some limitations, +as shown by the example below). + +It should be noted that the {\em unboxing of closures} pass (see below) +can introduce specialised arguments on non-recursive functions. (No other +place in the compiler currently does this.) + +\paragraph{Example: the well-known {\tt List.iter} function} +This function might be written like so: +\begin{verbatim} +let rec iter f l = + match l with + | [] -> () + | h :: t -> + f h; + iter f t +\end{verbatim} +and used like this: +\begin{verbatim} +let print_int x = + print_endline (string_of_int x) + +let run xs = + iter print_int (List.rev xs) +\end{verbatim} +The argument {\tt f} to {\tt iter} is invariant so the function may be +specialised: +\begin{verbatim} +let run xs = + let rec iter' f l = + (* The compiler knows: f holds the same value as foo throughout iter'. *) + match l with + | [] -> () + | h :: t -> + f h; + iter' f t + in + iter' print_int (List.rev xs) +\end{verbatim} +The compiler notes down that for the function {\tt iter'}, the argument +{\tt f} is specialised to the constant closure {\tt print\_int}. This +means that the body of {\tt iter'} may be simplified: +\begin{verbatim} +let run xs = + let rec iter' f l = + (* The compiler knows: f holds the same value as foo throughout iter'. *) + match l with + | [] -> () + | h :: t -> + print_int h; (* this is now a direct call *) + iter' f t + in + iter' print_int (List.rev xs) +\end{verbatim} +The call to {\tt print\_int} can indeed be inlined: +\begin{verbatim} +let run xs = + let rec iter' f l = + (* The compiler knows: f holds the same value as foo throughout iter'. *) + match l with + | [] -> () + | h :: t -> + print_endline (string_of_int h); + iter' f t + in + iter' print_int (List.rev xs) +\end{verbatim} +The unused specialised argument {\tt f} may now be removed, leaving: +\begin{verbatim} +let run xs = + let rec iter' l = + match l with + | [] -> () + | h :: t -> + print_endline (string_of_int h); + iter' t + in + iter' (List.rev xs) +\end{verbatim} + +\paragraph{Aside on invariant parameters.} The compiler cannot currently +detect invariance in cases such as the following. +\begin{verbatim} +let rec iter_swap f g l = + match l with + | [] -> () + | 0 :: t -> + iter_swap g f l + | h :: t -> + f h; + iter_swap f g t +\end{verbatim} + +\subsection{Assessment of specialisation benefit} + +The benefit of specialisation is assessed in a similar way as for inlining. +Specialised argument information may mean that the body of the function +being specialised can be simplified: the removed operations are accumulated +into a benefit. This, together with the size of the duplicated (specialised) +function declaration, is then assessed against the size of the call to the +original function. + +\section{Default settings of parameters}\label{defaults} + +The default settings (when not using {\tt -Oclassic}) are for one +round of optimisation using the following parameters. +% CR-soon mshinwell: for 4.04, let's autogenerate these. + +\begin{tableau}{|l|l|}{Parameter}{Setting} +\entree{{\tt -inline}}{10} +\entree{{\tt -inline-branch-factor}}{0.1} +\entree{{\tt -inline-alloc-cost}}{7} +\entree{{\tt -inline-branch-cost}}{5} +\entree{{\tt -inline-call-cost}}{5} +\entree{{\tt -inline-indirect-cost}}{4} +\entree{{\tt -inline-prim-cost}}{3} +\entree{{\tt -inline-lifting-benefit}}{1300} +\entree{{\tt -inline-toplevel}}{160} +\entree{{\tt -inline-max-depth}}{1} +\entree{{\tt -inline-max-unroll}}{0} +\entree{{\tt -unbox-closures-factor}}{10} +\end{tableau} + +\subsection{Settings at -O2 optimisation level} + +When {\tt -O2} is specified two rounds of optimisation are performed. +The first round uses the default parameters (see above). The second uses +the following parameters. + +\begin{tableau}{|l|l|}{Parameter}{Setting} +\entree{{\tt -inline}}{25} +\entree{{\tt -inline-branch-factor}}{Same as default} +\entree{{\tt -inline-alloc-cost}}{Double the default} +\entree{{\tt -inline-branch-cost}}{Double the default} +\entree{{\tt -inline-call-cost}}{Double the default} +\entree{{\tt -inline-indirect-cost}}{Double the default} +\entree{{\tt -inline-prim-cost}}{Double the default} +\entree{{\tt -inline-lifting-benefit}}{Same as default} +\entree{{\tt -inline-toplevel}}{400} +\entree{{\tt -inline-max-depth}}{2} +\entree{{\tt -inline-max-unroll}}{Same as default} +\entree{{\tt -unbox-closures-factor}}{Same as default} +\end{tableau} + +\subsection{Settings at -O3 optimisation level} + +When {\tt -O3} is specified three rounds of optimisation are performed. +The first two rounds are as for {\tt -O2}. The third round uses +the following parameters. + +\begin{tableau}{|l|l|}{Parameter}{Setting} +\entree{{\tt -inline}}{50} +\entree{{\tt -inline-branch-factor}}{Same as default} +\entree{{\tt -inline-alloc-cost}}{Triple the default} +\entree{{\tt -inline-branch-cost}}{Triple the default} +\entree{{\tt -inline-call-cost}}{Triple the default} +\entree{{\tt -inline-indirect-cost}}{Triple the default} +\entree{{\tt -inline-prim-cost}}{Triple the default} +\entree{{\tt -inline-lifting-benefit}}{Same as default} +\entree{{\tt -inline-toplevel}}{800} +\entree{{\tt -inline-max-depth}}{3} +\entree{{\tt -inline-max-unroll}}{1} +\entree{{\tt -unbox-closures-factor}}{Same as default} +\end{tableau} + +\section{Manual control of inlining and specialisation} + +Should the inliner prove recalcitrant and refuse to inline a particular +function, or if the observed inlining decisions are not to the programmer's +satisfaction for some other reason, inlining behaviour can be dictated by the +programmer directly in the source code. +One example where this might be appropriate is when the programmer, +but not the compiler, knows that a particular function call is on a cold +code path. It might be desirable to prevent inlining of the function so +that the code size along the hot path is kept smaller, so as to increase +locality. + +The inliner is directed using attributes. +For non-recursive functions (and one-step unrolling of recursive functions, +although {\tt \@unroll} is more clear for this purpose) +the following are supported: +\begin{options} +\item[{\machine{\@\@inline always}} or {\machine{\@\@inline never}}] Attached +to a {\em declaration} of a function or functor, these direct the inliner to +either +always or never inline, irrespective of the size/benefit calculation. (If +the function is recursive then the body is substituted and no special +action is taken for the recursive call site(s).) +{\machine{\@\@inline}} with no argument is equivalent to +{\machine{\@\@inline always}}. +\item[{\machine{\@inlined always}} or {\machine{\@inlined never}}] Attached +to a function {\em application}, these direct the inliner likewise. These +attributes at call sites override any other attribute that may be present +on the corresponding declaration. +{\machine{\@inlined}} with no argument is equivalent to +{\machine{\@inlined always}}. +\end{options} + +For recursive functions the relevant attributes are: +\begin{options} +\item[{\machine{\@\@specialise always}} or {\machine{\@\@specialise never}}]% +Attached to a declaration of a function +or functor, this directs the inliner to either always or never +specialise the function so +long as it has appropriate contextual knowledge, irrespective of the +size/benefit calculation. +{\machine{\@\@specialise}} with no argument is equivalent to +{\machine{\@\@specialise always}}. +\item[{\machine{\@specialised always}} or {\machine{\@specialised never}}]% +Attached to a function application, this +directs the inliner likewise. This attribute at a call site overrides any +other attribute that may be present on the corresponding declaration. +(Note that the function will still only be specialised if there exist +one or more invariant parameters whose values are known.) +{\machine{\@specialised}} with no argument is equivalent to +{\machine{\@specialised always}}. +\item[{\machine{\@unrolled }}$n$] This attribute is attached to a function +application and always takes an integer argument. Each time the inliner sees +the attribute it behaves as follows: +\begin{itemize} +\item If $n$ is zero or less, nothing happens. +\item Otherwise the function being called is substituted at the call site +with its body having been rewritten such that +any recursive calls to that function {\em or +any others in the same mutually-recursive group} are annotated with the +attribute {\tt unrolled(}$n - 1${\tt )}. Inlining may continue on that body. +\end{itemize} +As such, $n$ behaves as the ``maximum depth of unrolling''. +\end{options} + +A compiler warning will be emitted if it was found impossible to obey an +annotation from an {\tt \@inlined} or {\tt \@specialised} attribute. + +\paragraph{Example showing correct placement of attributes} +\begin{verbatim} +module F (M : sig type t end) = struct + let[@inline never] bar x = + x * 3 + + let foo x = + (bar [@inlined]) (42 + x) +end [@@inline never] + +module X = F [@inlined] (struct type t = int end) +\end{verbatim} + +\section{Simplification} + +Simplification, which is run in conjunction with inlining, +propagates information (known as {\em approximations}) about which +variables hold what values at runtime. Certain relationships between +variables and symbols are also tracked: for example, some variable may be +known to always hold the same value as some other variable; or perhaps +some variable may be known to always hold the value pointed to by some +symbol. + +The propagation can help to eliminate allocations in cases such as: +\begin{verbatim} +let f x y = + ... + let p = x, y in + ... + ... (fst p) ... (snd p) ... +\end{verbatim} +The projections from {\tt p} may be replaced by uses of the variables +{\tt x} and {\tt y}, potentially meaning that {\tt p} becomes unused. + +The propagation performed by the simplification pass is also important for +discovering which functions flow to indirect call sites. This can enable +the transformation of such call sites into direct call sites, which makes +them eligible for an inlining transformation. + +Note that no information is propagated about the contents of strings, +even in {\tt safe-string} mode, because it cannot yet be guaranteed +that they are immutable throughout a given program. + +\section{Other code motion transformations} + +\subsection{Lifting of constants}\label{lift-const} + +Expressions found to be constant will be lifted to symbol +bindings---that is to say, they will be statically allocated in the +object file---when +they evaluate to boxed values. Such constants may be straightforward numeric +constants, such as the floating-point number {\tt 42.0}, or more complicated +values such as constant closures. + +Lifting of constants to toplevel reduces allocation at runtime. + +The compiler aims to share constants lifted to toplevel such that there +are no duplicate definitions. However if {\tt .cmx} files are hidden +from the compiler then maximal sharing may not be possible. + +\paragraph{Notes about float arrays} % +The following language semantics apply specifically to constant float arrays. +(By ``constant float array'' is meant an array consisting entirely of floating +point numbers that are known at compile time. A common case is a literal +such as {\tt [| 42.0; 43.0; |]}. +\begin{itemize} +\item Constant float arrays at the toplevel are mutable and never shared. +(That is to say, for each +such definition there is a distinct symbol in the data section of the object +file pointing at the array.) +\item Constant float arrays not at toplevel are mutable and are created each +time the expression is evaluated. This can be thought of as an operation that +takes an immutable array (which in the source code has no associated name; let +us call it the {\em initialising array}) and +duplicates it into a fresh mutable array. +\begin{itemize} +\item If the array is of size four or less, the expression will create a +fresh block and write the values into it one by one. There is no reference +to the initialising array as a whole. + +\item Otherwise, the initialising array is lifted out and subject to the +normal constant sharing procedure; +creation of the array consists of bulk copying the initialising array +into a fresh value on the OCaml heap. +\end{itemize} +\end{itemize} + +\subsection{Lifting of toplevel let bindings} + +Toplevel {\tt let}-expressions may be lifted to symbol bindings to ensure +that the corresponding bound variables are not captured by closures. If the +defining expression of a given binding is found to be constant, it is bound +as such (the technical term is a {\em let-symbol} binding). + +Otherwise, the symbol is bound to a (statically-allocated) +{\em preallocated block} containing one field. At runtime, the defining +expression will be evaluated and the first field of the block filled with +the resulting value. This {\em initialise-symbol} binding +causes one extra indirection but ensures, by +virtue of the symbol's address being known at compile time, that uses of the +value are not captured by closures. + +It should be noted that the blocks corresponding to initialise-symbol +bindings are kept alive forever, by virtue of them occurring in a static +table of GC roots within the object file. This extended lifetime of +expressions may on occasion be surprising. If it is desired to create +some non-constant value (for example when writing GC tests) that does not +have this +extended lifetime, then it may be created and used inside a function, +with the application point of that function (perhaps at toplevel)---or +indeed the function declaration itself---marked +as to never be inlined. This technique prevents lifting of the definition +of the value in question (assuming of course that it is not constant). + +\section{Unboxing transformations} + +The transformations in this section relate to the splitting apart of +{\em boxed} (that is to say, non-immediate) values. They are largely +intended to reduce allocation, which tends to result in a runtime +performance profile with lower variance and smaller tails. + +\subsection{Unboxing of closure variables}\label{unbox-fvs} + +This transformation is enabled unless +{\tt -no-unbox-free-vars-of-closures} is provided. + +Variables that appear in closure environments may themselves be boxed +values. As such, they may be split into further closure variables, each +of which corresponds to some projection from the original closure variable(s). +This transformation is called {\em unboxing of closure variables} or +{\em unboxing of free variables of closures}. It is only applied when +there is +reasonable certainty that there are no uses of the boxed free variable itself +within the corresponding function bodies. +% CR-someday mshinwell: Actually, we probably don't check this carefully +% enough. It needs a global analysis in case there is an out-of-scope +% projection. + +\paragraph{Example:} In the following code, the compiler observes that +the closure returned from the function {\tt f} contains a variable {\tt pair} +(free in the body of {\tt f}) that may be split into two separate variables. +\begin{verbatim} +let f x0 x1 = + let pair = x0, x1 in + Printf.printf "foo\n"; + fun y -> + fst pair + snd pair + y +\end{verbatim} +After some simplification one obtains: +\begin{verbatim} +let f x0 x1 = + let pair_0 = x0 in + let pair_1 = x1 in + Printf.printf "foo\n"; + fun y -> + pair_0 + pair_1 + y +\end{verbatim} +and then: +\begin{verbatim} +let f x0 x1 = + Printf.printf "foo\n"; + fun y -> + x0 + x1 + y +\end{verbatim} +The allocation of the pair has been eliminated. + +This transformation does not operate if it would cause the closure to +contain more than twice as many closure variables as it did beforehand. + +\subsection{Unboxing of specialised arguments}\label{unbox-spec-args} + +This transformation is enabled unless +{\tt -no-unbox-specialised-args} is provided. + +It may become the case during compilation that one or more invariant arguments +to a function become specialised to a particular value. When such values are +themselves boxed the corresponding specialised arguments may be split into +more specialised arguments corresponding to the projections out of the boxed +value that occur within the function body. This transformation is called +{\em unboxing of specialised arguments}. It is only applied when there is +reasonable certainty that the boxed argument itself is unused within the +function. + +If the function in question is involved in a recursive group then unboxing +of specialised arguments may be immediately replicated across the group +based on the dataflow between invariant arguments. + +\paragraph{Example:} Having been given the following code, the compiler +will inline {\tt loop} into {\tt f}, and then observe {\tt inv} +being invariant and always the pair formed by adding {\tt 42} and {\tt 43} +to the argument {\tt x} of the function {\tt f}. +\begin{verbatim} +let rec loop inv xs = + match xs with + | [] -> fst inv + snd inv + | x::xs -> x + loop2 xs inv +and loop2 ys inv = + match ys with + | [] -> 4 + | y::ys -> y - loop inv ys + +let f x = + Printf.printf "%d\n" (loop (x + 42, x + 43) [1; 2; 3]) +\end{verbatim} +Since the functions have sufficiently few arguments, more specialised +arguments will be added. After some simplification one obtains: +\begin{verbatim} +let f x = + let rec loop' xs inv_0 inv_1 = + match xs with + | [] -> inv_0 + inv_1 + | x::xs -> x + loop2' xs inv_0 inv_1 + and loop2' ys inv_0 inv_1 = + match ys with + | [] -> 4 + | y::ys -> y - loop' ys inv_0 inv_1 + in + Printf.printf "%d\n" (loop' [1; 2; 3] (x + 42) (x + 43)) +\end{verbatim} +The allocation of the pair within {\tt f} has been removed. (Since the +two closures for {\tt loop'} and {\tt loop2'} are constant they will also be +lifted to toplevel with no runtime allocation penalty. This +would also happen without having run the transformation to unbox +specialise arguments.) + +The transformation to unbox specialised arguments never introduces extra +allocation. + +The transformation will not unbox arguments if it would result in the +original function having sufficiently many arguments so as to inhibit +tail-call optimisation. + +The transformation is implemented by creating a wrapper function that +accepts the original arguments. Meanwhile, the original function is renamed +and extra arguments are added corresponding to the unboxed specialised +arguments; this new function +is called from the wrapper. The wrapper will then be inlined +at direct call sites. Indeed, all call sites will be direct unless +{\tt -unbox-closures} is being used, since they will have been generated +by the compiler when originally specialising the function. (In the case +of {\tt -unbox-closures} other functions may appear with specialised +arguments; in this case there may be indirect calls and these will incur +a small penalty owing to having to bounce through the wrapper. The technique +of {\em direct call surrogates} used for {\tt -unbox-closures} is not +used by the transformation to unbox specialised arguments.) + +\subsection{Unboxing of closures}\label{unbox-closures} + +This transformation is {\em not} enabled by default. It may be enabled +using the {\tt -unbox-closures} flag. + +The transformation replaces closure variables by specialised arguments. +The aim is to cause more closures to become closed. It is particularly +applicable, as a means of reducing allocation, where the function concerned +cannot be inlined or specialised. For example, some non-recursive function +might be too large to inline; or some recursive function might offer +no opportunities for specialisation perhaps because its only argument is +one of type {\tt unit}. + +At present there may be a small penalty in terms of actual runtime +performance when this transformation is enabled, although more stable +performance may be obtained due to reduced allocation. It is recommended +that developers experiment to determine whether the option is beneficial +for their code. (It is expected that in the future it will be possible +for the performance degradation to be removed.) + +\paragraph{Simple example:} In the following code (which might typically +occur when {\tt g} is too large to inline) the value of {\tt x} would usually +be communicated to the application of the {\tt +} function via the closure +of {\tt g}. +\begin{verbatim} +let f x = + let g y = + x + y + in + (g [@inlined never]) 42 +\end{verbatim} +Unboxing of the closure causes the value for {\tt x} inside {\tt g} to +be passed as an argument to {\tt g} rather than through its closure. This +means that the closure of {\tt g} becomes constant and may be lifted to +toplevel, eliminating the runtime allocation. + +The transformation is implemented by adding a new wrapper function in the +manner of that used when unboxing specialised arguments. The closure +variables are still free in the wrapper, but the intention is that when +the wrapper is inlined at direct call sites, the relevant values are +passed directly to the main function via the new specialised arguments. + +Adding such a wrapper will penalise indirect calls to the function +(which might exist in arbitrary places; remember that this transformation +is not for example applied only on functions the compiler has produced +as a result of specialisation) since such calls will bounce through +the wrapper. To +mitigate this, if a function is small enough when weighed up against +the number of free variables being removed, it will be duplicated by the +transformation to obtain two versions: the original (used for indirect calls, +since we can do no better) and the wrapper/rewritten function pair as +described in the previous paragraph. The wrapper/rewritten function pair +will only be used at direct call sites of the function. (The wrapper in +this case is known as a {\em direct call surrogate}, since +it takes the place of another function---the unchanged version used for +indirect calls---at direct call sites.) + +The {\tt -unbox-closures-factor} command line flag, which takes an +integer, may be used to adjust the point at which a function is deemed +large enough to be ineligible for duplication. The benefit of +duplication is scaled by the integer before being evaluated against the +size. + +\paragraph{Harder example:} In the following code, there are two closure +variables that would typically cause closure allocations. One is called +{\tt fv} and occurs inside the function {\tt baz}; the other is called +{\tt z} and occurs inside the function {\tt bar}. +In this toy (yet sophisticated) example we again use an attribute to +simulate the typical situation where the first argument of {\tt baz} is +too large to inline. +\begin{verbatim} +let foo c = + let rec bar zs fv = + match zs with + | [] -> [] + | z::zs -> + let rec baz f = function + | [] -> [] + | a::l -> let r = fv + ((f [@inlined never]) a) in r :: baz f l + in + (map2 (fun y -> z + y) [z; 2; 3; 4]) @ bar zs fv + in + Printf.printf "%d" (List.length (bar [1; 2; 3; 4] c)) +\end{verbatim} +The code resulting from applying {\tt -O3 -unbox-closures} to this code +passes the free variables via function arguments in +order to eliminate all closure allocation in this example (aside from any +that might be performed inside {\tt printf}). + +\section{Removal of unused code and values}\label{remove-unused} + +\subsection{Removal of redundant let expressions} + +The simplification pass removes unused {\tt let} bindings so long as +their corresponding defining expressions have ``no effects''. See +the section ``Treatment of effects'' below for the precise definition of +this term. + +\subsection{Removal of redundant program constructs} + +This transformation is analogous to the removal of {\tt let}-expressions +whose defining expressions have no effects. It operates instead on symbol +bindings, removing those that have no effects. + +\subsection{Removal of unused arguments}\label{remove-unused-args} + +This transformation is only enabled by default for specialised arguments. +It may be enabled for all arguments using the {\tt -remove-unused-arguments} +flag. + +The pass analyses functions to determine which arguments are unused. +Removal is effected by creating a wrapper function, which will be inlined +at every direct call site, that accepts the original arguments and then +discards the unused ones before calling the original function. As a +consequence, this transformation may be detrimental if the original +function is usually indirectly called, since such calls will now bounce +through the wrapper. (The technique of {\em direct call surrogates} used +to reduce this penalty during unboxing of closure variables (see above) +does not yet apply to the pass that removes unused arguments.) + +\subsection{Removal of unused closure variables} + +This transformation performs an analysis across +the whole compilation unit to determine whether there exist closure variables +that are never used. Such closure variables are then eliminated. (Note that +this has to be a whole-unit analysis because a projection of a closure +variable from some particular closure may have propagated to an arbitrary +location within the code due to inlining.) + +\section{Other code transformations} + +\subsection{Transformation of non-escaping references into mutable variables} + +Flambda performs a simple analysis analogous to that performed elsewhere +in the compiler that can transform {\tt ref}s into mutable variables +that may then be held in registers (or on the stack as appropriate) rather +than being allocated on the OCaml heap. This only happens so long as the +reference concerned can be shown to not escape from its defining scope. + +\subsection{Substitution of closure variables for specialised arguments} + +This transformation discovers closure variables that are known to be +equal to specialised arguments. Such closure variables are replaced by +the specialised arguments; the closure variables may then be removed by +the ``removal of unused closure variables'' pass (see below). + +\section{Treatment of effects} + +The Flambda optimisers classify expressions in order to determine whether +an expression: +\begin{itemize} +\item does not need to be evaluated at all; and/or +\item may be duplicated. +\end{itemize} + +This is done by forming judgements on the {\em effects} and the {\em coeffects} +that might be performed were the expression to be executed. Effects talk +about how the expression might affect the world; coeffects talk about how +the world might affect the expression. + +Effects are classified as follows: +\begin{options} +\item[{\bf No effects:}] The expression does not change the observable state +of the world. For example, it must not write to any mutable storage, +call arbitrary external functions or change control flow (e.g. by raising +an exception). Note that allocation is {\em not} classed as having +``no effects'' (see below). +\begin{itemize} +\item It is assumed in the compiler that expressions with no +effects, whose results are not used, may be eliminated. (This typically +happens where the expression in question is the defining expression of a +{\tt let}; in such cases the {\tt let}-expression will be +eliminated.) It is further +assumed that such expressions with no effects may be +duplicated (and thus possibly executed more than once). +\item Exceptions arising from allocation points, for example +``out of memory'' or +exceptions propagated from finalizers or signal handlers, are treated as +``effects out of the ether'' and thus ignored for our determination here +of effectfulness. The same goes for floating point operations that may +cause hardware traps on some platforms. +\end{itemize} +\item[{\bf Only generative effects:}] The expression does not change the +observable state of the world save for possibly affecting the state of +the garbage collector by performing an allocation. Expressions +that only have generative effects and whose results are unused +may be eliminated by the compiler. However, unlike expressions with +``no effects'', such expressions will never be eligible for duplication. +\item[{\bf Arbitrary effects:}] All other expressions. +\end{options} + +There is a single classification for coeffects: +\begin{options} +\item[{\bf No coeffects:}] The expression does not observe the effects (in +the sense described above) of other expressions. For example, it must not +read from any mutable storage or call arbitrary external functions. +\end{options} + +It is assumed in the compiler that, subject to data dependencies, +expressions with neither effects nor coeffects may be reordered with +respect to other expressions. + +\section{Compilation of statically-allocated modules} + +Compilation of modules that are able to be statically allocated (for example, +the module corresponding to an entire compilation unit, as opposed to a first +class module dependent on values computed at runtime) initially follows the +strategy used for bytecode. A sequence of {\tt let}-bindings, which may be +interspersed with arbitrary effects, surrounds a record creation that becomes +the module block. The Flambda-specific transformation follows: these bindings +are lifted to toplevel symbols, as described above. + +\section{Inhibition of optimisation}\label{inhibition} + +Especially when writing benchmarking suites that run non-side-effecting +algorithms in loops, it may be found that the optimiser entirely +elides the code being benchmarked. This behaviour can be prevented by +using the {\tt Sys.opaque\_identity} function (which indeed behaves as a +normal OCaml function and does not possess any ``magic'' semantics). The +documentation of the {\tt Sys} module should be consulted for further details. + +\section{Use of unsafe operations}\label{unsafe} + +The behaviour of the Flambda simplification pass means that certain unsafe +operations, which may without Flambda or when using previous versions of +the compiler be safe, must not be used. This specifically refers to +functions found in the {\tt Obj} module. + +In particular, it is forbidden to change any value (for example using +{\tt Obj.set\_field} or {\tt Obj.set\_tag}) that is not mutable. +(Values returned from C stubs +are always treated as mutable.) The compiler will emit warning 59 if it +detects such a write---but it cannot warn in all cases. Here is an example +of code that will trigger the warning: +\begin{verbatim} +let f x = + let a = 42, x in + (Obj.magic a : int ref) := 1; + fst a +\end{verbatim} +The reason this is unsafe is because the simplification pass believes that +{\tt fst a} holds the value {\tt 42}; and indeed it must, unless type +soundness has been broken via unsafe operations. + +If it must be the case that code has to be written that triggers warning 59, +but the code is known to actually be correct (for some definition of +correct), then {\tt Sys.opaque\_identity} may be used to wrap the value +before unsafe operations are performed upon it. Great care must be taken +when doing this to ensure that the opacity is added at the correct place. +It must be emphasised that this use of {\tt Sys.opaque\_identity} is only +for {\bf exceptional} cases. It should not be used in normal code or to +try to guide the optimiser. + +As an example, this code will return the integer {\tt 1}: +\begin{verbatim} +let f x = + let a = Sys.opaque_identity (42, x) in + (Obj.magic a : int ref) := 1; + fst a +\end{verbatim} +However the following code will still return {\tt 42}: +\begin{verbatim} +let f x = + let a = 42, x in + Sys.opaque_identity (Obj.magic a : int ref) := 1; + fst a +\end{verbatim} + +High levels of inlining performed by Flambda may expose bugs in code +thought previously to be correct. Take care, for example, not +to add type annotations that claim some mutable value is always immediate +if it might be possible for an unsafe operation to update it to a boxed +value. + +\section{Glossary} + +The following terminology is used in this chapter of the manual. + +\begin{options} +\item[{\bf Call site}] See {\em direct call site} and % +{\em indirect call site} below. +\item[{\bf Closed function}] A function whose body has no free variables +except its parameters and any to which are bound other functions within +the same (possibly mutually-recursive) declaration. +\item[{\bf Closure}] The runtime representation of a function. This +includes pointers to the code of the function +together with the values of any variables that are used in the body of +the function but actually defined outside of the function, in the +enclosing scope. +The values of such variables, collectively known as the +{\em environment}, are required because the function may be +invoked from a place where the original bindings of such variables are +no longer in scope. A group of possibly +mutually-recursive functions defined using {\em let rec} all share a +single closure. (Note to developers: in the Flambda source code a +{\em closure} always corresponds to a single function; a +{\em set of closures} refers to a group of such.) +\item[{\bf Closure variable}] A member of the environment held within the +closure of a given function. +\item[{\bf Constant}] Some entity (typically an expression) the value of which +is known by the compiler at compile time. Constantness may be explicit from +the source code or inferred by the Flambda optimisers. +\item[{\bf Constant closure}] A closure that is statically allocated in an +object file. It is almost always the case that the environment portion of +such a closure is empty. +\item[{\bf Defining expression}] The expression {\tt e} in % +{\tt let x = e in e'}. +\item[{\bf Direct call site}] A place in a program's code where a function is +called and it is known at compile time which function it will always be. +\item[{\bf Indirect call site}] A place in a program's code where a function +is called but is not known to be a {\em direct call site}. +\item[{\bf Program}] A collection of {\em symbol bindings} forming the +definition of a single compilation unit (i.e. {\tt .cmx} file). +\item[{\bf Specialised argument}] An argument to a function that is known +to always hold a particular value at runtime. These are introduced by the +inliner when specialising recursive functions; and the {\tt unbox-closures} +pass. (See section\ \ref{specialisation}.) +\item[{\bf Symbol}] A name referencing a particular place in an object file +or executable image. At that particular place will be some constant value. +Symbols may be examined using operating system-specific tools (for +example {\tt objdump} on Linux). +\item[{\bf Symbol binding}] Analogous to a {\tt let}-expression but working +at the level of symbols defined in the object file. The address of a symbol is +fixed, but it may be bound to both constant and non-constant expressions. +\item[{\bf Toplevel}] An expression in the current program which is not +enclosed within any function declaration. +\item[{\bf Variable}] A named entity to which some OCaml value is bound by a +{\tt let} expression, pattern-matching construction, or similar. +\end{options} diff --git a/manual/manual/cmds/intf-c.etex b/manual/manual/cmds/intf-c.etex new file mode 100644 index 00000000..b8b5fcf7 --- /dev/null +++ b/manual/manual/cmds/intf-c.etex @@ -0,0 +1,2643 @@ +\chapter{Interfacing\label{c:intf-c} C with OCaml} +\pdfchapterfold{-9}{Interfacing C with OCaml} +%HEVEA\cutname{intfc.html} + +This chapter describes how user-defined primitives, written in C, can +be linked with OCaml code and called from OCaml functions, and how +these C functions can call back to OCaml code. + +\section{Overview and compilation information} +\pdfsection{Overview and compilation information} + +\subsection{Declaring primitives} + +\begin{syntax} +definition: ... + | 'external' value-name ':' typexpr '=' external-declaration +; +external-declaration: string-literal [ string-literal [ string-literal ] ] +\end{syntax} + +User primitives are declared in an implementation file or +@"struct"\ldots"end"@ module expression using the @"external"@ keyword: +\begin{alltt} + external \var{name} : \var{type} = \var{C-function-name} +\end{alltt} +This defines the value name \var{name} as a function with type +\var{type} that executes by calling the given C function. +For instance, here is how the "input" primitive is declared in the +standard library module "Pervasives": +\begin{verbatim} + external input : in_channel -> bytes -> int -> int -> int + = "input" +\end{verbatim} +Primitives with several arguments are always curried. The C function +does not necessarily have the same name as the ML function. + +External functions thus defined can be specified in interface files or +@"sig"\ldots"end"@ signatures either as regular values +\begin{alltt} + val \var{name} : \var{type} +\end{alltt} +thus hiding their implementation as C functions, or explicitly as +``manifest'' external functions +\begin{alltt} + external \var{name} : \var{type} = \var{C-function-name} +\end{alltt} +The latter is slightly more efficient, as it allows clients of the +module to call directly the C function instead of going through the +corresponding OCaml function. On the other hand, it should not be used +in library modules if they have side-effects at toplevel, as this +direct call interferes with the linker's algorithm for removing unused +modules from libraries at link-time. + +The arity (number of arguments) of a primitive is automatically +determined from its OCaml type in the "external" declaration, by +counting the number of function arrows in the type. For instance, +"input" above has arity 4, and the "input" C function is called with +four arguments. Similarly, +\begin{verbatim} + external input2 : in_channel * bytes * int * int -> int = "input2" +\end{verbatim} +has arity 1, and the "input2" C function receives one argument (which +is a quadruple of OCaml values). + +Type abbreviations are not expanded when determining the arity of a +primitive. For instance, +\begin{verbatim} + type int_endo = int -> int + external f : int_endo -> int_endo = "f" + external g : (int -> int) -> (int -> int) = "f" +\end{verbatim} +"f" has arity 1, but "g" has arity 2. This allows a primitive to +return a functional value (as in the "f" example above): just remember +to name the functional return type in a type abbreviation. + +The language accepts external declarations with one or two +flag strings in addition to the C function's name. These flags are +reserved for the implementation of the standard library. + +\subsection{Implementing primitives} + +User primitives with arity $n \leq 5$ are implemented by C functions +that take $n$ arguments of type "value", and return a result of type +"value". The type "value" is the type of the representations for OCaml +values. It encodes objects of several base types (integers, +floating-point numbers, strings,~\ldots) as well as OCaml data +structures. The type "value" and the associated conversion +functions and macros are described in detail below. For instance, +here is the declaration for the C function implementing the "input" +primitive: +\begin{verbatim} +CAMLprim value input(value channel, value buffer, value offset, value length) +{ + ... +} +\end{verbatim} +When the primitive function is applied in an OCaml program, the C +function is called with the values of the expressions to which the +primitive is applied as arguments. The value returned by the function is +passed back to the OCaml program as the result of the function +application. + +User primitives with arity greater than 5 should be implemented by two +C functions. The first function, to be used in conjunction with the +bytecode compiler "ocamlc", receives two arguments: a pointer to an +array of OCaml values (the values for the arguments), and an +integer which is the number of arguments provided. The other function, +to be used in conjunction with the native-code compiler "ocamlopt", +takes its arguments directly. For instance, here are the two C +functions for the 7-argument primitive "Nat.add_nat": +\begin{verbatim} +CAMLprim value add_nat_native(value nat1, value ofs1, value len1, + value nat2, value ofs2, value len2, + value carry_in) +{ + ... +} +CAMLprim value add_nat_bytecode(value * argv, int argn) +{ + return add_nat_native(argv[0], argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6]); +} +\end{verbatim} +The names of the two C functions must be given in the primitive +declaration, as follows: +\begin{alltt} + external \var{name} : \var{type} = + \var{bytecode-C-function-name} \var{native-code-C-function-name} +\end{alltt} +For instance, in the case of "add_nat", the declaration is: +\begin{verbatim} + external add_nat: nat -> int -> int -> nat -> int -> int -> int -> int + = "add_nat_bytecode" "add_nat_native" +\end{verbatim} + +Implementing a user primitive is actually two separate tasks: on the +one hand, decoding the arguments to extract C values from the given +OCaml values, and encoding the return value as an OCaml +value; on the other hand, actually computing the result from the arguments. +Except for very simple primitives, it is often preferable to have two +distinct C functions to implement these two tasks. The first function +actually implements the primitive, taking native C values as +arguments and returning a native C value. The second function, +often called the ``stub code'', is a simple wrapper around the first +function that converts its arguments from OCaml values to C values, +call the first function, and convert the returned C value to OCaml +value. For instance, here is the stub code for the "input" +primitive: +\begin{verbatim} +CAMLprim value input(value channel, value buffer, value offset, value length) +{ + return Val_long(getblock((struct channel *) channel, + &Byte(buffer, Long_val(offset)), + Long_val(length))); +} +\end{verbatim} +(Here, "Val_long", "Long_val" and so on are conversion macros for the +type "value", that will be described later. The "CAMLprim" macro +expands to the required compiler directives to ensure that the +function is exported and accessible from OCaml.) +The hard work is performed by the function "getblock", which is +declared as: +\begin{verbatim} +long getblock(struct channel * channel, char * p, long n) +{ + ... +} +\end{verbatim} + +To write C code that operates on OCaml values, the following +include files are provided: +\begin{tableau}{|l|p{12cm}|}{Include file}{Provides} +\entree{"caml/mlvalues.h"}{definition of the "value" type, and conversion +macros} +\entree{"caml/alloc.h"}{allocation functions (to create structured OCaml +objects)} +\entree{"caml/memory.h"}{miscellaneous memory-related functions +and macros (for GC interface, in-place modification of structures, etc).} +\entree{"caml/fail.h"}{functions for raising exceptions +(see section~\ref{s:c-exceptions})} +\entree{"caml/callback.h"}{callback from C to OCaml (see +section~\ref{s:callback}).} +\entree{"caml/custom.h"}{operations on custom blocks (see +section~\ref{s:custom}).} +\entree{"caml/intext.h"}{operations for writing user-defined +serialization and deserialization functions for custom blocks +(see section~\ref{s:custom}).} +\entree{"caml/threads.h"}{operations for interfacing in the presence + of multiple threads (see section~\ref{s:C-multithreading}).} +\end{tableau} +These files reside in the "caml/" subdirectory of the OCaml +standard library directory, which is returned by the command +"ocamlc -where" (usually "/usr/local/lib/ocaml" or "/usr/lib/ocaml"). + +By default, header files in the "caml/" subdirectory give only access +to the public interface of the OCaml runtime. It is possible to define +the macro "CAML_INTERNALS" to get access to a lower-level interface, +but this lower-level interface is more likely to change and break +programs that use it. + +{\bf Note:} It is recommended to define the macro "CAML_NAME_SPACE" +before including these header files. If you do not define it, the +header files will also define short names (without the "caml_" prefix) +for most functions, which usually produce clashes with names defined +by other C libraries that you might use. Including the header files +without "CAML_NAME_SPACE" is only supported for backward +compatibility. + +\subsection{Statically linking C code with OCaml code} +\label{staticlink-c-code} + +The OCaml runtime system comprises three main parts: the bytecode +interpreter, the memory manager, and a set of C functions that +implement the primitive operations. Some bytecode instructions are +provided to call these C functions, designated by their offset in a +table of functions (the table of primitives). + +In the default mode, the OCaml linker produces bytecode for the +standard runtime system, with a standard set of primitives. References +to primitives that are not in this standard set result in the +``unavailable C primitive'' error. (Unless dynamic loading of C +libraries is supported -- see section~\ref{dynlink-c-code} below.) + +In the ``custom runtime'' mode, the OCaml linker scans the +object files and determines the set of required primitives. Then, it +builds a suitable runtime system, by calling the native code linker with: +\begin{itemize} +\item the table of the required primitives; +\item a library that provides the bytecode interpreter, the +memory manager, and the standard primitives; +\item libraries and object code files (".o" files) mentioned on the +command line for the OCaml linker, that provide implementations +for the user's primitives. +\end{itemize} +This builds a runtime system with the required primitives. The OCaml +linker generates bytecode for this custom runtime system. The +bytecode is appended to the end of the custom runtime system, so that +it will be automatically executed when the output file (custom +runtime + bytecode) is launched. + +To link in ``custom runtime'' mode, execute the "ocamlc" command with: +\begin{itemize} +\item the "-custom" option; +\item the names of the desired OCaml object files (".cmo" and ".cma" files) ; +\item the names of the C object files and libraries (".o" and ".a" +files) that implement the required primitives. Under Unix and Windows, +a library named "lib"\var{name}".a" (respectively, ".lib") residing in one of +the standard library directories can also be specified as "-cclib -l"\var{name}. +\end{itemize} + +If you are using the native-code compiler "ocamlopt", the "-custom" +flag is not needed, as the final linking phase of "ocamlopt" always +builds a standalone executable. To build a mixed OCaml/C executable, +execute the "ocamlopt" command with: +\begin{itemize} +\item the names of the desired OCaml native object files (".cmx" and +".cmxa" files); +\item the names of the C object files and libraries (".o", ".a", +".so" or ".dll" files) that implement the required primitives. +\end{itemize} + +Starting with Objective Caml 3.00, it is possible to record the +"-custom" option as well as the names of C libraries in an OCaml +library file ".cma" or ".cmxa". For instance, consider an OCaml library +"mylib.cma", built from the OCaml object files "a.cmo" and "b.cmo", +which reference C code in "libmylib.a". If the library is +built as follows: +\begin{alltt} + ocamlc -a -o mylib.cma -custom a.cmo b.cmo -cclib -lmylib +\end{alltt} +users of the library can simply link with "mylib.cma": +\begin{alltt} + ocamlc -o myprog mylib.cma ... +\end{alltt} +and the system will automatically add the "-custom" and "-cclib +-lmylib" options, achieving the same effect as +\begin{alltt} + ocamlc -o myprog -custom a.cmo b.cmo ... -cclib -lmylib +\end{alltt} +The alternative is of course to build the library without extra +options: +\begin{alltt} + ocamlc -a -o mylib.cma a.cmo b.cmo +\end{alltt} +and then ask users to provide the "-custom" and "-cclib -lmylib" +options themselves at link-time: +\begin{alltt} + ocamlc -o myprog -custom mylib.cma ... -cclib -lmylib +\end{alltt} +The former alternative is more convenient for the final users of the +library, however. + +\subsection{Dynamically linking C code with OCaml code} +\label{dynlink-c-code} + +Starting with Objective Caml 3.03, an alternative to static linking of C code +using the "-custom" code is provided. In this mode, the OCaml linker +generates a pure bytecode executable (no embedded custom runtime +system) that simply records the names of dynamically-loaded libraries +containing the C code. The standard OCaml runtime system "ocamlrun" +then loads dynamically these libraries, and resolves references to the +required primitives, before executing the bytecode. + +This facility is currently supported and known to work well under +Linux, MacOS~X, and Windows. It is supported, but not +fully tested yet, under FreeBSD, Tru64, Solaris and Irix. It is not +supported yet under other Unixes. + +To dynamically link C code with OCaml code, the C code must first be +compiled into a shared library (under Unix) or DLL (under Windows). +This involves 1- compiling the C files with appropriate C compiler +flags for producing position-independent code (when required by the +operating system), and 2- building a +shared library from the resulting object files. The resulting shared +library or DLL file must be installed in a place where "ocamlrun" can +find it later at program start-up time (see +section~\ref{s-ocamlrun-dllpath}). +Finally (step 3), execute the "ocamlc" command with +\begin{itemize} +\item the names of the desired OCaml object files (".cmo" and ".cma" files) ; +\item the names of the C shared libraries (".so" or ".dll" files) that +implement the required primitives. Under Unix and Windows, +a library named "dll"\var{name}".so" (respectively, ".dll") residing +in one of the standard library directories can also be specified as +"-dllib -l"\var{name}. +\end{itemize} +Do {\em not} set the "-custom" flag, otherwise you're back to static linking +as described in section~\ref{staticlink-c-code}. +The "ocamlmklib" tool (see section~\ref{s-ocamlmklib}) +automates steps 2 and 3. + +As in the case of static linking, it is possible (and recommended) to +record the names of C libraries in an OCaml ".cma" library archive. +Consider again an OCaml library +"mylib.cma", built from the OCaml object files "a.cmo" and "b.cmo", +which reference C code in "dllmylib.so". If the library is +built as follows: +\begin{alltt} + ocamlc -a -o mylib.cma a.cmo b.cmo -dllib -lmylib +\end{alltt} +users of the library can simply link with "mylib.cma": +\begin{alltt} + ocamlc -o myprog mylib.cma ... +\end{alltt} +and the system will automatically add the "-dllib -lmylib" option, +achieving the same effect as +\begin{alltt} + ocamlc -o myprog a.cmo b.cmo ... -dllib -lmylib +\end{alltt} +Using this mechanism, users of the library "mylib.cma" do not need to +known that it references C code, nor whether this C code must be +statically linked (using "-custom") or dynamically linked. + +\subsection{Choosing between static linking and dynamic linking} + +After having described two different ways of linking C code with OCaml +code, we now review the pros and cons of each, to help developers of +mixed OCaml/C libraries decide. + +The main advantage of dynamic linking is that it preserves the +platform-independence of bytecode executables. That is, the bytecode +executable contains no machine code, and can therefore be compiled on +platform $A$ and executed on other platforms $B$, $C$, \ldots, as long +as the required shared libraries are available on all these +platforms. In contrast, executables generated by "ocamlc -custom" run +only on the platform on which they were created, because they embark a +custom-tailored runtime system specific to that platform. In +addition, dynamic linking results in smaller executables. + +Another advantage of dynamic linking is that the final users of the +library do not need to have a C compiler, C linker, and C runtime +libraries installed on their machines. This is no big deal under +Unix and Cygwin, but many Windows users are reluctant to install +Microsoft Visual C just to be able to do "ocamlc -custom". + +There are two drawbacks to dynamic linking. The first is that the +resulting executable is not stand-alone: it requires the shared +libraries, as well as "ocamlrun", to be installed on the machine +executing the code. If you wish to distribute a stand-alone +executable, it is better to link it statically, using "ocamlc -custom +-ccopt -static" or "ocamlopt -ccopt -static". Dynamic linking also +raises the ``DLL hell'' problem: some care must be taken to ensure +that the right versions of the shared libraries are found at start-up +time. + +The second drawback of dynamic linking is that it complicates the +construction of the library. The C compiler and linker flags to +compile to position-independent code and build a shared library vary +wildly between different Unix systems. Also, dynamic linking is not +supported on all Unix systems, requiring a fall-back case to static +linking in the Makefile for the library. The "ocamlmklib" command +(see section~\ref{s-ocamlmklib}) tries to hide some of these system +dependencies. + +In conclusion: dynamic linking is highly recommended under the native +Windows port, because there are no portability problems and it is much +more convenient for the end users. Under Unix, dynamic linking should +be considered for mature, frequently used libraries because it +enhances platform-independence of bytecode executables. For new or +rarely-used libraries, static linking is much simpler to set up in a +portable way. + +\subsection{Building standalone custom runtime systems} +\label{s:custom-runtime} + +It is sometimes inconvenient to build a custom runtime system each +time OCaml code is linked with C libraries, like "ocamlc -custom" does. +For one thing, the building of the runtime system is slow on some +systems (that have bad linkers or slow remote file systems); for +another thing, the platform-independence of bytecode files is lost, +forcing to perform one "ocamlc -custom" link per platform of interest. + +An alternative to "ocamlc -custom" is to build separately a custom +runtime system integrating the desired C libraries, then generate +``pure'' bytecode executables (not containing their own runtime +system) that can run on this custom runtime. This is achieved by the +"-make-runtime" and "-use-runtime" flags to "ocamlc". For example, +to build a custom runtime system integrating the C parts of the +``Unix'' and ``Threads'' libraries, do: +\begin{verbatim} + ocamlc -make-runtime -o /home/me/ocamlunixrun unix.cma threads.cma +\end{verbatim} +To generate a bytecode executable that runs on this runtime system, +do: +\begin{alltt} + ocamlc -use-runtime /home/me/ocamlunixrun -o myprog \char92 + unix.cma threads.cma {\it{your .cmo and .cma files}} +\end{alltt} +The bytecode executable "myprog" can then be launched as usual: +"myprog" \var{args} or "/home/me/ocamlunixrun myprog" \var{args}. + +Notice that the bytecode libraries "unix.cma" and "threads.cma" must +be given twice: when building the runtime system (so that "ocamlc" +knows which C primitives are required) and also when building the +bytecode executable (so that the bytecode from "unix.cma" and +"threads.cma" is actually linked in). + +\section{The \texttt{value} type} +\pdfsection{The value type} + +All OCaml objects are represented by the C type "value", +defined in the include file "caml/mlvalues.h", along with macros to +manipulate values of that type. An object of type "value" is either: +\begin{itemize} +\item an unboxed integer; +\item a pointer to a block inside the heap (such as the blocks +allocated through one of the \verb"caml_alloc_*" functions below); +\item a pointer to an object outside the heap (e.g., a pointer to a block +allocated by "malloc", or to a C variable). + %%% FIXME will change in 4.02.0 (?) +\end{itemize} + +\subsection{Integer values} + +Integer values encode 63-bit signed integers (31-bit on 32-bit +architectures). They are unboxed (unallocated). + +\subsection{Blocks} + +Blocks in the heap are garbage-collected, and therefore have strict +structure constraints. Each block includes a header containing the +size of the block (in words), and the tag of the block. +The tag governs how the contents of the blocks are structured. A tag +lower than "No_scan_tag" indicates a structured block, containing +well-formed values, which is recursively traversed by the garbage +collector. A tag greater than or equal to "No_scan_tag" indicates a +raw block, whose contents are not scanned by the garbage collector. +For the benefit of ad-hoc polymorphic primitives such as equality and +structured input-output, structured and raw blocks are further +classified according to their tags as follows: +\begin{tableau}{|l|p{10cm}|}{Tag}{Contents of the block} +\entree{0 to $\hbox{"No_scan_tag"}-1$}{A structured block (an array of +OCaml objects). Each field is a "value".} +\entree{"Closure_tag"}{A closure representing a functional value. The first +word is a pointer to a piece of code, the remaining words are +"value" containing the environment.} +\entree{"String_tag"}{A character string or a byte sequence.} +\entree{"Double_tag"}{A double-precision floating-point number.} +\entree{"Double_array_tag"}{An array or record of double-precision +floating-point numbers.} +\entree{"Abstract_tag"}{A block representing an abstract datatype.} +\entree{"Custom_tag"}{A block representing an abstract datatype + with user-defined finalization, comparison, hashing, + serialization and deserialization functions atttached.} +\end{tableau} + +\subsection{Pointers outside the heap} + +Any word-aligned pointer to an address outside the heap can be safely +cast to and from the type "value". This includes pointers returned by +"malloc", and pointers to C variables (of size at least one word) +obtained with the \verb'&' operator. + %%% FIXME will change in 4.02.0 (?) + +Caution: if a pointer returned by "malloc" is cast to the type "value" +and returned to OCaml, explicit deallocation of the pointer using +"free" is potentially dangerous, because the pointer may still be +accessible from the OCaml world. Worse, the memory space deallocated +by "free" can later be reallocated as part of the OCaml heap; the +pointer, formerly pointing outside the OCaml heap, now points inside +the OCaml heap, and this can crash the garbage collector. To avoid +these problems, it is preferable to wrap the pointer in a OCaml block +with tag "Abstract_tag" or "Custom_tag". + +\section{Representation of OCaml data types} +\pdfsection{Representation of OCaml data types} + +This section describes how OCaml data types are encoded in the +"value" type. + +\subsection{Atomic types} + +\begin{tableau}{|l|l|}{OCaml type}{Encoding} +\entree{"int"}{Unboxed integer values.} +\entree{"char"}{Unboxed integer values (ASCII code).} +\entree{"float"}{Blocks with tag "Double_tag".} +\entree{"bytes"}{Blocks with tag "String_tag".} +\entree{"string"}{Blocks with tag "String_tag".} +\entree{"int32"}{Blocks with tag "Custom_tag".} +\entree{"int64"}{Blocks with tag "Custom_tag".} +\entree{"nativeint"}{Blocks with tag "Custom_tag".} +\end{tableau} + +\subsection{Tuples and records} +\label{ss:tuples-and-records} + +Tuples are represented by pointers to blocks, with tag~0. + +Records are also represented by zero-tagged blocks. The ordering of +labels in the record type declaration determines the layout of +the record fields: the value associated to the label +declared first is stored in field~0 of the block, the value associated +to the second label goes in field~1, and so on. + +As an optimization, records whose fields all have static type "float" +are represented as arrays of floating-point numbers, with tag +"Double_array_tag". (See the section below on arrays.) + +As another optimization, unboxable record types are represented +specially; unboxable record types are the immutable record types that +have only one field. An unboxable type will be represented in one of +two ways: boxed or unboxed. Boxed record types are represented as +described above (by a block with tag 0 or "Double_array_tag"). An +unboxed record type is represented directly by the value of its field +(i.e. there is no block to represent the record itself). + +The representation is chosen according to the following, in decreasing +order of priority: +\begin{itemize} +\item An attribute ("[\@\@boxed]" or "[\@\@unboxed]") on the type declaration. +\item A compiler option ("-unboxed-types" or "-no-unboxed-types"). +\item The default representation. In the present version of OCaml, the +default is the boxed representation. +\end{itemize} + +\subsection{Arrays} + +Arrays of integers and pointers are represented like tuples, +that is, as pointers to blocks tagged~0. They are accessed with the +"Field" macro for reading and the "caml_modify" function for writing. + +Arrays of floating-point numbers (type "float array") +have a special, unboxed, more efficient representation. +These arrays are represented by pointers to blocks with tag +"Double_array_tag". They should be accessed with the "Double_field" +and "Store_double_field" macros. + +\subsection{Concrete data types} + +Constructed terms are represented either by unboxed integers (for +constant constructors) or by blocks whose tag encode the constructor +(for non-constant constructors). The constant constructors and the +non-constant constructors for a given concrete type are numbered +separately, starting from 0, in the order in which they appear in the +concrete type declaration. A constant constructor is represented by +the unboxed integer equal to its constructor number. A non-constant +constructor declared with $n$ arguments is represented by +a block of size $n$, tagged with the constructor number; the $n$ +fields contain its arguments. Example: + +\begin{tableau}{|l|p{8cm}|}{Constructed term}{Representation} +\entree{"()"}{"Val_int(0)"} +\entree{"false"}{"Val_int(0)"} +\entree{"true"}{"Val_int(1)"} +\entree{"[]"}{"Val_int(0)"} +\entree{"h::t"}{Block with size = 2 and tag = 0; first field +contains "h", second field "t".} +\end{tableau} + +As a convenience, "caml/mlvalues.h" defines the macros "Val_unit", +"Val_false" and "Val_true" to refer to "()", "false" and "true". + +The following example illustrates the assignment of +integers and block tags to constructors: +\begin{verbatim} +type t = + | A (* First constant constructor -> integer "Val_int(0)" *) + | B of string (* First non-constant constructor -> block with tag 0 *) + | C (* Second constant constructor -> integer "Val_int(1)" *) + | D of bool (* Second non-constant constructor -> block with tag 1 *) + | E of t * t (* Third non-constant constructor -> block with tag 2 *) +\end{verbatim} + + +As an optimization, unboxable concrete data types are represented +specially; a concrete data type is unboxable if it has exactly one +constructor and this constructor has exactly one argument. Unboxable +concrete data types are represented in the same ways as unboxable +record types: see the description in +section~\ref{ss:tuples-and-records}. + +\subsection{Objects} + +Objects are represented as blocks with tag "Object_tag". The first +field of the block refers to the object's class and associated method +suite, in a format that cannot easily be exploited from C. The second +field contains a unique object ID, used for comparisons. The remaining +fields of the object contain the values of the instance variables of +the object. It is unsafe to access directly instance variables, as the +type system provides no guarantee about the instance variables +contained by an object. +% Instance variables are stored in the order in which they +% appear in the class definition (taking inherited classes into +% account). + +One may extract a public method from an object using the C function +"caml_get_public_method" (declared in "".) +Since public method tags are hashed in the same way as variant tags, +and methods are functions taking self as first argument, if you want +to do the method call "foo#bar" from the C side, you should call: +\begin{verbatim} + callback(caml_get_public_method(foo, hash_variant("bar")), foo); +\end{verbatim} + +\subsection{Polymorphic variants} + +Like constructed terms, polymorphic variant values are represented either +as integers (for polymorphic variants without argument), or as blocks +(for polymorphic variants with an argument). Unlike constructed +terms, variant constructors are not numbered starting from 0, but +identified by a hash value (an OCaml integer), as computed by the C function +"hash_variant" (declared in ""): +the hash value for a variant constructor named, say, "VConstr" +is "hash_variant(\"VConstr\")". + +The variant value "`VConstr" is represented by +"hash_variant(\"VConstr\")". The variant value "`VConstr("\var{v}")" is +represented by a block of size 2 and tag 0, with field number 0 +containing "hash_variant(\"VConstr\")" and field number 1 containing +\var{v}. + +Unlike constructed values, polymorphic variant values taking several +arguments are not flattened. +That is, "`VConstr("\var{v}", "\var{w}")" is represented by a block +of size 2, whose field number 1 contains the representation of the +pair "("\var{v}", "\var{w}")", rather than a block of size 3 +containing \var{v} and \var{w} in fields 1 and 2. + +\section{Operations on values} +\pdfsection{Operations on values} + +\subsection{Kind tests} + +\begin{itemize} +\item "Is_long("\var{v}")" is true if value \var{v} is an immediate integer, +false otherwise +\item "Is_block("\var{v}")" is true if value \var{v} is a pointer to a block, +and false if it is an immediate integer. +\end{itemize} + +\subsection{Operations on integers} + +\begin{itemize} +\item "Val_long("\var{l}")" returns the value encoding the "long int" \var{l}. +\item "Long_val("\var{v}")" returns the "long int" encoded in value \var{v}. +\item "Val_int("\var{i}")" returns the value encoding the "int" \var{i}. +\item "Int_val("\var{v}")" returns the "int" encoded in value \var{v}. +\item "Val_bool("\var{x}")" returns the OCaml boolean representing the +truth value of the C integer \var{x}. +\item "Bool_val("\var{v}")" returns 0 if \var{v} is the OCaml boolean +"false", 1 if \var{v} is "true". +\item "Val_true", "Val_false" represent the OCaml booleans "true" and "false". +\end{itemize} + +\subsection{Accessing blocks} + +\begin{itemize} +\item "Wosize_val("\var{v}")" returns the size of the block \var{v}, in words, +excluding the header. +\item "Tag_val("\var{v}")" returns the tag of the block \var{v}. +\item "Field("\var{v}", "\var{n}")" returns the value contained in the +$n\th$ field of the structured block \var{v}. Fields are numbered from 0 to +$\hbox{"Wosize_val"}(v)-1$. +\item "Store_field("\var{b}", "\var{n}", "\var{v}")" stores the value +\var{v} in the field number \var{n} of value \var{b}, which must be a +structured block. +\item "Code_val("\var{v}")" returns the code part of the closure \var{v}. +\item "caml_string_length("\var{v}")" returns the length (number of bytes) +of the string or byte sequence \var{v}. +\item "Byte("\var{v}", "\var{n}")" returns the $n\th$ byte of the string +or byte sequence \var{v}, with type "char". Bytes are numbered from 0 to +$\hbox{"string_length"}(v)-1$. +\item "Byte_u("\var{v}", "\var{n}")" returns the $n\th$ byte of the string +or byte sequence \var{v}, with type "unsigned char". Bytes are +numbered from 0 to $\hbox{"string_length"}(v)-1$. +\item "String_val("\var{v}")" returns a pointer to the first byte of the string +\var{v}, with type "char *" or, when OCaml is configured with +"-force-safe-string", with type "const char *". +This pointer is a valid C string: there is a null byte after the last +byte in the string. However, OCaml strings can contain embedded null bytes, +which will confuse the usual C functions over strings. +\item "Bytes_val("\var{v}")" returns a pointer to the first byte of the +byte sequence \var{v}, with type "unsigned char *". +\item "Double_val("\var{v}")" returns the floating-point number contained in +value \var{v}, with type "double". +\item "Double_field("\var{v}", "\var{n}")" returns +the $n\th$ element of the array of floating-point numbers \var{v} (a +block tagged "Double_array_tag"). +\item "Store_double_field("\var{v}", "\var{n}", +"\var{d}")" stores the double precision floating-point number \var{d} +in the $n\th$ element of the array of floating-point numbers \var{v}. +\item "Data_custom_val("\var{v}")" returns a pointer to the data part +of the custom block \var{v}. This pointer has type "void *" and must +be cast to the type of the data contained in the custom block. +\item "Int32_val("\var{v}")" returns the 32-bit integer contained +in the "int32" \var{v}. +\item "Int64_val("\var{v}")" returns the 64-bit integer contained +in the "int64" \var{v}. +\item "Nativeint_val("\var{v}")" returns the long integer contained +in the "nativeint" \var{v}. +\item "caml_field_unboxed("\var{v}")" returns the value of the field +of a value \var{v} of any unboxed type (record or concrete data type). +\item "caml_field_boxed("\var{v}")" returns the value of the field +of a value \var{v} of any boxed type (record or concrete data type). +\item "caml_field_unboxable("\var{v}")" calls either +"caml_field_unboxed" or "caml_field_boxed" according to the default +representation of unboxable types in the current version of OCaml. +\end{itemize} +The expressions "Field("\var{v}", "\var{n}")", +"Byte("\var{v}", "\var{n}")" and +"Byte_u("\var{v}", "\var{n}")" +are valid l-values. Hence, they can be assigned to, resulting in an +in-place modification of value \var{v}. +Assigning directly to "Field("\var{v}", "\var{n}")" must +be done with care to avoid confusing the garbage collector (see +below). + +\subsection{Allocating blocks} + +\subsubsection{Simple interface} + +\begin{itemize} +\item +"Atom("\var{t}")" returns an ``atom'' (zero-sized block) with tag \var{t}. +Zero-sized blocks are preallocated outside of the heap. It is +incorrect to try and allocate a zero-sized block using the functions below. +For instance, "Atom(0)" represents the empty array. +\item +"caml_alloc("\var{n}", "\var{t}")" returns a fresh block of size \var{n} +with tag \var{t}. If \var{t} is less than "No_scan_tag", then the +fields of the block are initialized with a valid value in order to +satisfy the GC constraints. +\item +"caml_alloc_tuple("\var{n}")" returns a fresh block of size +\var{n} words, with tag 0. +\item +"caml_alloc_string("\var{n}")" returns a byte sequence (or string) value of +length \var{n} bytes. The sequence initially contains uninitialized bytes. +\item +"caml_alloc_initialized_string("\var{n}", "\var{p}")" returns a byte sequence +(or string) value of length \var{n} bytes. The value is initialized from the +\var{n} bytes starting at address \var{p}. +\item +"caml_copy_string("\var{s}")" returns a string or byte sequence value +containing a copy of the null-terminated C string \var{s} (a "char *"). +\item +"caml_copy_double("\var{d}")" returns a floating-point value initialized +with the "double" \var{d}. +\item +"caml_copy_int32("\var{i}")", "caml_copy_int64("\var{i}")" and +"caml_copy_nativeint("\var{i}")" return a value of OCaml type "int32", +"int64" and "nativeint", respectively, initialized with the integer +\var{i}. +\item +"caml_alloc_array("\var{f}", "\var{a}")" allocates an array of values, calling +function \var{f} over each element of the input array \var{a} to transform it +into a value. The array \var{a} is an array of pointers terminated by the +null pointer. The function \var{f} receives each pointer as argument, and +returns a value. The zero-tagged block returned by +"alloc_array("\var{f}", "\var{a}")" is filled with the values returned by the +successive calls to \var{f}. (This function must not be used to build +an array of floating-point numbers.) +\item +"caml_copy_string_array("\var{p}")" allocates an array of strings or byte +sequences, copied from the pointer to a string array \var{p} +(a "char **"). \var{p} must be NULL-terminated. +\item "caml_alloc_float_array("\var{n}")" allocates an array of floating point + numbers of size \var{n}. The array initially contains uninitialized values. +\item "caml_alloc_unboxed("\var{v}")" returns the value (of any unboxed +type) whose field is the value \var{v}. +\item "caml_alloc_boxed("\var{v}")" allocates and returns a value (of +any boxed type) whose field is the value \var{v}. +\item "caml_alloc_unboxable("\var{v}")" calls either +"caml_alloc_unboxed" or "caml_alloc_boxed" according to the default +representation of unboxable types in the current version of OCaml. +\end{itemize} + +\subsubsection{Low-level interface} + +The following functions are slightly more efficient than "caml_alloc", but +also much more difficult to use. + +From the standpoint of the allocation functions, blocks are divided +according to their size as zero-sized blocks, small blocks (with size +less than or equal to \verb"Max_young_wosize"), and large blocks (with +size greater than \verb"Max_young_wosize"). The constant +\verb"Max_young_wosize" is declared in the include file "mlvalues.h". It +is guaranteed to be at least 64 (words), so that any block with +constant size less than or equal to 64 can be assumed to be small. For +blocks whose size is computed at run-time, the size must be compared +against \verb"Max_young_wosize" to determine the correct allocation procedure. + +\begin{itemize} +\item +"caml_alloc_small("\var{n}", "\var{t}")" returns a fresh small block of size +$n \leq \hbox{"Max_young_wosize"}$ words, with tag \var{t}. +If this block is a structured block (i.e. if $t < \hbox{"No_scan_tag"}$), then +the fields of the block (initially containing garbage) must be initialized +with legal values (using direct assignment to the fields of the block) +before the next allocation. +\item +"caml_alloc_shr("\var{n}", "\var{t}")" returns a fresh block of size +\var{n}, with tag \var{t}. +The size of the block can be greater than \verb"Max_young_wosize". (It +can also be smaller, but in this case it is more efficient to call +"caml_alloc_small" instead of "caml_alloc_shr".) +If this block is a structured block (i.e. if $t < \hbox{"No_scan_tag"}$), then +the fields of the block (initially containing garbage) must be initialized +with legal values (using the "caml_initialize" function described below) +before the next allocation. +\end{itemize} + +\subsection{Raising exceptions} \label{s:c-exceptions} + +Two functions are provided to raise two standard exceptions: +\begin{itemize} +\item "caml_failwith("\var{s}")", where \var{s} is a null-terminated C string (with +type \verb"char *"), raises exception "Failure" with argument \var{s}. +\item "caml_invalid_argument("\var{s}")", where \var{s} is a null-terminated C +string (with type \verb"char *"), raises exception "Invalid_argument" +with argument \var{s}. +\end{itemize} + +Raising arbitrary exceptions from C is more delicate: the +exception identifier is dynamically allocated by the OCaml program, and +therefore must be communicated to the C function using the +registration facility described below in section~\ref{s:register-exn}. +Once the exception identifier is recovered in C, the following +functions actually raise the exception: +\begin{itemize} +\item "caml_raise_constant("\var{id}")" raises the exception \var{id} with +no argument; +\item "caml_raise_with_arg("\var{id}", "\var{v}")" raises the exception +\var{id} with the OCaml value \var{v} as argument; +\item "caml_raise_with_args("\var{id}", "\var{n}", "\var{v}")" +raises the exception \var{id} with the OCaml values +\var{v}"[0]", \ldots, \var{v}"["\var{n}"-1]" as arguments; +\item "caml_raise_with_string("\var{id}", "\var{s}")", where \var{s} is a +null-terminated C string, raises the exception \var{id} with a copy of +the C string \var{s} as argument. +\end{itemize} + +\section{Living in harmony with the garbage collector} +\pdfsection{Living in harmony with the garbage collector} + +Unused blocks in the heap are automatically reclaimed by the garbage +collector. This requires some cooperation from C code that +manipulates heap-allocated blocks. + +\subsection{Simple interface} + +All the macros described in this section are declared in the +"memory.h" header file. + +\begin{gcrule} +A function that has parameters or local variables of type "value" must +begin with a call to one of the "CAMLparam" macros and return with +"CAMLreturn", "CAMLreturn0", or "CAMLreturnT". In particular, "CAMLlocal" +and "CAMLxparam" can only be called \emph{after} "CAMLparam". +\end{gcrule} + +There are six "CAMLparam" macros: "CAMLparam0" to "CAMLparam5", which +take zero to five arguments respectively. If your function has no more +than 5 parameters of type "value", use the corresponding macros +with these parameters as arguments. If your function has more than 5 +parameters of type "value", use "CAMLparam5" with five of these +parameters, and use one or more calls to the "CAMLxparam" macros for +the remaining parameters ("CAMLxparam1" to "CAMLxparam5"). + +The macros "CAMLreturn", "CAMLreturn0", and "CAMLreturnT" are used to +replace the C +keyword "return". Every occurrence of "return x" must be replaced by +"CAMLreturn (x)" if "x" has type "value", or "CAMLreturnT (t, x)" +(where "t" is the type of "x"); every occurrence of "return" without +argument must be +replaced by "CAMLreturn0". If your C function is a procedure (i.e. if +it returns void), you must insert "CAMLreturn0" at the end (to replace +C's implicit "return"). + +\paragraph{Note:} some C compilers give bogus warnings about unused +variables "caml__dummy_xxx" at each use of "CAMLparam" and +"CAMLlocal". You should ignore them. + +\goodbreak + +Example: +\begin{verbatim} +void foo (value v1, value v2, value v3) +{ + CAMLparam3 (v1, v2, v3); + ... + CAMLreturn0; +} +\end{verbatim} + +\paragraph{Note:} if your function is a primitive with more than 5 arguments +for use with the byte-code runtime, its arguments are not "value"s and +must not be declared (they have types "value *" and "int"). + +\begin{gcrule} +Local variables of type "value" must be declared with one of the +"CAMLlocal" macros. Arrays of "value"s are declared with +"CAMLlocalN". These macros must be used at the beginning of the +function, not in a nested block. +\end{gcrule} + +The macros "CAMLlocal1" to "CAMLlocal5" declare and initialize one to +five local variables of type "value". The variable names are given as +arguments to the macros. "CAMLlocalN("\var{x}", "\var{n}")" declares +and initializes a local variable of type "value ["\var{n}"]". You can +use several calls to these macros if you have more than 5 local +variables. + +Example: +\begin{verbatim} +value bar (value v1, value v2, value v3) +{ + CAMLparam3 (v1, v2, v3); + CAMLlocal1 (result); + result = caml_alloc (3, 0); + ... + CAMLreturn (result); +} +\end{verbatim} + +\begin{gcrule} +Assignments to the fields of structured blocks must be done with the +"Store_field" macro (for normal blocks) or "Store_double_field" macro +(for arrays and records of floating-point numbers). Other assignments +must not use "Store_field" nor "Store_double_field". +\end{gcrule} + +"Store_field ("\var{b}", "\var{n}", "\var{v}")" stores the value +\var{v} in the field number \var{n} of value \var{b}, which must be a +block (i.e. "Is_block("\var{b}")" must be true). + +Example: +\begin{verbatim} +value bar (value v1, value v2, value v3) +{ + CAMLparam3 (v1, v2, v3); + CAMLlocal1 (result); + result = caml_alloc (3, 0); + Store_field (result, 0, v1); + Store_field (result, 1, v2); + Store_field (result, 2, v3); + CAMLreturn (result); +} +\end{verbatim} + +\paragraph{Warning:} The first argument of "Store_field" and +"Store_double_field" must be a variable declared by "CAMLparam*" or +a parameter declared by "CAMLlocal*" to ensure that a garbage +collection triggered by the evaluation of the other arguments will not +invalidate the first argument after it is computed. + +\paragraph{Use with CAMLlocalN:} Arrays of values declared using +"CAMLlocalN" must not be written to using "Store_field". +Use the normal C array syntax instead. + +\begin{gcrule} Global variables containing values must be registered +with the garbage collector using the "caml_register_global_root" function. +\end{gcrule} + +Registration of a global variable "v" is achieved by calling +"caml_register_global_root(&v)" just before or just after a valid +value is stored in "v" for the first time. You must not call any +of the OCaml runtime functions or macros between registering and +storing the value. + +A registered global variable "v" can be un-registered by calling +"caml_remove_global_root(&v)". + +If the contents of the global variable "v" are seldom modified after +registration, better performance can be achieved by calling +"caml_register_generational_global_root(&v)" to register "v" (after +its initialization with a valid "value", but before any allocation or +call to the GC functions), +and "caml_remove_generational_global_root(&v)" to un-register it. In +this case, you must not modify the value of "v" directly, but you must +use "caml_modify_generational_global_root(&v,x)" to set it to "x". +The garbage collector takes advantage of the guarantee that "v" is not +modified between calls to "caml_modify_generational_global_root" to scan it +less often. This improves performance if the +modifications of "v" happen less often than minor collections. + +\paragraph{Note:} The "CAML" macros use identifiers (local variables, type +identifiers, structure tags) that start with "caml__". Do not use any +identifier starting with "caml__" in your programs. + +\subsection{Low-level interface} + +% Il faudrait simplifier violemment ce qui suit. +% En gros, dire quand on n'a pas besoin de declarer les variables +% et dans quels cas on peut se passer de "Store_field". + +We now give the GC rules corresponding to the low-level allocation +functions "caml_alloc_small" and "caml_alloc_shr". You can ignore those rules +if you stick to the simplified allocation function "caml_alloc". + +\begin{gcrule} After a structured block (a block with tag less than +"No_scan_tag") is allocated with the low-level functions, all fields +of this block must be filled with well-formed values before the next +allocation operation. If the block has been allocated with +"caml_alloc_small", filling is performed by direct assignment to the fields +of the block: +\begin{alltt} + Field(\var{v}, \var{n}) = \nth{v}{n}; +\end{alltt} +If the block has been allocated with "caml_alloc_shr", filling is performed +through the "caml_initialize" function: +\begin{alltt} + caml_initialize(&Field(\var{v}, \var{n}), \nth{v}{n}); +\end{alltt} +\end{gcrule} + +The next allocation can trigger a garbage collection. The garbage +collector assumes that all structured blocks contain well-formed +values. Newly created blocks contain random data, which generally do +not represent well-formed values. + +If you really need to allocate before the fields can receive their +final value, first initialize with a constant value (e.g. +"Val_unit"), then allocate, then modify the fields with the correct +value (see rule~6). + +%% \begin{gcrule} Local variables and function parameters containing +%% values must be registered with the garbage collector (using the +%% "Begin_roots" and "End_roots" macros), if they are to survive a call +%% to an allocation function. +%% \end{gcrule} +%% +%% Registration is performed with the "Begin_roots" set of macros. +%% "Begin_roots1("\var{v}")" registers variable \var{v} with the garbage +%% collector. Generally, \var{v} will be a local variable or a +%% parameter of your function. It must be initialized to a valid value +%% (e.g. "Val_unit") before the first allocation. Likewise, +%% "Begin_roots2", \ldots, "Begin_roots5" +%% let you register up to 5 variables at the same time. "Begin_root" is +%% the same as "Begin_roots1". "Begin_roots_block("\var{ptr}","\var{size}")" +%% allows you to register an array of roots. \var{ptr} is a pointer to +%% the first element, and \var{size} is the number of elements in the +%% array. +%% +%% Once registered, each of your variables (or array element) has the +%% following properties: if it points to a heap-allocated block, this +%% block (and its contents) will not be reclaimed; moreover, if this +%% block is relocated by the garbage collector, the variable is updated +%% to point to the new location for the block. +%% +%% Each of the "Begin_roots" macros open a C block that must be closed +%% with a matching "End_roots" at the same nesting level. The block must +%% be exited normally (i.e. not with "return" or "goto"). However, the +%% roots are automatically un-registered if an OCaml exception is raised, +%% so you can exit the block with "failwith", "invalid_argument", or one +%% of the "raise" functions. +%% +%% {\bf Note:} The "Begin_roots" macros use a local variable and a +%% structure tag named "caml__roots_block". Do not use this identifier +%% in your programs. + +\begin{gcrule} Direct assignment to a field of a block, as in +\begin{alltt} + Field(\var{v}, \var{n}) = \var{w}; +\end{alltt} +is safe only if \var{v} is a block newly allocated by "caml_alloc_small"; +that is, if no allocation took place between the +allocation of \var{v} and the assignment to the field. In all other cases, +never assign directly. If the block has just been allocated by "caml_alloc_shr", +use "caml_initialize" to assign a value to a field for the first time: +\begin{alltt} + caml_initialize(&Field(\var{v}, \var{n}), \var{w}); +\end{alltt} +Otherwise, you are updating a field that previously contained a +well-formed value; then, call the "caml_modify" function: +\begin{alltt} + caml_modify(&Field(\var{v}, \var{n}), \var{w}); +\end{alltt} +\end{gcrule} + +To illustrate the rules above, here is a C function that builds and +returns a list containing the two integers given as parameters. +First, we write it using the simplified allocation functions: +\begin{verbatim} +value alloc_list_int(int i1, int i2) +{ + CAMLparam0 (); + CAMLlocal2 (result, r); + + r = caml_alloc(2, 0); /* Allocate a cons cell */ + Store_field(r, 0, Val_int(i2)); /* car = the integer i2 */ + Store_field(r, 1, Val_int(0)); /* cdr = the empty list [] */ + result = caml_alloc(2, 0); /* Allocate the other cons cell */ + Store_field(result, 0, Val_int(i1)); /* car = the integer i1 */ + Store_field(result, 1, r); /* cdr = the first cons cell */ + CAMLreturn (result); +} +\end{verbatim} +Here, the registering of "result" is not strictly needed, because no +allocation takes place after it gets its value, but it's easier and +safer to simply register all the local variables that have type "value". + +Here is the same function written using the low-level allocation +functions. We notice that the cons cells are small blocks and can be +allocated with "caml_alloc_small", and filled by direct assignments on +their fields. +\begin{verbatim} +value alloc_list_int(int i1, int i2) +{ + CAMLparam0 (); + CAMLlocal2 (result, r); + + r = caml_alloc_small(2, 0); /* Allocate a cons cell */ + Field(r, 0) = Val_int(i2); /* car = the integer i2 */ + Field(r, 1) = Val_int(0); /* cdr = the empty list [] */ + result = caml_alloc_small(2, 0); /* Allocate the other cons cell */ + Field(result, 0) = Val_int(i1); /* car = the integer i1 */ + Field(result, 1) = r; /* cdr = the first cons cell */ + CAMLreturn (result); +} +\end{verbatim} +In the two examples above, the list is built bottom-up. Here is an +alternate way, that proceeds top-down. It is less efficient, but +illustrates the use of "caml_modify". +\begin{verbatim} +value alloc_list_int(int i1, int i2) +{ + CAMLparam0 (); + CAMLlocal2 (tail, r); + + r = caml_alloc_small(2, 0); /* Allocate a cons cell */ + Field(r, 0) = Val_int(i1); /* car = the integer i1 */ + Field(r, 1) = Val_int(0); /* A dummy value + tail = caml_alloc_small(2, 0); /* Allocate the other cons cell */ + Field(tail, 0) = Val_int(i2); /* car = the integer i2 */ + Field(tail, 1) = Val_int(0); /* cdr = the empty list [] */ + caml_modify(&Field(r, 1), tail); /* cdr of the result = tail */ + CAMLreturn (r); +} +\end{verbatim} +It would be incorrect to perform +"Field(r, 1) = tail" directly, because the allocation of "tail" +has taken place since "r" was allocated. + + +\section{A complete example} +\pdfsection{A complete example} + +This section outlines how the functions from the Unix "curses" library +can be made available to OCaml programs. First of all, here is +the interface "curses.ml" that declares the "curses" primitives and +data types: +\begin{verbatim} +(* File curses.ml -- declaration of primitives and data types *) +type window (* The type "window" remains abstract *) +external initscr: unit -> window = "caml_curses_initscr" +external endwin: unit -> unit = "caml_curses_endwin" +external refresh: unit -> unit = "caml_curses_refresh" +external wrefresh : window -> unit = "caml_curses_wrefresh" +external newwin: int -> int -> int -> int -> window = "caml_curses_newwin" +external addch: char -> unit = "caml_curses_addch" +external mvwaddch: window -> int -> int -> char -> unit = "caml_curses_mvwaddch" +external addstr: string -> unit = "caml_curses_addstr" +external mvwaddstr: window -> int -> int -> string -> unit + = "caml_curses_mvwaddstr" +(* lots more omitted *) +\end{verbatim} +To compile this interface: +\begin{verbatim} + ocamlc -c curses.ml +\end{verbatim} + +To implement these functions, we just have to provide the stub code; +the core functions are already implemented in the "curses" library. +The stub code file, "curses_stubs.c", looks like this: +\begin{verbatim} +/* File curses_stubs.c -- stub code for curses */ +#include +#include +#include +#include +#include + +/* Encapsulation of opaque window handles (of type WINDOW *) + as OCaml custom blocks. */ + +static struct custom_operations curses_window_ops = { + "fr.inria.caml.curses_windows", + custom_finalize_default, + custom_compare_default, + custom_hash_default, + custom_serialize_default, + custom_deserialize_default, + custom_compare_ext_default +}; + +/* Accessing the WINDOW * part of an OCaml custom block */ +#define Window_val(v) (*((WINDOW **) Data_custom_val(v))) + +/* Allocating an OCaml custom block to hold the given WINDOW * */ +static value alloc_window(WINDOW * w) +{ + value v = alloc_custom(&curses_window_ops, sizeof(WINDOW *), 0, 1); + Window_val(v) = w; + return v; +} + +value caml_curses_initscr(value unit) +{ + CAMLparam1 (unit); + CAMLreturn (alloc_window(initscr())); +} + +value caml_curses_endwin(value unit) +{ + CAMLparam1 (unit); + endwin(); + CAMLreturn (Val_unit); +} + +value caml_curses_refresh(value unit) +{ + CAMLparam1 (unit); + refresh(); + CAMLreturn (Val_unit); +} + +value caml_curses_wrefresh(value win) +{ + CAMLparam1 (win); + wrefresh(Window_val(win)); + CAMLreturn (Val_unit); +} + +value caml_curses_newwin(value nlines, value ncols, value x0, value y0) +{ + CAMLparam4 (nlines, ncols, x0, y0); + CAMLreturn (alloc_window(newwin(Int_val(nlines), Int_val(ncols), + Int_val(x0), Int_val(y0)))); +} + +value caml_curses_addch(value c) +{ + CAMLparam1 (c); + addch(Int_val(c)); /* Characters are encoded like integers */ + CAMLreturn (Val_unit); +} + +value caml_curses_mvwaddch(value win, value x, value y, value c) +{ + CAMLparam4 (win, x, y, c); + mvwaddch(Window_val(win), Int_val(x), Int_val(y), Int_val(c)); + CAMLreturn (Val_unit); +} + +value caml_curses_addstr(value s) +{ + CAMLparam1 (s); + addstr(String_val(s)); + CAMLreturn (Val_unit); +} + +value caml_curses_mvwaddstr(value win, value x, value y, value s) +{ + CAMLparam4 (win, x, y, s); + mvwaddstr(Window_val(win), Int_val(x), Int_val(y), String_val(s)); + CAMLreturn (Val_unit); +} + +/* This goes on for pages. */ +\end{verbatim} + +The file "curses_stubs.c" can be compiled with: +\begin{verbatim} + cc -c -I`ocamlc -where` curses_stubs.c +\end{verbatim} +or, even simpler, +\begin{verbatim} + ocamlc -c curses_stubs.c +\end{verbatim} +(When passed a ".c" file, the "ocamlc" command simply calls the C +compiler on that file, with the right "-I" option.) + +Now, here is a sample OCaml program "prog.ml" that uses the "curses" +module: +\begin{verbatim} +(* File prog.ml -- main program using curses *) +open Curses;; +let main_window = initscr () in +let small_window = newwin 10 5 20 10 in + mvwaddstr main_window 10 2 "Hello"; + mvwaddstr small_window 4 3 "world"; + refresh(); + Unix.sleep 5; + endwin() +\end{verbatim} +To compile and link this program, run: +\begin{verbatim} + ocamlc -custom -o prog unix.cma curses.cmo prog.ml curses_stubs.o -cclib -lcurses +\end{verbatim} +(On some machines, you may need to put +"-cclib -lcurses -cclib -ltermcap" or "-cclib -ltermcap" +instead of "-cclib -lcurses".) + +%% Note by Damien: when I launch the program, it only displays "Hello" +%% and not "world". Why? + +\section{Advanced topic: callbacks from C to OCaml} \label{s:callback} +\pdfsection{Advanced topic: callbacks from C to OCaml} + +So far, we have described how to call C functions from OCaml. In this +section, we show how C functions can call OCaml functions, either as +callbacks (OCaml calls C which calls OCaml), or with the main program +written in C. + +\subsection{Applying OCaml closures from C} \label{s:callbacks} + +C functions can apply OCaml function values (closures) to OCaml values. +The following functions are provided to perform the applications: +\begin{itemize} +\item "caml_callback("\var{f, a}")" applies the functional value \var{f} to +the value \var{a} and returns the value returned by~\var{f}. +\item "caml_callback2("\var{f, a, b}")" applies the functional value \var{f} +(which is assumed to be a curried OCaml function with two arguments) to +\var{a} and \var{b}. +\item "caml_callback3("\var{f, a, b, c}")" applies the functional value \var{f} +(a curried OCaml function with three arguments) to \var{a}, \var{b} and \var{c}. +\item "caml_callbackN("\var{f, n, args}")" applies the functional value \var{f} +to the \var{n} arguments contained in the array of values \var{args}. +\end{itemize} +If the function \var{f} does not return, but raises an exception that +escapes the scope of the application, then this exception is +propagated to the next enclosing OCaml code, skipping over the C +code. That is, if an OCaml function \var{f} calls a C function \var{g} that +calls back an OCaml function \var{h} that raises a stray exception, then the +execution of \var{g} is interrupted and the exception is propagated back +into \var{f}. + +If the C code wishes to catch exceptions escaping the OCaml function, +it can use the functions "caml_callback_exn", "caml_callback2_exn", +"caml_callback3_exn", "caml_callbackN_exn". These functions take the same +arguments as their non-"_exn" counterparts, but catch escaping +exceptions and return them to the C code. The return value \var{v} of the +"caml_callback*_exn" functions must be tested with the macro +"Is_exception_result("\var{v}")". If the macro returns ``false'', no +exception occured, and \var{v} is the value returned by the OCaml +function. If "Is_exception_result("\var{v}")" returns ``true'', +an exception escaped, and its value (the exception descriptor) can be +recovered using "Extract_exception("\var{v}")". + +\paragraph{Warning:} If the OCaml function returned with an exception, +"Extract_exception" should be applied to the exception result prior +to calling a function that may trigger garbage collection. +Otherwise, if \var{v} is reachable during garbage collection, the runtime +can crash since \var{v} does not contain a valid value. + +Example: +\begin{verbatim} + value call_caml_f_ex(value closure, value arg) + { + CAMLparam2(closure, arg); + CAMLlocal2(res, tmp); + res = caml_callback_exn(closure, arg); + if(Is_exception_result(res)) { + res = Extract_exception(res); + tmp = caml_alloc(3, 0); /* Safe to allocate: res contains valid value. */ + ... + } + CAMLreturn (res); + } +\end{verbatim} + +\subsection{Obtaining or registering OCaml closures for use in C functions} + +There are two ways to obtain OCaml function values (closures) to +be passed to the "callback" functions described above. One way is to +pass the OCaml function as an argument to a primitive function. For +example, if the OCaml code contains the declaration +\begin{verbatim} + external apply : ('a -> 'b) -> 'a -> 'b = "caml_apply" +\end{verbatim} +the corresponding C stub can be written as follows: +\begin{verbatim} + CAMLprim value caml_apply(value vf, value vx) + { + CAMLparam2(vf, vx); + CAMLlocal1(vy); + vy = caml_callback(vf, vx); + CAMLreturn(vy); + } +\end{verbatim} + +Another possibility is to use the registration mechanism provided by +OCaml. This registration mechanism enables OCaml code to register +OCaml functions under some global name, and C code to retrieve the +corresponding closure by this global name. + +On the OCaml side, registration is performed by evaluating +"Callback.register" \var{n} \var{v}. Here, \var{n} is the global name +(an arbitrary string) and \var{v} the OCaml value. For instance: +\begin{verbatim} + let f x = print_string "f is applied to "; print_int x; print_newline() + let _ = Callback.register "test function" f +\end{verbatim} + +On the C side, a pointer to the value registered under name \var{n} is +obtained by calling "caml_named_value("\var{n}")". The returned +pointer must then be dereferenced to recover the actual OCaml value. +If no value is registered under the name \var{n}, the null pointer is +returned. For example, here is a C wrapper that calls the OCaml function "f" +above: +\begin{verbatim} + void call_caml_f(int arg) + { + caml_callback(*caml_named_value("test function"), Val_int(arg)); + } +\end{verbatim} + +The pointer returned by "caml_named_value" is constant and can safely +be cached in a C variable to avoid repeated name lookups. On the other +hand, the value pointed to can change during garbage collection and +must always be recomputed at the point of use. Here is a more +efficient variant of "call_caml_f" above that calls "caml_named_value" +only once: +\begin{verbatim} + void call_caml_f(int arg) + { + static value * closure_f = NULL; + if (closure_f == NULL) { + /* First time around, look up by name */ + closure_f = caml_named_value("test function"); + } + caml_callback(*closure_f, Val_int(arg)); + } +\end{verbatim} + +\subsection{Registering OCaml exceptions for use in C functions} \label{s:register-exn} + +The registration mechanism described above can also be used to +communicate exception identifiers from OCaml to C. The OCaml code +registers the exception by evaluating +"Callback.register_exception" \var{n} \var{exn}, where \var{n} is an +arbitrary name and \var{exn} is an exception value of the +exception to register. For example: +\begin{verbatim} + exception Error of string + let _ = Callback.register_exception "test exception" (Error "any string") +\end{verbatim} +The C code can then recover the exception identifier using +"caml_named_value" and pass it as first argument to the functions +"raise_constant", "raise_with_arg", and "raise_with_string" (described +in section~\ref{s:c-exceptions}) to actually raise the exception. For +example, here is a C function that raises the "Error" exception with +the given argument: +\begin{verbatim} + void raise_error(char * msg) + { + caml_raise_with_string(*caml_named_value("test exception"), msg); + } +\end{verbatim} + +\subsection{Main program in C} \label{s:main-c} + +In normal operation, a mixed OCaml/C program starts by executing the +OCaml initialization code, which then may proceed to call C +functions. We say that the main program is the OCaml code. In some +applications, it is desirable that the C code plays the role of the +main program, calling OCaml functions when needed. This can be achieved as +follows: +\begin{itemize} +\item The C part of the program must provide a "main" function, +which will override the default "main" function provided by the OCaml +runtime system. Execution will start in the user-defined "main" function +just like for a regular C program. + +\item At some point, the C code must call "caml_main(argv)" to +initialize the OCaml code. The "argv" argument is a C array of strings +(type "char **"), terminated with a "NULL" pointer, +which represents the command-line arguments, as +passed as second argument to "main". The OCaml array "Sys.argv" will +be initialized from this parameter. For the bytecode compiler, +"argv[0]" and "argv[1]" are also consulted to find the file containing +the bytecode. + +\item The call to "caml_main" initializes the OCaml runtime system, +loads the bytecode (in the case of the bytecode compiler), and +executes the initialization code of the OCaml program. Typically, this +initialization code registers callback functions using "Callback.register". +Once the OCaml initialization code is complete, control returns to the +C code that called "caml_main". + +\item The C code can then invoke OCaml functions using the callback +mechanism (see section~\ref{s:callbacks}). +\end{itemize} + +\subsection{Embedding the OCaml code in the C code} \label{s:embedded-code} + +The bytecode compiler in custom runtime mode ("ocamlc -custom") +normally appends the bytecode to the executable file containing the +custom runtime. This has two consequences. First, the final linking +step must be performed by "ocamlc". Second, the OCaml runtime library +must be able to find the name of the executable file from the +command-line arguments. When using "caml_main(argv)" as in +section~\ref{s:main-c}, this means that "argv[0]" or "argv[1]" must +contain the executable file name. + +An alternative is to embed the bytecode in the C code. The +"-output-obj" option to "ocamlc" is provided for this purpose. It +causes the "ocamlc" compiler to output a C object file (".o" file, +".obj" under Windows) containing the bytecode for the OCaml part of the +program, as well as a "caml_startup" function. The C object file +produced by "ocamlc -output-obj" can then be linked with C code using +the standard C compiler, or stored in a C library. + +The "caml_startup" function must be called from the main C program in +order to initialize the OCaml runtime and execute the OCaml +initialization code. Just like "caml_main", it takes one "argv" +parameter containing the command-line parameters. Unlike "caml_main", +this "argv" parameter is used only to initialize "Sys.argv", but not +for finding the name of the executable file. + +The "caml_startup" function calls the uncaught exception handler (or +enters the debugger, if running under ocamldebug) if an exception escapes +from a top-level module initialiser. Such exceptions may be caught in the +C code by instead using the "caml_startup_exn" function and testing the result +using {\tt Is_exception_result} (followed by {\tt Extract_exception} if +appropriate). + +The "-output-obj" option can also be used to obtain the C source file. +More interestingly, the same option can also produce directly a shared +library (".so" file, ".dll" under Windows) that contains the OCaml +code, the OCaml runtime system and any other static C code given to +"ocamlc" (".o", ".a", respectively, ".obj", ".lib"). This use of +"-output-obj" is very similar to a normal linking step, but instead of +producing a main program that automatically runs the OCaml code, it +produces a shared library that can run the OCaml code on demand. The +three possible behaviors of "-output-obj" are selected according +to the extension of the resulting file (given with "-o"). + +The native-code compiler "ocamlopt" also supports the "-output-obj" +option, causing it to output a C object file or a shared library +containing the native code for all OCaml modules on the command-line, +as well as the OCaml startup code. Initialization is performed by +calling "caml_startup" (or "caml_startup_exn") as in the case of the +bytecode compiler. + +For the final linking phase, in addition to the object file produced +by "-output-obj", you will have to provide the OCaml runtime +library ("libcamlrun.a" for bytecode, "libasmrun.a" for native-code), +as well as all C libraries that are required by the OCaml libraries +used. For instance, assume the OCaml part of your program uses the +Unix library. With "ocamlc", you should do: +\begin{alltt} + ocamlc -output-obj -o camlcode.o unix.cma {\it{other}} .cmo {\it{and}} .cma {\it{files}} + cc -o myprog {\it{C objects and libraries}} \char92 + camlcode.o -L`ocamlc -where` -lunix -lcamlrun +\end{alltt} +With "ocamlopt", you should do: +\begin{alltt} + ocamlopt -output-obj -o camlcode.o unix.cmxa {\it{other}} .cmx {\it{and}} .cmxa {\it{files}} + cc -o myprog {\it{C objects and libraries}} \char92 + camlcode.o -L`ocamlc -where` -lunix -lasmrun +\end{alltt} + +% -- This seems completely wrong -- Damien +% The shared libraries produced by "ocamlc -output-obj" or by "ocamlopt +% -output-obj" already contains the OCaml runtime library as +% well as all the needed C libraries. + +\paragraph{Warning:} On some ports, special options are required on the final +linking phase that links together the object file produced by the +"-output-obj" option and the remainder of the program. Those options +are shown in the configuration file "config/Makefile" generated during +compilation of OCaml, as the variable "LDFLAGS". +\begin{itemize} +\item Windows with the MSVC compiler: the object file produced by +OCaml have been compiled with the "/MD" flag, and therefore +all other object files linked with it should also be compiled with +"/MD". +\item other systems: you may have to add one or more of "-lcurses", +"-lm", "-ldl", depending on your OS and C compiler. +\end{itemize} + +\paragraph{Stack backtraces.} When OCaml bytecode produced by +"ocamlc -g" is embedded in a C program, no debugging information is +included, and therefore it is impossible to print stack backtraces on +uncaught exceptions. This is not the case when native code produced +by "ocamlopt -g" is embedded in a C program: stack backtrace +information is available, but the backtrace mechanism needs to be +turned on programmatically. This can be achieved from the OCaml side +by calling "Printexc.record_backtrace true" in the initialization of +one of the OCaml modules. This can also be achieved from the C side +by calling "caml_record_backtrace(Val_int(1));" in the OCaml-C glue code. + +\paragraph{Unloading the runtime.} + +In case the shared library produced with "-output-obj" is to be loaded and +unloaded repeatedly by a single process, care must be taken to unload the +OCaml runtime explicitly, in order to avoid various system resource leaks. + +Since 4.05, "caml_shutdown" function can be used to shut the runtime down +gracefully, which equals the following: +\begin{itemize} +\item Running the functions that were registered with "Pervasives.at_exit". +\item Triggering finalization of allocated custom blocks (see +section~\ref{s:custom}). For example, "Pervasives.in_channel" and +"Pervasives.out_channel" are represented by custom blocks that enclose file +descriptors, which are to be released. +\item Unloading the dependent shared libraries that were loaded by the runtime, +including "dynlink" plugins. +\item Freeing the memory blocks that were allocated by the runtime with +"malloc". Inside C primitives, it is advised to use "caml_stat_*" functions +from "memory.h" for managing static (that is, non-moving) blocks of heap +memory, as all the blocks allocated with these functions are automatically +freed by "caml_shutdown". For ensuring compatibility with legacy C stubs that +have used "caml_stat_*" incorrectly, this behaviour is only enabled if the +runtime is started with a specialized "caml_startup_pooled" function. +\end{itemize} + +As a shared library may have several clients simultaneously, it is made for +convenience that "caml_startup" (and "caml_startup_pooled") may be called +multiple times, given that each such call is paired with a corresponding call +to "caml_shutdown" (in a nested fashion). The runtime will be unloaded once +there are no outstanding calls to "caml_startup". + +Once a runtime is unloaded, it cannot be started up again without reloading the +shared library and reinitializing its static data. Therefore, at the moment, the +facility is only useful for building reloadable shared libraries. + + +\section{Advanced example with callbacks} +\pdfsection{Advanced example with callbacks} + +This section illustrates the callback facilities described in +section~\ref{s:callback}. We are going to package some OCaml functions +in such a way that they can be linked with C code and called from C +just like any C functions. The OCaml functions are defined in the +following "mod.ml" OCaml source: + +\begin{verbatim} +(* File mod.ml -- some "useful" OCaml functions *) + +let rec fib n = if n < 2 then 1 else fib(n-1) + fib(n-2) + +let format_result n = Printf.sprintf "Result is: %d\n" n + +(* Export those two functions to C *) + +let _ = Callback.register "fib" fib +let _ = Callback.register "format_result" format_result +\end{verbatim} + +Here is the C stub code for calling these functions from C: + +\begin{verbatim} +/* File modwrap.c -- wrappers around the OCaml functions */ + +#include +#include +#include +#include + +int fib(int n) +{ + static value * fib_closure = NULL; + if (fib_closure == NULL) fib_closure = caml_named_value("fib"); + return Int_val(caml_callback(*fib_closure, Val_int(n))); +} + +char * format_result(int n) +{ + static value * format_result_closure = NULL; + if (format_result_closure == NULL) + format_result_closure = caml_named_value("format_result"); + return strdup(String_val(caml_callback(*format_result_closure, Val_int(n)))); + /* We copy the C string returned by String_val to the C heap + so that it remains valid after garbage collection. */ +} +\end{verbatim} + +We now compile the OCaml code to a C object file and put it in a C +library along with the stub code in "modwrap.c" and the OCaml runtime system: +\begin{verbatim} + ocamlc -custom -output-obj -o modcaml.o mod.ml + ocamlc -c modwrap.c + cp `ocamlc -where`/libcamlrun.a mod.a && chmod +w mod.a + ar r mod.a modcaml.o modwrap.o +\end{verbatim} +(One can also use "ocamlopt -output-obj" instead of "ocamlc -custom +-output-obj". In this case, replace "libcamlrun.a" (the bytecode +runtime library) by "libasmrun.a" (the native-code runtime library).) + +Now, we can use the two functions "fib" and "format_result" in any C +program, just like regular C functions. Just remember to call +"caml_startup" (or "caml_startup_exn") once before. + +\begin{verbatim} +/* File main.c -- a sample client for the OCaml functions */ + +#include +#include + +extern int fib(int n); +extern char * format_result(int n); + +int main(int argc, char ** argv) +{ + int result; + + /* Initialize OCaml code */ + caml_startup(argv); + /* Do some computation */ + result = fib(10); + printf("fib(10) = %s\n", format_result(result)); + return 0; +} +\end{verbatim} + +To build the whole program, just invoke the C compiler as follows: +\begin{verbatim} + cc -o prog -I `ocamlc -where` main.c mod.a -lcurses +\end{verbatim} +(On some machines, you may need to put "-ltermcap" or +"-lcurses -ltermcap" instead of "-lcurses".) + +\section{Advanced topic: custom blocks} \label{s:custom} +\pdfsection{Advanced topic: custom blocks} + +Blocks with tag "Custom_tag" contain both arbitrary user data and a +pointer to a C struct, with type "struct custom_operations", that +associates user-provided finalization, comparison, hashing, +serialization and deserialization functions to this block. + +\subsection{The "struct custom_operations"} + +The "struct custom_operations" is defined in "" and +contains the following fields: +\begin{itemize} +\item "char *identifier" \\ +A zero-terminated character string serving as an identifier for +serialization and deserialization operations. + +\item "void (*finalize)(value v)" \\ +The "finalize" field contains a pointer to a C function that is called +when the block becomes unreachable and is about to be reclaimed. +The block is passed as first argument to the function. +The "finalize" field can also be "custom_finalize_default" to indicate that no +finalization function is associated with the block. + +\item "int (*compare)(value v1, value v2)" \\ +The "compare" field contains a pointer to a C function that is +called whenever two custom blocks are compared using OCaml's generic +comparison operators ("=", "<>", "<=", ">=", "<", ">" and +"compare"). The C function should return 0 if the data contained in +the two blocks are structurally equal, a negative integer if the data +from the first block is less than the data from the second block, and +a positive integer if the data from the first block is greater than +the data from the second block. + +The "compare" field can be set to "custom_compare_default"; this +default comparison function simply raises "Failure". + +\item "int (*compare_ext)(value v1, value v2)" \\ +(Since 3.12.1) +The "compare_ext" field contains a pointer to a C function that is +called whenever one custom block and one unboxed integer are compared using OCaml's generic +comparison operators ("=", "<>", "<=", ">=", "<", ">" and +"compare"). As in the case of the "compare" field, the C function +should return 0 if the two arguments are structurally equal, a +negative integer if the first argument compares less than the second +argument, and a positive integer if the first argument compares +greater than the second argument. + +The "compare_ext" field can be set to "custom_compare_ext_default"; this +default comparison function simply raises "Failure". + +\item "intnat (*hash)(value v)" \\ +The "hash" field contains a pointer to a C function that is called +whenever OCaml's generic hash operator (see module "Hashtbl") is +applied to a custom block. The C function can return an arbitrary +integer representing the hash value of the data contained in the +given custom block. The hash value must be compatible with the +"compare" function, in the sense that two structurally equal data +(that is, two custom blocks for which "compare" returns 0) must have +the same hash value. + +The "hash" field can be set to "custom_hash_default", in which case +the custom block is ignored during hash computation. + +\item "void (*serialize)(value v, uintnat * wsize_32, uintnat * wsize_64)" \\ +The "serialize" field contains a pointer to a C function that is +called whenever the custom block needs to be serialized (marshaled) +using the OCaml functions "output_value" or "Marshal.to_...". +For a custom block, those functions first write the identifier of the +block (as given by the "identifier" field) to the output stream, +then call the user-provided "serialize" function. That function is +responsible for writing the data contained in the custom block, using +the "serialize_..." functions defined in "" and listed +below. The user-provided "serialize" function must then store in its +"wsize_32" and "wsize_64" parameters the sizes in bytes of the data +part of the custom block on a 32-bit architecture and on a 64-bit +architecture, respectively. + +The "serialize" field can be set to "custom_serialize_default", +in which case the "Failure" exception is raised when attempting to +serialize the custom block. + +\item "uintnat (*deserialize)(void * dst)" \\ +The "deserialize" field contains a pointer to a C function that is +called whenever a custom block with identifier "identifier" needs to +be deserialized (un-marshaled) using the OCaml functions "input_value" +or "Marshal.from_...". This user-provided function is responsible for +reading back the data written by the "serialize" operation, using the +"deserialize_..." functions defined in "" and listed +below. It must then rebuild the data part of the custom block +and store it at the pointer given as the "dst" argument. Finally, it +returns the size in bytes of the data part of the custom block. +This size must be identical to the "wsize_32" result of +the "serialize" operation if the architecture is 32 bits, or +"wsize_64" if the architecture is 64 bits. + +The "deserialize" field can be set to "custom_deserialize_default" +to indicate that deserialization is not supported. In this case, +do not register the "struct custom_operations" with the deserializer +using "register_custom_operations" (see below). +\end{itemize} + +Note: the "finalize", "compare", "hash", "serialize" and "deserialize" +functions attached to custom block descriptors must never trigger a +garbage collection. Within these functions, do not call any of the +OCaml allocation functions, and do not perform a callback into OCaml +code. Do not use "CAMLparam" to register the parameters to these +functions, and do not use "CAMLreturn" to return the result. + +\subsection{Allocating custom blocks} + +Custom blocks must be allocated via the "caml_alloc_custom" function: +\begin{center} +"caml_alloc_custom("\var{ops}", "\var{size}", "\var{used}", "\var{max}")" +\end{center} +returns a fresh custom block, with room for \var{size} bytes of user +data, and whose associated operations are given by \var{ops} (a +pointer to a "struct custom_operations", usually statically allocated +as a C global variable). + +The two parameters \var{used} and \var{max} are used to control the +speed of garbage collection when the finalized object contains +pointers to out-of-heap resources. Generally speaking, the +OCaml incremental major collector adjusts its speed relative to the +allocation rate of the program. The faster the program allocates, the +harder the GC works in order to reclaim quickly unreachable blocks +and avoid having large amount of ``floating garbage'' (unreferenced +objects that the GC has not yet collected). + +Normally, the allocation rate is measured by counting the in-heap size +of allocated blocks. However, it often happens that finalized +objects contain pointers to out-of-heap memory blocks and other resources +(such as file descriptors, X Windows bitmaps, etc.). For those +blocks, the in-heap size of blocks is not a good measure of the +quantity of resources allocated by the program. + +The two arguments \var{used} and \var{max} give the GC an idea of how +much out-of-heap resources are consumed by the finalized block +being allocated: you give the amount of resources allocated to this +object as parameter \var{used}, and the maximum amount that you want +to see in floating garbage as parameter \var{max}. The units are +arbitrary: the GC cares only about the ratio $\var{used} / \var{max}$. + +For instance, if you are allocating a finalized block holding an X +Windows bitmap of \var{w} by \var{h} pixels, and you'd rather not +have more than 1 mega-pixels of unreclaimed bitmaps, specify +$\var{used} = \var{w} * \var{h}$ and $\var{max} = 1000000$. + +Another way to describe the effect of the \var{used} and \var{max} +parameters is in terms of full GC cycles. If you allocate many custom +blocks with $\var{used} / \var{max} = 1 / \var{N}$, the GC will then do one +full cycle (examining every object in the heap and calling +finalization functions on those that are unreachable) every \var{N} +allocations. For instance, if $\var{used} = 1$ and $\var{max} = 1000$, +the GC will do one full cycle at least every 1000 allocations of +custom blocks. + +If your finalized blocks contain no pointers to out-of-heap resources, +or if the previous discussion made little sense to you, just take +$\var{used} = 0$ and $\var{max} = 1$. But if you later find that the +finalization functions are not called ``often enough'', consider +increasing the $\var{used} / \var{max}$ ratio. + +\subsection{Accessing custom blocks} + +The data part of a custom block \var{v} can be +accessed via the pointer "Data_custom_val("\var{v}")". This pointer +has type "void *" and should be cast to the actual type of the data +stored in the custom block. + +The contents of custom blocks are not scanned by the garbage +collector, and must therefore not contain any pointer inside the OCaml +heap. In other terms, never store an OCaml "value" in a custom block, +and do not use "Field", "Store_field" nor "caml_modify" to access the data +part of a custom block. Conversely, any C data structure (not +containing heap pointers) can be stored in a custom block. + +\subsection{Writing custom serialization and deserialization functions} + +The following functions, defined in "", are provided to +write and read back the contents of custom blocks in a portable way. +Those functions handle endianness conversions when e.g. data is +written on a little-endian machine and read back on a big-endian machine. + +\begin{tableau}{|l|p{10cm}|}{Function}{Action} +\entree{"caml_serialize_int_1"}{Write a 1-byte integer} +\entree{"caml_serialize_int_2"}{Write a 2-byte integer} +\entree{"caml_serialize_int_4"}{Write a 4-byte integer} +\entree{"caml_serialize_int_8"}{Write a 8-byte integer} +\entree{"caml_serialize_float_4"}{Write a 4-byte float} +\entree{"caml_serialize_float_8"}{Write a 8-byte float} +\entree{"caml_serialize_block_1"}{Write an array of 1-byte quantities} +\entree{"caml_serialize_block_2"}{Write an array of 2-byte quantities} +\entree{"caml_serialize_block_4"}{Write an array of 4-byte quantities} +\entree{"caml_serialize_block_8"}{Write an array of 8-byte quantities} +\entree{"caml_deserialize_uint_1"}{Read an unsigned 1-byte integer} +\entree{"caml_deserialize_sint_1"}{Read a signed 1-byte integer} +\entree{"caml_deserialize_uint_2"}{Read an unsigned 2-byte integer} +\entree{"caml_deserialize_sint_2"}{Read a signed 2-byte integer} +\entree{"caml_deserialize_uint_4"}{Read an unsigned 4-byte integer} +\entree{"caml_deserialize_sint_4"}{Read a signed 4-byte integer} +\entree{"caml_deserialize_uint_8"}{Read an unsigned 8-byte integer} +\entree{"caml_deserialize_sint_8"}{Read a signed 8-byte integer} +\entree{"caml_deserialize_float_4"}{Read a 4-byte float} +\entree{"caml_deserialize_float_8"}{Read an 8-byte float} +\entree{"caml_deserialize_block_1"}{Read an array of 1-byte quantities} +\entree{"caml_deserialize_block_2"}{Read an array of 2-byte quantities} +\entree{"caml_deserialize_block_4"}{Read an array of 4-byte quantities} +\entree{"caml_deserialize_block_8"}{Read an array of 8-byte quantities} +\entree{"caml_deserialize_error"}{Signal an error during deserialization; +"input_value" or "Marshal.from_..." raise a "Failure" exception after +cleaning up their internal data structures} +\end{tableau} + +Serialization functions are attached to the custom blocks to which +they apply. Obviously, deserialization functions cannot be attached +this way, since the custom block does not exist yet when +deserialization begins! Thus, the "struct custom_operations" that +contain deserialization functions must be registered with the +deserializer in advance, using the "register_custom_operations" +function declared in "". Deserialization proceeds by +reading the identifier off the input stream, allocating a custom block +of the size specified in the input stream, searching the registered +"struct custom_operation" blocks for one with the same identifier, and +calling its "deserialize" function to fill the data part of the custom block. + +\subsection{Choosing identifiers} + +Identifiers in "struct custom_operations" must be chosen carefully, +since they must identify uniquely the data structure for serialization +and deserialization operations. In particular, consider including a +version number in the identifier; this way, the format of the data can +be changed later, yet backward-compatible deserialisation functions +can be provided. + +Identifiers starting with "_" (an underscore character) are reserved +for the OCaml runtime system; do not use them for your custom +data. We recommend to use a URL +("http://mymachine.mydomain.com/mylibrary/version-number") +or a Java-style package name +("com.mydomain.mymachine.mylibrary.version-number") +as identifiers, to minimize the risk of identifier collision. + +\subsection{Finalized blocks} + +Custom blocks generalize the finalized blocks that were present in +OCaml prior to version 3.00. For backward compatibility, the +format of custom blocks is compatible with that of finalized blocks, +and the "alloc_final" function is still available to allocate a custom +block with a given finalization function, but default comparison, +hashing and serialization functions. "caml_alloc_final("\var{n}", +"\var{f}", "\var{used}", "\var{max}")" returns a fresh custom block of +size \var{n}+1 words, with finalization function \var{f}. The first +word is reserved for storing the custom operations; the other +\var{n} words are available for your data. The two parameters +\var{used} and \var{max} are used to control the speed of garbage +collection, as described for "caml_alloc_custom". + +\section{Advanced topic: Big arrays and the OCaml-C interface} +\label{s:C-Bigarrays} + +This section explains how C stub code that interfaces C or Fortran +code with OCaml code can use big arrays. + +\subsection{Include file} + +The include file "" must be included in the C stub +file. It declares the functions, constants and macros discussed +below. + +\subsection{Accessing an OCaml bigarray from C or Fortran} + +If \var{v} is a OCaml "value" representing a big array, the expression +"Caml_ba_data_val("\var{v}")" returns a pointer to the data part of the array. +This pointer is of type "void *" and can be cast to the appropriate C +type for the array (e.g. "double []", "char [][10]", etc). + +Various characteristics of the OCaml big array can be consulted from C +as follows: +\begin{tableau}{|l|l|}{C expression}{Returns} +\entree{"Caml_ba_array_val("\var{v}")->num_dims"}{number of dimensions} +\entree{"Caml_ba_array_val("\var{v}")->dim["\var{i}"]"}{\var{i}-th dimension} +\entree{"Caml_ba_array_val("\var{v}")->flags & BIGARRAY_KIND_MASK"}{kind of array elements} +\end{tableau} +The kind of array elements is one of the following constants: +\begin{tableau}{|l|l|}{Constant}{Element kind} +\entree{"CAML_BA_FLOAT32"}{32-bit single-precision floats} +\entree{"CAML_BA_FLOAT64"}{64-bit double-precision floats} +\entree{"CAML_BA_SINT8"}{8-bit signed integers} +\entree{"CAML_BA_UINT8"}{8-bit unsigned integers} +\entree{"CAML_BA_SINT16"}{16-bit signed integers} +\entree{"CAML_BA_UINT16"}{16-bit unsigned integers} +\entree{"CAML_BA_INT32"}{32-bit signed integers} +\entree{"CAML_BA_INT64"}{64-bit signed integers} +\entree{"CAML_BA_CAML_INT"}{31- or 63-bit signed integers} +\entree{"CAML_BA_NATIVE_INT"}{32- or 64-bit (platform-native) integers} +\end{tableau} +% +The following example shows the passing of a two-dimensional big array +to a C function and a Fortran function. +\begin{verbatim} + extern void my_c_function(double * data, int dimx, int dimy); + extern void my_fortran_function_(double * data, int * dimx, int * dimy); + + value caml_stub(value bigarray) + { + int dimx = Caml_ba_array_val(bigarray)->dim[0]; + int dimy = Caml_ba_array_val(bigarray)->dim[1]; + /* C passes scalar parameters by value */ + my_c_function(Caml_ba_data_val(bigarray), dimx, dimy); + /* Fortran passes all parameters by reference */ + my_fortran_function_(Caml_ba_data_val(bigarray), &dimx, &dimy); + return Val_unit; + } +\end{verbatim} + +\subsection{Wrapping a C or Fortran array as an OCaml big array} + +A pointer \var{p} to an already-allocated C or Fortran array can be +wrapped and returned to OCaml as a big array using the "caml_ba_alloc" +or "caml_ba_alloc_dims" functions. +\begin{itemize} +\item +"caml_ba_alloc("\var{kind} "|" \var{layout}, \var{numdims}, \var{p}, \var{dims}")" + +Return an OCaml big array wrapping the data pointed to by \var{p}. +\var{kind} is the kind of array elements (one of the "CAML_BA_" +kind constants above). \var{layout} is "CAML_BA_C_LAYOUT" for an +array with C layout and "CAML_BA_FORTRAN_LAYOUT" for an array with +Fortran layout. \var{numdims} is the number of dimensions in the +array. \var{dims} is an array of \var{numdims} long integers, giving +the sizes of the array in each dimension. + +\item +"caml_ba_alloc_dims("\var{kind} "|" \var{layout}, \var{numdims}, +\var{p}, "(long) "\nth{dim}{1}, "(long) "\nth{dim}{2}, \ldots, "(long) "\nth{dim}{numdims}")" + +Same as "caml_ba_alloc", but the sizes of the array in each dimension +are listed as extra arguments in the function call, rather than being +passed as an array. +\end{itemize} +% +The following example illustrates how statically-allocated C and +Fortran arrays can be made available to OCaml. +\begin{verbatim} + extern long my_c_array[100][200]; + extern float my_fortran_array_[300][400]; + + value caml_get_c_array(value unit) + { + long dims[2]; + dims[0] = 100; dims[1] = 200; + return caml_ba_alloc(CAML_BA_NATIVE_INT | CAML_BA_C_LAYOUT, + 2, my_c_array, dims); + } + + value caml_get_fortran_array(value unit) + { + return caml_ba_alloc_dims(CAML_BA_FLOAT32 | CAML_BA_FORTRAN_LAYOUT, + 2, my_fortran_array_, 300L, 400L); + } +\end{verbatim} + +\section{Advanced topic: cheaper C call} +\label{s:C-cheaper-call} + +This section describe how to make calling C functions cheaper. + +{\bf Note:} this only applies to the native compiler. So whenever you +use any of these methods, you have to provide an alternative byte-code +stub that ignores all the special annotations. + +\subsection{Passing unboxed values} + +We said earlier that all OCaml objects are represented by the C type +"value", and one has to use macros such as "Int_val" to decode data from +the "value" type. It is however possible to tell the OCaml native-code +compiler to do this for us and pass arguments unboxed to the C function. +Similarly it is possible to tell OCaml to expect the result unboxed and box +it for us. + +The motivation is that, by letting `ocamlopt` deal with boxing, it can +often decide to suppress it entirely. + +For instance let's consider this example: + +\begin{verbatim} +external foo : float -> float -> float = "foo" + +let f a b = + let len = Array.length a in + assert (Array.length b = len); + let res = Array.make len 0. in + for i = 0 to len - 1 do + res.(i) <- foo a.(i) b.(i) + done +\end{verbatim} + +Float arrays are unboxed in OCaml, however the C function "foo" expect +its arguments as boxed floats and returns a boxed float. Hence the +OCaml compiler has no choice but to box "a.(i)" and "b.(i)" and unbox +the result of "foo". This results in the allocation of "3 * len" +temporary float values. + +Now if we annotate the arguments and result with "[\@unboxed]", the +native-code compiler will be able to avoid all these allocations: + +\begin{verbatim} +external foo + : (float [@unboxed]) + -> (float [@unboxed]) + -> (float [@unboxed]) + = "foo_byte" "foo" +\end{verbatim} + +In this case the C functions must look like: + +\begin{verbatim} +CAMLprim double foo(double a, double b) +{ + ... +} + +CAMLprim value foo_byte(value a, value b) +{ + return caml_copy_double(foo(Double_val(a), Double_val(b))) +} +\end{verbatim} + +For convenicence, when all arguments and the result are annotated with +"[\@unboxed]", it is possible to put the attribute only once on the +declaration itself. So we can also write instead: + +\begin{verbatim} +external foo : float -> float -> float = "foo_byte" "foo" [@@unboxed] +\end{verbatim} + +The following table summarize what OCaml types can be unboxed, and +what C types should be used in correspondence: + +\begin{tableau}{|l|l|}{OCaml type}{C type} +\entree{"float"}{"double"} +\entree{"int32"}{"int32_t"} +\entree{"int64"}{"int64_t"} +\entree{"nativeint"}{"intnat"} +\end{tableau} + +Similarly, it is possible to pass untagged OCaml integers between +OCaml and C. This is done by annotating the arguments and/or result +with "[\@untagged]": + +\begin{verbatim} +external f : string -> (int [@untagged]) = "f_byte" "f" +\end{verbatim} + +The corresponding C type must be "intnat". + +{\bf Note:} do not use the C "int" type in correspondence with "(int +[\@untagged])". This is because they often differ in size. + +\subsection{Direct C call} + +In order to be able to run the garbage collector in the middle of +a C function, the OCaml native-code compiler generates some bookkeeping +code around C calls. Technically it wraps every C call with the C function +"caml_c_call" which is part of the OCaml runtime. + +For small functions that are called repeatedly, this indirection can have +a big impact on performances. However this is not needed if we know that +the C function doesn't allocate and doesn't raise exceptions. We can +instruct the OCaml native-code compiler of this fact by annotating the +external declaration with the attribute "[\@\@noalloc]": + +\begin{verbatim} +external bar : int -> int -> int = "foo" [@@noalloc] +\end{verbatim} + +In this case calling "bar" from OCaml is as cheap as calling any other +OCaml function, except for the fact that the OCaml compiler can't +inline C functions... + +\subsection{Example: calling C library functions without indirection} + +Using these attributes, it is possible to call C library functions +with no indirection. For instance many math functions are defined this +way in the OCaml standard library: + +\begin{verbatim} +external sqrt : float -> float = "caml_sqrt_float" "sqrt" + [@@unboxed] [@@noalloc] +(** Square root. *) + +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +(** Exponential. *) + +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +(** Natural logarithm. *) +\end{verbatim} + +\section{Advanced topic: multithreading} +\label{s:C-multithreading} + +Using multiple threads (shared-memory concurrency) in a mixed OCaml/C +application requires special precautions, which are described in this +section. + +\subsection{Registering threads created from C} + +Callbacks from C to OCaml are possible only if the calling thread is +known to the OCaml run-time system. Threads created from OCaml (through +the "Thread.create" function of the system threads library) are +automatically known to the run-time system. If the application +creates additional threads from C and wishes to callback into OCaml +code from these threads, it must first register them with the run-time +system. The following functions are declared in the include file +"". + +\begin{itemize} +\item +"caml_c_thread_register()" registers the calling thread with the OCaml +run-time system. Returns 1 on success, 0 on error. Registering an +already-register thread does nothing and returns 0. +\item +"caml_c_thread_unregister()" must be called before the thread + terminates, to unregister it from the OCaml run-time system. +Returns 1 on success, 0 on error. If the calling thread was not +previously registered, does nothing and returns 0. +\end{itemize} + +\subsection{Parallel execution of long-running C code} + +The OCaml run-time system is not reentrant: at any time, at most one +thread can be executing OCaml code or C code that uses the OCaml +run-time system. Technically, this is enforced by a ``master lock'' +that any thread must hold while executing such code. + +When OCaml calls the C code implementing a primitive, the master lock +is held, therefore the C code has full access to the facilities of the +run-time system. However, no other thread can execute OCaml code +concurrently with the C code of the primitive. + +If a C primitive runs for a long time or performs potentially blocking +input-output operations, it can explicitly release the master lock, +enabling other OCaml threads to run concurrently with its operations. +The C code must re-acquire the master lock before returning to OCaml. +This is achieved with the following functions, declared in +the include file "". + +\begin{itemize} +\item +"caml_release_runtime_system()" +The calling thread releases the master lock and other OCaml resources, +enabling other threads to run OCaml code in parallel with the execution +of the calling thread. +\item +"caml_acquire_runtime_system()" +The calling thread re-acquires the master lock and other OCaml +resources. It may block until no other thread uses the OCaml run-time +system. +\end{itemize} + +After "caml_release_runtime_system()" was called and until +"caml_acquire_runtime_system()" is called, the C code must not access +any OCaml data, nor call any function of the run-time system, nor call +back into OCaml code. Consequently, arguments provided by OCaml to the +C primitive must be copied into C data structures before calling +"caml_release_runtime_system()", and results to be returned to OCaml +must be encoded as OCaml values after "caml_acquire_runtime_system()" +returns. + +Example: the following C primitive invokes "gethostbyname" to find the +IP address of a host name. The "gethostbyname" function can block for +a long time, so we choose to release the OCaml run-time system while it +is running. +\begin{verbatim} +CAMLprim stub_gethostbyname(value vname) +{ + CAMLparam1 (vname); + CAMLlocal1 (vres); + struct hostent * h; + char * name; + + /* Copy the string argument to a C string, allocated outside the + OCaml heap. */ + name = caml_stat_strdup(String_val(vname)); + /* Release the OCaml run-time system */ + caml_release_runtime_system(); + /* Resolve the name */ + h = gethostbyname(name); + /* Free the copy of the string, which we might as well do before + acquiring the runtime system to benefit from parallelism. */ + caml_stat_free(name); + /* Re-acquire the OCaml run-time system */ + caml_acquire_runtime_system(); + /* Encode the relevant fields of h as the OCaml value vres */ + ... /* Omitted */ + /* Return to OCaml */ + CAMLreturn (vres); +} +\end{verbatim} + +Callbacks from C to OCaml must be performed while holding the master +lock to the OCaml run-time system. This is naturally the case if the +callback is performed by a C primitive that did not release the +run-time system. If the C primitive released the run-time system +previously, or the callback is performed from other C code that was +not invoked from OCaml (e.g. an event loop in a GUI application), the +run-time system must be acquired before the callback and released +after: +\begin{verbatim} + caml_acquire_runtime_system(); + /* Resolve OCaml function vfun to be invoked */ + /* Build OCaml argument varg to the callback */ + vres = callback(vfun, varg); + /* Copy relevant parts of result vres to C data structures */ + caml_release_runtime_system(); +\end{verbatim} + +Note: the "acquire" and "release" functions described above were +introduced in OCaml 3.12. Older code uses the following historical +names, declared in "": +\begin{itemize} +\item "caml_enter_blocking_section" as an alias for + "caml_release_runtime_system" +\item "caml_leave_blocking_section" as an alias for + "caml_acquire_runtime_system" +\end{itemize} +Intuition: a ``blocking section'' is a piece of C code that does not +use the OCaml run-time system, typically a blocking input/output operation. + +\section{Advanced topic: interfacing with Windows Unicode APIs} +\label{s:interfacing-windows-unicode-apis} + +This section contains some general guidelines for writing C stubs that use +Windows Unicode APIs. + +{\bf Note:} This is an experimental feature of OCaml: the set of APIs below, as +well as their exact semantics are not final and subject to change in future +releases. + +The OCaml system under Windows can be configured at build time in one of two +modes: + +\begin{itemize} + +\item {\bf legacy mode:} All path names, environment variables, command line +arguments, etc. on the OCaml side are assumed to be encoded using the current +8-bit code page of the system. + +\item {\bf Unicode mode:} All path names, environment variables, command line +arguments, etc. on the OCaml side are assumed to be encoded using UTF-8. + +\end{itemize} + +In what follows, we say that a string has the \emph{OCaml encoding} if it is +encoded in UTF-8 when in Unicode mode, in the current code page in legacy mode, +or is an arbitrary string under Unix. A string has the \emph{platform encoding} +if it is encoded in UTF-16 under Windows or is an arbitrary string under Unix. + +From the point of view of the writer of C stubs, the challenges of interacting +with Windows Unicode APIs are twofold: + +\begin{itemize} + +\item The Windows API uses the UTF-16 encoding to support Unicode. The runtime +system performs the necessary conversions so that the OCaml programmer only +needs to deal with the OCaml encoding. C stubs that call Windows Unicode APIs +need to use specific runtime functions to perform the necessary conversions in a +compatible way. + +\item When writing stubs that need to be compiled under both Windows and Unix, +the stubs need to be written in a way that allow the necessary conversions under +Windows but that also work under Unix, where typically nothing particular needs +to be done to support Unicode. + +\end{itemize} + +The native C character type under Windows is "WCHAR", two bytes wide, while +under Unix it is "char", one byte wide. A type "char_os" is defined in +"" that stands for the concrete C character type of each +platform. Strings in the platform encoding are of type "char_os *". + +The following functions are exposed to help write compatible C stubs. To use +them, you need to include both "" and "". + +\begin{itemize} + +\item "char_os* caml_stat_strdup_to_os(const char *)" copies the argument while +translating from OCaml encoding to the platform encoding. This function is +typically used to convert the "char *" underlying an OCaml string before passing +it to an operating system API that takes a Unicode argument. Under Unix, it is +equivalent to "caml_stat_strdup". + +{\bf Note:} For maximum backwards compatibility in Unicode mode, if the argument +is not a valid UTF-8 string, this function will fall back to assuming that it is +encoded in the current code page. + +\item "char* caml_stat_strdup_of_os(const char_os *)" copies the argument while +translating from the platform encoding to the OCaml encoding. It is the inverse +of "caml_stat_strdup_to_os". This function is typically used to convert a string +obtained from the operating system before passing it on to OCaml code. Under +Unix, it is equivalent to "caml_stat_strdup". + +\item "value caml_copy_string_of_os(char_os *)" allocates an OCaml string with +contents equal to the argument string converted to the OCaml encoding. This +function is essentially equivalent to "caml_stat_strdup_of_os" followed by +"caml_copy_string", except that it avoids the allocation of the intermediate +string returned by "caml_stat_strdup_of_os". Under Unix, it is equivalent to +"caml_copy_string". + +\end{itemize} + +{\bf Note:} The strings returned by "caml_stat_strdup_to_os" and +"caml_stat_strdup_of_os" are allocated using "caml_stat_alloc", so they need to +be deallocated using "caml_stat_free" when they are no longer needed. + +\paragraph{Example} We want to bind the function "getenv" in a way that works +both under Unix and Windows. Under Unix this function has the prototype: + +\begin{verbatim} + char *getenv(const char *); +\end{verbatim} +While the Unicode version under Windows has the prototype: +\begin{verbatim} + WCHAR *_wgetenv(const WCHAR *); +\end{verbatim} + +In terms of "char_os", both functions take an argument of type "char_os *" and +return a result of the same type. We begin by choosing the right implementation +of the function to bind: + +\begin{verbatim} +#ifdef _WIN32 +#define getenv_os _wgetenv +#else +#define getenv_os getenv +#endif +\end{verbatim} + +The rest of the binding is the same for both platforms: + +\begin{verbatim} +/* The following define is necessary because the API is experimental */ +#define CAML_INTERNALS + +#include +#include +#include +#include +#include +#include + +CAMLprim value stub_getenv(value var_name) +{ + CAMLparam1(var_name); + CAMLlocal1(var_value); + char_os *var_name_os, *var_value_os; + + var_name_os = caml_stat_strdup_to_os(String_val(var_name)); + var_value_os = getenv_os(var_name_os); + caml_stat_free(var_name_os); + + if (var_value_os == NULL) + caml_raise_not_found(); + + var_value = caml_copy_string_of_os(var_value_os); + + CAMLreturn(var_value); +} +\end{verbatim} + +\section{Building mixed C/OCaml libraries: \texttt{ocamlmklib}} +\label{s-ocamlmklib} + +The "ocamlmklib" command facilitates the construction of libraries +containing both OCaml code and C code, and usable both in static +linking and dynamic linking modes. This command is available under +Windows since Objective Caml 3.11 and under other operating systems since +Objective Caml 3.03. + +The "ocamlmklib" command takes three kinds of arguments: +\begin{itemize} +\item OCaml source files and object files (".cmo", ".cmx", ".ml") +comprising the OCaml part of the library; +\item C object files (".o", ".a", respectively, ".obj", ".lib") + comprising the C part of the library; +\item Support libraries for the C part ("-l"\var{lib}). +\end{itemize} +It generates the following outputs: +\begin{itemize} +\item An OCaml bytecode library ".cma" incorporating the ".cmo" and +".ml" OCaml files given as arguments, and automatically referencing the +C library generated with the C object files. +\item An OCaml native-code library ".cmxa" incorporating the ".cmx" and +".ml" OCaml files given as arguments, and automatically referencing the +C library generated with the C object files. +\item If dynamic linking is supported on the target platform, a +".so" (respectively, ".dll") shared library built from the C object files given as arguments, +and automatically referencing the support libraries. +\item A C static library ".a"(respectively, ".lib") built from the C object files. +\end{itemize} +In addition, the following options are recognized: +\begin{options} +\item["-cclib", "-ccopt", "-I", "-linkall"] +These options are passed as is to "ocamlc" or "ocamlopt". +See the documentation of these commands. +\item["-rpath", "-R", "-Wl,-rpath", "-Wl,-R"] +These options are passed as is to the C compiler. Refer to the +documentation of the C compiler. +\item["-custom"] Force the construction of a statically linked library +only, even if dynamic linking is supported. +\item["-failsafe"] Fall back to building a statically linked library +if a problem occurs while building the shared library (e.g. some of +the support libraries are not available as shared libraries). +\item["-L"\var{dir}] Add \var{dir} to the search path for support +libraries ("-l"\var{lib}). +\item["-ocamlc" \var{cmd}] Use \var{cmd} instead of "ocamlc" to call +the bytecode compiler. +\item["-ocamlopt" \var{cmd}] Use \var{cmd} instead of "ocamlopt" to call +the native-code compiler. +\item["-o" \var{output}] Set the name of the generated OCaml library. +"ocamlmklib" will generate \var{output}".cma" and/or \var{output}".cmxa". +If not specified, defaults to "a". +\item["-oc" \var{outputc}] Set the name of the generated C library. +"ocamlmklib" will generate "lib"\var{outputc}".so" (if shared +libraries are supported) and "lib"\var{outputc}".a". +If not specified, defaults to the output name given with "-o". +\end{options} + +\noindent +On native Windows, the following environment variable is also consulted: + +\begin{options} +\item["OCAML_FLEXLINK"] Alternative executable to use instead of the +configured value. Primarily used for bootstrapping. +\end{options} + +\paragraph{Example} Consider an OCaml interface to the standard "libz" +C library for reading and writing compressed files. Assume this +library resides in "/usr/local/zlib". This interface is +composed of an OCaml part "zip.cmo"/"zip.cmx" and a C part "zipstubs.o" +containing the stub code around the "libz" entry points. The +following command builds the OCaml libraries "zip.cma" and "zip.cmxa", +as well as the companion C libraries "dllzip.so" and "libzip.a": +\begin{verbatim} +ocamlmklib -o zip zip.cmo zip.cmx zipstubs.o -lz -L/usr/local/zlib +\end{verbatim} +If shared libraries are supported, this performs the following +commands: +\begin{verbatim} +ocamlc -a -o zip.cma zip.cmo -dllib -lzip \ + -cclib -lzip -cclib -lz -ccopt -L/usr/local/zlib +ocamlopt -a -o zip.cmxa zip.cmx -cclib -lzip \ + -cclib -lzip -cclib -lz -ccopt -L/usr/local/zlib +gcc -shared -o dllzip.so zipstubs.o -lz -L/usr/local/zlib +ar rc libzip.a zipstubs.o +\end{verbatim} +Note: This example is on a Unix system. The exact command lines +may be different on other systems. + +If shared libraries are not supported, the following commands are +performed instead: +\begin{verbatim} +ocamlc -a -custom -o zip.cma zip.cmo -cclib -lzip \ + -cclib -lz -ccopt -L/usr/local/zlib +ocamlopt -a -o zip.cmxa zip.cmx -lzip \ + -cclib -lz -ccopt -L/usr/local/zlib +ar rc libzip.a zipstubs.o +\end{verbatim} +Instead of building simultaneously the bytecode library, the +native-code library and the C libraries, "ocamlmklib" can be called +three times to build each separately. Thus, +\begin{verbatim} +ocamlmklib -o zip zip.cmo -lz -L/usr/local/zlib +\end{verbatim} +builds the bytecode library "zip.cma", and +\begin{verbatim} +ocamlmklib -o zip zip.cmx -lz -L/usr/local/zlib +\end{verbatim} +builds the native-code library "zip.cmxa", and +\begin{verbatim} +ocamlmklib -o zip zipstubs.o -lz -L/usr/local/zlib +\end{verbatim} +builds the C libraries "dllzip.so" and "libzip.a". Notice that the +support libraries ("-lz") and the corresponding options +("-L/usr/local/zlib") must be given on all three invocations of "ocamlmklib", +because they are needed at different times depending on whether shared +libraries are supported. diff --git a/manual/manual/cmds/lexyacc.etex b/manual/manual/cmds/lexyacc.etex new file mode 100644 index 00000000..6053de89 --- /dev/null +++ b/manual/manual/cmds/lexyacc.etex @@ -0,0 +1,729 @@ +\chapter{Lexer and parser generators (ocamllex, ocamlyacc)} +\label{c:ocamlyacc} +\pdfchapter{Lexer and parser generators (ocamllex, ocamlyacc)} +%HEVEA\cutname{lexyacc.html} + +This chapter describes two program generators: "ocamllex", that +produces a lexical analyzer from a set of regular expressions with +associated semantic actions, and "ocamlyacc", that produces a parser +from a grammar with associated semantic actions. + +These program generators are very close to the well-known "lex" and +"yacc" commands that can be found in most C programming environments. +This chapter assumes a working knowledge of "lex" and "yacc": while +it describes the input syntax for "ocamllex" and "ocamlyacc" and the +main differences with "lex" and "yacc", it does not explain the basics +of writing a lexer or parser description in "lex" and "yacc". Readers +unfamiliar with "lex" and "yacc" are referred to ``Compilers: +principles, techniques, and tools'' by Aho, Sethi and Ullman +(Addison-Wesley, 1986), or ``Lex $\&$ Yacc'', by Levine, Mason and +Brown (O'Reilly, 1992). + +\section{Overview of \texttt{ocamllex}} + +The "ocamllex" command produces a lexical analyzer from a set of regular +expressions with attached semantic actions, in the style of +"lex". Assuming the input file is \var{lexer}".mll", executing +\begin{alltt} + ocamllex \var{lexer}.mll +\end{alltt} +produces OCaml code for a lexical analyzer in file \var{lexer}".ml". +This file defines one lexing function per entry point in the lexer +definition. These functions have the same names as the entry +points. Lexing functions take as argument a lexer buffer, and return +the semantic attribute of the corresponding entry point. + +Lexer buffers are an abstract data type implemented in the standard +library module "Lexing". The functions "Lexing.from_channel", +"Lexing.from_string" and "Lexing.from_function" create +lexer buffers that read from an input channel, a character string, or +any reading function, respectively. (See the description of module +"Lexing" in chapter~\ref{c:stdlib}.) + +When used in conjunction with a parser generated by "ocamlyacc", the +semantic actions compute a value belonging to the type "token" defined +by the generated parsing module. (See the description of "ocamlyacc" +below.) + +\subsection{Options} +The following command-line options are recognized by "ocamllex". + +\begin{options} + +\item["-ml"] +Output code that does not use OCaml's built-in automata +interpreter. Instead, the automaton is encoded by OCaml functions. +This option mainly is useful for debugging "ocamllex", using it for +production lexers is not recommended. + +\item["-o" \var{output-file}] +Specify the name of the output file produced by "ocamllex". +The default is the input file name with its extension replaced by ".ml". + +\item["-q"] +Quiet mode. "ocamllex" normally outputs informational messages +to standard output. They are suppressed if option "-q" is used. + +\item["-v" or "-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-help" or "--help"] +Display a short usage summary and exit. +% +\end{options} + +\section{Syntax of lexer definitions} + +The format of lexer definitions is as follows: +\begin{alltt} +\{ \var{header} \} +let \var{ident} = \var{regexp} \ldots +[refill \{ \var{refill-handler} \}] +rule \var{entrypoint} [\nth{arg}{1}\ldots{} \nth{arg}{n}] = + parse \var{regexp} \{ \var{action} \} + | \ldots + | \var{regexp} \{ \var{action} \} +and \var{entrypoint} [\nth{arg}{1}\ldots{} \nth{arg}{n}] = + parse \ldots +and \ldots +\{ \var{trailer} \} +\end{alltt} +Comments are delimited by "(*" and "*)", as in OCaml. +The "parse" keyword, can be replaced by the "shortest" keyword, with +the semantic consequences explained below. + +Refill handlers are a recent (optional) feature introduced in 4.02, +documented below in subsection~\ref{ss:refill-handlers}. + +\subsection{Header and trailer} +The {\it header} and {\it trailer} sections are arbitrary OCaml +text enclosed in curly braces. Either or both can be omitted. If +present, the header text is copied as is at the beginning of the +output file and the trailer text at the end. Typically, the +header section contains the "open" directives required +by the actions, and possibly some auxiliary functions used in the +actions. + +\subsection{Naming regular expressions} + +Between the header and the entry points, one can give names to +frequently-occurring regular expressions. This is written +@"let" ident "=" regexp@. +In regular expressions that follow this declaration, the identifier +\var{ident} can be used as shorthand for \var{regexp}. + +\subsection{Entry points} + +The names of the entry points must be valid identifiers for OCaml +values (starting with a lowercase letter). +Similarily, the arguments \texttt{\var{arg$_1$}\ldots{} +\var{arg$_n$}} must be valid identifiers for OCaml. +Each entry point becomes an +OCaml function that takes $n+1$ arguments, +the extra implicit last argument being of type "Lexing.lexbuf". +Characters are read from the "Lexing.lexbuf" argument and matched +against the regular expressions provided in the rule, until a prefix +of the input matches one of the rule. The corresponding action is +then evaluated and returned as the result of the function. + + +If several regular expressions match a prefix of the input, the +``longest match'' rule applies: the regular expression that matches +the longest prefix of the input is selected. In case of tie, the +regular expression that occurs earlier in the rule is selected. + +However, if lexer rules are introduced with the "shortest" keyword in +place of the "parse" keyword, then the ``shortest match'' rule applies: +the shortest prefix of the input is selected. In case of tie, the +regular expression that occurs earlier in the rule is still selected. +This feature is not intended for use in ordinary lexical analyzers, it +may facilitate the use of "ocamllex" as a simple text processing tool. + + + +\subsection{Regular expressions} + +The regular expressions are in the style of "lex", with a more +OCaml-like syntax. +\begin{syntax} +regexp: + \ldots +\end{syntax} +\begin{options} + +\item[@"'" regular-char || escape-sequence "'"@] +A character constant, with the same syntax as OCaml character +constants. Match the denoted character. + +\item["_"] +(underscore) Match any character. + +\item[@"eof"@] +Match the end of the lexer input.\\ +{\bf Note:} On some systems, with interactive input, an end-of-file +may be followed by more characters. However, "ocamllex" will not +correctly handle regular expressions that contain "eof" followed by +something else. + +\item[@'"' { string-character } '"'@] +A string constant, with the same syntax as OCaml string +constants. Match the corresponding sequence of characters. + +\item[@'[' character-set ']'@] +Match any single character belonging to the given +character set. Valid character sets are: single +character constants @"'" @c@ "'"@; ranges of characters +@"'" @c@_1 "'" "-" "'" @c@_2 "'"@ (all characters between $c_1$ and $c_2$, +inclusive); and the union of two or more character sets, denoted by +concatenation. + +\item[@'[' '^' character-set ']'@] +Match any single character not belonging to the given character set. + + +\item[@regexp_1 '#' regexp_2@] +(difference of character sets) +Regular expressions @regexp_1@ and @regexp_2@ must be character sets +defined with @'['\ldots ']'@ (or a single character expression or +underscore "_"). +Match the difference of the two specified character sets. + + +\item[@regexp '*'@] +(repetition) Match the concatenation of zero or more +strings that match @regexp@. + +\item[@regexp '+'@] +(strict repetition) Match the concatenation of one or more +strings that match @regexp@. + +\item[@regexp '?'@] +(option) Match the empty string, or a string matching @regexp@. + +\item[@regexp_1 '|' regexp_2@] +(alternative) Match any string that matches @regexp_1@ or @regexp_2@ + +\item[@regexp_1 regexp_2@] +(concatenation) Match the concatenation of two strings, the first +matching @regexp_1@, the second matching @regexp_2@. + +\item[@'(' regexp ')'@] +Match the same strings as @regexp@. + +\item[@ident@] +Reference the regular expression bound to @ident@ by an earlier +@"let" ident "=" regexp@ definition. + +\item[@regexp 'as' ident@] +Bind the substring matched by @regexp@ to identifier @ident@. +\end{options} + +Concerning the precedences of operators, "#" has the highest precedence, +followed by "*", "+" and "?", +then concatenation, then "|" (alternation), then "as". + +\subsection{Actions} + +The actions are arbitrary OCaml expressions. They are evaluated in +a context where the identifiers defined by using the "as" construct +are bound to subparts of the matched string. +Additionally, "lexbuf" is bound to the current lexer +buffer. Some typical uses for "lexbuf", in conjunction with the +operations on lexer buffers provided by the "Lexing" standard library +module, are listed below. + +\begin{options} +\item["Lexing.lexeme lexbuf"] +Return the matched string. + +\item["Lexing.lexeme_char lexbuf "$n$] +Return the $n\th$ +character in the matched string. The first character corresponds to $n = 0$. + +\item["Lexing.lexeme_start lexbuf"] +Return the absolute position in the input text of the beginning of the +matched string (i.e. the offset of the first character of the matched +string). The first character read from the input text has offset 0. + +\item["Lexing.lexeme_end lexbuf"] +Return the absolute position in the input text of the end of the +matched string (i.e. the offset of the first character after the +matched string). The first character read from the input text has +offset 0. + +\newcommand{\sub}[1]{$_{#1}$}% +\item[\var{entrypoint} {[\var{exp\sub{1}}\ldots{} \var{exp\sub{n}}]} "lexbuf"] +(Where \var{entrypoint} is the name of another entry point in the same +lexer definition.) Recursively call the lexer on the given entry point. +Notice that "lexbuf" is the last argument. +Useful for lexing nested comments, for example. + +\end{options} + +\subsection{Variables in regular expressions} +The "as" construct is similar to ``\emph{groups}'' as provided by +numerous regular expression packages. +The type of these variables can be "string", "char", "string option" +or "char option". + +We first consider the case of linear patterns, that is the case when +all "as" bound variables are distinct. +In @regexp 'as' ident@, the type of @ident@ normally is "string" (or +"string option") except +when @regexp@ is a character constant, an underscore, a string +constant of length one, a character set specification, or an +alternation of those. Then, the type of @ident@ is "char" (or "char +option"). +Option types are introduced when overall rule matching does not +imply matching of the bound sub-pattern. This is in particular the +case of @'(' regexp 'as' ident ')' '?'@ and of +@regexp_1 '|' '(' regexp_2 'as' ident ')'@. + +There is no linearity restriction over "as" bound variables. +When a variable is bound more than once, the previous rules are to be +extended as follows: +\begin{itemize} +\item A variable is a "char" variable when all its occurrences bind +"char" occurrences in the previous sense. +\item A variable is an "option" variable when the overall expression +can be matched without binding this variable. +\end{itemize} +For instance, in +"('a' as x) | ( 'a' (_ as x) )" the variable "x" is of type +"char", whereas in +"(\"ab\" as x) | ( 'a' (_ as x) ? )" the variable "x" is of type +"string option". + + +In some cases, a successful match may not yield a unique set of bindings. +For instance the matching of \verb+aba+ by the regular expression +"(('a'|\"ab\") as x) ((\"ba\"|'a') as y)" may result in binding +either +\verb+x+ to \verb+"ab"+ and \verb+y+ to \verb+"a"+, or +\verb+x+ to \verb+"a"+ and \verb+y+ to \verb+"ba"+. +The automata produced "ocamllex" on such ambiguous regular +expressions will select one of the possible resulting sets of +bindings. +The selected set of bindings is purposely left unspecified. + +\subsection{Refill handlers} +\label{ss:refill-handlers} + +By default, when ocamllex reaches the end of its lexing buffer, it +will silently call the "refill_buff" function of "lexbuf" structure +and continue lexing. It is sometimes useful to be able to take control +of refilling action; typically, if you use a library for asynchronous +computation, you may want to wrap the refilling action in a delaying +function to avoid blocking synchronous operations. + +Since OCaml 4.02, it is possible to specify a \var{refill-handler}, +a function that will be called when refill happens. It is passed the +continuation of the lexing, on which it has total control. The OCaml +expression used as refill action should have a type that is an +instance of +\begin{verbatim} + (Lexing.lexbuf -> 'a) -> Lexing.lexbuf -> 'a +\end{verbatim} +where the first argument is the continuation which captures the +processing ocamllex would usually perform (refilling the buffer, then +calling the lexing function again), and the result type that +instantiates ['a] should unify with the result type of all lexing +rules. + +As an example, consider the following lexer that is parametrized over +an arbitrary monad: +\begin{verbatim} +{ +type token = EOL | INT of int | PLUS + +module Make (M : sig + type 'a t + val return: 'a -> 'a t + val bind: 'a t -> ('a -> 'b t) -> 'b t + val fail : string -> 'a t + + (* Set up lexbuf *) + val on_refill : Lexing.lexbuf -> unit t + end) += struct + +let refill_handler k lexbuf = + M.bind (M.on_refill lexbuf) (fun () -> k lexbuf) + +} + +refill {refill_handler} + +rule token = parse +| [' ' '\t'] + { token lexbuf } +| '\n' + { M.return EOL } +| ['0'-'9']+ as i + { M.return (INT (int_of_string i)) } +| '+' + { M.return PLUS } +| _ + { M.fail "unexpected character" } +{ +end +} +\end{verbatim} + +\subsection{Reserved identifiers} + +All identifiers starting with "__ocaml_lex" are reserved for use by +"ocamllex"; do not use any such identifier in your programs. + + +\section{Overview of \texttt{ocamlyacc}} + +The "ocamlyacc" command produces a parser from a context-free grammar +specification with attached semantic actions, in the style of "yacc". +Assuming the input file is \var{grammar}".mly", executing +\begin{alltt} + ocamlyacc \var{options} \var{grammar}.mly +\end{alltt} +produces OCaml code for a parser in the file \var{grammar}".ml", +and its interface in file \var{grammar}".mli". + +The generated module defines one parsing function per entry point in +the grammar. These functions have the same names as the entry points. +Parsing functions take as arguments a lexical analyzer (a function +from lexer buffers to tokens) and a lexer buffer, and return the +semantic attribute of the corresponding entry point. Lexical analyzer +functions are usually generated from a lexer specification by the +"ocamllex" program. Lexer buffers are an abstract data type +implemented in the standard library module "Lexing". Tokens are values from +the concrete type "token", defined in the interface file +\var{grammar}".mli" produced by "ocamlyacc". + +\section{Syntax of grammar definitions} + +Grammar definitions have the following format: +\begin{alltt} +\%\{ + \var{header} +\%\} + \var{declarations} +\%\% + \var{rules} +\%\% + \var{trailer} +\end{alltt} + +Comments are enclosed between \verb|/*| and \verb|*/| (as in C) in the +``declarations'' and ``rules'' sections, and between \verb|(*| and +\verb|*)| (as in OCaml) in the ``header'' and ``trailer'' sections. + +\subsection{Header and trailer} + +The header and the trailer sections are OCaml code that is copied +as is into file \var{grammar}".ml". Both sections are optional. The header +goes at the beginning of the output file; it usually contains +"open" directives and auxiliary functions required by the semantic +actions of the rules. The trailer goes at the end of the output file. + +\subsection{Declarations} + +Declarations are given one per line. They all start with a \verb"%" sign. + +\begin{options} + +\item[@"%token" constr \ldots constr@] +Declare the given symbols @constr \ldots constr@ +as tokens (terminal symbols). These symbols +are added as constant constructors for the "token" concrete type. + +\item[@"%token" "<" typexpr ">" constr \ldots constr@] +Declare the given symbols @constr \ldots constr@ as tokens with an +attached attribute of the +given type. These symbols are added as constructors with arguments of +the given type for the "token" concrete type. The @typexpr@ part is +an arbitrary OCaml type expression, except that all type +constructor names must be fully qualified (e.g. "Modname.typename") +for all types except standard built-in types, even if the proper +\verb|open| directives (e.g. \verb|open Modname|) were given in the +header section. That's because the header is copied only to the ".ml" +output file, but not to the ".mli" output file, while the @typexpr@ part +of a \verb"%token" declaration is copied to both. + +\item[@"%start" symbol \ldots symbol@] +Declare the given symbols as entry points for the grammar. For each +entry point, a parsing function with the same name is defined in the +output module. Non-terminals that are not declared as entry points +have no such parsing function. Start symbols must be given a type with +the \verb|%type| directive below. + +\item[@"%type" "<" typexpr ">" symbol \ldots symbol@] +Specify the type of the semantic attributes for the given symbols. +This is mandatory for start symbols only. Other nonterminal symbols +need not be given types by hand: these types will be inferred when +running the output files through the OCaml compiler (unless the +\verb"-s" option is in effect). The @typexpr@ part is an arbitrary OCaml +type expression, except that all type constructor names must be +fully qualified, as explained above for "%token". + +\item[@"%left" symbol \ldots symbol@] +\item[@"%right" symbol \ldots symbol@] +\item[@"%nonassoc" symbol \ldots symbol@] + +Associate precedences and associativities to the given symbols. All +symbols on the same line are given the same precedence. They have +higher precedence than symbols declared before in a \verb"%left", +\verb"%right" or \verb"%nonassoc" line. They have lower precedence +than symbols declared after in a \verb"%left", \verb"%right" or +\verb"%nonassoc" line. The symbols are declared to associate to the +left (\verb"%left"), to the right (\verb"%right"), or to be +non-associative (\verb"%nonassoc"). The symbols are usually tokens. +They can also be dummy nonterminals, for use with the \verb"%prec" +directive inside the rules. + +The precedence declarations are used in the following way to +resolve reduce/reduce and shift/reduce conflicts: +\begin{itemize} +\item Tokens and rules have precedences. By default, the precedence + of a rule is the precedence of its rightmost terminal. You + can override this default by using the @"%prec"@ directive in the rule. +\item A reduce/reduce conflict + is resolved in favor of the first rule (in the order given by the + source file), and "ocamlyacc" outputs a warning. +\item A shift/reduce conflict + is resolved by comparing the precedence of the rule to be + reduced with the precedence of the token to be shifted. If the + precedence of the rule is higher, then the rule will be reduced; + if the precedence of the token is higher, then the token will + be shifted. +\item A shift/reduce conflict between a rule and a token with the + same precedence will be resolved using the associativity: if the + token is left-associative, then the parser will reduce; if the + token is right-associative, then the parser will shift. If the + token is non-associative, then the parser will declare a syntax + error. +\item When a shift/reduce conflict cannot be resolved using the above + method, then "ocamlyacc" will output a warning and the parser will + always shift. +\end{itemize} + +\end{options} + +\subsection{Rules} + +The syntax for rules is as usual: +\begin{alltt} +\var{nonterminal} : + \var{symbol} \ldots \var{symbol} \{ \var{semantic-action} \} + | \ldots + | \var{symbol} \ldots \var{symbol} \{ \var{semantic-action} \} +; +\end{alltt} +% +Rules can also contain the \verb"%prec "{\it symbol} directive in the +right-hand side part, to override the default precedence and +associativity of the rule with the precedence and associativity of the +given symbol. + +Semantic actions are arbitrary OCaml expressions, that +are evaluated to produce the semantic attribute attached to +the defined nonterminal. The semantic actions can access the +semantic attributes of the symbols in the right-hand side of +the rule with the \verb"$" notation: \verb"$1" is the attribute for the +first (leftmost) symbol, \verb"$2" is the attribute for the second +symbol, etc. + +The rules may contain the special symbol "error" to indicate +resynchronization points, as in "yacc". + +Actions occurring in the middle of rules are not supported. + +Nonterminal symbols are like regular OCaml symbols, except that they +cannot end with "'" (single quote). + +\subsection{Error handling} + +Error recovery is supported as follows: when the parser reaches an +error state (no grammar rules can apply), it calls a function named +"parse_error" with the string "\"syntax error\"" as argument. The default +"parse_error" function does nothing and returns, thus initiating error +recovery (see below). The user can define a customized "parse_error" +function in the header section of the grammar file. + +The parser also enters error recovery mode if one of the grammar +actions raises the "Parsing.Parse_error" exception. + +In error recovery mode, the parser discards states from the +stack until it reaches a place where the error token can be shifted. +It then discards tokens from the input until it finds three successive +tokens that can be accepted, and starts processing with the first of +these. If no state can be uncovered where the error token can be +shifted, then the parser aborts by raising the "Parsing.Parse_error" +exception. + +Refer to documentation on "yacc" for more details and guidance in how +to use error recovery. + +\section{Options} + +The "ocamlyacc" command recognizes the following options: + +\begin{options} + +\item["-b"{\it prefix}] +Name the output files {\it prefix}".ml", {\it prefix}".mli", +{\it prefix}".output", instead of the default naming convention. + +\item["-q"] +This option has no effect. + +\item["-v"] +Generate a description of the parsing tables and a report on conflicts +resulting from ambiguities in the grammar. The description is put in +file \var{grammar}".output". + +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-"] +Read the grammar specification from standard input. The default +output file names are "stdin.ml" and "stdin.mli". + +\item["--" \var{file}] +Process \var{file} as the grammar specification, even if its name +starts with a dash (-) character. This option must be the last on the +command line. + +\end{options} + +At run-time, the "ocamlyacc"-generated parser can be debugged by +setting the "p" option in the "OCAMLRUNPARAM" environment variable +(see section~\ref{ocamlrun-options}). This causes the pushdown +automaton executing the parser to print a trace of its action (tokens +shifted, rules reduced, etc). The trace mentions rule numbers and +state numbers that can be interpreted by looking at the file +\var{grammar}".output" generated by "ocamlyacc -v". + +\section{A complete example} + +The all-time favorite: a desk calculator. This program reads +arithmetic expressions on standard input, one per line, and prints +their values. Here is the grammar definition: +\begin{verbatim} + /* File parser.mly */ + %token INT + %token PLUS MINUS TIMES DIV + %token LPAREN RPAREN + %token EOL + %left PLUS MINUS /* lowest precedence */ + %left TIMES DIV /* medium precedence */ + %nonassoc UMINUS /* highest precedence */ + %start main /* the entry point */ + %type main + %% + main: + expr EOL { $1 } + ; + expr: + INT { $1 } + | LPAREN expr RPAREN { $2 } + | expr PLUS expr { $1 + $3 } + | expr MINUS expr { $1 - $3 } + | expr TIMES expr { $1 * $3 } + | expr DIV expr { $1 / $3 } + | MINUS expr %prec UMINUS { - $2 } + ; +\end{verbatim} +Here is the definition for the corresponding lexer: +\begin{verbatim} + (* File lexer.mll *) + { + open Parser (* The type token is defined in parser.mli *) + exception Eof + } + rule token = parse + [' ' '\t'] { token lexbuf } (* skip blanks *) + | ['\n' ] { EOL } + | ['0'-'9']+ as lxm { INT(int_of_string lxm) } + | '+' { PLUS } + | '-' { MINUS } + | '*' { TIMES } + | '/' { DIV } + | '(' { LPAREN } + | ')' { RPAREN } + | eof { raise Eof } +\end{verbatim} +Here is the main program, that combines the parser with the lexer: +\begin{verbatim} + (* File calc.ml *) + let _ = + try + let lexbuf = Lexing.from_channel stdin in + while true do + let result = Parser.main Lexer.token lexbuf in + print_int result; print_newline(); flush stdout + done + with Lexer.Eof -> + exit 0 +\end{verbatim} +To compile everything, execute: +\begin{verbatim} + ocamllex lexer.mll # generates lexer.ml + ocamlyacc parser.mly # generates parser.ml and parser.mli + ocamlc -c parser.mli + ocamlc -c lexer.ml + ocamlc -c parser.ml + ocamlc -c calc.ml + ocamlc -o calc lexer.cmo parser.cmo calc.cmo +\end{verbatim} + +\section{Common errors} + +\begin{options} + +\item[ocamllex: transition table overflow, automaton is too big] + +The deterministic automata generated by "ocamllex" are limited to at +most 32767 transitions. The message above indicates that your lexer +definition is too complex and overflows this limit. This is commonly +caused by lexer definitions that have separate rules for each of the +alphabetic keywords of the language, as in the following example. +\begin{verbatim} +rule token = parse + "keyword1" { KWD1 } +| "keyword2" { KWD2 } +| ... +| "keyword100" { KWD100 } +| ['A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '0'-'9' '_'] * as id + { IDENT id} +\end{verbatim} +To keep the generated automata small, rewrite those definitions with +only one general ``identifier'' rule, followed by a hashtable lookup +to separate keywords from identifiers: +\begin{verbatim} +{ let keyword_table = Hashtbl.create 53 + let _ = + List.iter (fun (kwd, tok) -> Hashtbl.add keyword_table kwd tok) + [ "keyword1", KWD1; + "keyword2", KWD2; ... + "keyword100", KWD100 ] +} +rule token = parse + ['A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '0'-'9' '_'] * as id + { try + Hashtbl.find keyword_table id + with Not_found -> + IDENT id } +\end{verbatim} + +\item[ocamllex: Position memory overflow, too many bindings] +The deterministic automata generated by "ocamllex" maintain a table of +positions inside the scanned lexer buffer. The size of this table is +limited to at most 255 cells. This error should not show up in normal +situations. + +\end{options} diff --git a/manual/manual/cmds/native.etex b/manual/manual/cmds/native.etex new file mode 100644 index 00000000..c06a8186 --- /dev/null +++ b/manual/manual/cmds/native.etex @@ -0,0 +1,231 @@ +\chapter{Native-code compilation (ocamlopt)} \label{c:nativecomp} +\pdfchapter{Native-code compilation (ocamlopt)} +%HEVEA\cutname{native.html} + +This chapter describes the OCaml high-performance +native-code compiler "ocamlopt", which compiles OCaml source files to +native code object files and links these object files to produce +standalone executables. + +The native-code compiler is only available on certain platforms. +It produces code that runs faster than the bytecode produced by +"ocamlc", at the cost of increased compilation time and executable code +size. Compatibility with the bytecode compiler is extremely high: the +same source code should run identically when compiled with "ocamlc" and +"ocamlopt". + +It is not possible to mix native-code object files produced by "ocamlopt" +with bytecode object files produced by "ocamlc": a program must be +compiled entirely with "ocamlopt" or entirely with "ocamlc". Native-code +object files produced by "ocamlopt" cannot be loaded in the toplevel +system "ocaml". + +\section{Overview of the compiler} + +The "ocamlopt" command has a command-line interface very close to that +of "ocamlc". It accepts the same types of arguments, and processes them +sequentially, after all options have been processed: + +\begin{itemize} +\item +Arguments ending in ".mli" are taken to be source files for +compilation unit interfaces. Interfaces specify the names exported by +compilation units: they declare value names with their types, define +public data types, declare abstract data types, and so on. From the +file \var{x}".mli", the "ocamlopt" compiler produces a compiled interface +in the file \var{x}".cmi". The interface produced is identical to that +produced by the bytecode compiler "ocamlc". + +\item +Arguments ending in ".ml" are taken to be source files for compilation +unit implementations. Implementations provide definitions for the +names exported by the unit, and also contain expressions to be +evaluated for their side-effects. From the file \var{x}".ml", the "ocamlopt" +compiler produces two files: \var{x}".o", containing native object code, +and \var{x}".cmx", containing extra information for linking and +optimization of the clients of the unit. The compiled implementation +should always be referred to under the name \var{x}".cmx" (when given +a ".o" or ".obj" file, "ocamlopt" assumes that it contains code compiled from C, +not from OCaml). + +The implementation is checked against the interface file \var{x}".mli" +(if it exists) as described in the manual for "ocamlc" +(chapter~\ref{c:camlc}). + +\item +Arguments ending in ".cmx" are taken to be compiled object code. These +files are linked together, along with the object files obtained +by compiling ".ml" arguments (if any), and the OCaml standard +library, to produce a native-code executable program. The order in +which ".cmx" and ".ml" arguments are presented on the command line is +relevant: compilation units are initialized in that order at +run-time, and it is a link-time error to use a component of a unit +before having initialized it. Hence, a given \var{x}".cmx" file must come +before all ".cmx" files that refer to the unit \var{x}. + +\item +Arguments ending in ".cmxa" are taken to be libraries of object code. +Such a library packs in two files (\var{lib}".cmxa" and \var{lib}".a"/".lib") +a set of object files (".cmx" and ".o"/".obj" files). Libraries are build with +"ocamlopt -a" (see the description of the "-a" option below). The object +files contained in the library are linked as regular ".cmx" files (see +above), in the order specified when the library was built. The only +difference is that if an object file contained in a library is not +referenced anywhere in the program, then it is not linked in. + +\item +Arguments ending in ".c" are passed to the C compiler, which generates +a ".o"/".obj" object file. This object file is linked with the program. + +\item +Arguments ending in ".o", ".a" or ".so" (".obj", ".lib" and ".dll" +under Windows) are assumed to be C object files and +libraries. They are linked with the program. + +\end{itemize} + +The output of the linking phase is a regular Unix or Windows +executable file. It does not need "ocamlrun" to run. + +\section{Options} + +The following command-line options are recognized by "ocamlopt". +The options "-pack", "-a", "-shared", "-c" and "-output-obj" are mutually +exclusive. + +% Configure boolean variables used by the macros in unified-options.etex +\compfalse +\nattrue +\topfalse +% unified-options gathers all options across the native/bytecode +% compilers and toplevel +\input{unified-options.tex} + +\paragraph{Options for the IA32 architecture} +The IA32 code generator (Intel Pentium, AMD Athlon) supports the +following additional option: + +\begin{options} +\item["-ffast-math"] Use the IA32 instructions to compute +trigonometric and exponential functions, instead of calling the +corresponding library routines. The functions affected are: +"atan", "atan2", "cos", "log", "log10", "sin", "sqrt" and "tan". +The resulting code runs faster, but the range of supported arguments +and the precision of the result can be reduced. In particular, +trigonometric operations "cos", "sin", "tan" have their range reduced to +$[-2^{64}, 2^{64}]$. +\end{options} + +\paragraph{Options for the AMD64 architecture} +The AMD64 code generator (64-bit versions of Intel Pentium and AMD +Athlon) supports the following additional options: + +\begin{options} +\item["-fPIC"] Generate position-independent machine code. This is +the default. +\item["-fno-PIC"] Generate position-dependent machine code. +\end{options} + +\paragraph{Contextual control of command-line options} + +The compiler command line can be modified ``from the outside'' +with the following mechanisms. These are experimental +and subject to change. They should be used only for experimental and +development work, not in released packages. + +\begin{options} +\item["OCAMLPARAM" \rm(environment variable)] +A set of arguments that will be inserted before or after the arguments from +the command line. Arguments are specified in a comma-separated list +of "name=value" pairs. A "_" is used to specify the position of +the command line arguments, i.e. "a=x,_,b=y" means that "a=x" should be +executed before parsing the arguments, and "b=y" after. Finally, +an alternative separator can be specified as the +first character of the string, within the set ":|; ,". +\item["ocaml_compiler_internal_params" \rm(file in the stdlib directory)] +A mapping of file names to lists of arguments that +will be added to the command line (and "OCAMLPARAM") arguments. +\item["OCAML_FLEXLINK" \rm(environment variable)] +Alternative executable to use on native +Windows for "flexlink" instead of the +configured value. Primarily used for bootstrapping. +\end{options} + +\section{Common errors} + +The error messages are almost identical to those of "ocamlc". +See section~\ref{s:comp-errors}. + +\section{Running executables produced by ocamlopt} + +Executables generated by "ocamlopt" are native, stand-alone executable +files that can be invoked directly. They do +not depend on the "ocamlrun" bytecode runtime system nor on +dynamically-loaded C/OCaml stub libraries. + +During execution of an "ocamlopt"-generated executable, +the following environment variables are also consulted: +\begin{options} +\item["OCAMLRUNPARAM"] Same usage as in "ocamlrun" + (see section~\ref{ocamlrun-options}), except that option "l" + is ignored (the operating system's stack size limit + is used instead). +\item["CAMLRUNPARAM"] If "OCAMLRUNPARAM" is not found in the + environment, then "CAMLRUNPARAM" will be used instead. If + "CAMLRUNPARAM" is not found, then the default values will be used. +\end{options} + +\section{Compatibility with the bytecode compiler} +\label{s:compat-native-bytecode} + +This section lists the known incompatibilities between the bytecode +compiler and the native-code compiler. Except on those points, the two +compilers should generate code that behave identically. + +\begin{itemize} + +\item Signals are detected only when the program performs an +allocation in the heap. That is, if a signal is delivered while in a +piece of code that does not allocate, its handler will not be called +until the next heap allocation. + +\item Stack overflow, typically caused by excessively deep recursion, +is not always turned into a "Stack_overflow" exception like the +bytecode compiler does. The runtime system makes a best effort to +trap stack overflows and raise the "Stack_overflow" exception, but +sometimes it fails and a ``segmentation fault'' or another system fault +occurs instead. + +\item On ARM and PowerPC processors (32 and 64 bits), fused + multiply-add (FMA) instructions can be generated for a + floating-point multiplication followed by a floating-point addition + or subtraction, as in "x *. y +. z". The FMA instruction avoids + rounding the intermediate result "x *. y", which is generally + beneficial, but produces floating-point results that differ slightly + from those produced by the bytecode interpreter. + +\item On IA32 processors only (Intel and AMD x86 processors in 32-bit +mode), some intermediate results in floating-point computations are +kept in extended precision rather than being rounded to double +precision like the bytecode compiler always does. Floating-point +results can therefore differ slightly between bytecode and native code. + +\item The native-code compiler performs a number of optimizations that +the bytecode compiler does not perform, especially when the Flambda +optimizer is active. In particular, the native-code compiler +identifies and eliminates ``dead code'', i.e.\ computations that do +not contribute to the results of the program. For example, +\begin{verbatim} + let _ = ignore M.f +\end{verbatim} +contains a reference to compilation unit "M" when compiled to +bytecode. This reference forces "M" to be linked and its +initialization code to be executed. The native-code compiler +eliminates the reference to "M", hence the compilation unit "M" may +not be linked and executed. A workaround is to compile "M" with the +"-linkall" flag so that it will always be linked and executed, even if +not referenced. See also the "Sys.opaque_identity" function from the +"Sys" standard library module. + +\end{itemize} + diff --git a/manual/manual/cmds/ocamlbuild.etex b/manual/manual/cmds/ocamlbuild.etex new file mode 100644 index 00000000..9a55b48a --- /dev/null +++ b/manual/manual/cmds/ocamlbuild.etex @@ -0,0 +1,6 @@ +\chapter{The ocamlbuild compilation manager} \label{c:ocamlbuild} +\pdfchapter{The ocamlbuild compilation manager} + +Since OCaml version 4.03, the ocamlbuild compilation manager is +distributed separately from the OCaml compiler. The project is now +hosted at \url{https://github.com/ocaml/ocamlbuild/}. diff --git a/manual/manual/cmds/ocamldoc.etex b/manual/manual/cmds/ocamldoc.etex new file mode 100644 index 00000000..d7346bb4 --- /dev/null +++ b/manual/manual/cmds/ocamldoc.etex @@ -0,0 +1,1136 @@ +\chapter{The documentation generator (ocamldoc)} \label{c:ocamldoc} +\pdfchapter{The documentation generator (ocamldoc)} +%HEVEA\cutname{ocamldoc.html} + +This chapter describes OCamldoc, a tool that generates documentation from +special comments embedded in source files. The comments used by OCamldoc +are of the form "(**"\ldots"*)" and follow the format described +in section \ref{s:ocamldoc-comments}. + +OCamldoc can produce documentation in various formats: HTML, \LaTeX , +TeXinfo, Unix man pages, and "dot" dependency graphs. Moreover, +users can add their own custom generators, as explained in +section \ref{s:ocamldoc-custom-generators}. + +In this chapter, we use the word {\em element} to refer to any of the +following parts of an OCaml source file: a type declaration, a value, +a module, an exception, a module type, a type constructor, a record +field, a class, a class type, a class method, a class value or a class +inheritance clause. + +\section{Usage} \label{s:ocamldoc-usage} + +\subsection{Invocation} + +OCamldoc is invoked via the command "ocamldoc", as follows: +\begin{alltt} + ocamldoc \var{options} \var{sourcefiles} +\end{alltt} + +\subsubsection*{Options for choosing the output format} + +The following options determine the format for the generated +documentation. + +\begin{options} +\item["-html"] +Generate documentation in HTML default format. The generated HTML pages +are stored in the current directory, or in the directory specified +with the {\bf\tt -d} option. You can customize the style of the +generated pages by editing the generated "style.css" file, or by providing +your own style sheet using option "-css-style". +The file "style.css" is not generated if it already exists or if -css-style is used. + +\item["-latex"] +Generate documentation in \LaTeX\ default format. The generated +\LaTeX\ document is saved in file "ocamldoc.out", or in the file +specified with the {\bf\tt -o} option. The document uses the style file +"ocamldoc.sty". This file is generated when using the "-latex" option, +if it does not already exist. +You can change this file to customize the style of your \LaTeX\ documentation. + +\item["-texi"] +Generate documentation in TeXinfo default format. The generated +\LaTeX\ document is saved in file "ocamldoc.out", or in the file +specified with the {\bf\tt -o} option. + +\item["-man"] +Generate documentation as a set of Unix "man" pages. The generated pages +are stored in the current directory, or in the directory specified +with the {\bf\tt -d} option. + +\item["-dot"] +Generate a dependency graph for the toplevel modules, in a format suitable +for displaying and processing by "dot". The "dot" tool is available from +\url{http://www.research.att.com/sw/tools/graphviz/}. +The textual representation of the graph is written to the file +"ocamldoc.out", or to the file specified with the {\bf\tt -o} option. +Use "dot ocamldoc.out" to display it. + +\item["-g" \var{file.cm[o,a,xs]}] +Dynamically load the given file, which defines a custom documentation +generator. See section \ref{s:ocamldoc-compilation-and-usage}. This +option is supported by the "ocamldoc" command (to load ".cmo" and ".cma" files) +and by its native-code version "ocamldoc.opt" (to load ".cmxs" files). +If the given file is a simple one and does not exist in +the current directory, then ocamldoc looks for it in the custom +generators default directory, and in the directories specified with +optional "-i" options. + +\item["-customdir"] +Display the custom generators default directory. + +\item["-i" \var{directory}] +Add the given directory to the path where to look for custom generators. + +\end{options} + +\subsubsection*{General options} + +\begin{options} + +\item["-d" \var{dir}] +Generate files in directory \var{dir}, rather than the current directory. + +\item["-dump" \var{file}] +Dump collected information into \var{file}. This information can be +read with the "-load" option in a subsequent invocation of "ocamldoc". + +\item["-hide" \var{modules}] +Hide the given complete module names in the generated documentation. +\var{modules} is a list of complete module names separated + by '","', without blanks. For instance: "Pervasives,M2.M3". + +\item["-inv-merge-ml-mli"] +Reverse the precedence of implementations and interfaces when merging. +All elements +in implementation files are kept, and the {\bf\tt -m} option +indicates which parts of the comments in interface files are merged +with the comments in implementation files. + +\item["-keep-code"] +Always keep the source code for values, methods and instance variables, +when available. + +\item["-load" \var{file}] +Load information from \var{file}, which has been produced by +"ocamldoc -dump". Several "-load" options can be given. + +\item["-m" \var{flags}] +Specify merge options between interfaces and implementations. +(see section \ref{s:ocamldoc-merge} for details). +\var{flags} can be one or several of the following characters: +\begin{options} + \item["d"] merge description + \item["a"] merge "\@author" + \item["v"] merge "\@version" + \item["l"] merge "\@see" + \item["s"] merge "\@since" + \item["b"] merge "\@before" + \item["o"] merge "\@deprecated" + \item["p"] merge "\@param" + \item["e"] merge "\@raise" + \item["r"] merge "\@return" + \item["A"] merge everything +\end{options} + +\item["-no-custom-tags"] +Do not allow custom \@-tags (see section \ref{s:ocamldoc-tags}). + +\item["-no-stop"] +Keep elements placed after/between the "(**/**)" special comment(s) +(see section \ref{s:ocamldoc-comments}). + +\item["-o" \var{file}] +Output the generated documentation to \var{file} instead of "ocamldoc.out". +This option is meaningful only in conjunction with the +{\bf\tt -latex}, {\bf\tt -texi}, or {\bf\tt -dot} options. + +\item["-pp" \var{command}] +Pipe sources through preprocessor \var{command}. + +\item["-impl" \var{filename}] +Process the file \var{filename} as an implementation file, even if its +extension is not ".ml". + +\item["-intf" \var{filename}] +Process the file \var{filename} as an interface file, even if its +extension is not ".mli". + +\item["-text" \var{filename}] +Process the file \var{filename} as a text file, even if its +extension is not ".txt". + +\item["-sort"] +Sort the list of top-level modules before generating the documentation. + +\item["-stars"] +Remove blank characters until the first asterisk ('"*"') in each +line of comments. + +\item["-t" \var{title}] +Use \var{title} as the title for the generated documentation. + +\item["-intro" \var{file}] +Use content of \var{file} as ocamldoc text to use as introduction (HTML, +\LaTeX{} and TeXinfo only). +For HTML, the file is used to create the whole "index.html" file. + +\item["-v"] +Verbose mode. Display progress information. + +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-warn-error"] +Treat Ocamldoc warnings as errors. + +\item["-hide-warnings"] +Do not print OCamldoc warnings. + +\item["-help" or "--help"] +Display a short usage summary and exit. +% +\end{options} + +\subsubsection*{Type-checking options} + +OCamldoc calls the OCaml type-checker to obtain type +information. The following options impact the type-checking phase. +They have the same meaning as for the "ocamlc" and "ocamlopt" commands. + +\begin{options} + +\item["-I" \var{directory}] +Add \var{directory} to the list of directories search for compiled +interface files (".cmi" files). + +\item["-nolabels"] +Ignore non-optional labels in types. + +\item["-rectypes"] +Allow arbitrary recursive types. (See the "-rectypes" option to "ocamlc".) + +\end{options} + +\subsubsection*{Options for generating HTML pages} + +The following options apply in conjunction with the "-html" option: + +\begin{options} +\item["-all-params"] +Display the complete list of parameters for functions and methods. + +\item["-charset" \var{charset}] +Add information about character encoding being \var{charset} +(default is iso-8859-1). + +\item["-colorize-code"] +Colorize the OCaml code enclosed in "[ ]" and "{[ ]}", using colors +to emphasize keywords, etc. If the code fragments are not +syntactically correct, no color is added. + +\item["-css-style" \var{filename}] +Use \var{filename} as the Cascading Style Sheet file. + +\item["-index-only"] +Generate only index files. + +\item["-short-functors"] +Use a short form to display functors: +\begin{alltt} +module M : functor (A:Module) -> functor (B:Module2) -> sig .. end +\end{alltt} +is displayed as: +\begin{alltt} +module M (A:Module) (B:Module2) : sig .. end +\end{alltt} + +\end{options} + +\subsubsection*{Options for generating \LaTeX\ files} + +The following options apply in conjunction with the "-latex" option: + +\begin{options} +\item["-latex-value-prefix" \var{prefix}] +Give a prefix to use for the labels of the values in the generated +\LaTeX\ document. +The default prefix is the empty string. You can also use the options +{\tt -latex-type-prefix}, {\tt -latex-exception-prefix}, +{\tt -latex-module-prefix}, +{\tt -latex-module-type-prefix}, {\tt -latex-class-prefix}, +{\tt -latex-class-type-prefix}, +{\tt -latex-attribute-prefix} and {\tt -latex-method-prefix}. + +These options are useful when you have, for example, a type and a value with + the same name. If you do not specify prefixes, \LaTeX\ will complain about +multiply defined labels. + +\item["-latextitle" \var{n,style}] +Associate style number \var{n} to the given \LaTeX\ sectioning command +\var{style}, e.g. "section" or "subsection". (\LaTeX\ only.) This is +useful when including the generated document in another \LaTeX\ document, +at a given sectioning level. The default association is 1 for "section", +2 for "subsection", 3 for "subsubsection", 4 for "paragraph" and 5 for +"subparagraph". + +\item["-noheader"] +Suppress header in generated documentation. + +\item["-notoc"] +Do not generate a table of contents. + +\item["-notrailer"] +Suppress trailer in generated documentation. + +\item["-sepfiles"] +Generate one ".tex" file per toplevel module, instead of the global +"ocamldoc.out" file. +\end{options} + +\subsubsection*{Options for generating TeXinfo files} + +The following options apply in conjunction with the "-texi" option: + +\begin{options} +\item["-esc8"] +Escape accented characters in Info files. + +\item["-info-entry"] +Specify Info directory entry. + +\item["-info-section"] +Specify section of Info directory. + +\item["-noheader"] +Suppress header in generated documentation. + +\item["-noindex"] +Do not build index for Info files. + +\item["-notrailer"] +Suppress trailer in generated documentation. +\end{options} + +\subsubsection*{Options for generating "dot" graphs} + +The following options apply in conjunction with the "-dot" option: + +\begin{options} +\item["-dot-colors" \var{colors}] +Specify the colors to use in the generated "dot" code. +When generating module dependencies, "ocamldoc" uses different colors +for modules, depending on the directories in which they reside. +When generating types dependencies, "ocamldoc" uses different colors +for types, depending on the modules in which they are defined. +\var{colors} is a list of color names separated by '","', as +in "Red,Blue,Green". The available colors are the ones supported by +the "dot" tool. + +\item["-dot-include-all"] +Include all modules in the "dot" output, not only modules given +on the command line or loaded with the {\bf\tt -load} option. + +\item["-dot-reduce"] +Perform a transitive reduction of the dependency graph before +outputting the "dot" code. This can be useful if there are +a lot of transitive dependencies that clutter the graph. + +\item["-dot-types"] +Output "dot" code describing the type dependency graph instead of +the module dependency graph. +\end{options} + +\subsubsection*{Options for generating man files} + +The following options apply in conjunction with the "-man" option: + +\begin{options} +\item["-man-mini"] +Generate man pages only for modules, module types, classes and class +types, instead of pages for all elements. + +\item["-man-suffix" \var{suffix}] +Set the suffix used for generated man filenames. Default is '"3o"', +as in "List.3o". + +\item["-man-section" \var{section}] +Set the section number used for generated man filenames. Default is '"3"'. + +\end{options} + +\subsection{Merging of module information} +\label{s:ocamldoc-merge} + +Information on a module can be extracted either from the ".mli" or ".ml" +file, or both, depending on the files given on the command line. +When both ".mli" and ".ml" files are given for the same module, +information extracted from these files is merged according to the +following rules: +\begin{itemize} +\item Only elements (values, types, classes, ...) declared in the ".mli" +file are kept. In other terms, definitions from the ".ml" file that are +not exported in the ".mli" file are not documented. +\item Descriptions of elements and descriptions in \@-tags are handled +as follows. If a description for the same element or in the same +\@-tag of the same element is present in both files, then the +description of the ".ml" file is concatenated to the one in the ".mli" file, +if the corresponding "-m" flag is given on the command line. +If a description is present in the ".ml" file and not in the +".mli" file, the ".ml" description is kept. +In either case, all the information given in the ".mli" file is kept. +\end{itemize} + +\subsection{Coding rules} +\label{s:ocamldoc-rules} +The following rules must be respected in order to avoid name clashes +resulting in cross-reference errors: +\begin{itemize} +\item In a module, there must not be two modules, two module types or + a module and a module type with the same name. + In the default HTML generator, modules "ab" and "AB" will be printed + to the same file on case insensitive file systems. +\item In a module, there must not be two classes, two class types or + a class and a class type with the same name. +\item In a module, there must not be two values, two types, or two + exceptions with the same name. +\item Values defined in tuple, as in "let (x,y,z) = (1,2,3)" +are not kept by OCamldoc. +\item Avoid the following construction: +\begin{caml_eval} +module Foo = struct module Bar = struct let x = 1 end end;; +\end{caml_eval} +\begin{caml_example*}{verbatim} +open Foo (* which has a module Bar with a value x *) +module Foo = + struct + module Bar = + struct + let x = 1 + end + end + let dummy = Bar.x +\end{caml_example*} +In this case, OCamldoc will associate "Bar.x" to the "x" of module +"Foo" defined just above, instead of to the "Bar.x" defined in the +opened module "Foo". +\end{itemize} + +\section{Syntax of documentation comments} +\label{s:ocamldoc-comments} + +Comments containing documentation material are called {\em special +comments} and are written between "(**" and "*)". Special comments +must start exactly with "(**". Comments beginning with "(" and more +than two "*" are ignored. + +\subsection{Placement of documentation comments} +OCamldoc can associate comments to some elements of the language +encountered in the source files. The association is made according to +the locations of comments with respect to the language elements. The +locations of comments in ".mli" and ".ml" files are different. + +%%%%%%%%%%%%% +\subsubsection{Comments in ".mli" files} +A special comment is associated to an element if it is placed before or +after the element.\\ +A special comment before an element is associated to this element if~: +\begin{itemize} +\item There is no blank line or another special comment between the special +comment and the element. However, a regular comment can occur between +the special comment and the element. +\item The special comment is not already associated to the previous element. +\item The special comment is not the first one of a toplevel module. +\end{itemize} + +A special comment after an element is associated to this element if +there is no blank line or comment between the special comment and the +element. + +There are two exceptions: for constructors and record fields in +type definitions, the associated comment can only be placed after the +constructor or field definition, without blank lines or other comments +between them. The special comment for a constructor +with another constructor following must be placed before the '"|"' +character separating the two constructors. + +The following sample interface file "foo.mli" illustrates the +placement rules for comments in ".mli" files. + +\begin{caml_eval} +class cl = object end +\end{caml_eval} +\begin{caml_example*}{signature} +(** The first special comment of the file is the comment associated + with the whole module.*) + + +(** Special comments can be placed between elements and are kept + by the OCamldoc tool, but are not associated to any element. + @-tags in these comments are ignored.*) + +(*******************************************************************) +(** Comments like the one above, with more than two asterisks, + are ignored. *) + +(** The comment for function f. *) +val f : int -> int -> int +(** The continuation of the comment for function f. *) + +(** Comment for exception My_exception, even with a simple comment + between the special comment and the exception.*) +(* Hello, I'm a simple comment :-) *) +exception My_exception of (int -> int) * int + +(** Comment for type weather *) +type weather = +| Rain of int (** The comment for constructor Rain *) +| Sun (** The comment for constructor Sun *) + +(** Comment for type weather2 *) +type weather2 = +| Rain of int (** The comment for constructor Rain *) +| Sun (** The comment for constructor Sun *) +(** I can continue the comment for type weather2 here + because there is already a comment associated to the last constructor.*) + +(** The comment for type my_record *) +type my_record = { + foo : int ; (** Comment for field foo *) + bar : string ; (** Comment for field bar *) + } + (** Continuation of comment for type my_record *) + +(** Comment for foo *) +val foo : string +(** This comment is associated to foo and not to bar. *) +val bar : string +(** This comment is associated to bar. *) + +(** The comment for class my_class *) +class my_class : + object + (** A comment to describe inheritance from cl *) + inherit cl + + (** The comment for attribute tutu *) + val mutable tutu : string + + (** The comment for attribute toto. *) + val toto : int + + (** This comment is not attached to titi since + there is a blank line before titi, but is kept + as a comment in the class. *) + + val titi : string + + (** Comment for method toto *) + method toto : string + + (** Comment for method m *) + method m : float -> int + end + +(** The comment for the class type my_class_type *) +class type my_class_type = + object + (** The comment for variable x. *) + val mutable x : int + + (** The commend for method m. *) + method m : int -> int +end + +(** The comment for module Foo *) +module Foo : + sig + (** The comment for x *) + val x : int + + (** A special comment that is kept but not associated to any element *) + end + +(** The comment for module type my_module_type. *) +module type my_module_type = + sig + (** The comment for value x. *) + val x : int + + (** The comment for module M. *) + module M : + sig + (** The comment for value y. *) + val y : int + + (* ... *) + end + + end + +\end{caml_example*} + +%%%%%%%%%%%%% +\subsubsection{Comments in {\tt .ml} files} + +A special comment is associated to an element if it is placed before +the element and there is no blank line between the comment and the +element. Meanwhile, there can be a simple comment between the special +comment and the element. There are two exceptions, for +constructors and record fields in type definitions, whose associated +comment must be placed after the constructor or field definition, +without blank line between them. The special comment for a constructor +with another constructor following must be placed before the '"|"' +character separating the two constructors. + +The following example of file "toto.ml" shows where to place comments +in a ".ml" file. + +\begin{caml_example*}{verbatim} +(** The first special comment of the file is the comment associated + to the whole module. *) + +(** The comment for function f *) +let f x y = x + y + +(** This comment is not attached to any element since there is another + special comment just before the next element. *) + +(** Comment for exception My_exception, even with a simple comment + between the special comment and the exception.*) +(* A simple comment. *) +exception My_exception of (int -> int) * int + +(** Comment for type weather *) +type weather = +| Rain of int (** The comment for constructor Rain *) +| Sun (** The comment for constructor Sun *) + +(** The comment for type my_record *) +type my_record = { + foo : int ; (** Comment for field foo *) + bar : string ; (** Comment for field bar *) + } + +(** The comment for class my_class *) +class my_class = + object + (** A comment to describe inheritance from cl *) + inherit cl + + (** The comment for the instance variable tutu *) + val mutable tutu = "tutu" + (** The comment for toto *) + val toto = 1 + val titi = "titi" + (** Comment for method toto *) + method toto = tutu ^ "!" + (** Comment for method m *) + method m (f : float) = 1 + end + +(** The comment for class type my_class_type *) +class type my_class_type = + object + (** The comment for the instance variable x. *) + val mutable x : int + (** The commend for method m. *) + method m : int -> int + end + +(** The comment for module Foo *) +module Foo = + struct + (** The comment for x *) + let x = 0 + (** A special comment in the class, but not associated to any element. *) + end + +(** The comment for module type my_module_type. *) +module type my_module_type = + sig + (* Comment for value x. *) + val x : int + (* ... *) + end +\end{caml_example} + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{The Stop special comment} +The special comment "(**/**)" tells OCamldoc to discard +elements placed after this comment, up to the end of the current +class, class type, module or module type, or up to the next stop comment. +For instance: +\begin{caml_example*}{signature} +class type foo = + object + (** comment for method m *) + method m : string + + (**/**) + + (** This method won't appear in the documentation *) + method bar : int + end + +(** This value appears in the documentation, since the Stop special comment + in the class does not affect the parent module of the class.*) +val foo : string + +(**/**) +(** The value bar does not appear in the documentation.*) +val bar : string +(**/**) + +(** The type t appears since in the documentation since the previous stop comment +toggled off the "no documentation mode". *) +type t = string +\end{caml_example*} + +The {\bf\tt -no-stop} option to "ocamldoc" causes the Stop special +comments to be ignored. + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Syntax of documentation comments} + +The inside of documentation comments "(**"\ldots"*)" consists of +free-form text with optional formatting annotations, followed by +optional {\em tags} giving more specific information about parameters, +version, authors, \ldots\ The tags are distinguished by a leading "\@" +character. Thus, a documentation comment has the following shape: +\begin{verbatim} +(** The comment begins with a description, which is text formatted + according to the rules described in the next section. + The description continues until the first non-escaped '@' character. + @author Mr Smith + @param x description for parameter x +*) +\end{verbatim} +Some elements support only a subset of all \@-tags. Tags that are not +relevant to the documented element are simply ignored. For instance, +all tags are ignored when documenting type constructors, record +fields, and class inheritance clauses. Similarly, a "\@param" tag on a +class instance variable is ignored. + +At last, "(**)" is the empty documentation comment. + +%%%%%%%%%%%%% + +% enable section numbering for subsubsections (PR#6189, item 3) +\setcounter{secnumdepth}{3} + +\subsection{Text formatting} + +Here is the BNF grammar for the simple markup language used to format +text descriptions. + +\newpage + +\begin{syntax} +text: {{text-element}} +; +\end{syntax} + +\noindent +\begin{syntaxleft} +\nonterm{text-element}\is{} +\end{syntaxleft} + +\begin{tabular}{rlp{10cm}} +@||@&@ '{' {{ "0" \ldots "9" }} text '}' @ & format @text@ as a section header; + the integer following "{" indicates the sectioning level. \\ +@||@&@ '{' {{ "0" \ldots "9" }} ':' @ \nt{label} @ text '}' @ & + same, but also associate the name \nt{label} to the current point. + This point can be referenced by its fully-qualified label in a + "{!" command, just like any other element. \\ +@||@&@ '{b' text '}' @ & set @text@ in bold. \\ +@||@&@ '{i' text '}' @ & set @text@ in italic. \\ +@||@&@ '{e' text '}' @ & emphasize @text@. \\ +@||@&@ '{C' text '}' @ & center @text@. \\ +@||@&@ '{L' text '}' @ & left align @text@. \\ +@||@&@ '{R' text '}' @ & right align @text@. \\ +@||@&@ '{ul' list '}' @ & build a list. \\ +@||@&@ '{ol' list '}' @ & build an enumerated list. \\ +@||@&@ '{{:' string '}' text '}' @ & put a link to the given address +(given as @string@) on the given @text@. \\ +@||@&@ '[' string ']' @ & set the given @string@ in source code style. \\ +@||@&@ '{[' string ']}' @ & set the given @string@ in preformatted + source code style.\\ +@||@&@ '{v' string 'v}' @ & set the given @string@ in verbatim style. \\ +@||@&@ '{%' string '%}' @ & target-specific content + (\LaTeX\ code by default, see details + in \ref{sss:target-specific-syntax}) \\ +@||@&@ '{!' string '}' @ & insert a cross-reference to an element + (see section \ref{sss:crossref} for the syntax of cross-references).\\ +@||@&@ '{!modules:' string string ... '}' @ & insert an index table +for the given module names. Used in HTML only.\\ +@||@&@ '{!indexlist}' @ & insert a table of links to the various indexes +(types, values, modules, ...). Used in HTML only.\\ +@||@&@ '{^' text '}' @ & set text in superscript.\\ +@||@&@ '{_' text '}' @ & set text in subscript.\\ +@||@& \nt{escaped-string} & typeset the given string as is; +special characters ('"{"', '"}"', '"["', '"]"' and '"\@"') +must be escaped by a '"\\"'\\ +@||@& \nt{blank-line} & force a new line. +\end{tabular} \\ + +\subsubsection{List formatting} + +\begin{syntax} +list: +| {{ '{-' text '}' }} +| {{ '{li' text '}' }} +\end{syntax} + +A shortcut syntax exists for lists and enumerated lists: +\begin{verbatim} +(** Here is a {b list} +- item 1 +- item 2 +- item 3 + +The list is ended by the blank line.*) +\end{verbatim} +is equivalent to: +\begin{verbatim} +(** Here is a {b list} +{ul {- item 1} +{- item 2} +{- item 3}} +The list is ended by the blank line.*) +\end{verbatim} + +The same shortcut is available for enumerated lists, using '"+"' +instead of '"-"'. +Note that only one list can be defined by this shortcut in nested lists. + +\subsubsection{Cross-reference formatting} +\label{sss:crossref} + +Cross-references are fully qualified element names, as in the example +"{!Foo.Bar.t}". This is an ambiguous reference as it may designate +a type name, a value name, a class name, etc. It is possible to make +explicit the intended syntactic class, using "{!type:Foo.Bar.t}" to +designate a type, and "{!val:Foo.Bar.t}" a value of the same name. + +The list of possible syntactic class is as follows: +\begin{center} +\begin{tabular}{rl} +\multicolumn{1}{c}{"tag"} & \multicolumn{1}{c}{syntactic class}\\ \hline +"module:" & module \\ +"modtype:" & module type \\ +"class:" & class \\ +"classtype:" & class type \\ +"val:" & value \\ +"type:" & type \\ +"exception:" & exception \\ +"attribute:" & attribute \\ +"method:" & class method \\ +"section:" & ocamldoc section \\ +"const:" & variant constructor \\ +"recfield:" & record field +\end{tabular} +\end{center} + +In the case of variant constructors or record field, the constructor +or field name should be preceded by the name of the correspond type -- +to avoid the ambiguity of several types having the same constructor +names. For example, the constructor "Node" of the type "tree" will be +referenced as "{!tree.Node}" or "{!const:tree.Node}", or possibly +"{!Mod1.Mod2.tree.Node}" from outside the module. + +\subsubsection{First sentence} + +In the description of a value, type, exception, module, module type, class +or class type, the {\em first sentence} is sometimes used in indexes, or +when just a part of the description is needed. The first sentence +is composed of the first characters of the description, until +\begin{itemize} +\item the first dot followed by a blank, or +\item the first blank line +\end{itemize} +outside of the following text formatting : +@ '{ul' list '}' @, +@ '{ol' list '}' @, +@ '[' string ']' @, +@ '{[' string ']}' @, +@ '{v' string 'v}' @, +@ '{%' string '%}' @, +@ '{!' string '}' @, +@ '{^' text '}' @, +@ '{_' text '}' @. + +\subsubsection{Target-specific formatting} +\label{sss:target-specific-syntax} + +The content inside "{%foo: ... %}" is target-specific and will only be +interpreted by the backend "foo", and ignored by the others. The +backends of the distribution are "latex", "html", "texi" and "man". If +no target is specified (syntax "{% ... %}"), "latex" is chosen by +default. Custom generators may support their own target prefix. + +\subsubsection{Recognized HTML tags} +The HTML tags "..", +"..", +"..", +"

", +"
    ..
", +"
  • ..
  • ", +"
    ..
    " and +".." can be used instead of, respectively, +@ '{b ..}' @, +@ '[..]' @, +@ '{i ..}' @, +@ '{ul ..}' @, +@ '{ol ..}' @, +@ '{li ..}' @, +@ '{C ..}' @ and +"{[0-9] ..}". + +%disable section numbering for subsubsections +\setcounter{secnumdepth}{2} + +%%%%%%%%%%%%% +\subsection{Documentation tags (\@-tags)} +\label{s:ocamldoc-tags} + +\subsubsection{Predefined tags} +The following table gives the list of predefined \@-tags, with their +syntax and meaning.\\ + +\begin{tabular}{|p{5cm}|p{10cm}|}\hline +@ "@author" string @ & The author of the element. One author per +"\@author" tag. +There may be several "\@author" tags for the same element. \\ \hline + +@ "@deprecated" text @ & The @text@ should describe when the element was +deprecated, what to use as a replacement, and possibly the reason +for deprecation. \\ \hline + +@ "@param" id text @ & Associate the given description (@text@) to the +given parameter name @id@. This tag is used for functions, +methods, classes and functors. \\ \hline + +@ "@raise" Exc text @ & Explain that the element may raise + the exception @Exc@. \\ \hline + +@ "@return" text @ & Describe the return value and + its possible values. This tag is used for functions + and methods. \\ \hline + +@ "@see" '<' URL '>' text @ & Add a reference to the @URL@ +with the given @text@ as comment. \\ \hline + +@ "@see" "'"@\nt{filename}@"'" text @ & Add a reference to the given file name +(written between single quotes), with the given @text@ as comment. \\ \hline + +@ "@see" '"'@\nt{document-name}@'"' text @ & Add a reference to the given +document name (written between double quotes), with the given @text@ +as comment. \\ \hline + +@ "@since" string @ & Indicate when the element was introduced. \\ \hline + +@ "@before" @ \nt{version} @ text @ & Associate the given description (@text@) +to the given \nt{version} in order to document compatibility issues. \\ \hline + +@ "@version" string @ & The version number for the element. \\ \hline +\end{tabular} + +\subsubsection{Custom tags} +\label{s:ocamldoc-custom-tags} +You can use custom tags in the documentation comments, but they will +have no effect if the generator used does not handle them. To use a +custom tag, for example "foo", just put "\@foo" with some text in your +comment, as in: +\begin{verbatim} +(** My comment to show you a custom tag. +@foo this is the text argument to the [foo] custom tag. +*) +\end{verbatim} + +To handle custom tags, you need to define a custom generator, +as explained in section \ref{s:ocamldoc-handling-custom-tags}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Custom generators} +\label{s:ocamldoc-custom-generators} + +OCamldoc operates in two steps: +\begin{enumerate} +\item analysis of the source files; +\item generation of documentation, through a documentation generator, + which is an object of class "Odoc_args.class_generator". +\end{enumerate} +Users can provide their own documentation generator to be used during +step 2 instead of the default generators. +All the information retrieved during the analysis step is available through +the "Odoc_info" module, which gives access to all the types and functions + representing the elements found in the given modules, with their associated +description. + +The files you can use to define custom generators are installed in the +"ocamldoc" sub-directory of the OCaml standard library. + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{The generator modules} +The type of a generator module depends on the kind of generated documentation. +Here is the list of generator module types, with the name of the generator +class in the module~: +\begin{itemize} +\item for HTML~: "Odoc_html.Html_generator" (class "html"), +\item for \LaTeX~: "Odoc_latex.Latex_generator" (class "latex"), +\item for TeXinfo~: "Odoc_texi.Texi_generator" (class "texi"), +\item for man pages~: "Odoc_man.Man_generator" (class "man"), +\item for graphviz (dot)~: "Odoc_dot.Dot_generator" (class "dot"), +\item for other kinds~: "Odoc_gen.Base" (class "generator"). +\end{itemize} +That is, to define a new generator, one must implement a module with +the expected signature, and with the given generator class, providing +the "generate" method as entry point to make the generator generates +documentation for a given list of modules~: + +\begin{verbatim} + method generate : Odoc_info.Module.t_module list -> unit +\end{verbatim} + +\noindent{}This method will be called with the list of analysed and possibly +merged "Odoc_info.t_module" structures. + +It is recommended to inherit from the current generator of the same +kind as the one you want to define. Doing so, it is possible to +load various custom generators to combine improvements brought by each one. + +This is done using first class modules (see chapter \ref{s-first-class-modules}). + +The easiest way to define a custom generator is the following this example, +here extending the current HTML generator. We don't have to know if this is +the original HTML generator defined in ocamldoc or if it has been extended +already by a previously loaded custom generator~: + +\begin{verbatim} +module Generator (G : Odoc_html.Html_generator) = +struct + class html = + object(self) + inherit G.html as html + (* ... *) + + method generate module_list = + (* ... *) + () + + (* ... *) + end +end;; + +let _ = Odoc_args.extend_html_generator (module Generator : Odoc_gen.Html_functor);; +\end{verbatim} + +To know which methods to override and/or which methods are available, +have a look at the different base implementations, depending on the +kind of generator you are extending~: +\newcommand\ocamldocsrc[2]{\href{https://github.com/ocaml/ocaml/blob/{\ocamlversion}/ocamldoc/odoc_#1.ml}{#2}} +\begin{itemize} +\item for HTML~: \ocamldocsrc{html}{"odoc_html.ml"}, +\item for \LaTeX~: \ocamldocsrc{latex}{"odoc_latex.ml"}, +\item for TeXinfo~: \ocamldocsrc{texi}{"odoc_texi.ml"}, +\item for man pages~: \ocamldocsrc{man}{"odoc_man.ml"}, +\item for graphviz (dot)~: \ocamldocsrc{dot}{"odoc_dot.ml"}. +\end{itemize} + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Handling custom tags} +\label{s:ocamldoc-handling-custom-tags} + +Making a custom generator handle custom tags (see +\ref{s:ocamldoc-custom-tags}) is very simple. + +\subsubsection*{For HTML} +Here is how to develop a HTML generator handling your custom tags. + +The class "Odoc_html.Generator.html" inherits +from the class "Odoc_html.info", containing a field "tag_functions" which is a +list pairs composed of a custom tag (e.g. "\"foo\"") and a function taking +a "text" and returning HTML code (of type "string"). +To handle a new tag "bar", extend the current HTML generator + and complete the "tag_functions" field: +\begin{verbatim} +module Generator (G : Odoc_html.Html_generator) = +struct + class html = + object(self) + inherit G.html + + (** Return HTML code for the given text of a bar tag. *) + method html_of_bar t = (* your code here *) + + initializer + tag_functions <- ("bar", self#html_of_bar) :: tag_functions + end +end +let _ = Odoc_args.extend_html_generator (module Generator : Odoc_gen.Html_functor);; +\end{verbatim} + +Another method of the class "Odoc_html.info" will look for the +function associated to a custom tag and apply it to the text given to +the tag. If no function is associated to a custom tag, then the method +prints a warning message on "stderr". + +\subsubsection{For other generators} +You can act the same way for other kinds of generators. + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Adding command line options} +The command line analysis is performed after loading the module containing the +documentation generator, thus allowing command line options to be added to the + list of existing ones. Adding an option can be done with the function +\begin{verbatim} + Odoc_args.add_option : string * Arg.spec * string -> unit +\end{verbatim} +\noindent{}Note: Existing command line options can be redefined using +this function. + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Compilation and usage} +\label{s:ocamldoc-compilation-and-usage} + +%%%%%%%%%%%%%% +\subsubsection{Defining a custom generator class in one file} +Let "custom.ml" be the file defining a new generator class. +Compilation of "custom.ml" can be performed by the following command~: +\begin{alltt} + ocamlc -I +ocamldoc -c custom.ml +\end{alltt} +\noindent{}The file "custom.cmo" is created and can be used this way~: +\begin{alltt} + ocamldoc -g custom.cmo \var{other-options} \var{source-files} +\end{alltt} +\noindent{}Options selecting a built-in generator to "ocamldoc", such as +"-html", have no effect if a custom generator of the same kind is provided using +"-g". If the kinds do not match, the selected built-in generator is used and the +custom one is ignored. + +%%%%%%%%%%%%%% +\subsubsection{Defining a custom generator class in several files} +It is possible to define a generator class in several modules, which +are defined in several files \var{\nth{file}{1}}".ml"["i"], +\var{\nth{file}{2}}".ml"["i"], ..., \var{\nth{file}{n}}".ml"["i"]. A ".cma" +library file must be created, including all these files. + +The following commands create the "custom.cma" file from files +\var{\nth{file}{1}}".ml"["i"], ..., \var{\nth{file}{n}}".ml"["i"]~: +\begin{alltt} +ocamlc -I +ocamldoc -c \var{\nth{file}{1}}.ml\textrm{[}i\textrm{]} +ocamlc -I +ocamldoc -c \var{\nth{file}{2}}.ml\textrm{[}i\textrm{]} +... +ocamlc -I +ocamldoc -c \var{\nth{file}{n}}.ml\textrm{[}i\textrm{]} +ocamlc -o custom.cma -a \var{\nth{file}{1}}.cmo \var{\nth{file}{2}}.cmo ... \var{\nth{file}{n}}.cmo +\end{alltt} +\noindent{}Then, the following command uses "custom.cma" as custom generator: +\begin{alltt} + ocamldoc -g custom.cma \var{other-options} \var{source-files} +\end{alltt} diff --git a/manual/manual/cmds/plugins.etex b/manual/manual/cmds/plugins.etex new file mode 100644 index 00000000..7fd02e4f --- /dev/null +++ b/manual/manual/cmds/plugins.etex @@ -0,0 +1,88 @@ +\chapter{Compiler plugins\label{c:plugins}} +\pdfchapterfold{-9}{Compiler plugind} +%HEVEA\cutname{plugins.html} + +\section{Overview} + +Starting from OCaml 4.03, it is possible to extend the native and bytecode compilers +with plugins using the "-plugin" command line option of both tools. +This possibility is also available for "ocamldep" for OCaml version ulterior to 4.05. +Beware however that plugins are an advanced feature of which the design +is still in flux and breaking changes may happen in the future. Plugins features +are based on the compiler library API. In complement, new hooks have been added to +the compiler to increase its flexibility. + +In particular, hooks are available in the +\ifouthtml\ahref{libref/Pparse.html}{\texttt{Pparse} module} +\else\texttt{Pparse} module (see section~\ref{Pparse})\fi +to transform the parsed abstract syntax tree, providing similar functionality +to extension point based preprocessors. +Other hooks are available to analyze the typed tree in the +\ifouthtml\ahref{libref/Typemod.html}{\texttt{Typemod} module} +\else\texttt{Typemod} module (see section~\ref{Typemod})\fi +after the type-checking phase of the compiler. Since the typed tree relies +on numerous invariants that play a vital part in ulterior phases of the +compiler, it is not possible however to transform the typed tree. +Similarly, the intermediary lambda representation can be modified by using the +hooks provided in the +\ifouthtml\ahref{libref/Simplif.html}{\texttt{Simplif} module} +\else\texttt{Simplif} module (see section~\ref{Simplif})\fi. +A plugin can also add new options to a tool through the +"Clflags.add_arguments" function (see +\ifouthtml\ahref{libref/Clflags.html}{\texttt{Clflags} module} +\else\texttt{Clflags} module (see section~\ref{Clflags})\fi). + +Plugins are dynamically loaded and need to be compiled in the same mode (i.e. +native or bytecode) that the tool they extend. + +\section{Basic example} + +As an illustration, we shall build a simple "Hello world" plugin that adds +a simple statement "print_endline \"Hello from:$sourcefile\"" to a compiled file. + +The simplest way to implement this feature is to modify the abstract syntax +tree. We will therefore add an hooks to the "Pparse.ImplementationHooks". +Since the proposed modification is very basic, we could implement the hook +directly. However, for the sake of this illustration, we use the "Ast_mapper" +structure that provides a better path to build more interesting plugins. + +The first step is to build the AST fragment corresponding to the +evaluation of "print_endline": +\begin{verbatim} + let print_endline name = + let open Ast_helper in + let print_endline = Exp.ident + @@ Location.mknoloc @@Longident.Lident "print_endline" in + let hello = Exp.constant @@ Const.string @@ "Hello from: " ^ name in + Str.eval @@ Exp.apply print_endline [Asttypes.Nolabel, hello] +\end{verbatim}% +Then, we can construct an ast mapper that adds this fragment to the parsed +ast tree. +\begin{verbatim} +let add_hello name (mapper:Ast_mapper.mapper) structure = + let default = Ast_mapper.default_mapper in + (print_endline name) :: (default.structure default structure) + +let ast_mapper name = + { Ast_mapper.default_mapper with structure = add_hello name } +\end{verbatim}% +% +Once this AST mapper is constructed, we need to convert it to a hook and adds this +hook to the "Pparse.ImplementationsHooks". +\begin{verbatim} +let transform hook_info structure = + let astm = ast_mapper hook_info.Misc.sourcefile in + astm.structure astm structure + +let () = Pparse.ImplementationHooks.add_hook "Hello world hook" transform +\end{verbatim} +% +The resulting simplistic plugin can then be compiled with +\begin{verbatim} +$ ocamlopt -I +compiler-libs -shared plugin.ml -o plugin.cmxs +\end{verbatim} +% +Compiling other files with this plugin enabled is then as simple as +\begin{verbatim} +$ ocamlopt -plugin plugin.cmxs test.ml -o test +\end{verbatim} diff --git a/manual/manual/cmds/profil.etex b/manual/manual/cmds/profil.etex new file mode 100644 index 00000000..31b6ed95 --- /dev/null +++ b/manual/manual/cmds/profil.etex @@ -0,0 +1,176 @@ +\chapter{Profiling (ocamlprof)} \label{c:profiler} +\pdfchapter{Profiling (ocamlprof)} +%HEVEA\cutname{profil.html} + +This chapter describes how the execution of OCaml +programs can be profiled, by recording how many times functions are +called, branches of conditionals are taken, \ldots + +\section{Compiling for profiling} + +Before profiling an execution, the program must be compiled in +profiling mode, using the "ocamlcp" front-end to the "ocamlc" compiler +(see chapter~\ref{c:camlc}) or the "ocamloptp" front-end to the +"ocamlopt" compiler (see chapter~\ref{c:nativecomp}). When compiling +modules separately, "ocamlcp" or "ocamloptp" must be used when +compiling the modules (production of ".cmo" or ".cmx" files), and can +also be used (though this is not strictly necessary) when linking them +together. + +\paragraph{Note} If a module (".ml" file) doesn't have a corresponding +interface (".mli" file), then compiling it with "ocamlcp" will produce +object files (".cmi" and ".cmo") that are not compatible with the ones +produced by "ocamlc", which may lead to problems (if the ".cmi" or +".cmo" is still around) when switching between profiling and +non-profiling compilations. To avoid this problem, you should always +have a ".mli" file for each ".ml" file. The same problem exists with +"ocamloptp". + +\paragraph{Note} To make sure your programs can be compiled in +profiling mode, avoid using any identifier that begins with +"__ocaml_prof". + +The amount of profiling information can be controlled through the "-P" +option to "ocamlcp" or "ocamloptp", followed by one or several letters +indicating which parts of the program should be profiled: + +%% description des options +\begin{options} +\item["a"] all options +\item["f"] function calls : a count point is set at the beginning of +each function body +\item["i"] {\bf if \ldots then \ldots else \ldots} : count points are set in +both {\bf then} branch and {\bf else} branch +\item["l"] {\bf while, for} loops: a count point is set at the beginning of +the loop body +\item["m"] {\bf match} branches: a count point is set at the beginning of the +body of each branch +\item["t"] {\bf try \ldots with \ldots} branches: a count point is set at the +beginning of the body of each branch +\end{options} + +For instance, compiling with "ocamlcp -P film" profiles function calls, +if\ldots then\ldots else\ldots, loops and pattern matching. + +Calling "ocamlcp" or "ocamloptp" without the "-P" option defaults to +"-P fm", meaning that only function calls and pattern matching are +profiled. + +\paragraph{Note} For compatibility with previous releases, "ocamlcp" +also accepts the "-p" option, with the same arguments and behaviour as +"-P". + +The "ocamlcp" and "ocamloptp" commands also accept all the options of +the corresponding "ocamlc" or "ocamlopt" compiler, except the "-pp" +(preprocessing) option. + + +\section{Profiling an execution} + +Running an executable that has been compiled with "ocamlcp" or +"ocamloptp" records the execution counts for the specified parts of +the program and saves them in a file called "ocamlprof.dump" in the +current directory. + +If the environment variable "OCAMLPROF_DUMP" is set when the program +exits, its value is used as the file name instead of "ocamlprof.dump". + +The dump file is written only if the program terminates +normally (by calling "exit" or by falling through). It is not written +if the program terminates with an uncaught exception. + +If a compatible dump file already exists in the current directory, then the +profiling information is accumulated in this dump file. This allows, for +instance, the profiling of several executions of a program on +different inputs. Note that dump files produced by byte-code +executables (compiled with "ocamlcp") are compatible with the dump +files produced by native executables (compiled with "ocamloptp"). + +\section{Printing profiling information} + +The "ocamlprof" command produces a source listing of the program modules +where execution counts have been inserted as comments. For instance, +\begin{verbatim} + ocamlprof foo.ml +\end{verbatim} +prints the source code for the "foo" module, with comments indicating +how many times the functions in this module have been called. Naturally, +this information is accurate only if the source file has not been modified +after it was compiled. + +The following options are recognized by "ocamlprof": + +\begin{options} + +\item["-args" \var{filename}] + Read additional newline-terminated command line arguments from \var{filename}. + +\item["-args0" \var{filename}] + Read additional null character terminated command line arguments from \var{filename}. + +\item["-f" \var{dumpfile}] +Specifies an alternate dump file of profiling information to be read. + +\item["-F" \var{string}] +Specifies an additional string to be output with profiling information. +By default, "ocamlprof" will annotate programs with comments of the form +{\tt (* \var{n} *)} where \var{n} is the counter value for a profiling +point. With option {\tt -F \var{s}}, the annotation will be +{\tt (* \var{s}\var{n} *)}. + +\item["-impl" \var{filename}] +Process the file \var{filename} as an implementation file, even if its +extension is not ".ml". + +\item["-intf" \var{filename}] +Process the file \var{filename} as an interface file, even if its +extension is not ".mli". + +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-help" or "--help"] +Display a short usage summary and exit. +% +\end{options} + +\section{Time profiling} + +Profiling with "ocamlprof" only records execution counts, not the actual +time spent within each function. There is currently no way to perform +time profiling on bytecode programs generated by "ocamlc". + +Native-code programs generated by "ocamlopt" can be profiled for time +and execution counts using the "-p" option and the standard Unix +profiler "gprof". Just add the "-p" option when compiling and linking +the program: +\begin{alltt} + ocamlopt -o myprog -p \var{other-options} \var{files} + ./myprog + gprof myprog +\end{alltt} +OCaml function names in the output of "gprof" have the following format: +\begin{alltt} + \var{Module-name}_\var{function-name}_\var{unique-number} +\end{alltt} +Other functions shown are either parts of the OCaml run-time system or +external C functions linked with the program. + +The output of "gprof" is described in the Unix manual page for +"gprof(1)". It generally consists of two parts: a ``flat'' profile +showing the time spent in each function and the number of invocation +of each function, and a ``hierarchical'' profile based on the call +graph. Currently, only the Intel x86 ports of "ocamlopt" under +Linux, BSD and MacOS X support the two profiles. On other platforms, +"gprof" will report only the ``flat'' profile with just time +information. When reading the output of "gprof", keep in mind that +the accumulated times computed by "gprof" are based on heuristics and +may not be exact. + +\paragraph{Note} The "ocamloptp" command also accepts the "-p" +option. In that case, both kinds of profiling are performed by the +program, and you can display the results with the "gprof" and "ocamlprof" +commands, respectively. diff --git a/manual/manual/cmds/runtime.etex b/manual/manual/cmds/runtime.etex new file mode 100644 index 00000000..97232f67 --- /dev/null +++ b/manual/manual/cmds/runtime.etex @@ -0,0 +1,281 @@ +\chapter{The runtime system (ocamlrun)} \label{c:runtime} +\pdfchapter{The runtime system (ocamlrun)} +%HEVEA\cutname{runtime.html} + +The "ocamlrun" command executes bytecode files produced by the +linking phase of the "ocamlc" command. + +\section{Overview} + +The "ocamlrun" command comprises three main parts: the bytecode +interpreter, that actually executes bytecode files; the memory +allocator and garbage collector; and a set of C functions that +implement primitive operations such as input/output. + +The usage for "ocamlrun" is: +\begin{alltt} + ocamlrun \var{options} \var{bytecode-executable} \nth{arg}{1} ... \nth{arg}{n} +\end{alltt} +The first non-option argument is taken to be the name of the file +containing the executable bytecode. (That file is searched in the +executable path as well as in the current directory.) The remaining +arguments are passed to the OCaml program, in the string array +"Sys.argv". Element 0 of this array is the name of the +bytecode executable file; elements 1 to \var{n} are the remaining +arguments \nth{arg}{1} to \nth{arg}{n}. + +As mentioned in chapter~\ref{c:camlc}, the bytecode executable files +produced by the "ocamlc" command are self-executable, and manage to +launch the "ocamlrun" command on themselves automatically. That is, +assuming "a.out" is a bytecode executable file, +\begin{alltt} + a.out \nth{arg}{1} ... \nth{arg}{n} +\end{alltt} +works exactly as +\begin{alltt} + ocamlrun a.out \nth{arg}{1} ... \nth{arg}{n} +\end{alltt} +Notice that it is not possible to pass options to "ocamlrun" when +invoking "a.out" directly. + +\begin{windows} +Under several versions of Windows, bytecode executable files are +self-executable only if their name ends in ".exe". It is recommended +to always give ".exe" names to bytecode executables, e.g. compile +with "ocamlc -o myprog.exe ..." rather than "ocamlc -o myprog ...". +\end{windows} + +\section{Options} \label{ocamlrun-options} + +The following command-line options are recognized by "ocamlrun". + +\begin{options} + +\item["-b"] +When the program aborts due to an uncaught exception, print a detailed +``back trace'' of the execution, showing where the exception was +raised and which function calls were outstanding at this point. The +back trace is printed only if the bytecode executable contains +debugging information, i.e. was compiled and linked with the "-g" +option to "ocamlc" set. This is equivalent to setting the "b" flag +in the "OCAMLRUNPARAM" environment variable (see below). +\item["-I" \var{dir}] +Search the directory \var{dir} for dynamically-loaded libraries, +in addition to the standard search path (see +section~\ref{s-ocamlrun-dllpath}). +\item["-p"] +Print the names of the primitives known to this version of +"ocamlrun" and exit. +\item["-v"] +Direct the memory manager to print some progress messages on +standard error. This is equivalent to setting "v=63" in the +"OCAMLRUNPARAM" environment variable (see below). +\item["-version"] +Print version string and exit. +\item["-vnum"] +Print short version number and exit. + +\end{options} + +\noindent +The following environment variables are also consulted: + +\begin{options} +\item["CAML_LD_LIBRARY_PATH"] Additional directories to search for + dynamically-loaded libraries (see section~\ref{s-ocamlrun-dllpath}). + +\item["OCAMLLIB"] The directory containing the OCaml standard + library. (If "OCAMLLIB" is not set, "CAMLLIB" will be used instead.) + Used to locate the "ld.conf" configuration file for + dynamic loading (see section~\ref{s-ocamlrun-dllpath}). If not set, + default to the library directory specified when compiling OCaml. + +\item["OCAMLRUNPARAM"] Set the runtime system options + and garbage collection parameters. + (If "OCAMLRUNPARAM" is not set, "CAMLRUNPARAM" will be used instead.) + This variable must be a sequence of parameter specifications separated + by commas. + A parameter specification is an option letter followed by an "=" + sign, a decimal number (or an hexadecimal number prefixed by "0x"), + and an optional multiplier. The options are documented below; + the last six correspond to the fields of the + "control" record documented in +\ifouthtml + \ahref{libref/Gc.html}{Module \texttt{Gc}}. +\else + section~\ref{Gc}. +\fi + \begin{options} + \item[b] (backtrace) Trigger the printing of a stack backtrace + when an uncaught exception aborts the program. + This option takes no argument. + \item[p] (parser trace) Turn on debugging support for + "ocamlyacc"-generated parsers. When this option is on, + the pushdown automaton that executes the parsers prints a + trace of its actions. This option takes no argument. + \item[R] (randomize) Turn on randomization of all hash tables by default + (see +\ifouthtml + \ahref{libref/Hashtbl.html}{Module \texttt{Hashtbl}}). +\else + section~\ref{Hashtbl}). +\fi + This option takes no argument. + \item[h] The initial size of the major heap (in words). + \item[a] ("allocation_policy") The policy used for allocating in the + OCaml heap. Possible values are 0 for the next-fit policy, and 1 + for the first-fit policy. Next-fit is usually faster, but first-fit + is better for avoiding fragmentation and the associated heap + compactions. + \item[s] ("minor_heap_size") Size of the minor heap. (in words) + \item[i] ("major_heap_increment") Default size increment for the + major heap. (in words) + \item[o] ("space_overhead") The major GC speed setting. + \item[O] ("max_overhead") The heap compaction trigger setting. + \item[l] ("stack_limit") The limit (in words) of the stack size. + \item[v] ("verbose") What GC messages to print to stderr. This + is a sum of values selected from the following: + \begin{options} + \item[1 (= 0x001)] Start of major GC cycle. + \item[2 (= 0x002)] Minor collection and major GC slice. + \item[4 (= 0x004)] Growing and shrinking of the heap. + \item[8 (= 0x008)] Resizing of stacks and memory manager tables. + \item[16 (= 0x010)] Heap compaction. + \item[32 (= 0x020)] Change of GC parameters. + \item[64 (= 0x040)] Computation of major GC slice size. + \item[128 (= 0x080)] Calling of finalization functions + \item[256 (= 0x100)] Startup messages (loading the bytecode + executable file, resolving shared libraries). + \item[512 (= 0x200)] Computation of compaction-triggering condition. + \item[1024 (= 0x400)] Output GC statistics at program exit. + \end{options} + \item[c] ("cleanup_on_exit") Shut the runtime down gracefully on exit (see + "caml_shutdown" in section~\ref{s:embedded-code}). The option also enables + pooling (as in "caml_startup_pooled"). This mode can be used to detect + leaks with a third-party memory debugger. + \end{options} + The multiplier is "k", "M", or "G", for multiplication by $2^{10}$, + $2^{20}$, and $2^{30}$ respectively. + + If the option letter is not recognized, the whole parameter is ignored; + if the equal sign or the number is missing, the value is taken as 1; + if the multiplier is not recognized, it is ignored. + + For example, on a 32-bit machine, under "bash" the command +\begin{verbatim} + export OCAMLRUNPARAM='b,s=256k,v=0x015' +\end{verbatim} + tells a subsequent "ocamlrun" to print backtraces for uncaught exceptions, + set its initial minor heap size to 1~megabyte and + print a message at the start of each major GC cycle, when the heap + size changes, and when compaction is triggered. + +\item["CAMLRUNPARAM"] If "OCAMLRUNPARAM" is not found in the + environment, then "CAMLRUNPARAM" will be used instead. If + "CAMLRUNPARAM" is also not found, then the default values will be used. + +\item["PATH"] List of directories searched to find the bytecode +executable file. +\end{options} + +\section{Dynamic loading of shared libraries} \label{s-ocamlrun-dllpath} + +On platforms that support dynamic loading, "ocamlrun" can link +dynamically with C shared libraries (DLLs) providing additional C primitives +beyond those provided by the standard runtime system. The names for +these libraries are provided at link time as described in +section~\ref{dynlink-c-code}), and recorded in the bytecode executable +file; "ocamlrun", then, locates these libraries and resolves references +to their primitives when the bytecode executable program starts. + +The "ocamlrun" command searches shared libraries in the following +directories, in the order indicated: +\begin{enumerate} +\item Directories specified on the "ocamlrun" command line with the +"-I" option. +\item Directories specified in the "CAML_LD_LIBRARY_PATH" environment +variable. +\item Directories specified at link-time via the "-dllpath" option to +"ocamlc". (These directories are recorded in the bytecode executable +file.) +\item Directories specified in the file "ld.conf". This file resides +in the OCaml standard library directory, and lists directory +names (one per line) to be searched. Typically, it contains only one +line naming the "stublibs" subdirectory of the OCaml standard +library directory. Users can add there the names of other directories +containing frequently-used shared libraries; however, for consistency +of installation, we recommend that shared libraries are installed +directly in the system "stublibs" directory, rather than adding lines +to the "ld.conf" file. +\item Default directories searched by the system dynamic loader. +Under Unix, these generally include "/lib" and "/usr/lib", plus the +directories listed in the file "/etc/ld.so.conf" and the environment +variable "LD_LIBRARY_PATH". Under Windows, these include the Windows +system directories, plus the directories listed in the "PATH" +environment variable. +\end{enumerate} + +\section{Common errors} + +This section describes and explains the most frequently encountered +error messages. + +\begin{options} + +\item[{\it filename}": no such file or directory"] +If {\it filename} is the name of a self-executable bytecode file, this +means that either that file does not exist, or that it failed to run +the "ocamlrun" bytecode interpreter on itself. The second possibility +indicates that OCaml has not been properly installed on your +system. + +\item["Cannot exec ocamlrun"] +(When launching a self-executable bytecode file.) The "ocamlrun" + could not be found in the executable path. Check that OCaml + has been properly installed on your system. + +\item["Cannot find the bytecode file"] +The file that "ocamlrun" is trying to execute (e.g. the file given as +first non-option argument to "ocamlrun") either does not exist, or is +not a valid executable bytecode file. + +\item["Truncated bytecode file"] +The file that "ocamlrun" is trying to execute is not a valid executable +bytecode file. Probably it has been truncated or mangled since +created. Erase and rebuild it. + +\item["Uncaught exception"] +The program being executed contains a ``stray'' exception. That is, +it raises an exception at some point, and this exception is never +caught. This causes immediate termination of the program. The name of +the exception is printed, along with its string, byte sequence, and +integer arguments +(arguments of more complex types are not correctly printed). +To locate the context of the uncaught exception, compile the program +with the "-g" option and either run it again under the "ocamldebug" +debugger (see chapter~\ref{c:debugger}), or run it with "ocamlrun -b" +or with the "OCAMLRUNPARAM" environment variable set to "b=1". + +\item["Out of memory"] +The program being executed requires more memory than available. Either +the program builds excessively large data structures; or the program +contains too many nested function calls, and the stack overflows. In +some cases, your program is perfectly correct, it just requires more +memory than your machine provides. In other cases, the ``out of +memory'' message reveals an error in your program: non-terminating +recursive function, allocation of an excessively large array, +string or byte sequence, attempts to build an infinite list or other +data structure, \ldots + +To help you diagnose this error, run your program with the "-v" option +to "ocamlrun", or with the "OCAMLRUNPARAM" environment variable set to +"v=63". If it displays lots of ``"Growing stack"\ldots'' +messages, this is probably a looping recursive function. If it +displays lots of ``"Growing heap"\ldots'' messages, with the heap size +growing slowly, this is probably an attempt to construct a data +structure with too many (infinitely many?) cells. If it displays few +``"Growing heap"\ldots'' messages, but with a huge increment in the +heap size, this is probably an attempt to build an excessively large +array, string or byte sequence. + +\end{options} diff --git a/manual/manual/cmds/spacetime.etex b/manual/manual/cmds/spacetime.etex new file mode 100644 index 00000000..7abc7095 --- /dev/null +++ b/manual/manual/cmds/spacetime.etex @@ -0,0 +1,126 @@ +\chapter{Memory profiling with Spacetime} +\pdfchapterfold{-9}{Memory profiling with Spacetime} +%HEVEA\cutname{spacetime.html} + +\section{Overview} + +Spacetime is the name given to functionality within the OCaml compiler that +provides for accurate profiling of the memory behaviour of a program. +Using Spacetime it is possible to determine the source of memory leaks +and excess memory allocation quickly and easily. Excess allocation slows +programs down both by imposing a higher load on the garbage collector and +reducing the cache locality of the program's code. Spacetime provides +full backtraces for every allocation that occurred on the OCaml heap +during the lifetime of the program including those in C stubs. + +Spacetime only analyses the memory behaviour of a program with respect to +the OCaml heap allocators and garbage collector. It does not analyse +allocation on the C heap. Spacetime does not affect the memory behaviour +of a program being profiled with the exception of any change caused by the +overhead of profiling (see section\ \ref{runtimeoverhead})---for example +the program running slower might cause it to allocate less memory in total. + +Spacetime is currently only available for x86-64 targets and has only been +tested on Linux systems (although it is expected to work on most modern +Unix-like systems and provision has been made for running under +Windows). It is expected that the set of supported platforms will +be extended in the future. + +\section{How to use it} + +\subsection{Building} + +To use Spacetime it is necessary to use an OCaml compiler that was +configured with the {\tt -spacetime} option. It is not possible to select +Spacetime on a per-source-file basis or for a subset of files in a project; +all files involved in the executable being profiled must be built with the +Spacetime compiler. Only native code compilation is supported (not +bytecode). + +If the {\tt libunwind} library is not available on the system then it will +not be possible for Spacetime to profile allocations occurring within +C stubs. If the {\tt libunwind} library is available but in an unusual +location then that location may be specified to the {\tt configure} script +using the {\tt -libunwinddir} option (or alternatively, using separate +{\tt -libunwindinclude} and {\tt -libunwindlib} options). + +OPAM switches will be provided for Spacetime-configured compilers. + +Once the appropriate compiler has been selected the program should be +built as normal (ensuring that all files are built with the Spacetime +compiler---there is currently no protection to ensure this is the case, but +it is essential). For many uses it will not be necessary to change the +code of the program to use the profiler. + +Spacetime-configured compilers run slower and occupy more memory than their +counterparts. It is hoped this will be fixed in the future as part of +improved cross compilation support. + +\subsection{Running} + +Programs built with Spacetime instrumentation have a dependency on +the {\tt libunwind} library unless that was unavailable at configure time or +the {\tt -disable-libunwind} option was specified +(see section\ \ref{runtimeoverhead}). + +Setting the {\tt OCAML\_SPACETIME\_INTERVAL} environment variable to an +integer representing a number of milliseconds before running a program built +with Spacetime will cause memory profiling to be in operation when the +program is started. The contents of the OCaml heap will be sampled each +time the number of milliseconds that the program has spent executing since the +last sample exceeds the given number. (Note that the time base is combined +user plus system time---{\em not} wall clock time. This peculiarity may be +changed in future.) + +The program being profiled must exit normally or be caused to exit using +the {\tt SIGINT} signal (e.g. by pressing Ctrl+C). When the program exits +files will be written in the directory that was the working directory when +the program was started. One Spacetime file will be written for each +process that was involved, indexed by process ID; there will normally only +be one such. The Spacetime files may be substantial. The directory to which +they are written may be overridden by setting +the {\tt OCAML\_SPACETIME\_SNAPSHOT\_DIR} environment variable before the +program is started. + +Instead of using the automatic snapshot facility described above it is also +possible to manually control Spacetime profiling. (The environment variables +{\tt OCAML\_SPACETIME\_INTERVAL} and {\tt OCAML\_SPACETIME\_SNAPSHOT\_DIR} +are then not relevant.) Full documentation as regards this method of profiling +is provided in the standard library documentation (section\ \ref{c:stdlib}) +for the {\tt Spacetime} module. + +\subsection{Analysis} + +The compiler distribution does not itself provide the facility for analysing +Spacetime output files; this is left to external tools. The first such tool +will appear in OPAM as a package called {\tt prof_spacetime}. That tool will +provide interactive graphical and terminal-based visualisation of +the results of profiling. + +\section{Runtime overhead}\label{runtimeoverhead} + +The runtime overhead imposed by Spacetime varies considerably depending on +the particular program being profiled. The overhead may be as low as +ten percent---but more usually programs should be expected to run at perhaps +a third or quarter of their normal speed. It is expected that this overhead +will be reduced in future versions of the compiler. + +Execution speed of instrumented programs may be increased by using a compiler +configured with the {\tt -disable-libunwind} option. This prevents collection +of profiling information from C stubs. + +Programs running with Spacetime instrumentation consume significantly more +memory than their non-instrumented counterparts. It is expected that this +memory overhead will also be reduced in the future. + +\section{For developers} + +The compiler distribution provides an ``{\tt otherlibs}'' library called +{\tt raw\_spacetime\_lib} for decoding Spacetime files. This library +provides facilities to read not only memory profiling information but also +the full dynamic call graph of the profiled program which is written into +Spacetime output files. + +A library package {\tt spacetime\_lib} will be provided in OPAM +to provide an interface for decoding profiling information at a higher +level than that provided by {\tt raw\_spacetime\_lib}. diff --git a/manual/manual/cmds/top.etex b/manual/manual/cmds/top.etex new file mode 100644 index 00000000..0ac39a22 --- /dev/null +++ b/manual/manual/cmds/top.etex @@ -0,0 +1,451 @@ +\chapter{The toplevel system or REPL (ocaml)} \label{c:camllight} +\pdfchapter{The toplevel system or REPL (ocaml)} +%HEVEA\cutname{toplevel.html} + +This chapter describes the toplevel system for OCaml, that permits +interactive use of the OCaml system +through a read-eval-print loop (REPL). In this mode, the system repeatedly +reads OCaml phrases from the input, then typechecks, compile and +evaluate them, then prints the inferred type and result value, if +any. The system prints a "#" (sharp) prompt before reading each +phrase. + +Input to the toplevel can span several lines. It is terminated by @";;"@ (a +double-semicolon). The toplevel input consists in one or several +toplevel phrases, with the following syntax: + +\begin{syntax} +toplevel-input: + {{ definition }} ';;' + | expr ';;' + | '#' ident [ directive-argument ] ';;' +; +directive-argument: + string-literal + | integer-literal + | value-path + | 'true' || 'false' +\end{syntax} + +A phrase can consist of a definition, like those found in +implementations of compilation units or in @'struct' \ldots 'end'@ +module expressions. The definition can bind value names, type names, +an exception, a module name, or a module type name. The toplevel +system performs the bindings, then prints the types and values (if +any) for the names thus defined. + +A phrase may also consist in a value expression +(section~\ref{s:value-expr}). It is simply evaluated +without performing any bindings, and its value is +printed. + +Finally, a phrase can also consist in a toplevel directive, +starting with @"#"@ (the sharp sign). These directives control the +behavior of the toplevel; they are listed below in +section~\ref{s:toplevel-directives}. + +\begin{unix} +The toplevel system is started by the command "ocaml", as follows: +\begin{alltt} + ocaml \var{options} \var{objects} # interactive mode + ocaml \var{options} \var{objects} \var{scriptfile} # script mode +\end{alltt} +\var{options} are described below. +\var{objects} are filenames ending in ".cmo" or ".cma"; they are +loaded into the interpreter immediately after \var{options} are set. +\var{scriptfile} is any file name not ending in ".cmo" or ".cma". + +If no \var{scriptfile} is given on the command line, the toplevel system +enters interactive mode: phrases are read on standard input, results +are printed on standard output, errors on standard error. End-of-file +on standard input terminates "ocaml" (see also the "#quit" directive +in section~\ref{s:toplevel-directives}). + +On start-up (before the first phrase is read), if the file +".ocamlinit" exists in the current directory, +its contents are read as a sequence of OCaml phrases +and executed as per the "#use" directive +described in section~\ref{s:toplevel-directives}. +The evaluation outcode for each phrase are not displayed. +If the current directory does not contain an ".ocamlinit" file, but +the user's home directory (environment variable "HOME") does, the +latter is read and executed as described below. + +The toplevel system does not perform line editing, but it can +easily be used in conjunction with an external line editor such as +"ledit", "ocaml2" or "rlwrap" +\begin{latexonly} +(see the Caml Hump "http://caml.inria.fr/humps/index_framed_caml.html"). +\end{latexonly} +\begin{htmlonly} +(see the +\ahref{http://caml.inria.fr/humps/index\_framed\_caml.html}{Caml Hump}). +\end{htmlonly} +Another option is to use "ocaml" under Gnu Emacs, which gives the +full editing power of Emacs (command "run-caml" from library "inf-caml"). + +At any point, the parsing, compilation or evaluation of the current +phrase can be interrupted by pressing "ctrl-C" (or, more precisely, +by sending the "INTR" signal to the "ocaml" process). The toplevel +then immediately returns to the "#" prompt. + +If \var{scriptfile} is given on the command-line to "ocaml", the toplevel +system enters script mode: the contents of the file are read as a +sequence of OCaml phrases and executed, as per the "#use" +directive (section~\ref{s:toplevel-directives}). The outcome of the +evaluation is not printed. On reaching the end of file, the "ocaml" +command exits immediately. No commands are read from standard input. +"Sys.argv" is transformed, ignoring all OCaml parameters, and +starting with the script file name in "Sys.argv.(0)". + +In script mode, the first line of the script is ignored if it starts +with "#!". Thus, it should be possible to make the script +itself executable and put as first line "#!/usr/local/bin/ocaml", +thus calling the toplevel system automatically when the script is +run. However, "ocaml" itself is a "#!" script on most installations +of OCaml, and Unix kernels usually do not handle nested "#!" +scripts. A better solution is to put the following as the first line +of the script: +\begin{verbatim} + #!/usr/local/bin/ocamlrun /usr/local/bin/ocaml +\end{verbatim} + +\end{unix} + +\section{Options} \label{s:toplevel-options} + +The following command-line options are recognized by the "ocaml" command. +% Configure boolean variables used by the macros in unified-options.etex +\compfalse +\natfalse +\toptrue +% unified-options gathers all options across the native/bytecode +% compilers and toplevel +\input{unified-options.tex} + +\begin{unix} +The following environment variables are also consulted: +\begin{options} +\item["OCAMLTOP_UTF_8"] When printing string values, non-ascii bytes +($ {} > "\0x7E" $) are printed as decimal escape sequence if "OCAMLTOP_UTF_8" is +set to false. Otherwise, they are printed unescaped. + +\item["TERM"] When printing error messages, the toplevel system +attempts to underline visually the location of the error. It +consults the "TERM" variable to determines the type of output terminal +and look up its capabilities in the terminal database. + +\item["HOME"] Directory where the ".ocamlinit" file is searched. +\end{options} +\end{unix} + +\section{Toplevel directives} +\label{s:toplevel-directives} + +The following directives control the toplevel behavior, load files in +memory, and trace program execution. + +{\bf Note:} all directives start with a "#" (sharp) symbol. This "#" +must be typed before the directive, and must not be confused with the +"#" prompt displayed by the interactive loop. For instance, +typing "#quit;;" will exit the toplevel loop, but typing "quit;;" +will result in an ``unbound value "quit"'' error. + +% +% Remark: this list of options should be kept synchronized with the documentation +% in toplevel/topdirs.ml. +% +\begin{options} +\item[General] + \begin{options} + \item["#help;;"] + Prints a list of all available directives, with corresponding argument type + if appropriate. + \item["#quit;;"] + Exit the toplevel loop and terminate the "ocaml" command. + \end{options} + +\item[Loading codes] + \begin{options} + + \item["#cd \""\var{dir-name}"\";;"] + Change the current working directory. + + \item["#directory \""\var{dir-name}"\";;"] + Add the given directory to the list of directories searched for + source and compiled files. + + \item["#remove_directory \""\var{dir-name}"\";;"] + Remove the given directory from the list of directories searched for + source and compiled files. Do nothing if the list does not contain + the given directory. + + \item["#load \""\var{file-name}"\";;"] + Load in memory a bytecode object file (".cmo" file) or library file + (".cma" file) produced by the batch compiler "ocamlc". + + \item["#load_rec \""\var{file-name}"\";;"] + Load in memory a bytecode object file (".cmo" file) or library file + (".cma" file) produced by the batch compiler "ocamlc". + When loading an object file that depends on other modules + which have not been loaded yet, the .cmo files for these modules + are searched and loaded as well, recursively. The loading order + is not specified. + + \item["#use \""\var{file-name}"\";;"] + Read, compile and execute source phrases from the given file. + This is textual inclusion: phrases are processed just as if + they were typed on standard input. The reading of the file stops at + the first error encountered. + + \item["#mod_use \""\var{file-name}"\";;"] + Similar to "#use" but also wrap the code into a top-level module of the + same name as capitalized file name without extensions, following + semantics of the compiler. + \end{options} + +For directives that take file names as arguments, if the given file +name specifies no directory, the file is searched in the following +directories: +\begin{enumerate} + \item In script mode, the directory containing the script currently + executing; in interactive mode, the current working directory. + \item Directories added with the "#directory" directive. + \item Directories given on the command line with "-I" options. + \item The standard library directory. +\end{enumerate} + +\item[Environment queries] + \begin{options} + \item["#show_class "\var{class-path}";;"]\vspace{-4.7ex} + \item["#show_class_type "\var{class-path}";;"]\vspace{-4.7ex} + \item["#show_exception "\var{ident}";;"]\vspace{-4.7ex} + \item["#show_module "\var{module-path}";;"]\vspace{-4.7ex} + \item["#show_module_type "\var{modtype-path}";;"]\vspace{-4.7ex} + \item["#show_type "\var{typeconstr}";;"]\vspace{-4.7ex} + \item["#show_val "\var{value-path}";;"] + Print the signature of the corresponding component. + + \item["#show "\var{ident}";;"] + Print the signatures of components with name \var{ident} in all the + above categories. + \end{options} + +\item[Pretty-printing] + \begin{options} + + \item["#install_printer "\var{printer-name}";;"] + This directive registers the function named \var{printer-name} (a + value path) as a printer for values whose types match the argument + type of the function. That is, the toplevel loop will call + \var{printer-name} when it has such a value to print. + + The printing function \var{printer-name} should have type + @"Format.formatter" "->" @t@ "->" "unit"@, where @@t@@ is the + type for the values to be printed, and should output its textual + representation for the value of type @@t@@ on the given formatter, + using the functions provided by the "Format" library. For backward + compatibility, \var{printer-name} can also have type + @@t@ "->" "unit"@ and should then output on the standard + formatter, but this usage is deprecated. + + \item["#print_depth "\var{n}";;"] + Limit the printing of values to a maximal depth of \var{n}. + The parts of values whose depth exceeds \var{n} are printed as "..." + (ellipsis). + + \item["#print_length "\var{n}";;"] + Limit the number of value nodes printed to at most \var{n}. + Remaining parts of values are printed as "..." (ellipsis). + + \item["#remove_printer "\var{printer-name}";;"] + Remove the named function from the table of toplevel printers. +\end{options} + +\item[Tracing] + \begin{options} + \item["#trace "\var{function-name}";;"] + After executing this directive, all calls to the function named + \var{function-name} will be ``traced''. That is, the argument and the + result are displayed for each call, as well as the exceptions escaping + out of the function, raised either by the function itself or by + another function it calls. If the function is curried, each argument + is printed as it is passed to the function. + + \item["#untrace "\var{function-name}";;"] + Stop tracing the given function. + + \item["#untrace_all;;"] + Stop tracing all functions traced so far. + \end{options} + +\item[Compiler options] + \begin{options} + \item["#labels "\var{bool}";;"] + Ignore labels in function types if argument is "false", or switch back + to default behaviour (commuting style) if argument is "true". + + \item["#ppx \""\var{file-name}"\";;"] + After parsing, pipe the abstract syntax tree through the preprocessor + command. + + \item["#principal "\var{bool}";;"] + If the argument is "true", check information paths during + type-checking, to make sure that all types are derived in a principal + way. If the argument is "false", do not check information paths. + + \item["#rectypes;;"] + Allow arbitrary recursive types during type-checking. Note: once + enabled, this option cannot be disabled because that would lead to + unsoundness of the type system. + + \item["#warn_error \""\var{warning-list}"\";;"] + Treat as errors the warnings enabled by the argument and as normal + warnings the warnings disabled by the argument. + + \item["#warnings \""\var{warning-list}"\";;"] + Enable or disable warnings according to the argument. + + \end{options} + +\end{options} + +\section{The toplevel and the module system} \label{s:toplevel-modules} + +Toplevel phrases can refer to identifiers defined in compilation units +with the same mechanisms as for separately compiled units: either by +using qualified names ("Modulename.localname"), or by using +the "open" construct and unqualified names (see section~\ref{s:names}). + +However, before referencing another compilation unit, an +implementation of that unit must be present in memory. +At start-up, the toplevel system contains implementations for all the +modules in the the standard library. Implementations for user modules +can be entered with the "#load" directive described above. Referencing +a unit for which no implementation has been provided +results in the error "Reference to undefined global `...'". + +Note that entering "open "\var{Mod} merely accesses the compiled +interface (".cmi" file) for \var{Mod}, but does not load the +implementation of \var{Mod}, and does not cause any error if no +implementation of \var{Mod} has been loaded. The error +``reference to undefined global \var{Mod}'' will occur only when +executing a value or module definition that refers to \var{Mod}. + +\section{Common errors} + +This section describes and explains the most frequently encountered +error messages. + +\begin{options} + +\item[Cannot find file \var{filename}] +The named file could not be found in the current directory, nor in the +directories of the search path. + +If \var{filename} has the format \var{mod}".cmi", this +means you have referenced the compilation unit \var{mod}, but its +compiled interface could not be found. Fix: compile \var{mod}".mli" or +\var{mod}".ml" first, to create the compiled interface \var{mod}".cmi". + +If \var{filename} has the format \var{mod}".cmo", this +means you are trying to load with "#load" a bytecode object file that +does not exist yet. Fix: compile \var{mod}".ml" first. + +If your program spans several directories, this error can also appear +because you haven't specified the directories to look into. Fix: use +the "#directory" directive to add the correct directories to the +search path. + +\item[This expression has type \nth{t}{1}, but is used with type \nth{t}{2}] +See section~\ref{s:comp-errors}. + +\item[Reference to undefined global \var{mod}] +You have neglected to load in memory an implementation for a module +with "#load". See section~\ref{s:toplevel-modules} above. + +\end{options} + +\section{Building custom toplevel systems: \texttt{ocamlmktop}} + +The "ocamlmktop" command builds OCaml toplevels that +contain user code preloaded at start-up. + +The "ocamlmktop" command takes as argument a set of ".cmo" and ".cma" +files, and links them with the object files that implement the OCaml toplevel. +The typical use is: +\begin{verbatim} + ocamlmktop -o mytoplevel foo.cmo bar.cmo gee.cmo +\end{verbatim} +This creates the bytecode file "mytoplevel", containing the OCaml toplevel +system, plus the code from the three ".cmo" +files. This toplevel is directly executable and is started by: +\begin{verbatim} + ./mytoplevel +\end{verbatim} +This enters a regular toplevel loop, except that the code from +"foo.cmo", "bar.cmo" and "gee.cmo" is already loaded in memory, just as +if you had typed: +\begin{verbatim} + #load "foo.cmo";; + #load "bar.cmo";; + #load "gee.cmo";; +\end{verbatim} +on entrance to the toplevel. The modules "Foo", "Bar" and "Gee" are +not opened, though; you still have to do +\begin{verbatim} + open Foo;; +\end{verbatim} +yourself, if this is what you wish. + +\subsection{Options} + +The following command-line options are recognized by "ocamlmktop". + +\begin{options} + +\item["-cclib" \var{libname}] +Pass the "-l"\var{libname} option to the C linker when linking in +``custom runtime'' mode. See the corresponding option for +"ocamlc", in chapter~\ref{c:camlc}. + +\item["-ccopt" \var{option}] +Pass the given option to the C compiler and linker, when linking in +``custom runtime'' mode. See the corresponding option for +"ocamlc", in chapter~\ref{c:camlc}. + +\item["-custom"] +Link in ``custom runtime'' mode. See the corresponding option for +"ocamlc", in chapter~\ref{c:camlc}. + +\item["-I" \var{directory}] +Add the given directory to the list of directories searched for +compiled object code files (".cmo" and ".cma"). + +\item["-o" \var{exec-file}] +Specify the name of the toplevel file produced by the linker. +The default is "a.out". + +\end{options} + +\section{The native toplevel: \texttt{ocamlnat}\ (experimental)} + +{\bf This section describes a tool that is not yet officially supported % +but may be found useful.} + +OCaml code executing in the traditional toplevel system uses the bytecode +interpreter. When increased performance is required, or for testing +programs that will only execute correctly when compiled to native code, +the {\em native toplevel} may be used instead. + +For the majority of installations the native toplevel will not have been +installed along with the rest of the OCaml toolchain. In such circumstances +it will be necessary to build the OCaml distribution from source. +From the built source tree of the distribution you may use +{\tt make natruntop} to build and execute a native toplevel. (Alternatively +{\tt make ocamlnat} can be used, which just performs the build step.) + +If the {\tt make install} command is run after having built the native +toplevel then the {\tt ocamlnat} program (either from the source or the +installation directory) may be invoked directly rather than using +{\tt make natruntop}. diff --git a/manual/manual/cmds/unified-options.etex b/manual/manual/cmds/unified-options.etex new file mode 100644 index 00000000..796d65a5 --- /dev/null +++ b/manual/manual/cmds/unified-options.etex @@ -0,0 +1,789 @@ +% +% This file describes the native/bytecode compiler and toplevel +% options. Since specific options can exist in only a subset of +% \{toplevel, bytecode compiler, native compiler \} and their description +% might differ across this subset, this file uses macros to adapt the +% description tool by tool: +\long\def\comp#1{\ifcomp#1\else\fi} +% \long is needed for multiparagraph macros +\long\def\nat#1{\ifnat#1\else\fi} +\long\def\top#1{\iftop#1\else\fi} +\long\def\notop#1{\iftop\else#1\fi} +% ( Note that the previous definitions relies on the three boolean values +% \top, \nat and \comp. The manual section must therefore +% set these boolean values accordingly. +% ) +% The macros (\comp, \nat, \top) adds a supplementary text +% if we are respectively in the (bytecode compiler, native compiler, toplevel) +% section. +% The toplevel options are quite different from the compilers' options. +% It is therefore useful to have also a substractive \notop macro +% that prints its content only outside of the topvel section +% +% For instance, to add an option "-foo" that applies to the native and +% bytecode compiler, one can write +% \notop{\item["-foo"] +% ... +% } +% +% Similarly, an option "-bar" only available in the native compiler +% can be introduced with +% \nat{\item["-bar"] +% ... +% } +% These macros can be also used to add information that are only relevant to +% some tools or differ slightly from one tool to another. For instance, we +% define the following macro for the pairs cma/cmxa cmo/cmxo and ocamlc/ocamlopt +% +\def\cma{\comp{.cma}\nat{.cmxa}} +\def\cmo{\comp{.cmo}\nat{.cmx}} +\def\qcmo{{\machine\cmo}} +\def\qcma{{\machine\cma}} +\def\ocamlx{\comp{ocamlc}\nat{ocamlopt}} +% +% +\begin{options} +\notop{% +\item["-a"] +Build a library(\nat{".cmxa" and ".a"/".lib" files}\comp{".cma" file}) +with the object files (\nat{".cmx" and ".o"/".obj" files}\comp{ ".cmo" files}) +given on the command line, instead of linking them into an executable file. +The name of the library must be set with the "-o" option. + +If \comp{"-custom", }"-cclib" or "-ccopt" options are passed on the command +line, these options are stored in the resulting \qcma library. Then, +linking with this library automatically adds back the \comp{"-custom", } +"-cclib" and "-ccopt" options as if they had been provided on the +command line, unless the "-noautolink" option is given. +}%notop + +\item["-absname"] +Force error messages to show absolute paths for file names. + +\notop{\item["-annot"] +Dump detailed information about the compilation (types, bindings, +tail-calls, etc). The information for file \var{src}".ml" +is put into file \var{src}".annot". In case of a type error, dump +all the information inferred by the type-checker before the error. +The \var{src}".annot" file can be used with the emacs commands given in +"emacs/caml-types.el" to display types and other annotations +interactively. +}%notop + +\item["-args" \var{filename}] +Read additional newline-terminated command line arguments from \var{filename}. +\top{It is not possible to pass a \var{scriptfile} via file to the toplevel. +}%top +\item["-args0" \var{filename}] + Read additional null character terminated command line arguments from \var{filename}. +\top{It is not possible to pass a \var{scriptfile} via file to the toplevel. +}%top + + +\notop{\item["-bin-annot"] +Dump detailed information about the compilation (types, bindings, +tail-calls, etc) in binary format. The information for file \var{src}".ml" +(resp. \var{src}".mli") is put into file \var{src}".cmt" +(resp. \var{src}".cmti"). In case of a type error, dump +all the information inferred by the type-checker before the error. +The "*.cmt" and "*.cmti" files produced by "-bin-annot" contain +more information and are much more compact than the files produced by +"-annot". +}%notop + +\notop{\item["-c"] +Compile only. Suppress the linking phase of the +compilation. Source code files are turned into compiled files, but no +executable file is produced. This option is useful to +compile modules separately. +}%notop + +\notop{% +\item["-cc" \var{ccomp}] +Use \var{ccomp} as the C linker \nat{called to build the final executable } +\comp{when linking in ``custom runtime'' mode (see the "-custom" option)} +and as the C compiler for compiling ".c" source files. +}%notop + +\notop{% +\item["-cclib" "-l"\var{libname}] +Pass the "-l"\var{libname} option to the \comp{C} linker +\comp{when linking in ``custom runtime'' mode (see the "-custom" option)}. +This causes the given C library to be linked with the program. +}%notop + +\notop{% +\item["-ccopt" \var{option}] +Pass the given option to the C compiler and linker. +\comp{When linking in ``custom runtime'' mode, for instance}% +\nat{For instance,}% +"-ccopt -L"\var{dir} causes the C linker to search for C libraries in +directory \var{dir}.\comp{(See the "-custom" option.)} +}%notop + +\notop{% +\item["-color" \var{mode}] +Enable or disable colors in compiler messages (especially warnings and errors). +The following modes are supported: +\begin{description} + \item["auto"] use heuristics to enable colors only if the output supports them (an ANSI-compatible tty terminal); + \item["always"] enable colors unconditionally; + \item["never"] disable color output. +\end{description} +The default setting is 'auto', and the current heuristic +checks that the "TERM" environment variable exists and is +not empty or "dumb", and that 'isatty(stderr)' holds. + +The environment variable "OCAML_COLOR" is considered if "-color" is not +provided. Its values are auto/always/never as above. +}%notop + +\comp{% +\item["-compat-32"] +Check that the generated bytecode executable can run on 32-bit +platforms and signal an error if it cannot. This is useful when +compiling bytecode on a 64-bit machine. +}%comp + +\nat{% +\item["-compact"] +Optimize the produced code for space rather than for time. This +results in slightly smaller but slightly slower programs. The default is to +optimize for speed. +}%nat + +\item["-config"] +Print the version number of {\machine\ocamlx} and a detailed +summary of its configuration, then exit. + +\comp{% +\item["-custom"] +Link in ``custom runtime'' mode. In the default linking mode, the +linker produces bytecode that is intended to be executed with the +shared runtime system, "ocamlrun". In the custom runtime mode, the +linker produces an output file that contains both the runtime system +and the bytecode for the program. The resulting file is larger, but it +can be executed directly, even if the "ocamlrun" command is not +installed. Moreover, the ``custom runtime'' mode enables static +linking of OCaml code with user-defined C functions, as described in +chapter~\ref{c:intf-c}. +\begin{unix} +Never use the "strip" command on executables produced by "ocamlc -custom", +this would remove the bytecode part of the executable. +\end{unix} +\begin{unix} +Security warning: never set the ``setuid'' or ``setgid'' bits on executables +produced by "ocamlc -custom", this would make them vulnerable to attacks. +\end{unix} +}%comp + +\notop{% +\item["-depend" \var{ocamldep-args}] +Compute dependencies, as the "ocamldep" command would do. The remaining +arguments are interpreted as if they were given to the "ocamldep" command. +}%notop + +\comp{ +\item["-dllib" "-l"\var{libname}] +Arrange for the C shared library "dll"\var{libname}".so" +("dll"\var{libname}".dll" under Windows) to be loaded dynamically +by the run-time system "ocamlrun" at program start-up time. +}%comp + +\comp{\item["-dllpath" \var{dir}] +Adds the directory \var{dir} to the run-time search path for shared +C libraries. At link-time, shared libraries are searched in the +standard search path (the one corresponding to the "-I" option). +The "-dllpath" option simply stores \var{dir} in the produced +executable file, where "ocamlrun" can find it and use it as +described in section~\ref{s-ocamlrun-dllpath}. +}%comp + +\notop{% +\item["-for-pack" \var{module-path}] +Generate an object file (\qcmo\nat{ and ".o"/".obj" files}) +that can later be included +as a sub-module (with the given access path) of a compilation unit +constructed with "-pack". For instance, +{\machine\ocamlx\ -for-pack\ P\ -c\ A.ml} +will generate {\machine a.\cmo}\nat{ and "a.o" files} that can +later be used with {\machine \ocamlx\ -pack\ -o\ P\cmo\ a\cmo}. +Note: you can still pack a module that was compiled without +"-for-pack" but in this case exceptions will be printed with the wrong +names. +}%notop + +\notop{% +\item["-g"] +Add debugging information while compiling and linking. This option is +required in order to \comp{be able to debug the program with "ocamldebug" +(see chapter~\ref{c:debugger}), and to} produce stack backtraces when +the program terminates on an uncaught exception (see +section~\ref{ocamlrun-options}). +}%notop + +\notop{% +\item["-i"] +Cause the compiler to print all defined names (with their inferred +types or their definitions) when compiling an implementation (".ml" +file). No compiled files (".cmo" and ".cmi" files) are produced. +This can be useful to check the types inferred by the +compiler. Also, since the output follows the syntax of interfaces, it +can help in writing an explicit interface (".mli" file) for a file: +just redirect the standard output of the compiler to a ".mli" file, +and edit that file to remove all declarations of unexported names. +}%notop + +\item["-I" \var{directory}] +Add the given directory to the list of directories searched for +\nat{compiled interface files (".cmi"), compiled object code files (".cmx"), +and libraries (".cmxa").} +\comp{compiled interface files (".cmi"), compiled object code files ".cmo", +libraries (".cma") and C libraries specified with "-cclib -lxxx".} +\top{source and compiled files.} +By default, the current directory is searched first, then the standard +library directory. Directories added with "-I" are searched after the +current directory, in the order in which they were given on the command line, +but before the standard library directory. See also option "-nostdlib". + +If the given directory starts with "+", it is taken relative to the +standard library directory. For instance, "-I +unix" adds the +subdirectory "unix" of the standard library to the search path. + +\top{% +Directories can also be added to the list once +the toplevel is running with the "#directory" directive +(section~\ref{s:toplevel-directives}). +}%top + +\top{% +\item["-init" \var{file}] +Load the given file instead of the default initialization file. +The default file is ".ocamlinit" in the current directory if it +exists, otherwise ".ocamlinit" in the user's home directory. +}%top + +\notop{% +\item["-impl" \var{filename}] +Compile the file \var{filename} as an implementation file, even if its +extension is not ".ml". +}%notop + +\nat{% +\item["-inline" \var{n}] +Set aggressiveness of inlining to \var{n}, where \var{n} is a positive +integer. Specifying "-inline 0" prevents all functions from being +inlined, except those whose body is smaller than the call site. Thus, +inlining causes no expansion in code size. The default aggressiveness, +"-inline 1", allows slightly larger functions to be inlined, resulting +in a slight expansion in code size. Higher values for the "-inline" +option cause larger and larger functions to become candidate for +inlining, but can result in a serious increase in code size. +}%nat + +\notop{% +\item["-intf" \var{filename}] +Compile the file \var{filename} as an interface file, even if its +extension is not ".mli". +}%notop + +\notop{% +\item["-intf-suffix" \var{string}] +Recognize file names ending with \var{string} as interface files +(instead of the default ".mli"). +}%\notop + +\item["-labels"] +Labels are not ignored in types, labels may be used in applications, +and labelled parameters can be given in any order. This is the default. + +\notop{% +\item["-linkall"] +Force all modules contained in libraries to be linked in. If this +flag is not given, unreferenced modules are not linked in. When +building a library (option "-a"), setting the "-linkall" option forces all +subsequent links of programs involving that library to link all the +modules contained in the library. When compiling a module (option +"-c"), setting the "-linkall" option ensures that this module will +always be linked if it is put in a library and this library is linked. +}%notop + +\nat{% +\item["-linscan"] +Use linear scan register allocation. Compiling with this allocator is faster +than with the usual graph coloring allocator, sometimes quite drastically so for +long functions and modules. On the other hand, the generated code can be a bit +slower. +}%nat + +\comp{% +\item["-make-runtime"] +Build a custom runtime system (in the file specified by option "-o") +incorporating the C object files and libraries given on the command +line. This custom runtime system can be used later to execute +bytecode executables produced with the +"ocamlc -use-runtime" \var{runtime-name} option. +See section~\ref{s:custom-runtime} for more information. +}%comp + +\notop{% +\item["-no-alias-deps"] +Do not record dependencies for module aliases. See +section~\ref{s:module-alias} for more information. +}%notop + +\item["-no-app-funct"] +Deactivates the applicative behaviour of functors. With this option, +each functor application generates new types in its result and +applying the same functor twice to the same argument yields two +incompatible structures. + +\item["-noassert"] +Do not compile assertion checks. Note that the special form +"assert false" is always compiled because it is typed specially. +\notop{This flag has no effect when linking already-compiled files.} + +\notop{% +\item["-noautolink"] +When linking \qcma libraries, ignore \comp{"-custom",} "-cclib" and "-ccopt" +options potentially contained in the libraries (if these options were +given when building the libraries). This can be useful if a library +contains incorrect specifications of C libraries or C options; in this +case, during linking, set "-noautolink" and pass the correct C +libraries and options on the command line. +}% + +\nat{% +\item["-nodynlink"] +Allow the compiler to use some optimizations that are valid only for code +that is never dynlinked. +}%nat + +\item["-nolabels"] +Ignore non-optional labels in types. Labels cannot be used in +applications, and parameter order becomes strict. + +\top{% +\item["-noprompt"] +Do not display any prompt when waiting for input. +}%top + +\top{% +\item["-nopromptcont"] +Do not display the secondary prompt when waiting for continuation +lines in multi-line inputs. This should be used e.g. when running +"ocaml" in an "emacs" window. +}%top + +\item["-nostdlib"] +\top{% +Do not include the standard library directory in the list of +directories searched for source and compiled files. +}%top +\comp{% +Do not include the standard library directory in the list of +directories searched for +compiled interface files (".cmi"), compiled object code files +(".cmo"), libraries (".cma"), and C libraries specified with +"-cclib -lxxx". See also option "-I". +}%comp +\nat{% +Do not automatically add the standard library directory the list of +directories searched for compiled interface files (".cmi"), compiled +object code files (".cmx"), and libraries (".cmxa"). See also option +"-I". +}%nat + +\notop{% +\item["-o" \var{exec-file}] +Specify the name of the output file produced by the +\nat{linker}\comp{compiler}. The +default output name is "a.out" under Unix and "camlprog.exe" under +Windows. If the "-a" option is given, specify the name of the library +produced. If the "-pack" option is given, specify the name of the +packed object file produced. If the "-output-obj" option is given, +specify the name of the output file produced. +\nat{If the "-shared" option is given, specify the name of plugin +file produced.} +\comp{If the "-c" option is given, specify the name of the object +file produced for the {\em next} source file that appears on the +command line.} +}%notop + +\notop{% +\item["-opaque"] +When the native compiler compiles an implementation, by default it +produces a ".cmx" file containing information for cross-module +optimization. It also expects ".cmx" files to be present for the +dependencies of the currently compiled source, and uses them for +optimization. Since OCaml 4.03, the compiler will emit a warning if it +is unable to locate the ".cmx" file of one of those dependencies. + +The "-opaque" option, available since 4.04, disables cross-module +optimization information for the currently compiled unit. When +compiling ".mli" interface, using "-opaque" marks the compiled ".cmi" +interface so that subsequent compilations of modules that depend on it +will not rely on the corresponding ".cmx" file, nor warn if it is +absent. When the native compiler compiles a ".ml" implementation, +using "-opaque" generates a ".cmx" that does not contain any +cross-module optimization information. + +Using this option may degrade the quality of generated code, but it +reduces compilation time, both on clean and incremental +builds. Indeed, with the native compiler, when the implementation of +a compilation unit changes, all the units that depend on it may need +to be recompiled -- because the cross-module information may have +changed. If the compilation unit whose implementation changed was +compiled with "-opaque", no such recompilation needs to occur. This +option can thus be used, for example, to get faster edit-compile-test +feedback loops. +}%notop + +\notop{% +\item["-open" \var{Module}] +Opens the given module before processing the interface or +implementation files. If several "-open" options are given, +they are processed in order, just as if +the statements "open!" \var{Module1}";;" "..." "open!" \var{ModuleN}";;" +were added at the top of each file. +}%notop + +\notop{% +\item["-output-obj"] +Cause the linker to produce a C object file instead of +\comp{a bytecode executable file}\nat{an executable file}. +This is useful to wrap OCaml code as a C library, +callable from any C program. See chapter~\ref{c:intf-c}, +section~\ref{s:embedded-code}. The name of the output object file +must be set with the "-o" option. +This option can also be used to produce a \comp{C source file (".c" extension) or +a} compiled shared/dynamic library (".so" extension, ".dll" under Windows). +}%notop + +\nat{% +\item["-p"] +Generate extra code to write profile information when the program is +executed. The profile information can then be examined with the +analysis program "gprof". (See chapter~\ref{c:profiler} for more +information on profiling.) The "-p" option must be given both at +compile-time and at link-time. Linking object files not compiled with +"-p" is possible, but results in less precise profiling. + +\begin{unix} See the Unix manual page for "gprof(1)" for more +information about the profiles. + +Full support for "gprof" is only available for certain platforms +(currently: Intel x86 32 and 64 bits under Linux, BSD and MacOS X). +On other platforms, the "-p" option will result in a less precise +profile (no call graph information, only a time profile). +\end{unix} + +\begin{windows} +The "-p" option does not work under Windows. +\end{windows} +}%nat + +\nat{% +\item["-pack"] +Build an object file (".cmx" and ".o"/".obj" files) and its associated compiled +interface (".cmi") that combines the ".cmx" object +files given on the command line, making them appear as sub-modules of +the output ".cmx" file. The name of the output ".cmx" file must be +given with the "-o" option. For instance, +\begin{verbatim} + ocamlopt -pack -o P.cmx A.cmx B.cmx C.cmx +\end{verbatim} +generates compiled files "P.cmx", "P.o" and "P.cmi" describing a +compilation unit having three sub-modules "A", "B" and "C", +corresponding to the contents of the object files "A.cmx", "B.cmx" and +"C.cmx". These contents can be referenced as "P.A", "P.B" and "P.C" +in the remainder of the program. + +The ".cmx" object files being combined must have been compiled with +the appropriate "-for-pack" option. In the example above, +"A.cmx", "B.cmx" and "C.cmx" must have been compiled with +"ocamlopt -for-pack P". + +Multiple levels of packing can be achieved by combining "-pack" with +"-for-pack". Consider the following example: +\begin{verbatim} + ocamlopt -for-pack P.Q -c A.ml + ocamlopt -pack -o Q.cmx -for-pack P A.cmx + ocamlopt -for-pack P -c B.ml + ocamlopt -pack -o P.cmx Q.cmx B.cmx +\end{verbatim} +The resulting "P.cmx" object file has sub-modules "P.Q", "P.Q.A" +and "P.B". +}%nat + +\comp{% +\item["-pack"] +Build a bytecode object file (".cmo" file) and its associated compiled +interface (".cmi") that combines the object +files given on the command line, making them appear as sub-modules of +the output ".cmo" file. The name of the output ".cmo" file must be +given with the "-o" option. For instance, +\begin{verbatim} + ocamlc -pack -o p.cmo a.cmo b.cmo c.cmo +\end{verbatim} +generates compiled files "p.cmo" and "p.cmi" describing a compilation +unit having three sub-modules "A", "B" and "C", corresponding to the +contents of the object files "a.cmo", "b.cmo" and "c.cmo". These +contents can be referenced as "P.A", "P.B" and "P.C" in the remainder +of the program. +}%comp + + +\notop{% +\item["-plugin" \var{plugin}] +Dynamically load the code of the given \var{plugin} +(a ".cmo", ".cma" or ".cmxs" file) in the compiler. \var{plugin} must exist in +the same kind of code as the compiler ({\machine \ocamlx.byte} must load bytecode +plugins, while {\machine \ocamlx.opt} must load native code plugins), and +extension adaptation is done automatically for ".cma" files (to ".cmxs" files +if the compiler is compiled in native code). +}%notop + +\notop{% +\item["-pp" \var{command}] +Cause the compiler to call the given \var{command} as a preprocessor +for each source file. The output of \var{command} is redirected to +an intermediate file, which is compiled. If there are no compilation +errors, the intermediate file is deleted afterwards. +}%notop + +\item["-ppx" \var{command}] +After parsing, pipe the abstract syntax tree through the preprocessor +\var{command}. The module "Ast_mapper", described in +\ifouthtml +chapter~\ref{c:parsinglib}: \ahref{libref/Ast\_mapper.html}{ \texttt{Ast_mapper} } +\else section~\ref{Ast-underscoremapper}\fi, +implements the external interface of a preprocessor. + +\item["-principal"] +Check information path during type-checking, to make sure that all +types are derived in a principal way. When using labelled arguments +and/or polymorphic methods, this flag is required to ensure future +versions of the compiler will be able to infer types correctly, even +if internal algorithms change. +All programs accepted in "-principal" mode are also accepted in the +default mode with equivalent types, but different binary signatures, +and this may slow down type checking; yet it is a good idea to +use it once before publishing source code. + +\item["-rectypes"] +Allow arbitrary recursive types during type-checking. By default, +only recursive types where the recursion goes through an object type +are supported.\notop{Note that once you have created an interface using this +flag, you must use it again for all dependencies.} + +\notop{% +\item["-runtime-variant" \var{suffix}] +Add the \var{suffix} string to the name of the runtime library used by +the program. Currently, only one such suffix is supported: "d", and +only if the OCaml compiler was configured with option +"-with-debug-runtime". This suffix gives the debug version of the +runtime, which is useful for debugging pointer problems in low-level +code such as C stubs. +}%notop + +\nat{% +\item["-S"] +Keep the assembly code produced during the compilation. The assembly +code for the source file \var{x}".ml" is saved in the file \var{x}".s". +}%nat + +\nat{% +\item["-shared"] +Build a plugin (usually ".cmxs") that can be dynamically loaded with +the "Dynlink" module. The name of the plugin must be +set with the "-o" option. A plugin can include a number of OCaml +modules and libraries, and extra native objects (".o", ".obj", ".a", +".lib" files). Building native plugins is only supported for some +operating system. Under some systems (currently, +only Linux AMD 64), all the OCaml code linked in a plugin must have +been compiled without the "-nodynlink" flag. Some constraints might also +apply to the way the extra native objects have been compiled (under +Linux AMD 64, they must contain only position-independent code). +}%nat + +\item["-safe-string"] +Enforce the separation between types "string" and "bytes", +thereby making strings read-only. This is the default. + +\item["-short-paths"] +When a type is visible under several module-paths, use the shortest +one when printing the type's name in inferred interfaces and error and +warning messages. Identifier names starting with an underscore "_" or +containing double underscores "__" incur a penalty of $+10$ when computing +their length. + +\top{ +\item["-stdin"] +Read the standard input as a script file rather than starting an +interactive session. +}%top + +\item["-strict-sequence"] +Force the left-hand part of each sequence to have type unit. + +\item["-strict-formats"] +Reject invalid formats that were accepted in legacy format +implementations. You should use this flag to detect and fix such +invalid formats, as they will be rejected by future OCaml versions. + +\notop{% +\item["-unboxed-types"] +When a type is unboxable (i.e. a record with a single argument or a +concrete datatype with a single constructor of one argument) it will +be unboxed unless annotated with "[@@ocaml.boxed]". +}%notop + +\notop{% +\item["-no-unboxed-types"] +When a type is unboxable it will be boxed unless annotated with +"[@@ocaml.unboxed]". This is the default. +}%notop + +\item["-unsafe"] +Turn bound checking off for array and string accesses (the "v.(i)" and +"s.[i]" constructs). Programs compiled with "-unsafe" are therefore +\comp{slightly} faster, but unsafe: anything can happen if the program +accesses an array or string outside of its bounds. +\notop{% +Additionally, turn off the check for zero divisor in integer division + and modulus operations. With "-unsafe", an integer division +(or modulus) by zero can halt the program or continue with an +unspecified result instead of raising a "Division_by_zero" exception. +}%notop + +\item["-unsafe-string"] +Identify the types "string" and "bytes", thereby making strings writable. +This is intended for compatibility with old source code and should not +be used with new software. + +\comp{% +\item["-use-runtime" \var{runtime-name}] +Generate a bytecode executable file that can be executed on the custom +runtime system \var{runtime-name}, built earlier with +"ocamlc -make-runtime" \var{runtime-name}. +See section~\ref{s:custom-runtime} for more information. +}%comp + +\item["-v"] +Print the version number of the compiler and the location of the +standard library directory, then exit. + +\item["-verbose"] +Print all external commands before they are executed, +\nat{in particular invocations of the assembler, C compiler, and linker.} +\comp{in particular invocations of the C compiler and linker in "-custom" mode.} +Useful to debug C library problems. + +\comp{% +\item["-vmthread"] +Compile or link multithreaded programs, in combination with the +VM-level "threads" library described in chapter~\ref{c:threads}. +}%comp + +\notop{% +\item["-version" or "-vnum"] +Print the version number of the compiler in short form (e.g. "3.11.0"), +then exit. +}%notop + +\top{% +\item["-version"] +Print version string and exit. + +\item["-vnum"] +Print short version number and exit. + +\item["-no-version"] +Do not print the version banner at startup. +}%top + +\item["-w" \var{warning-list}] +Enable, disable, or mark as fatal the warnings specified by the argument +\var{warning-list}. +Each warning can be {\em enabled} or {\em disabled}, and each warning +can be {\em fatal} or {\em non-fatal}. +If a warning is disabled, it isn't displayed and doesn't affect +compilation in any way (even if it is fatal). If a warning is +enabled, it is displayed normally by the compiler whenever the source +code triggers it. If it is enabled and fatal, the compiler will also +stop with an error after displaying it. + +The \var{warning-list} argument is a sequence of warning specifiers, +with no separators between them. A warning specifier is one of the +following: + +\begin{options} +\item["+"\var{num}] Enable warning number \var{num}. +\item["-"\var{num}] Disable warning number \var{num}. +\item["@"\var{num}] Enable and mark as fatal warning number \var{num}. +\item["+"\var{num1}..\var{num2}] Enable warnings in the given range. +\item["-"\var{num1}..\var{num2}] Disable warnings in the given range. +\item["@"\var{num1}..\var{num2}] Enable and mark as fatal warnings in +the given range. +\item["+"\var{letter}] Enable the set of warnings corresponding to +\var{letter}. The letter may be uppercase or lowercase. +\item["-"\var{letter}] Disable the set of warnings corresponding to +\var{letter}. The letter may be uppercase or lowercase. +\item["@"\var{letter}] Enable and mark as fatal the set of warnings +corresponding to \var{letter}. The letter may be uppercase or +lowercase. +\item[\var{uppercase-letter}] Enable the set of warnings corresponding +to \var{uppercase-letter}. +\item[\var{lowercase-letter}] Disable the set of warnings corresponding +to \var{lowercase-letter}. +\end{options} + +Warning numbers and letters which are out of the range of warnings +that are currently defined are ignored. The warnings are as follows. +\begin{options} +\input{warnings-help.tex} +\end{options} + +The default setting is "-w +a-4-6-7-9-27-29-32..42-44-45-48-50-60". +It is displayed by {\machine\ocamlx\ -help}. +Note that warnings 5 and 10 are not always triggered, depending on +the internals of the type checker. + + +\item["-warn-error" \var{warning-list}] +Mark as fatal the warnings specified in the argument \var{warning-list}. +The compiler will stop with an error when one of these warnings is +emitted. The \var{warning-list} has the same meaning as for +the "-w" option: a "+" sign (or an uppercase letter) marks the +corresponding warnings as fatal, a "-" +sign (or a lowercase letter) turns them back into non-fatal warnings, +and a "@" sign both enables and marks as fatal the corresponding +warnings. + +Note: it is not recommended to use warning sets (i.e. letters) as +arguments to "-warn-error" +in production code, because this can break your build when future versions +of OCaml add some new warnings. + +The default setting is "-warn-error -a+31" (only warning 31 is fatal). + +\item["-warn-help"] +Show the description of all available warning numbers. + +\notop{% +\item["-where"] +Print the location of the standard library, then exit. +}%notop + +\item["-" \var{file}] +\notop{Process \var{file} as a file name, even if it starts with a dash ("-") +character.} +\top{Use \var{file} as a script file name, even when it starts with a +hyphen (-).} + +\item["-help" or "--help"] +Display a short usage summary and exit. + +\end{options} +% diff --git a/manual/manual/foreword.etex b/manual/manual/foreword.etex new file mode 100644 index 00000000..6c68d7e2 --- /dev/null +++ b/manual/manual/foreword.etex @@ -0,0 +1,82 @@ +\chapter*{Foreword} +\markboth{Foreword}{} +%HEVEA\cutname{foreword.html} + +This manual documents the release \ocamlversion\ of the OCaml +system. It is organized as follows. +\begin{itemize} +\item Part~\ref{p:tutorials}, ``An introduction to OCaml'', +gives an overview of the language. +\item Part~\ref{p:refman}, ``The OCaml language'', is the +reference description of the language. +\item Part~\ref{p:commands}, ``The OCaml tools'', documents +the compilers, toplevel system, and programming utilities. +\item Part~\ref{p:library}, ``The OCaml library'', describes the +modules provided in the standard library. +\begin{latexonly} +\item Part~\ref{p:appendix}, ``Appendix'', contains an +index of all identifiers defined in the standard library, and an +index of keywords. +\end{latexonly} +\end{itemize} + +\section*{Conventions} + +OCaml runs on several operating systems. The parts of +this manual that are specific to one operating system are presented as +shown below: + +\begin{unix} This is material specific to the Unix family of operating +systems, including Linux and \hbox{MacOS~X}. +\end{unix} + +\begin{windows} This is material specific to Microsoft Windows + (XP, Vista, 7, 8, 10). +\end{windows} + +\section*{License} + +The OCaml system is copyright \copyright\ 1996--\number\year\ +Institut National de Recherche en Informatique et en +Automatique (INRIA). +INRIA holds all ownership rights to the OCaml system. + +The OCaml system is open source and can be freely +redistributed. See the file "LICENSE" in the distribution for +licensing information. + +The present documentation is copyright \copyright\ \number\year\ +Institut National de Recherche en Informatique et en +Automatique (INRIA). The OCaml documentation and user's +manual may be reproduced and distributed in whole or +in part, subject to the following conditions: +\begin{itemize} +\item The copyright notice above and this permission notice must be +preserved complete on all complete or partial copies. +\item Any translation or derivative work of the OCaml +documentation and user's manual must be approved by the authors in +writing before distribution. +\item If you distribute the OCaml +documentation and user's manual in part, instructions for obtaining +the complete version of this manual must be included, and a +means for obtaining a complete version provided. +\item Small portions may be reproduced as illustrations for reviews or +quotes in other works without this permission notice if proper +citation is given. +\end{itemize} + +\section*{Availability} + +\begin{latexonly} +The complete OCaml distribution can be accessed via the Web +sites \url{http://www.ocaml.org/} and \url{http://caml.inria.fr/}. +The former Web site contains a lot of additional information on OCaml. +\end{latexonly} + +\begin{htmlonly} +The complete OCaml distribution can be accessed via the +\href{http://www.ocaml.org/}{community Caml Web site} and the +\href{http://caml.inria.fr/}{older Caml Web site}. +The \href{http://www.ocaml.org/}{community Caml Web site} +contains a lot of additional information on OCaml. +\end{htmlonly} diff --git a/manual/manual/htmlman/.gitignore b/manual/manual/htmlman/.gitignore new file mode 100644 index 00000000..3cecdc2c --- /dev/null +++ b/manual/manual/htmlman/.gitignore @@ -0,0 +1,8 @@ +*.html +*.haux +*.hind +libref +manual.hmanual +manual.hmanual.kwd +manual.css +*.htoc diff --git a/manual/manual/htmlman/contents_motif.gif b/manual/manual/htmlman/contents_motif.gif new file mode 100644 index 0000000000000000000000000000000000000000..5d3d016702478a74ae10ef900888bdd3c379aa3b GIT binary patch literal 316 zcmZ?wbhEHb6krfw_{abP1q~Da{|7M?|0yXbc;*)57nP)@D5MqT=PE=5_$p-PCZ?xa zDU{?V>s1uwGARCJVPs%nX3zm?0h!{!^!$#Qv4ElRF^Oazg%$xP4gr?K20Vui7@8Cq z96<~aYG7bFXduDE)_gF*K!Sm#!2w8tc?<#^EKH0F0@&nWDh*(OL4iR)0LC#eU{Fv% q765UP1Rz|v0LZ;S{U8800mw%-4`?77pMe2nUBZC|MrJMs25SIR**_xy literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.eot b/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..487aa40a07b90c78d74205677641a6c5a4bbdf97 GIT binary patch literal 24643 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 c4Z65kK7P^C=W0PK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.ttf b/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a330a88d000a8ff83a608b4865e49f5f8c441db8 GIT binary patch literal 54032 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 literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff b/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..9c671f401f93cd8b0fe90b6393aea33d2cb84079 GIT binary patch literal 25472 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 literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff2 b/manual/manual/htmlman/fonts/fira-sans-v8-latin-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3d2169952f43b6b97d9105735b3561136f3aa2df GIT binary patch literal 21016 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 XaQ@nFa^oksTKt(FxW!c33jhEB@qd@P literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/libgraph.gif b/manual/manual/htmlman/libgraph.gif new file mode 100644 index 0000000000000000000000000000000000000000..b385985b13d8f91851761f15db95b0e26f47f204 GIT binary patch literal 2149 zcmV-r2%7gtNk%v~VIcxm0e}Di00030|Nkri0000X0#*S40{)DTsmtvTqnxzbi?iOm z`wxcVNS5Y_rs~SJ?hD8AOxN~}=lag~{tpZahs2`sh)gP%%%<}RjY_A~s`ZM^YPa03 z_X`e-$K-YS={|^`_I7nD%c!-#&xX9S(_y`#(IZ0V* zd5M{+xyjk-`3V{-I!anXw&W@eT z|2*wpzJY?&{Zls2Tf%L=ru!#VFFHRpK#y+EgjjsY)hNz1qYo z)~!e+a{Zc9E7-9;ERsFT!z|jhI&`vqJHsv9xv}Wlje9rm3%PpxhT!WrFbBYb3tu2? zII#r8iW@gz>^O2n$smRDx@Q?0<&T+T36!dNb6$g;(}^DEm7Pbm0Xw5}8W37(fTx$S zhTR%mMZmB3nVb!|HY$V=S5vE}8iH<(zZnM?ZYs6B$Le+yCf-daaOlj$uFL+}dIVt2 z&pGFw3wcE52pL-Nj&1s4^tg7bPHjIoZu36=ji0A)%We7Pci(IjQCA#f&jBctWu&=f zU4#-&NMVH*UWj3a8g9s8haP&km4wMTAdZ2wjRqHM*{xT>f+40TT?sB?HREYDQg!2I zIYPCgWIZzVqhmoLHKbxi5_P0uNdmQ`U`_J$q+e0uG^Jiu+H~bzS<F~pL6&w@A^+jy)Eg8GCaV;IQ^zkeqt2FW}C8Kn*Dk+n+@^Baj%x}x5 z$jlkc`O;hp&Kv1G3eOk$9176g+U%~-pBNo3(R3o+3De~&t)|nPNS!X!XHuOB*6kj= zu-2D&O|R8tg5Au^Tq8_2C212Zc9?5#W46K$zgfQ> z=d91_E4J?K>!jFj;BS8oYPY3oO>~S|gif2_eFxfetgJrR-m@9OUrXtT=FC1lr`AA- z8H=U%?t6jj9Y<@b32&BAV;2tX z(C<|CcmQlh2ZQ~AqJ93m6a1n_J^JMjJ|jw>{RJz4VR57ftIz0b6&MWFtq@Zk5DLMBo?u`J#biN=U2t<{K;R1aVyqYDq=tFg zPgm;2!=`brHc`w&{uQS-MH>x*K%!&ft5n1$FIo|dxgug9xOj&vY65g<45JwzLPk2M zF>70l;~eJLkvb--jFg#{Y(50YKnik@B6^jLvIoR77KDoEOXNcqc}V=t2a=Cu&Jbq4giYz4+Nm;PqDbj@Ibf+|h={P-_Qj`LfrxOinLxcLzmByi^a8oKAm|8cdz5%Ly zE9p;rid2y5^r%EFnpJ12(wb(}s71{xNu}xrs+Q!dHYKZ2xr)`U;xw*sE$dM0`qr@e z6s%rFYa7%mIJS;;t9Hd}QpL(rj3ySbk`wG=-8$F8>eZ|!g{)TP+E2f-0kDmDDP=dR z*)=rIi0%xn8b-@mM}C&Chuv#i37gm0W-Eq&wAOKMTcFf3Y_+c~ilidQ4+lPQfsS3O z@3j8oo)RVRcEx>a_s%CL_>mTI&7EqWNNW`GDYt<9Gi@47w?_jGk6Fu+UX~tf^KV&XDAA>uexbnZyQ(QS< zz;i%YB99^o>amG~^;;WCOC-Ouk8g!PIwNC<0^wW%t@dinT4xl-NaWpEL^ja*-S$cW`RKLRe+BXjx^r&L&Xaq;7MJkRokKksZTr*0g3y0RR9y>lH4J literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/next_motif.gif b/manual/manual/htmlman/next_motif.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f84bacfb26ea6a4141ad407ff4fb77954171fea GIT binary patch literal 317 zcmZ?wbhEHb6krfw_{abP1q~Da{|AwZ|CALJJaY^3i%L>c6w-?Fa}^>2d=)Zt6Vp?z z6!KClO7toUav2nVvM@3*Ff-_YG=q$BV0wPX%oqrcNic)NoH!IY7zB6@8}Kj-us9lk z7$CL+2ZMnG4_ouW1Z2ulL4bpWfr*g;NHKx6GcYhUIw%M*FhEp-DFfUZHARYuTK(sM{cnnYuPzb0WB7s6C9B5!<=3-#51_0IeJqZ8+ literal 0 HcmV?d00001 diff --git a/manual/manual/htmlman/previous_motif.gif b/manual/manual/htmlman/previous_motif.gif new file mode 100644 index 0000000000000000000000000000000000000000..8c8a3e6430050e67e2e71dbd1f99fb9caf6176bf GIT binary patch literal 317 zcmZ?wbhEHb6krfw_{abP1q~Da{|AwZ|CALJJaY^3i%L>c6w-?Fa}^>2d=)Zt6Vp?z z6bgz`%k(M=av2nVvM@3*Ff-_YG=q$BV0wPX%oqrcNhmWYviw rA^>J9009F?7$^Z^BLGMh0|ST;RSz`=t{-8nfkDE721aHs1_o;Y3u!(; literal 0 HcmV?d00001 diff --git a/manual/manual/index.tex b/manual/manual/index.tex new file mode 100644 index 00000000..aff78b9f --- /dev/null +++ b/manual/manual/index.tex @@ -0,0 +1,20 @@ +\ifouthtml +\begin{rawhtml} + +\end{rawhtml} +\else +\chapter*{Index to the library} +\markright{Index to the library} +\addcontentsline{toc}{chapter}{Index to the library} +\myprintindex{\jobname.ind} +\fi +\chapter*{Index of keywords} +\markright{Index of keywords} +\addcontentsline{toc}{chapter}{Index of keywords} +\myprintindex{\jobname.kwd.ind} diff --git a/manual/manual/infoman/.gitignore b/manual/manual/infoman/.gitignore new file mode 100644 index 00000000..916af019 --- /dev/null +++ b/manual/manual/infoman/.gitignore @@ -0,0 +1,5 @@ +*.haux +*.hind +*.info*.gz +*.info.body* +ocaml.hocaml.kwd diff --git a/manual/manual/library/.cvsignore b/manual/manual/library/.cvsignore new file mode 100644 index 00000000..8955ee04 --- /dev/null +++ b/manual/manual/library/.cvsignore @@ -0,0 +1,5 @@ +*.tex +*.htex +arithstatus.mli +ocamldoc.out +ocamldoc.sty diff --git a/manual/manual/library/.gitignore b/manual/manual/library/.gitignore new file mode 100644 index 00000000..8955ee04 --- /dev/null +++ b/manual/manual/library/.gitignore @@ -0,0 +1,5 @@ +*.tex +*.htex +arithstatus.mli +ocamldoc.out +ocamldoc.sty diff --git a/manual/manual/library/Makefile b/manual/manual/library/Makefile new file mode 100644 index 00000000..d085f504 --- /dev/null +++ b/manual/manual/library/Makefile @@ -0,0 +1,86 @@ +CORE_INTF=Pervasives.tex + +CSLDIR=$(RELEASEDIR) + +STDLIB_INTF= Arg.tex Array.tex ArrayLabels.tex Char.tex Complex.tex \ + Digest.tex Filename.tex Format.tex \ + Gc.tex Genlex.tex Hashtbl.tex Int32.tex Int64.tex \ + Lazy.tex Lexing.tex List.tex ListLabels.tex Map.tex Marshal.tex \ + MoreLabels.tex Nativeint.tex Obj.tex Oo.tex \ + Parsing.tex Printexc.tex Printf.tex Queue.tex Random.tex Scanf.tex \ + Set.tex Sort.tex Stack.tex Stream.tex String.tex StringLabels.tex Sys.tex \ + Weak.tex Callback.tex Buffer.tex StdLabels.tex \ + Bytes.tex BytesLabels.tex Spacetime.tex + +COMPILER_LIBS_PLUGIN_HOOKS=Pparse.tex Typemod.tex + +COMPILER_LIBS_INTF=Asthelper.tex Astmapper.tex Asttypes.tex \ + Lexer.tex Location.tex Longident.tex Parse.tex Pprintast.tex Printast.tex \ + $(COMPILER_LIBS_PLUGIN_HOOKS) + +OTHERLIB_INTF=Unix.tex UnixLabels.tex Str.tex \ + Graphics.tex GraphicsX11.tex \ + Thread.tex Mutex.tex Condition.tex Event.tex ThreadUnix.tex \ + Dynlink.tex Bigarray.tex + +INTF=$(CORE_INTF) $(STDLIB_INTF) $(COMPILER_LIBS_INTF) $(OTHERLIB_INTF) + +BLURB=core.tex builtin.tex stdlib.tex compilerlibs.tex \ + libunix.tex libstr.tex libnum.tex libgraph.tex \ + libthreads.tex libdynlink.tex libbigarray.tex + +FILES=$(BLURB) $(INTF) + +SRC=../../.. + +LD_PATH := $(SRC)/otherlibs/unix/:$(SRC)/otherlibs/str/ +SET_LD_PATH=CAML_LD_LIBRARY_PATH=$(LD_PATH) + +FORMAT=../../tools/format-intf +TEXQUOTE=../../tools/texquote2 + +VPATH=.:$(STDLIB_DIR):$(CSLDIR)/parsing:$(CSLDIR)/otherlibs/unix:$(CSLDIR)/otherlibs/str:$(CSLDIR)/otherlibs/graph:$(CSLDIR)/otherlibs/threads:$(CSLDIR)/otherlibs/dynlink:$(CSLDIR)/otherlibs/bigarray + +etex-files: $(BLURB) +all: libs + +libs: $(FILES) + +OCAMLDOC=$(if $(wildcard $(CSLDIR)/ocamldoc/ocamldoc.opt),\ + $(CSLDIR)/ocamldoc/ocamldoc.opt,\ + $(SET_LD_PATH) $(CSLDIR)/byterun/ocamlrun $(CSLDIR)/ocamldoc/ocamldoc) \ + -nostdlib -initially-opened-module Pervasives + +# Copy and unprefix the standard library when needed +include $(SRC)/ocamldoc/Makefile.unprefix + + +$(INTF): interfaces +interfaces: $(STDLIB_CMIS) + $(OCAMLDOC) -latex \ + -I $(STDLIB_UNPREFIXED) \ + $(STDLIB_MLIS) \ + -sepfiles \ + -latextitle "1,subsection*" \ + -latextitle "2,subsubsection*" \ + -latex-type-prefix "TYP" \ + -latex-module-prefix "" \ + -latex-module-type-prefix "" \ + -latex-value-prefix "" + mv -f Ast_helper.tex Asthelper.tex + mv -f Ast_mapper.tex Astmapper.tex + +clean: + rm -f $(FILES) + +.SUFFIXES: +.SUFFIXES: .tex .etex .mli + +.etex.tex: $(TEXQUOTE) + @$(TEXQUOTE) < $*.etex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex + + +.mli.tex: $(FORMAT) + $(FORMAT) $< > $*.tex < $< diff --git a/manual/manual/library/builtin.etex b/manual/manual/library/builtin.etex new file mode 100644 index 00000000..404f5608 --- /dev/null +++ b/manual/manual/library/builtin.etex @@ -0,0 +1,281 @@ +\section{Built-in types and predefined exceptions} + +The following built-in types and predefined exceptions are always +defined in the +compilation environment, but are not part of any module. As a +consequence, they can only be referred by their short names. + +%\vspace{0.1cm} +\subsection*{Built-in types} +%\vspace{0.1cm} + +\begin{ocamldoccode} + type int +\end{ocamldoccode} +\index{int@\verb`int`} +\begin{ocamldocdescription} + The type of integer numbers. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type char +\end{ocamldoccode} +\index{char@\verb`char`} +\begin{ocamldocdescription} + The type of characters. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type bytes +\end{ocamldoccode} +\index{bytes@\verb`bytes`} +\begin{ocamldocdescription} + The type of (writable) byte sequences. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type string +\end{ocamldoccode} +\index{string@\verb`string`} +\begin{ocamldocdescription} + The type of (read-only) character strings. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type float +\end{ocamldoccode} +\index{float@\verb`float`} +\begin{ocamldocdescription} + The type of floating-point numbers. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type bool = false | true +\end{ocamldoccode} +\index{bool@\verb`bool`} +\begin{ocamldocdescription} + The type of booleans (truth values). +\end{ocamldocdescription} + +\begin{ocamldoccode} + type unit = () +\end{ocamldoccode} +\index{unit@\verb`unit`} +\begin{ocamldocdescription} + The type of the unit value. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type exn +\end{ocamldoccode} +\index{exn@\verb`exn`} +\begin{ocamldocdescription} + The type of exception values. +\end{ocamldocdescription} + +\begin{ocamldoccode} + type 'a array +\end{ocamldoccode} +\index{array@\verb`array`} +\begin{ocamldocdescription} + The type of arrays whose elements have type "'a". +\end{ocamldocdescription} + +\begin{ocamldoccode} + type 'a list = [] | :: of 'a * 'a list +\end{ocamldoccode} +\index{list@\verb`list`} +\begin{ocamldocdescription} + The type of lists whose elements have type "'a". +\end{ocamldocdescription} + +\begin{ocamldoccode} +type 'a option = None | Some of 'a +\end{ocamldoccode} +\index{option@\verb`option`} +\begin{ocamldocdescription} + The type of optional values of type "'a". +\end{ocamldocdescription} + +\begin{ocamldoccode} +type int32 +\end{ocamldoccode} +\index{int32@\verb`int32`} +\begin{ocamldocdescription} + The type of signed 32-bit integers. + See the "Int32"[\moduleref{Int32}] module. +\end{ocamldocdescription} + +\begin{ocamldoccode} +type int64 +\end{ocamldoccode} +\index{int64@\verb`int64`} +\begin{ocamldocdescription} + The type of signed 64-bit integers. + See the "Int64"[\moduleref{Int64}] module. +\end{ocamldocdescription} + +\begin{ocamldoccode} +type nativeint +\end{ocamldoccode} +\index{nativeint@\verb`nativeint`} +\begin{ocamldocdescription} + The type of signed, platform-native integers (32 bits on 32-bit + processors, 64 bits on 64-bit processors). + See the "Nativeint"[\moduleref{Nativeint}] module. +\end{ocamldocdescription} + +\begin{ocamldoccode} +type ('a, 'b, 'c, 'd, 'e, 'f) format6 +\end{ocamldoccode} +\index{format4@\verb`format4`} +\begin{ocamldocdescription} + The type of format strings. "'a" is the type of the parameters of + the format, "'f" is the result type for the "printf"-style + functions, "'b" is the type of the first argument given to "%a" and + "%t" printing functions (see module "Printf"[\moduleref{Printf}]), + "'c" is the result type of these functions, and also the type of the + argument transmitted to the first argument of "kprintf"-style + functions, "'d" is the result type for the "scanf"-style functions + (see module "Scanf"[\moduleref{Scanf}]), + and "'e" is the type of the receiver function for the "scanf"-style + functions. +\end{ocamldocdescription} + +\begin{ocamldoccode} +type 'a lazy_t +\end{ocamldoccode} +\index{lazyt@\verb`lazy_t`} +\begin{ocamldocdescription} + This type is used to implement the "Lazy"[\moduleref{Lazy}] module. + It should not be used directly. +\end{ocamldocdescription} + +%\vspace{0.1cm} +\subsection*{Predefined exceptions} +%\vspace{0.1cm} + +\begin{ocamldoccode} +exception Match_failure of (string * int * int) +\end{ocamldoccode} +\index{Matchfailure@\verb`Match_failure`} +\begin{ocamldocdescription} + Exception raised when none of the cases of a pattern-matching + apply. The arguments are the location of the "match" keyword + in the source code (file name, line number, column number). +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Assert_failure of (string * int * int) +\end{ocamldoccode} +\index{Assertfailure@\verb`Assert_failure`} +\begin{ocamldocdescription} + Exception raised when an assertion fails. The arguments are + the location of the "assert" keyword in the source code + (file name, line number, column number). +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Invalid_argument of string +\end{ocamldoccode} +\index{Invalidargument@\verb`Invalid_argument`} +\begin{ocamldocdescription} + Exception raised by library functions to signal that the given + arguments do not make sense. The string gives some information + to the programmer. As a general rule, this exception should not + be caught, it denotes a programming error and the code should be + modified not to trigger it. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Failure of string +\end{ocamldoccode} +\index{Failure@\verb`Failure`} +\begin{ocamldocdescription} + Exception raised by library functions to signal that they are + undefined on the given arguments. The string is meant to give some + information to the programmer; you must \emph{not} pattern match on + the string literal because it may change in future versions (use + \verb`Failure _` instead). +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Not_found +\end{ocamldoccode} +\index{Notfound@\verb`Not_found`} +\begin{ocamldocdescription} + Exception raised by search functions when the desired object + could not be found. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Out_of_memory +\end{ocamldoccode} +\index{Outofmemory@\verb`Out_of_memory`} +\begin{ocamldocdescription} + Exception raised by the garbage collector + when there is insufficient memory to complete the computation. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Stack_overflow +\end{ocamldoccode} +\index{Stackoverflow@\verb`Stack_overflow`} +\begin{ocamldocdescription} + Exception raised by the bytecode interpreter when the evaluation + stack reaches its maximal size. This often indicates infinite + or excessively deep recursion in the user's program. + (Not fully implemented by the native-code compiler; + see section~\ref{s:compat-native-bytecode}.) +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Sys_error of string +\end{ocamldoccode} +\index{Syserror@\verb`Sys_error`} +\begin{ocamldocdescription} + Exception raised by the input/output functions to report an + operating system error. The string is meant to give some + information to the programmer; you must \emph{not} pattern match on + the string literal because it may change in future versions (use + \verb`Sys_error _` instead). +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception End_of_file +\end{ocamldoccode} +\index{Endoffile@\verb`End_of_file`} +\begin{ocamldocdescription} + Exception raised by input functions to signal that the + end of file has been reached. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Division_by_zero +\end{ocamldoccode} +\index{Divisionbyzero@\verb`Division_by_zero`} +\begin{ocamldocdescription} + Exception raised by integer division and remainder operations + when their second argument is zero. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Sys_blocked_io +\end{ocamldoccode} +\index{Sysblockedio@\verb`Sys_blocked_io`} +\begin{ocamldocdescription} + A special case of "Sys_error" raised when no I/O is possible + on a non-blocking I/O channel. +\end{ocamldocdescription} + +\begin{ocamldoccode} +exception Undefined_recursive_module of (string * int * int) +\end{ocamldoccode} +\index{Undefinedrecursivemodule@\verb`Undefined_recursive_module`} +\begin{ocamldocdescription} + Exception raised when an ill-founded recursive module definition + is evaluated. (See section~\ref{s-recursive-modules}.) + The arguments are the location of the definition in the source code + (file name, line number, column number). +\end{ocamldocdescription} + diff --git a/manual/manual/library/compilerlibs.etex b/manual/manual/library/compilerlibs.etex new file mode 100644 index 00000000..db924cc5 --- /dev/null +++ b/manual/manual/library/compilerlibs.etex @@ -0,0 +1,74 @@ +\chapter{The compiler front-end} \label{c:parsinglib}\cutname{parsing.html} +\pdfchapterfold{-1}{The compiler front-end} + +This chapter describes the OCaml front-end, which declares the abstract +syntax tree used by the compiler, provides a way to parse, print +and pretty-print OCaml code, and ultimately allows to write abstract +syntax tree preprocessors invoked via the {\tt -ppx} flag (see chapters~\ref{c:camlc} +and~\ref{c:nativecomp}) and plugins invoked via the {\tt -plugin} flag +(see chapter~\ref{c:plugins}). + +It is important to note that the exported front-end interface follows the evolution of the OCaml language and implementation, and thus does not provide {\bf any} backwards compatibility guarantees. + +The front-end is a part of "compiler-libs" library. +Programs that use the "compiler-libs" library should be built as follows: +\begin{alltt} + ocamlfind ocamlc \var{other options} -package compiler-libs.common \var{other files} + ocamlfind ocamlopt \var{other options} -package compiler-libs.common \var{other files} +\end{alltt} +Use of the {\tt ocamlfind} utility is recommended. However, if this is not possible, an alternative method may be used: +\begin{alltt} + ocamlc \var{other options} -I +compiler-libs ocamlcommon.cma \var{other files} + ocamlopt \var{other options} -I +compiler-libs ocamlcommon.cmxa \var{other files} +\end{alltt} +For interactive use of the "compiler-libs" library, start "ocaml" and +type\\*"#load \"compiler-libs/ocamlcommon.cma\";;". + +% Some of the files below are commented out as the documentation is too poor +% or they are thought to be nonessential. + +\ifouthtml +\begin{links} +\item \ahref{libref/Ast\_helper.html}{Module \texttt{Ast_helper}: helper functions for AST construction} +\item \ahref{libref/Ast\_mapper.html}{Module \texttt{Ast_mapper}: -ppx rewriter interface} +\item \ahref{libref/Asttypes.html}{Module \texttt{Asttypes}: auxiliary types used by Parsetree} +% \item \ahref{libref/Lexer.html}{Module \texttt{Lexer}: OCaml syntax lexing} +\item \ahref{libref/Location.html}{Module \texttt{Location}: source code locations} +\item \ahref{libref/Longident.html}{Module \texttt{Longident}: long identifiers} +\item \ahref{libref/Parse.html}{Module \texttt{Parse}: OCaml syntax parsing} +\item \ahref{libref/Parsetree.html}{Module \texttt{Parsetree}: OCaml syntax tree} +\item \ahref{libref/Pprintast.html}{Module \texttt{Pprintast}: OCaml syntax printing} +% \item \ahref{libref/Printast.html}{Module \texttt{Printast}: AST printing} +\end{links} + +\else +% Ast_helper is excluded from the PDF and text manuals. +% It is over 20 pages long and does not have doc-comments. It is expected +% that Ast_helper will be only useful in the HTML manual (to look up signatures). +% \input{Asthelper.tex} +\input{Astmapper.tex} +\input{Asttypes.tex} +% \input{Lexer.tex} +\input{Location.tex} +\input{Longident.tex} +\input{Parse.tex} +\input{Parsetree.tex} +\input{Pprintast.tex} +% \input{Printast.tex} +\fi + +\ifouthtml +The following modules provides hooks for compiler plugins: +\begin{links} +\item \ahref{libref/Pparse.html}{Module \texttt{Pparse}: OCaml parser driver} +\item \ahref{libref/Typemod.html}{Module \texttt{Typemod}: +OCaml module type checking} +\item \ahref{libref/Simplif.html}{Module \texttt{Simplif}: Lambda simplification} +\item \ahref{libref/Clflags.html}{Module \texttt{Clflags}: command line flags} +\end{links} +\else +\input{Pparse.tex} +\input{Typemod.tex} +\input{Simplif.tex} +\input{Clflags.tex} +\fi diff --git a/manual/manual/library/core.etex b/manual/manual/library/core.etex new file mode 100644 index 00000000..58297eab --- /dev/null +++ b/manual/manual/library/core.etex @@ -0,0 +1,36 @@ +\chapter{The core library} \label{c:corelib}\cutname{core.html} +\pdfchapterfold{-1}{The core library} + +This chapter describes the OCaml core library, which is + composed of declarations for built-in types and exceptions, plus +the module "Pervasives" that provides basic operations on these + built-in types. The "Pervasives" module is special in two +ways: +\begin{itemize} +\item It is automatically linked with the user's object code files by +the "ocamlc" command (chapter~\ref{c:camlc}). + +\item It is automatically ``opened'' when a compilation starts, or +when the toplevel system is launched. Hence, it is possible to use +unqualified identifiers to refer to the functions provided by the +"Pervasives" module, without adding a "open Pervasives" directive. +\end{itemize} + +\section*{Conventions} + +The declarations of the built-in types and the components of module +"Pervasives" are printed one by one in typewriter font, followed by a +short comment. All library modules and the components they provide are +indexed at the end of this report. + +\input{builtin.tex} + +\ifouthtml +\section{Module {\tt Pervasives}: the initially opened module} +\begin{links} +\item \ahref{libref/Pervasives.html}{Module \texttt{Pervasives}: the initially opened module} +\end{links} +\else +\input{Pervasives.tex} +\fi + diff --git a/manual/manual/library/libbigarray.etex b/manual/manual/library/libbigarray.etex new file mode 100644 index 00000000..a11d0589 --- /dev/null +++ b/manual/manual/library/libbigarray.etex @@ -0,0 +1,37 @@ +\chapter{The bigarray library} +\pdfchapterfold{-1}{The bigarray library} +%HEVEA\cutname{libbigarray.html} + +The "bigarray" library has now been integrated into OCaml's standard +library. + +The "bigarray" functionality may now be found in the standard library +\ifouthtml + \ahref{libref/Bigarray.html}{\texttt{Bigarray} module}, +\else + \texttt{Bigarray} module, +\fi +except for the "map_file" function which is now +part of the \hyperref[c:unix]{Unix library}. The documentation has +been integrated into the documentation for the standard library. + +The legacy "bigarray" library bundled with the compiler is a +compatibility library with exactly the same interface as before, +i.e. with "map_file" included. + +We strongly recommend that you port your code to use the standard +library version instead, as the changes required are minimal. + +If you choose to use the compatibility library, you must link your +programs as follows: +\begin{alltt} + ocamlc \var{other options} bigarray.cma \var{other files} + ocamlopt \var{other options} bigarray.cmxa \var{other files} +\end{alltt} +For interactive use of the "bigarray" compatibility library, do: +\begin{alltt} + ocamlmktop -o mytop bigarray.cma + ./mytop +\end{alltt} +or (if dynamic linking of C libraries is supported on your platform), +start "ocaml" and type "#load \"bigarray.cma\";;". diff --git a/manual/manual/library/libdynlink.etex b/manual/manual/library/libdynlink.etex new file mode 100644 index 00000000..2d4d92d9 --- /dev/null +++ b/manual/manual/library/libdynlink.etex @@ -0,0 +1,29 @@ +\chapter{The dynlink library: dynamic loading and linking of object files} +\pdfchapterfold{-1}{The dynlink library: dynamic loading and linking of object files} +%HEVEA\cutname{libdynlink.html} + +The "dynlink" library supports type-safe dynamic loading and linking +of bytecode object files (".cmo" and ".cma" files) in a running +bytecode program, or of native plugins (usually ".cmxs" files) in a +running native program. Type safety is ensured by limiting the set of +modules from the running program that the loaded object file can +access, and checking that the running program and the loaded object +file have been compiled against the same interfaces for these modules. +In native code, there are also some compatibility checks on the +implementations (to avoid errors with cross-module optimizations); it +might be useful to hide ".cmx" files when building native plugins so +that they remain independent of the implementation of modules in the +main program. + +Programs that use the "dynlink" library simply need to link +"dynlink.cma" or "dynlink.cmxa" with their object files and other libraries. + +\ifouthtml +\begin{links} +\item \ahref{libref/Dynlink.html}{Module \texttt{Dynlink}: dynamic loading of bytecode object files} +\end{links} + +\else +\input{Dynlink.tex} +\fi + diff --git a/manual/manual/library/libgraph.etex b/manual/manual/library/libgraph.etex new file mode 100644 index 00000000..28759f5b --- /dev/null +++ b/manual/manual/library/libgraph.etex @@ -0,0 +1,100 @@ +\chapter{The graphics library} +\pdfchapterfold{-1}{The graphics library} +%HEVEA\cutname{libgraph.html} + +The "graphics" library provides a set of portable drawing primitives. +Drawing takes place +in a separate window that is created when "Graphics.open_graph" is called. + +\begin{unix} +This library is implemented under the X11 windows system. +Programs that use the "graphics" library must be linked as follows: +\begin{alltt} + ocamlc \var{other options} graphics.cma \var{other files} +\end{alltt} +For interactive use of the "graphics" library, do: +\begin{alltt} + ocamlmktop -o mytop graphics.cma + ./mytop +\end{alltt} +or (if dynamic linking of C libraries is supported on your platform), +start "ocaml" and type "#load \"graphics.cma\";;". + +Here are the graphics mode specifications supported by +"Graphics.open_graph" on +the X11 implementation of this library: +the argument to "Graphics.open_graph" has the format +"\""{\it display-name} {\it geometry\/}"\"", +where {\it display-name} is the name of the X-windows display to +connect to, and {\it geometry} is a standard X-windows geometry +specification. The two components are separated by a space. Either can +be omitted, or both. Examples: +\begin{options} +\item["Graphics.open_graph \"foo:0\""] +connects to the display "foo:0" and creates a window with the default geometry +\item["Graphics.open_graph \"foo:0 300x100+50-0\""] +connects to the display "foo:0" and creates a window 300 pixels wide +by 100 pixels tall, at location $(50,0)$ +\item["Graphics.open_graph \" 300x100+50-0\""] +connects to the default display and creates a window 300 pixels wide +by 100 pixels tall, at location $(50,0)$ +\item["Graphics.open_graph \"\""] +connects to the default display and creates a window with the default +geometry. +\end{options} +\end{unix} + +\begin{windows} +This library is available both for standalone compiled programs and +under the toplevel application "ocamlwin.exe". For the latter, this +library must be loaded in-core by typing +\begin{verbatim} + #load "graphics.cma";; +\end{verbatim} +\end{windows} + +The screen coordinates are interpreted as shown in the figure below. +Notice that the coordinate system used is the same as in mathematics: +$y$ increases from the bottom of the screen to the top of the screen, +and angles are measured counterclockwise (in degrees). +Drawing is clipped to the screen. +% +\begin{latexonly} +\begin{center} +\setlength{\unitlength}{0.5mm} +\begin{picture}(130,100)(-10,-10) +\thicklines +\put(-10,0){\vector(1,0){130}} +\put(125,0){\makebox(0,0)[l]{$x$}} +\put(0,-10){\vector(0,1){100}} +\put(0,95){\makebox(0,0){$y$}} +\thinlines +\put(100,80){\line(-1,0){105}} +\put(100,80){\line(0,-1){85}} +\put(95,75){\makebox(0,0)[tr]{Screen}} +\put(100,-10){\makebox(0,0){\tt size\_x()}} +\put(-10,80){\makebox(0,0)[r]{\tt size\_y()}} +\put(30,40){\makebox(4,4){\rule{2mm}{2mm}}} +\put(36,40){pixel at $(x,y)$} +\put(30,40){\line(-1,0){35}} +\put(30,-10){\makebox(0,0){$x$}} +\put(30,40){\line(0,-1){45}} +\put(-10,40){\makebox(0,0)[r]{$y$}} +\end{picture} +\end{center} +\end{latexonly} + +\begin{htmlonly} +\begin{center} +\imgsrc{libgraph.gif} +\end{center} +\end{htmlonly} +% + +\ifouthtml +\begin{links} +\item \ahref{libref/Graphics.html}{Module \texttt{Graphics}: machine-independent graphics primitives} +\end{links} +\else +\input{Graphics.tex} +\fi diff --git a/manual/manual/library/libgraph.fig b/manual/manual/library/libgraph.fig new file mode 100644 index 00000000..55a6d1de --- /dev/null +++ b/manual/manual/library/libgraph.fig @@ -0,0 +1,29 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +2 1 0 1 0 7 0 0 -1 0.000 0 0 7 1 0 2 + 1 1 1.00 60.00 120.00 + 1050 3375 4575 3375 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1200 3525 1200 825 +2 1 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 3 + 1125 1200 3750 1200 3750 3450 +2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 0 0 3 + 1125 2400 2475 2400 2475 3450 +2 2 0 1 0 0 0 0 20 0.000 0 0 7 0 0 5 + 2475 2400 2550 2400 2550 2325 2475 2325 2475 2400 +4 0 0 0 0 0 12 0.0000 4 135 525 2325 1500 Screen\001 +4 0 0 0 0 0 12 0.0000 4 180 990 2175 2250 point at (x,y)\001 +4 0 0 0 0 0 12 0.0000 4 90 90 2400 3600 x\001 +4 0 0 0 0 0 12 0.0000 4 135 90 975 2475 y\001 +4 0 0 0 0 0 12 0.0000 4 180 450 1050 750 y axis\001 +4 0 0 0 0 14 12 0.0000 4 180 840 225 1200 size_y()\001 +4 0 0 0 0 14 12 0.0000 4 165 840 3375 3600 size_x()\001 +4 0 0 0 0 0 12 0.0000 4 135 450 4650 3375 x axis\001 diff --git a/manual/manual/library/libgraph.png b/manual/manual/library/libgraph.png new file mode 100644 index 0000000000000000000000000000000000000000..5841bfc805ca0a3a57a0881a218083157f947652 GIT binary patch literal 1046 zcmeAS@N?(olHy`uVBq!ia0y~yU{YjYU<_kq28y(b-B$ooEa{HEjtmSN`?>!lvI6;R z0X`wFK>Gjx|4VPqzYAnpl(EaktG3V_a`|R5eA`AtRQ&%`U zlzbLY^09LWHZoc2XIgUN+W857bG;S5_&eyy26=fO3tDtbeo?lfnVgM^OYy-3cIUh; zvHTNHJdJy*5*DHz@@=p8>MidZKhFL5x8hgv_7`7F0t8fhMS?sOTSbC4t@yyBX;diN zb>esT`&)cw)2ANzThPyr@kB#?ON_6IBil)j%ruRgiq>Ig;l*KC@!6^xOBSW(z&WfPxb|!ovo)xou`J5guG+N%?Wqv@T=dZ@Mg~10k)gI5blz1Rw zFysC61^J7oG;FLBK5$%f-@>(LpB^Z;Ib-_CH}~wNMr+a}vR%by07s?F#X)|jx*Xo*(3BbVlqKbO1KISJ|;FIl4zxMo(~ov!u2gVL}6`19{Y z2IuN4Z$F(mV-;q(C06f(SA45dQ|0%g+FL&TNv=$0Ui+f-@El!*sVNhjfX1K`MS|(O zH~1ayZw@Y7X#FQwd@)aZIs3zK*5x-I@VakXB06z(?Tn3C(QnN5o8MZdHqrZ@ZA8(x z=p6q&ZW^bLs=qF~oGiPeKcK7MY3Xyrw(xK5J984J{48F|cAMjAV|Br@n*0h5*Y#7m z(!PEytlN5ZQuv#T9@kbam@51ttnA_`O_N;rD8aNVQi|sFYlD~kNakPSsi?{|(f?ig zgcGT%6Hiyv3#F<%d&PE6y7N+Hu}b;66B>7UG*8ae7V6qCT)!X~czyc|>h&W36>dZCo-{=D_V0Iuo`miu_=z#rEEnVobgTSoOj!)08H;5JI$V|M~c3^)cYtr1(;{qOFVsD+0SvXa2WHfepMI<6k_mn L^>bP0l+XkKc{R}1 literal 0 HcmV?d00001 diff --git a/manual/manual/library/libnum.etex b/manual/manual/library/libnum.etex new file mode 100644 index 00000000..5e53a196 --- /dev/null +++ b/manual/manual/library/libnum.etex @@ -0,0 +1,14 @@ +\chapter{The num library: arbitrary-precision rational arithmetic} +\pdfchapterfold{-3}{The num library: arbitrary-precision integer and rational arithmetic} +%HEVEA\cutname{libnum.html} + +The "num" library implements integer arithmetic and rational +arithmetic in arbitrary precision. It was split off the core +OCaml distribution starting with the 4.06.0 release, and can now be found +at \url{https://github.com/ocaml/num}. + +New applications that need arbitrary-precision arithmetic should use the +"Zarith" library (\url{https://github.com/ocaml/Zarith}) instead of the "Num" +library, and older applications that already use "Num" are encouraged to +switch to "Zarith". "Zarith" delivers much better performance than "Num" +and has a nicer API. diff --git a/manual/manual/library/libstr.etex b/manual/manual/library/libstr.etex new file mode 100644 index 00000000..a1939f8a --- /dev/null +++ b/manual/manual/library/libstr.etex @@ -0,0 +1,32 @@ +\chapter{The str library: regular expressions and string processing} +\pdfchapterfold{-1}{The str library: regular expressions and string processing} +%HEVEA\cutname{libstr.html} + +The "str" library provides high-level string processing functions, +some based on regular expressions. It is intended to support the kind +of file processing that is usually performed with scripting languages +such as "awk", "perl" or "sed". + +Programs that use the "str" library must be linked as follows: +\begin{alltt} + ocamlc \var{other options} str.cma \var{other files} + ocamlopt \var{other options} str.cmxa \var{other files} +\end{alltt} +For interactive use of the "str" library, do: +\begin{alltt} + ocamlmktop -o mytop str.cma + ./mytop +\end{alltt} +or (if dynamic linking of C libraries is supported on your platform), +start "ocaml" and type "#load \"str.cma\";;". + +\ifouthtml +\begin{links} +\item \ahref{libref/Str.html}{Module \texttt{Str}: regular expressions and string processing} +\end{links} + +\else +\input{Str.tex} +\fi + + diff --git a/manual/manual/library/libthreads.etex b/manual/manual/library/libthreads.etex new file mode 100644 index 00000000..795373c8 --- /dev/null +++ b/manual/manual/library/libthreads.etex @@ -0,0 +1,60 @@ +\chapter{The threads library} +\label{c:threads}\cutname{threads.html} +\pdfchapterfold{-5}{The threads library} +%HEVEA\cutname{libthreads.html} + +The "threads" library allows concurrent programming in OCaml. +It provides multiple threads of control (also called lightweight +processes) that execute concurrently in the same memory space. Threads +communicate by in-place modification of shared data structures, or by +sending and receiving data on communication channels. + +The "threads" library is implemented by time-sharing on a single +processor. It will not take advantage of multi-processor machines. +Using this library will therefore never make programs run +faster. However, many programs are easier to write when structured as +several communicating processes. + +Two implementations of the "threads" library are available, depending +on the capabilities of the operating system: +\begin{itemize} +\item System threads. This implementation builds on the OS-provided threads +facilities: POSIX 1003.1c threads for Unix, and Win32 threads for +Windows. When available, system threads support both bytecode and +native-code programs. +\item VM-level threads. This implementation performs time-sharing and +context switching at the level of the OCaml virtual machine (bytecode +interpreter). It is available on Unix systems, and supports only +bytecode programs. It cannot be used with native-code programs. +\end{itemize} +Programs that use system threads must be linked as follows: +\begin{alltt} + ocamlc -I +threads \var{other options} unix.cma threads.cma \var{other files} + ocamlopt -I +threads \var{other options} unix.cmxa threads.cmxa \var{other files} +\end{alltt} +Compilation units that use the "threads" library must also be compiled with +the "-I +threads" option (see chapter~\ref{c:camlc}). + +Programs that use VM-level threads must be compiled with the "-vmthread" +option to "ocamlc" (see chapter~\ref{c:camlc}), and be linked as follows: +\begin{alltt} + ocamlc -vmthread \var{other options} threads.cma \var{other files} +\end{alltt} +Compilation units that use "threads" library must also be compiled with +the "-vmthread" option (see chapter~\ref{c:camlc}). + +\ifouthtml +\begin{links} +\item \ahref{libref/Thread.html}{Module \texttt{Thread}: lightweight threads} +\item \ahref{libref/Mutex.html}{Module \texttt{Mutex}: locks for mutual exclusion} +\item \ahref{libref/Condition.html}{Module \texttt{Condition}: condition variables to synchronize between threads} +\item \ahref{libref/Event.html}{Module \texttt{Event}: first-class synchronous communication} +\item \ahref{libref/ThreadUnix.html}{Module \texttt{ThreadUnix}: thread-compatible system calls} +\end{links} +\else +\input{Thread.tex} +\input{Mutex.tex} +\input{Condition.tex} +\input{Event.tex} +\input{ThreadUnix.tex} +\fi diff --git a/manual/manual/library/libunix.etex b/manual/manual/library/libunix.etex new file mode 100644 index 00000000..6514a9f1 --- /dev/null +++ b/manual/manual/library/libunix.etex @@ -0,0 +1,98 @@ +\chapter{The unix library: Unix system calls} +\pdfchapterfold{-1}{The unix library: Unix system calls} +%HEVEA\cutname{libunix.html} +\label{c:unix} + +The "unix" library makes many Unix +system calls and system-related library functions available to +OCaml programs. This chapter describes briefly the functions +provided. Refer to sections 2~and~3 of the Unix manual for more +details on the behavior of these functions. + +\ifouthtml +\begin{links} +\item \ahref{libref/Unix.html}{Module \texttt{Unix}: Unix system calls} +\item \ahref{libref/UnixLabels.html}{Module \texttt{UnixLabels}: Labeled + Unix system calls} +\end{links} +\fi + +Not all functions are provided by all Unix variants. If some functions +are not available, they will raise "Invalid_arg" when called. + +Programs that use the "unix" library must be linked as follows: +\begin{alltt} + ocamlc \var{other options} unix.cma \var{other files} + ocamlopt \var{other options} unix.cmxa \var{other files} +\end{alltt} +For interactive use of the "unix" library, do: +\begin{alltt} + ocamlmktop -o mytop unix.cma + ./mytop +\end{alltt} +or (if dynamic linking of C libraries is supported on your platform), +start "ocaml" and type "#load \"unix.cma\";;". + +\begin{windows} +A fairly complete emulation of the Unix system calls is provided in +the Windows version of OCaml. The end of this chapter gives +more information on the functions that are not supported under Windows. +\end{windows} + +\begin{latexonly} +\input{Unix.tex} + +\section{Module \texttt{UnixLabels}: labelized version of the interface} +\label{UnixLabels} +\index{UnixLabels (module)@\verb~UnixLabels~ (module)}% +\pdfsection{Module UnixLabels: labelized version of the interface} + +This module is identical to "Unix"~(\ref{Unix}), and only differs by +the addition of labels. You may see these labels directly by looking +at "unixLabels.mli", or by using the "ocamlbrowser" tool. + +\newpage +\end{latexonly} + +\begin{windows} +The Cygwin port of OCaml fully implements all functions from +the Unix module. The native Win32 ports implement a subset of them. +Below is a list of the functions that are not implemented, or only +partially implemented, by the Win32 ports. Functions not mentioned are +fully implemented and behave as described previously in this chapter. + +\begin{tableau}{|l|p{8cm}|}{Functions}{Comment} +\entree{"fork"}{not implemented, use "create_process" or threads} +\entree{"wait"}{not implemented, use "waitpid"} +\entree{"waitpid"}{can only wait for a given PID, not any child process} +\entree{"getppid"}{not implemented (meaningless under Windows)} +\entree{"nice"}{not implemented} +\entree{"truncate", "ftruncate"}{not implemented} +\entree{"link"}{implemented (since 3.02)} +\entree{"symlink", "readlink"}{implemented (since 4.03.0)} +\entree{"access"}{execute permission "X_OK" cannot be tested, + it just tests for read permission instead} +\entree{"fchmod"}{not implemented} +\entree{"chown", "fchown"}{not implemented (make no sense on a DOS +file system)} +\entree{"umask"}{not implemented} +\entree{"mkfifo"}{not implemented} +\entree{"kill"}{partially implemented (since 4.00.0): only the "sigkill" signal +is implemented} +\entree{"pause"}{not implemented (no inter-process signals in Windows)} +\entree{"alarm"}{not implemented} +\entree{"times"}{partially implemented, will not report timings for child +processes} +\entree{"getitimer", "setitimer"}{not implemented} +\entree{"getuid", "geteuid", "getgid", "getegid"}{always return 1} +\entree{"getgroups"}{always returns "[|1|]" (since 2.00)} +\entree{"setuid", "setgid", "setgroups"}{not implemented} +\entree{"getpwnam", "getpwuid"}{always raise "Not_found"} +\entree{"getgrnam", "getgrgid"}{always raise "Not_found"} +\entree{type "socket_domain"}{"PF_INET" is fully supported; +"PF_INET6" is fully supported (since 4.01.0); "PF_UNIX" is not supported } +\entree{"establish_server"}{not implemented; use threads} +\entree{terminal functions ("tc*")}{not implemented} +\end{tableau} + +\end{windows} diff --git a/manual/manual/library/stdlib.etex b/manual/manual/library/stdlib.etex new file mode 100644 index 00000000..fb0e5578 --- /dev/null +++ b/manual/manual/library/stdlib.etex @@ -0,0 +1,200 @@ +\chapter{The standard library} \label{c:stdlib}\cutname{stdlib.html} +\pdfchapterfold{-32}{The standard library} + +This chapter describes the functions provided by the OCaml +standard library. The modules from the standard library are +automatically linked with the user's object code files by the "ocamlc" +command. Hence, these modules can be used in standalone programs without +having to add any ".cmo" file on the command line for the linking +phase. Similarly, in interactive use, these globals can be used in +toplevel phrases without having to load any ".cmo" file in memory. + +Unlike the "Pervasives" module from the core library, the modules from the +standard library are not automatically ``opened'' when a compilation +starts, or when the toplevel system is launched. Hence it is necessary +to use qualified identifiers to refer to the functions provided by these +modules, or to add "open" directives. + +\label{stdlib:top} + +\section*{Conventions} + +For easy reference, the modules are listed below in alphabetical order +of module names. +For each module, the declarations from its signature are printed +one by one in typewriter font, followed by a short comment. +All modules and the identifiers they export are indexed at the end of +this report. + +\begin{latexonly} +\section*{Overview} + +Here is a short listing, by theme, of the standard library modules. + +\subsubsection*{Data structures:} +\begin{tabular}{lll} +% Beware: these entries must be written in a very rigidly-defined +% format, or the check-stdlib-modules script will complain. +"String" & p.~\pageref{String} & string operations \\ +"Bytes" & p.~\pageref{Bytes} & operations on byte sequences\\ +"Array" & p.~\pageref{Array} & array operations \\ +"List" & p.~\pageref{List} & list operations \\ +"StdLabels" & p.~\pageref{StdLabels} & labelized versions of +the above 4 modules \\ +"Char" & p.~\pageref{Char} & character operations \\ +"Uchar" & p.~\pageref{Uchar} & Unicode characters \\ +"Sort" & p.~\pageref{Sort} & (deprecated) \\ +"Hashtbl" & p.~\pageref{Hashtbl} & hash tables and hash functions \\ +"Random" & p.~\pageref{Random} & pseudo-random number generator \\ +"Set" & p.~\pageref{Set} & sets over ordered types \\ +"Map" & p.~\pageref{Map} & association tables over ordered types \\ +"MoreLabels" & p.~\pageref{MoreLabels} & labelized versions of +"Hashtbl", "Set", and "Map" \\ +"Oo" & p.~\pageref{Oo} & useful functions on objects \\ +"Stack" & p.~\pageref{Stack} & last-in first-out stacks \\ +"Queue" & p.~\pageref{Queue} & first-in first-out queues \\ +"Buffer" & p.~\pageref{Buffer} & buffers that grow on demand \\ +"Seq" & p.~\pageref{Seq} & functional iterators \\ +"Lazy" & p.~\pageref{Lazy} & delayed evaluation \\ +"Weak" & p.~\pageref{Weak} & references that don't prevent objects +from being garbage-collected \\ +"Ephemeron" & p.~\pageref{Ephemeron} & ephemerons and weak hash tables \\ +"Bigarray" & p.~\pageref{Bigarray} & large, multi-dimensional, numerical arrays +\end{tabular} +\subsubsection*{Arithmetic:} +\begin{tabular}{lll} +"Complex" & p.~\pageref{Complex} & Complex numbers \\ +"Float" & p.~\pageref{Float} & Floating-point numbers \\ +"Int32" & p.~\pageref{Int32} & operations on 32-bit integers \\ +"Int64" & p.~\pageref{Int64} & operations on 64-bit integers \\ +"Nativeint" & p.~\pageref{Nativeint} & operations on platform-native +integers +\end{tabular} +\subsubsection{Input/output:} +\begin{tabular}{lll} +"Format" & p.~\pageref{Format} & pretty printing with automatic +indentation and line breaking \\ +"Marshal" & p.~\pageref{Marshal} & marshaling of data structures \\ +"Printf" & p.~\pageref{Printf} & formatting printing functions \\ +"Scanf" & p.~\pageref{Scanf} & formatted input functions \\ +"Digest" & p.~\pageref{Digest} & MD5 message digest \\ +\end{tabular} +\subsubsection{Parsing:} +\begin{tabular}{lll} +"Genlex" & p.~\pageref{Genlex} & a generic lexer over streams \\ +"Lexing" & p.~\pageref{Lexing} & the run-time library for lexers generated by "ocamllex" \\ +"Parsing" & p.~\pageref{Parsing} & the run-time library for parsers generated by "ocamlyacc" \\ +"Stream" & p.~\pageref{Stream} & basic functions over streams \\ +\end{tabular} +\subsubsection{System interface:} +\begin{tabular}{lll} +"Arg" & p.~\pageref{Arg} & parsing of command line arguments \\ +"Callback" & p.~\pageref{Callback} & registering OCaml functions to +be called from C \\ +"Filename" & p.~\pageref{Filename} & operations on file names \\ +"Gc" & p.~\pageref{Gc} & memory management control and statistics \\ +"Printexc" & p.~\pageref{Printexc} & a catch-all exception handler \\ +"Spacetime" & p.~\pageref{Spacetime} & memory profiler \\ +"Sys" & p.~\pageref{Sys} & system interface \\ +\end{tabular} +\end{latexonly} + +\ifouthtml +\begin{links} +\item \ahref{libref/Arg.html}{Module \texttt{Arg}: parsing of command line arguments} +\item \ahref{libref/Array.html}{Module \texttt{Array}: array operations} +\item \ahref{libref/ArrayLabels.html}{Module \texttt{ArrayLabels}: array operations (with labels)} +\item \ahref{libref/Bigarray.html}{Module \texttt{Bigarray}: large, multi-dimensional, numerical arrays} +\item \ahref{libref/Buffer.html}{Module \texttt{Buffer}: extensible buffers} +\item \ahref{libref/Bytes.html}{Module \texttt{Bytes}: byte sequences} +\item \ahref{libref/BytesLabels.html}{Module \texttt{BytesLabels}: byte sequences (with labels)} +\item \ahref{libref/Callback.html}{Module \texttt{Callback}: registering OCaml values with the C runtime} +\item \ahref{libref/Char.html}{Module \texttt{Char}: character operations} +\item \ahref{libref/Complex.html}{Module \texttt{Complex}: Complex numbers} +\item \ahref{libref/Digest.html}{Module \texttt{Digest}: MD5 message digest} +\item \ahref{libref/Ephemeron.html}{Module \texttt{Ephemeron}: Ephemerons and weak hash table} +\item \ahref{libref/Filename.html}{Module \texttt{Filename}: operations on file names} +\item \ahref{libref/Float.html}{Module \texttt{Float}: Floating-point numbers} +\item \ahref{libref/Format.html}{Module \texttt{Format}: pretty printing} +\item \ahref{libref/Gc.html}{Module \texttt{Gc}: memory management control and statistics; finalized values} +\item \ahref{libref/Genlex.html}{Module \texttt{Genlex}: a generic lexical analyzer} +\item \ahref{libref/Hashtbl.html}{Module \texttt{Hashtbl}: hash tables and hash functions} +\item \ahref{libref/Int32.html}{Module \texttt{Int32}: 32-bit integers} +\item \ahref{libref/Int64.html}{Module \texttt{Int64}: 64-bit integers} +\item \ahref{libref/Lazy.html}{Module \texttt{Lazy}: deferred computations} +\item \ahref{libref/Lexing.html}{Module \texttt{Lexing}: the run-time library for lexers generated by \texttt{ocamllex}} +\item \ahref{libref/List.html}{Module \texttt{List}: list operations} +\item \ahref{libref/ListLabels.html}{Module \texttt{ListLabels}: list operations (with labels)} +\item \ahref{libref/Map.html}{Module \texttt{Map}: association tables over ordered types} +\item \ahref{libref/Marshal.html}{Module \texttt{Marshal}: marshaling of data structures} +\item \ahref{libref/MoreLabels.html}{Module \texttt{MoreLabels}: Include modules \texttt{Hashtbl}, \texttt{Map} and \texttt{Set} with labels} +\item \ahref{libref/Nativeint.html}{Module \texttt{Nativeint}: processor-native integers} +\item \ahref{libref/Oo.html}{Module \texttt{Oo}: object-oriented extension} +\item \ahref{libref/Parsing.html}{Module \texttt{Parsing}: the run-time library for parsers generated by \texttt{ocamlyacc}} +\item \ahref{libref/Printexc.html}{Module \texttt{Printexc}: facilities for printing exceptions} +\item \ahref{libref/Printf.html}{Module \texttt{Printf}: formatting printing functions} +\item \ahref{libref/Queue.html}{Module \texttt{Queue}: first-in first-out queues} +\item \ahref{libref/Random.html}{Module \texttt{Random}: pseudo-random number generator (PRNG)} +\item \ahref{libref/Scanf.html}{Module \texttt{Scanf}: formatted input functions} +\item \ahref{libref/Seq.html}{Module \texttt{Seq}: functional iterators} +\item \ahref{libref/Set.html}{Module \texttt{Set}: sets over ordered types} +\item \ahref{libref/Sort.html}{Module \texttt{Sort}: deprecated} +\item \ahref{libref/Spacetime.html}{Module \texttt{Spacetime}: memory profiler} +\item \ahref{libref/Stack.html}{Module \texttt{Stack}: last-in first-out stacks} +\item \ahref{libref/StdLabels.html}{Module \texttt{StdLabels}: Include modules \texttt{Array}, \texttt{List} and \texttt{String} with labels} +\item \ahref{libref/Stream.html}{Module \texttt{Stream}: streams and parsers} +\item \ahref{libref/String.html}{Module \texttt{String}: string operations} +\item \ahref{libref/StringLabels.html}{Module \texttt{StringLabels}: string operations (with labels)} +\item \ahref{libref/Sys.html}{Module \texttt{Sys}: system interface} +\item \ahref{libref/Uchar.html}{Module \texttt{Uchar}: Unicode characters} +\item \ahref{libref/Weak.html}{Module \texttt{Weak}: arrays of weak pointers} +\end{links} +\else +\input{Arg.tex} +\input{Array.tex} +\input{ArrayLabels.tex} +\input{Bigarray.tex} +\input{Buffer.tex} +\input{Bytes.tex} +\input{BytesLabels.tex} +\input{Callback.tex} +\input{Char.tex} +\input{Complex.tex} +\input{Digest.tex} +\input{Ephemeron.tex} +\input{Filename.tex} +\input{Float.tex} +\input{Format.tex} +\input{Gc.tex} +\input{Genlex.tex} +\input{Hashtbl.tex} +\input{Int32.tex} +\input{Int64.tex} +\input{Lazy.tex} +\input{Lexing.tex} +\input{List.tex} +\input{ListLabels.tex} +\input{Map.tex} +\input{Marshal.tex} +\input{MoreLabels.tex} +\input{Nativeint.tex} +\input{Oo.tex} +\input{Parsing.tex} +\input{Printexc.tex} +\input{Printf.tex} +\input{Queue.tex} +\input{Random.tex} +\input{Scanf.tex} +\input{Seq.tex} +\input{Set.tex} +\input{Sort.tex} +\input{Spacetime.tex} +\input{Stack.tex} +\input{StdLabels.tex} +\input{Stream.tex} +\input{String.tex} +\input{StringLabels.tex} +\input{Sys.tex} +\input{Uchar.tex} +\input{Weak.tex} +\fi diff --git a/manual/manual/macros.hva b/manual/manual/macros.hva new file mode 100644 index 00000000..343eb7d6 --- /dev/null +++ b/manual/manual/macros.hva @@ -0,0 +1,200 @@ +% Colors for links +\def\visited@color{\#0d46a3} +\def\link@color{\#4286f4} +\def\hover@color{\@getstylecolor{subsection}} +\newstyle{a:link}{color:\link@color;text-decoration:underline;} +\newstyle{a:visited}{color:\visited@color;text-decoration:underline;} +\newstyle{a:hover}{color:black;text-decoration:underline;background-color:\hover@color} + + +\newstyle{@media all}{@font-face \{ +/* fira-sans-regular - latin */ + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Fira Sans Regular'), local('FiraSans-Regular'), + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.eot?\#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.svg\#FiraSans') format('svg'); /* Legacy iOS */ +\}} + +% Compact layout +\newstyle{body}{ + max-width:750px; + width: 85\%; + margin: auto; + background: \#f7f7f7; + margin-top: 80px; + font-size: 1rem; +} + +% selects the index's title +\newstyle{.maintitle}{ + font-family: "Fira Sans", sans-serif; + text-align: center; +} + +\newstyle{h1, h2, h3}{ + font-family: "Fira Sans", sans-serif; + font-weight: normal; + border-bottom: 1px solid black; +} + +\newstyle{pre}{ + font-size: 1rem; + background: beige; + border: 1px solid grey; + padding: 10px; + overflow-y:auto; + white-space: pre-wrap; +} + +% More spacing between lines and inside tables +\newstyle{p,ul}{line-height:1.3em} +\newstyle{.cellpadding1 tr td}{padding:1px 4px} + +%Styles for caml-example and friends +\newstyle{div.caml-output}{color:maroon;} +\newstyle{div.caml-example pre}{margin:2ex 0px;} +% Styles for toplevel mode only +\newstyle{div.caml-example.toplevel div.caml-input::before} + {content:"\#"; color:black;} +\newstyle{div.caml-example.toplevel div.caml-input}{color:\#006000;} +%%% +\newcommand{\input@color}{\htmlcolor{006000}} +\newcommand{\output@color}{\maroon} +\newcommand{\machine}{\tt} +\newenvironment{machineenv}{\begin{alltt}}{\end{alltt}} +\newcommand{\firstline}{\ } +\newcommand{\examplespace}{\ } +\newcommand{\nextline}{\examplespace\ } +\newcommand{\@zyva}{\firstline\renewcommand{\?}{\nextline}} +\let\?=\@zyva +\newenvironment{camlunder}{\@style{U}}{} +\newcommand{\caml}{\begin{alltt}\renewcommand{\;}{}\renewcommand{\\}{\char92}\def\<{\begin{camlunder}}\def\>{\end{camlunder}}\activebracefalse} +\newcommand{\endcaml}{\activebracetrue\end{alltt} +} +\renewcommand{\:}{\renewcommand{\?}{\@zyva}} +\newcommand{\var}[1]{\textit{#1}} + +% Caml-example environment +\newcommand{\camlexample}[1]{ + \ifthenelse{\equal{#1}{toplevel}} + {\renewcommand{\examplespace}{\ }} + {\renewcommand{\examplespace}{}} + \fi + \@open{div}{class="caml-example #1"} +} +\newcommand{\endcamlexample}{ + \@close{div} + \renewcommand{\examplespace}{\ } +} + +\newcommand{\camlinput}{\@open{div}{class="caml-input"}} +\newcommand{\endcamlinput}{\@close{div}} +\newcommand{\camloutput}{\@open{div}{class="caml-output ok"}} +\newcommand{\endcamloutput}{\@close{div}} +\newcommand{\camlerror}{\@open{div}{class="caml-output error"}} +\newcommand{\endcamlerror}{\@close{div}} +\newcommand{\camlwarn}{\@open{div}{class="caml-output warn"}} +\newcommand{\endcamlwarn}{\@close{div}} + +\newenvironment{library}{}{} +\newcounter{page} +\newenvironment{comment}{\begin{quote}}{\end{quote}} +\newcommand{\nth}[2]{\({#1}_{#2}\)} +\newenvironment{options}{\begin{description}}{\end{description}} + + +%%venant de macros.tex + +\def\versionspecific#1{\begin{quote}\textsf{#1:}\quad} +\def\unix{\versionspecific{Unix}} +\def\endunix{\end{quote}} +\def\macos{\versionspecific{MacOS~9}} +\def\endmacos{\end{quote}} +\def\windows{\versionspecific{Windows}} +\def\endwindows{\end{quote}} + +\def\requirements{\trivlist \item[\hskip\labelsep {\bf Requirements.}]} +\def\endrequirements{\endtrivlist} +\def\installation{\trivlist \item[\hskip\labelsep {\bf Installation.}]} +\def\endinstallation{\endtrivlist} +\def\troubleshooting{\trivlist \item[\hskip\labelsep {\bf Troubleshooting.}]} +\def\endtroubleshooting{\endtrivlist} + +\newtheorem{gcrule}{Rule} + +% Pour les tables de priorites et autres tableaux a deux colonnes, encadres + +\def\entree#1#2{#1 & #2 \\} +\def\tableau#1#2#3{% +\par +\@open{div}{class="tableau"} +\begin{center}% +\begin{tabular*}{.8\linewidth}{#1}% +\multicolumn{1}{c}{\textbf{#2}} & +\multicolumn{1}{c}{\textbf{#3}} \\ +%%#2 & #3 \\% +}% +\def\endtableau{\end{tabular*}\end{center}\@close{div}\par} + +\newstyle{.tableau, .syntax, .syntaxleft}{ + /* same width as body */ + max-width: 750px; + overflow-y: auto; +} + +% L'environnement library (pour composer les descriptions des modules +% de bibliotheque). + + +\def\restoreindent{\begingroup\let\@listI=\@savedlistI} +\def\endrestoreindent{\endgroup} + + +% PDF stuff + +\def\pdfchapterfold#1#2{} +\def\pdfsection#1{} +\def\pdfchapter{\pdfchapterfold{0}} + +%%% Pour camlidl + +\def\transl#1{$[\![\mbox{#1}]\!]$} + +% Pour l'index +\usepackage{multind} +\let\indexentry=\index +\renewcommand{\index}[1]{\indexentry{\jobname}{#1}} +\def\ikwd#1{\indexentry{\jobname.kwd}{#1}} +% nth + +\def\th{^{\mbox{\scriptsize th}}} +\renewcommand{\hbox}[1]{\mbox{#1}} + +% Notations pour les metavariables +\def\nmth#1#2#3{\({#1}_{#2}^{#3}\)} +\def\optvar#1{[\var{#1}\/]} +\def\event{§§} +\def\fromoneto#1#2{$#1 = 1,\ldots{} , #2$} + +\newcommand{\vfill}{} +\def\number{} +\def\year{2013} + +% Pour alltt +\def\rminalltt#1{{\rm #1}} +\def\goodbreak{\ \\} +\def\@savedlistI{} + +%List of links with no space around items +\newstyle{.li-links}{margin:0ex 0ex;} +\newenvironment{links} +{\setenvclass{itemize}{ftoc2}\setenvclass{li-itemize}{li-links}\itemize} +{\enditemize} + +\newenvironment{maintitle}{\@open{div}{class="maintitle"}}{\@close{div}} diff --git a/manual/manual/macros.tex b/manual/manual/macros.tex new file mode 100644 index 00000000..454bff2a --- /dev/null +++ b/manual/manual/macros.tex @@ -0,0 +1,252 @@ +\makeatletter +% Pour hevea +\newif\ifouthtml\outhtmlfalse +\newcommand{\cutname}[1]{} +% Notations pour les metavariables +\def\var#1{{\it#1}} +\def\nth#1#2{${\it#1}_{#2}$} +\def\nmth#1#2#3{${\it#1}_{#2}^{#3}$} +\def\optvar#1{\textrm{[}\var{#1}\/\textrm{]}} +\def\event{$\bowtie$} +\def\fromoneto#1#2{$#1 = 1, \ldots, #2$} + +% Pour avoir les exposants sur la ligne au-dessus (???) + +\ifplaintext +\fontdimen14\tensy=12pt +\fi + +% Numerotation +\setcounter{secnumdepth}{2} % Pour numeroter les \subsection +\setcounter{tocdepth}{1} % Pour ne pas mettre les \subsection + % dans la table des matieres + +% Pour avoir "_" qui marche en mode math et en mode normal +\catcode`\_=13 +\catcode`\=8 +\def\_{\hbox{\tt\char95}} +\def_{\ifmmode\else\_\fi} + +\ifplaintext +\def\ttstretch{\tt} +\else +\def\ttstretch{\tt\spaceskip=5.77pt plus 1.83pt minus 1.22pt} +% La fonte cmr10 a normalement des espaces de 5.25pt non extensibles. +% En 11 pt ca fait 5.77 pt. On lui ajoute la meme flexibilite que +% cmr10 agrandie a 11 pt. +\fi + +% Pour la traduction "xxxx" -> {\machine{xxxx}} faite par texquote2 +\def\machine#1{\mbox{\ttstretch{#1}}} + +% Pour la traduction "\begin{verbatim}...\end{verbatim}" +% -> "\begin{machineenv}...\end{machineenv}" +% faite aussi par texquote2. +\newenvironment{machineenv}{\alltt}{\endalltt} + +% Environnements + +\newlength{\versionwidth} +\setbox0=\hbox{\bf Windows:} \setlength{\versionwidth}{\wd0} + +\def\versionspecific#1{ + \begin{description}\item[#1:]~\\} + +\def\unix{\versionspecific{Unix}} +\def\endunix{\end{description}} +%\def\macos{\versionspecific{MacOS 9}} +%\def\endmacos{\end{description}} +\def\windows{\versionspecific{Windows}} +\def\endwindows{\end{description}} + +\def\requirements{\trivlist \item[\hskip\labelsep {\bf Requirements.}]} +\def\endrequirements{\endtrivlist} +\def\installation{\trivlist \item[\hskip\labelsep {\bf Installation.}]} +\def\endinstallation{\endtrivlist} +\def\troubleshooting{\trivlist \item[\hskip\labelsep {\bf Troubleshooting.}]} +\def\endtroubleshooting{\endtrivlist} + +\newtheorem{gcrule}{Rule} + +% Pour les tables de priorites et autres tableaux a deux colonnes, encadres + +\def\tableau#1#2#3{% +\begin{center} +\begin{tabular}{#1} +\hline +#2 & #3 \\ +\hline +} +\def\endtableau{\hline\end{tabular}\end{center}} +\def\entree#1#2{#1 & #2 \\} + +% L'environnement option + +\def\optionitem[#1]{\if@noparitem \@donoparitem + \else \if@inlabel \indent \par \fi + \ifhmode \unskip\unskip \par \fi + \if@newlist \if@nobreak \@nbitem \else + \addpenalty\@beginparpenalty + \addvspace\@topsep \addvspace{-\parskip}\fi + \else \addpenalty\@itempenalty \addvspace\itemsep + \fi + \global\@inlabeltrue +\fi +\everypar{\global\@minipagefalse\global\@newlistfalse + \if@inlabel\global\@inlabelfalse \hskip -\parindent \box\@labels + \penalty\z@ \fi + \everypar{}}\global\@nobreakfalse +\if@noitemarg \@noitemargfalse \if@nmbrlist \refstepcounter{\@listctr}\fi \fi +\setbox\@tempboxa\hbox{\makelabel{#1}}% +\global\setbox\@labels +\ifdim \wd\@tempboxa >\labelwidth + \hbox{\unhbox\@labels + \hskip -\leftmargin + \box\@tempboxa}\hfil\break + \else + \hbox{\unhbox\@labels + \hskip -\leftmargin + \hbox to\leftmargin {\makelabel{#1}\hfil}} + \fi + \ignorespaces} + +\def\optionlabel#1{\bf #1} +\def\options{\list{}{\let\makelabel\optionlabel\let\@item\optionitem}} +\def\endoptions{\endlist} + +% L'environnement library (pour composer les descriptions des modules +% de bibliotheque). + +\def\comment{\penalty200\list{}{}\item[]} +\def\endcomment{\endlist\penalty-100} + +\def\library{ +\begingroup +\raggedright +\let\@savedlistI=\@listI% +\def\@listI{\leftmargin\leftmargini\parsep 0pt plus 1pt\topsep 0pt plus 2pt}% +\itemsep 0pt +\topsep 0pt plus 2pt +\partopsep 0pt +} + +\def\endlibrary{ +\endgroup +} + +\def\restoreindent{\begingroup\let\@listI=\@savedlistI} +\def\endrestoreindent{\endgroup} + +% ^^A...^^A: compose l'interieur en \tt, comme \verb + +\catcode`\^^A=\active +\def{% +\begingroup\catcode``=13\@noligs\ttstretch\let\do\@makeother\dospecials% +\def\@xobeysp{\leavevmode\penalty100\ }% +\@vobeyspaces\frenchspacing\catcode`\^^A=\active\def{\endgroup}} + +% Pour l'index + +\let\indexentry=\index +\def\index{\indexentry{\jobname}} +\def\ikwd{\indexentry{\jobname.kwd}} + +% Les en-tetes personnalises + +\pagestyle{myheadings} +\def\partmark#1{\markboth{Part \thepart. \ #1}{}} +\def\chaptermark#1{\markright{Chapter \thechapter. \ #1}} + +% nth + +\def\th{^{\hbox{\scriptsize th}}} + +% Pour annuler l'espacement vertical qui suit un "verbatim" +\def\cancelverbatim{\vspace{-\topsep}\vspace{-\parskip}}% exact. + +% Pour annuler l'espacement vertical entre deux \item consecutifs dans \options +\def\cancelitemspace{\vspace{-8mm}}% determine empiriquement + +% Pour faire la cesure apres _ dans les identificateurs +\def\={\discretionary{}{}{}} +\def\cuthere{\discretionary{}{}{}} + +% Pour la coupure en petits documents + +\let\mysection=\section + +%%% Augmenter l'espace entre numero de section +% et nom de section dans la table des matieres. + +\ifplaintext\else +\def\l@section{\@dottedtocline{1}{1.5em}{2.8em}} % D'origine: 2.3 +\fi + +% Pour alltt + +\def\rminalltt#1{{\rm #1}} + +% redefinition de l'environnement alltt pour que les {} \ et % soient +% dans la bonne fonte + +\let\@oldalltt=\alltt +\let\@oldendalltt=\endalltt +\renewenvironment{alltt}{% +\begingroup% +\renewcommand{\{}{\char`\{}% +\renewcommand{\}}{\char`\}}% +\renewcommand{\\}{\char`\\}% +\renewcommand{\%}{\char`\%}% +\@oldalltt% +}{% +\@oldendalltt% +\endgroup% +} + +% Index stuff -- cf multind.sty + +\def\printindex#1#2{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi + \columnseprule \z@ \columnsep 35pt + \newpage \phantomsection \twocolumn[{\Large\bf #2 \vskip4ex}] + \markright{\uppercase{#2}} + \addcontentsline{toc}{chapter}{#2} + \pdfsection{#2} + \@input{#1.ind}} + +% PDF stuff -- no longer needed, Hyperref does the job + +\def\pdfchapterfold#1#2{} +\def\pdfchapter#1{} +\def\pdfsection#1{} + +%\ifpdf +%\newcount\pdflabel +%\pdflabel=1 +%\def\pdfchapterfold#1#2{ +%\pdfdest num \pdflabel fit +%\pdfoutline goto num \pdflabel count #1 {\arabic{chapter}. #2} +%\global\advance\pdflabel by 1 +%} +%\def\pdfsection#1{ +%\pdfdest num \pdflabel fit +%\pdfoutline goto num \pdflabel {#1} +%\global\advance\pdflabel by 1 +%} +%\else +%\def\pdfchapterfold#1#2{} +%\def\pdfsection#1{} +%\fi +% +%\def\pdfchapter{\pdfchapterfold{0}} + +%%% Pour camlidl + +\def\transl#1{$[\![\mbox{#1}]\!]$} + +%%% Pour les references des modules +\newcommand{\moduleref}[1]{\ref{#1}} +%%% Fin des hacks + +\newenvironment{maintitle}{\begin{center}}{\end{center}} + +\makeatother diff --git a/manual/manual/manual.hva b/manual/manual/manual.hva new file mode 100644 index 00000000..942dde96 --- /dev/null +++ b/manual/manual/manual.hva @@ -0,0 +1,3 @@ +\input{book.hva} +\input{macros.hva} +\newif\ifouthtml\outhtmltrue diff --git a/manual/manual/manual.inf b/manual/manual/manual.inf new file mode 100644 index 00000000..65f64104 --- /dev/null +++ b/manual/manual/manual.inf @@ -0,0 +1,121 @@ +\input{book.hva} +\renewcommand{\@indexsection}[1]{\chapter{#1}} +\newcommand{\black}{\htmlcolor{#000000}} +\newcommand{\machine}{\tt} +\newenvironment{machineenv}{\begin{alltt}}{\end{alltt}} +\newenvironment{camlunder}{\@style{U}}{} +\newcommand{\caml}{\begin{alltt}\renewcommand{\\}{\char92}\def\<{\begin{camlunder}}\def\>{\end{camlunder}}\activebracefalse} +\newcommand{\endcaml}{\activebracetrue\end{alltt}} +\newcommand{\?}{\black\#\blue } +\renewcommand{\:}{\maroon} +\def\camlinput{} +\def\endcamlinput{} +\def\camloutput{} +\def\endcamloutput{} +\def\camlerror{} +\def\endcamlerror{} +\def\camlwarn{} +\def\endcamlwarn{} +\newcommand{\var}[1]{\textit{#1}} + +\newenvironment{library}{}{} +\newcounter{page} +\newenvironment{comment}{\begin{quote}}{\end{quote}} +\newcommand{\nth}[2]{\({#1}_{#2}\)} +\newenvironment{options}{\begin{description}}{\end{description}} + + +%%venant de macros.tex +\newif\ifouthtml\outhtmlfalse +\def\versionspecific#1{ +\quad\textsf{#1:} +\begin{quote}} + +\def\unix{\versionspecific{Unix}} +\def\endunix{\end{quote}} +\def\macos{\versionspecific{MacOS}} +\def\endmacos{\end{quote}} +\def\windows{\versionspecific{Windows}} +\def\endwindows{\end{quote}} + +\def\requirements{\trivlist \item[\hskip\labelsep {\bf Requirements.}]} +\def\endrequirements{\endtrivlist} +\def\installation{\trivlist \item[\hskip\labelsep {\bf Installation.}]} +\def\endinstallation{\endtrivlist} +\def\troubleshooting{\trivlist \item[\hskip\labelsep {\bf Troubleshooting.}]} +\def\endtroubleshooting{\endtrivlist} + +\newtheorem{gcrule}{Rule} + +% Pour les tables de priorites et autres tableaux a deux colonnes, encadres + +%\def\entree#1#2{#1 & #2 \\} +%\def\tableau#1#2#3{% +%\par\begin{center}% +%\begin{tabular}{#1}% +%\multicolumn{1}{c}{\textbf{#2}} & +%\multicolumn{1}{c}{\textbf{#3}} \\ +%%#2 & #3 \\% +%}% +%\def\endtableau{\end{tabular}\end{center}\par} + +% Pour les tables de priorites et autres tableaux a deux colonnes, encadres + +\def\tableau#1#2#3{% +\begin{center} +\begin{tabular}{#1} +\hline +\multicolumn{1}{|c|}{\textbf{#2}} & \multicolumn{1}{c|}{\textbf{#3}} \\ +\hline +} +\def\endtableau{\hline\end{tabular}\end{center}} +\def\entree#1#2{#1 & #2 \\} + + + +% L'environnement library (pour composer les descriptions des modules +% de bibliotheque). + + +\def\restoreindent{\begingroup\let\@listI=\@savedlistI} +\def\endrestoreindent{\endgroup} + + +% PDF stuff + +\def\pdfchapterfold#1#2{} +\def\pdfsection#1{} +\def\pdfchapter{\pdfchapterfold{0}} + +%%% Pour camlidl + +\def\transl#1{$[\![\mbox{#1}]\!]$} + +% Pour l'index +\usepackage{multind} +\let\indexentry=\index +\renewcommand{\index}[1]{\indexentry{\jobname}{#1}} +\def\ikwd#1{\indexentry{\jobname.kwd}{#1}} + + +% nth +\def\th{^{\mbox{\scriptsize th}}} +\renewcommand{\hbox}[1]{\mbox{#1}} + +% Notations pour les metavariables +\def\nmth#1#2#3{\({#1}_{#2}^{#3}\)} +\def\optvar#1{[\var{#1}\/]} +\def\event{§§} +\def\fromoneto#1#2{$#1 = 1,\ldots{} , #2$} + +\newcommand{\vfill}{} +\def\number{} +\def\year{2013} + +% Pour alltt + +\def\rminalltt#1{{\rm #1}} + +\def\goodbreak{\ \\} + +\def\@savedlistI{} diff --git a/manual/manual/manual.info.header b/manual/manual/manual.info.header new file mode 100644 index 00000000..74665158 --- /dev/null +++ b/manual/manual/manual.info.header @@ -0,0 +1,4 @@ +INFO-DIR-SECTION OCaml Programming Language +START-INFO-DIR-ENTRY +* ocaml: (ocaml). OCaml Reference Manual +END-INFO-DIR-ENTRY diff --git a/manual/manual/manual.tex b/manual/manual/manual.tex new file mode 100644 index 00000000..c318ba76 --- /dev/null +++ b/manual/manual/manual.tex @@ -0,0 +1,42 @@ +\documentclass[11pt]{book} +\usepackage[latin1]{inputenc} +%HEVEA\@def@charset{US-ASCII}% +\usepackage{alltt} +\usepackage{fullpage} +\usepackage{syntaxdef} +\usepackage{multind} +\usepackage{html} +\usepackage{textcomp} +\usepackage{caml-sl} +\usepackage{ocamldoc} +\usepackage{xspace} +\newif\ifplaintext +\plaintextfalse +%\newif\ifpdf +%\pdffalse + +\input{macros.tex} + +% Add meta tag to the generated head tag +\ifouthtml +\let\oldmeta=\@meta +\renewcommand{\@meta}{ +\oldmeta +\begin{rawhtml} + +\end{rawhtml} +} +\fi + +\usepackage{hyperref} +%\makeatletter \def\@wrindex#1#2{\xdef \@indexfile{\csname #1@idxfile\endcsname}\@@wrindex#2||\\}\makeatother +\def\th{^{\hbox{\scriptsize th}}} + +\raggedbottom +\input{version.tex} +%HEVEA\tocnumber +%HEVEA\setcounter{cuttingdepth}{1} +%HEVEA\title{The OCaml system, release \ocamlversion} +\input{allfiles.tex} + + diff --git a/manual/manual/pdfmanual.tex b/manual/manual/pdfmanual.tex new file mode 100644 index 00000000..73264605 --- /dev/null +++ b/manual/manual/pdfmanual.tex @@ -0,0 +1,31 @@ +%\pdfoutput=1 +\pdfpagewidth=21cm +\pdfpageheight=11in +\pdfcompresslevel=7 + +\documentclass[11pt]{book} + +\usepackage[latin1]{inputenc} +\usepackage{alltt} +\usepackage{fullpage} +\usepackage{syntaxdef} +\usepackage{multind} +\usepackage{html} +\usepackage{textcomp} +\usepackage{caml-sl} +\usepackage{ocamldoc} +\usepackage{xspace} + +\newif\ifplaintext +\plaintextfalse +%\newif\ifpdf +%\pdftrue +\input macros.tex + +\usepackage[colorlinks,linkcolor=blue]{hyperref} +\def\th{^{\hbox{\scriptsize th}}} + +\raggedbottom +\input{version.tex} + +\input allfiles.tex diff --git a/manual/manual/plaintext.tex b/manual/manual/plaintext.tex new file mode 100644 index 00000000..86201b4b --- /dev/null +++ b/manual/manual/plaintext.tex @@ -0,0 +1,17 @@ +\documentclass[11pt]{report} + +\usepackage{plaintext} +\usepackage[latin1]{inputenc} +\usepackage{alltt} +\usepackage{fullpage} +\usepackage{syntaxdef} +\usepackage{multind} +\usepackage{html} +\usepackage{caml-sl} + +\newif\ifplaintext +\plaintexttrue +%\newif\ifpdf +%\pdffalse +\input macros.tex +\input allfiles.tex diff --git a/manual/manual/refman/.cvsignore b/manual/manual/refman/.cvsignore new file mode 100644 index 00000000..81ccbe71 --- /dev/null +++ b/manual/manual/refman/.cvsignore @@ -0,0 +1,2 @@ +*.tex +*.htex diff --git a/manual/manual/refman/.gitignore b/manual/manual/refman/.gitignore new file mode 100644 index 00000000..81ccbe71 --- /dev/null +++ b/manual/manual/refman/.gitignore @@ -0,0 +1,2 @@ +*.tex +*.htex diff --git a/manual/manual/refman/Makefile b/manual/manual/refman/Makefile new file mode 100644 index 00000000..61883ae5 --- /dev/null +++ b/manual/manual/refman/Makefile @@ -0,0 +1,43 @@ +FILES= refman.tex lex.tex names.tex values.tex const.tex types.tex \ + patterns.tex expr.tex typedecl.tex modtypes.tex modules.tex compunit.tex \ + exten.tex classes.tex + +TOPDIR=../../.. + +include $(TOPDIR)/Makefile.tools + +LD_PATH="$(TOPDIR)/otherlibs/str:$(TOPDIR)/otherlibs/unix" + +CAMLLATEX=$(SET_LD_PATH) $(OCAMLRUN) ../../tools/caml-tex2 \ + -caml "TERM=norepeat $(OCAML)" -n 80 -v false +TRANSF=$(SET_LD_PATH) $(OCAMLRUN) ../../tools/transf +TEXQUOTE=../../tools/texquote2 + +ALLFILES=$(FILES) + +etex-files: $(ALLFILES) +all: $(ALLFILES) + +clean: + rm -f $(ALLFILES) + +.SUFFIXES: +.SUFFIXES: .etex .tex + +exten.tex:exten.etex + @$(CAMLLATEX) -o $*.caml_tex_error.tex $*.etex \ + && mv $*.caml_tex_error.tex $*.gen.tex \ + && $(TRANSF) < $*.gen.tex > $*.transf_error.tex \ + && mv $*.transf_error.tex $*.gen.tex\ + && $(TEXQUOTE) < $*.gen.tex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex +.etex.tex: + @$(TRANSF) < $*.etex > $*.transf_error.tex \ + && mv $*.transf_error.tex $*.gen.tex\ + && $(TEXQUOTE) < $*.gen.tex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex + + +$(ALLFILES): ../../tools/transf $(TEXQUOTE) diff --git a/manual/manual/refman/classes.etex b/manual/manual/refman/classes.etex new file mode 100644 index 00000000..2480357c --- /dev/null +++ b/manual/manual/refman/classes.etex @@ -0,0 +1,530 @@ +\section{Classes} +\pdfsection{Classes} +%HEVEA\cutname{classes.html} +Classes are defined using a small language, similar to the module +language. + +\subsection{Class types} + +Class types are the class-level equivalent of type expressions: they +specify the general shape and type properties of classes. + +\ikwd{object\@\texttt{object}} +\ikwd{end\@\texttt{end}} +\ikwd{inherit\@\texttt{inherit}} +\ikwd{val\@\texttt{val}} +\ikwd{mutable\@\texttt{mutable}} +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} +\ikwd{virtual\@\texttt{virtual}|see{\texttt{val}, \texttt{method}, \texttt{class}}} +\ikwd{constraint\@\texttt{constraint}} + +\begin{syntax} +class-type: + [['?']label-name':'] typexpr '->' class-type + | class-body-type +; +class-body-type: + 'object' ['(' typexpr ')'] {class-field-spec} 'end' + | ['[' typexpr {',' typexpr} ']'] classtype-path + | 'let' 'open' module-path 'in' class-body-type +; +%\end{syntax} \begin{syntax} +class-field-spec: + 'inherit' class-body-type + | 'val' ['mutable'] ['virtual'] inst-var-name ':' typexpr + | 'val' 'virtual' 'mutable' inst-var-name ':' typexpr + | 'method' ['private'] ['virtual'] method-name ':' poly-typexpr + | 'method' 'virtual' 'private' method-name ':' poly-typexpr + | 'constraint' typexpr '=' typexpr +\end{syntax} +See also the following language extensions: +\hyperref[s:attributes]{attributes} and +\hyperref[s:extension-nodes]{extension nodes}. + +\subsubsection*{Simple class expressions} + +The expression @classtype-path@ is equivalent to the class type bound to +the name @classtype-path@. Similarly, the expression +@'[' typexpr_1 ',' \ldots typexpr_n ']' classtype-path@ is equivalent to +the parametric class type bound to the name @classtype-path@, in which +type parameters have been instantiated to respectively @typexpr_1@, +\ldots @typexpr_n@. + +\subsubsection*{Class function type} + +The class type expression @typexpr '->' class-type@ is the type of +class functions (functions from values to classes) that take as +argument a value of type @typexpr@ and return as result a class of +type @class-type@. + +\subsubsection*{Class body type} + +The class type expression +@'object' ['(' typexpr ')'] {class-field-spec} 'end'@ +is the type of a class body. It specifies its instance variables and +methods. In this type, @typexpr@ is matched against the self type, therefore +providing a name for the self type. + +A class body will match a class body type if it provides definitions +for all the components specified in the class body type, and these +definitions meet the type requirements given in the class body type. +Furthermore, all methods either virtual or public present in the class +body must also be present in the class body type (on the other hand, some +instance variables and concrete private methods may be omitted). A +virtual method will match a concrete method, which makes it possible +to forget its implementation. An immutable instance variable will match a +mutable instance variable. + +\subsubsection*{Local opens} + +Local opens are supported in class types since OCaml 4.06. + +\subsubsection*{Inheritance} + +\ikwd{inherit\@\texttt{inherit}} + +The inheritance construct @'inherit' class-body-type@ provides for inclusion of +methods and instance variables from other class types. +The instance variable and method types from @class-body-type@ are added +into the current class type. + +\subsubsection*{Instance variable specification} + +\ikwd{val\@\texttt{val}} +\ikwd{mutable\@\texttt{mutable}} + +A specification of an instance variable is written +@'val' ['mutable'] ['virtual'] inst-var-name ':' typexpr@, where +@inst-var-name@ +is the name of the instance variable and @typexpr@ its expected type. +% +The flag @'mutable'@ indicates whether this instance variable can be +physically modified. +% +The flag @'virtual'@ indicates that this instance variable is not +initialized. It can be initialized later through inheritance. + +An instance variable specification will hide any previous +specification of an instance variable of the same name. + +\subsubsection*{Method specification} +\label{sec-methspec} + +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} + +The specification of a method is written +@'method' ['private'] method-name ':' poly-typexpr@, where +@method-name@ is the name of the method and @poly-typexpr@ its +expected type, possibly polymorphic. The flag @'private'@ indicates +that the method cannot be accessed from outside the object. + +The polymorphism may be left implicit in public method specifications: +any type variable which is not bound to a class parameter and does not +appear elsewhere inside the class specification will be assumed to be +universal, and made polymorphic in the resulting method type. +Writing an explicit polymorphic type will disable this behaviour. + +If several specifications are present for the same method, they +must have compatible types. +Any non-private specification of a method forces it to be public. + +\subsubsection*{Virtual method specification} + +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} + +A virtual method specification is written @'method' ['private'] +'virtual' method-name ':' poly-typexpr@, where @method-name@ is the +name of the method and @poly-typexpr@ its expected type. + +\subsubsection*{Constraints on type parameters} + +\ikwd{constraint\@\texttt{constraint}} + +The construct @'constraint' typexpr_1 '=' typexpr_2@ forces the two +type expressions to be equal. This is typically used to specify type +parameters: in this way, they can be bound to specific type +expressions. + +\subsection{Class expressions} + +Class expressions are the class-level equivalent of value expressions: +they evaluate to classes, thus providing implementations for the +specifications expressed in class types. + +\ikwd{object\@\texttt{object}} +\ikwd{end\@\texttt{end}} +\ikwd{fun\@\texttt{fun}} +\ikwd{let\@\texttt{let}} +\ikwd{and\@\texttt{and}} +\ikwd{inherit\@\texttt{inherit}} +\ikwd{as\@\texttt{as}} +\ikwd{val\@\texttt{val}} +\ikwd{mutable\@\texttt{mutable}} +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} +\ikwd{constraint\@\texttt{constraint}} +\ikwd{initializer\@\texttt{initializer}} + +\begin{syntax} +class-expr: + class-path + | '[' typexpr {',' typexpr} ']' class-path + | '(' class-expr ')' + | '(' class-expr ':' class-type ')' + | class-expr {{argument}} + | 'fun' {{parameter}} '->' class-expr + | 'let' ['rec'] let-binding {'and' let-binding} 'in' class-expr + | 'object' class-body 'end' + | 'let' 'open' module-path 'in' class-expr +; +%BEGIN LATEX +\end{syntax} \begin{syntax} +%END LATEX +class-field: + 'inherit' class-expr ['as' lowercase-ident] + | 'inherit!' class-expr ['as' lowercase-ident] + | 'val' ['mutable'] inst-var-name [':' typexpr] '=' expr + | 'val!' ['mutable'] inst-var-name [':' typexpr] '=' expr + | 'val' ['mutable'] 'virtual' inst-var-name ':' typexpr + | 'val' 'virtual' 'mutable' inst-var-name ':' typexpr + | 'method' ['private'] method-name {parameter} [':' typexpr] '=' expr + | 'method!' ['private'] method-name {parameter} [':' typexpr] '=' expr + | 'method' ['private'] method-name ':' poly-typexpr '=' expr + | 'method!' ['private'] method-name ':' poly-typexpr '=' expr + | 'method' ['private'] 'virtual' method-name ':' poly-typexpr + | 'method' 'virtual' 'private' method-name ':' poly-typexpr + | 'constraint' typexpr '=' typexpr + | 'initializer' expr +\end{syntax} +See also the following language extensions: +\hyperref[s:locally-abstract]{locally abstract types}, +\hyperref[s:attributes]{attributes} and +\hyperref[s:extension-nodes]{extension nodes}. + +\subsubsection*{Simple class expressions} + +The expression @class-path@ evaluates to the class bound to the name +@class-path@. Similarly, the expression +@'[' typexpr_1 ',' \ldots typexpr_n ']' class-path@ +evaluates to the parametric class bound to the name @class-path@, +in which type parameters have been instantiated respectively to +@typexpr_1@, \ldots @typexpr_n@. + +The expression @'(' class-expr ')'@ evaluates to the same module as +@class-expr@. + +The expression @'(' class-expr ':' class-type ')'@ checks that +@class-type@ matches the type of @class-expr@ (that is, that the +implementation @class-expr@ meets the type specification +@class-type@). The whole expression evaluates to the same class as +@class-expr@, except that all components not specified in +@class-type@ are hidden and can no longer be accessed. + +\subsubsection*{Class application} + +Class application is denoted by juxtaposition of (possibly labeled) +expressions. It denotes the class whose constructor is the first +expression applied to the given arguments. The arguments are +evaluated as for expression application, but the constructor itself will +only be evaluated when objects are created. In particular, side-effects +caused by the application of the constructor will only occur at object +creation time. + +\subsubsection*{Class function} + +The expression @'fun' [['?']label-name':']pattern '->' class-expr@ evaluates +to a function from values to classes. +When this function is applied to a value \var{v}, this value is +matched against the pattern @pattern@ and the result is the result of +the evaluation of @class-expr@ in the extended environment. + +Conversion from functions with default values to functions with +patterns only works identically for class functions as for normal +functions. + +The expression +\begin{center} +@"fun" parameter_1 \ldots parameter_n "->" class-expr@ +\end{center} +is a short form for +\begin{center} +@"fun" parameter_1 "->" \ldots "fun" parameter_n "->" expr@ +\end{center} + +\subsubsection*{Local definitions} + +The {\tt let} and {\tt let rec} constructs bind value names locally, +as for the core language expressions. + +If a local definition occurs at the very beginning of a class +definition, it will be evaluated when the class is created (just as if +the definition was outside of the class). +Otherwise, it will be evaluated when the object constructor is called. + +\subsubsection*{Local opens} + +Local opens are supported in class expressions since OCaml 4.06. + +\subsubsection*{Class\label{ss:class-body} body} +\begin{syntax} +class-body: ['(' pattern [':' typexpr] ')'] { class-field } +\end{syntax} +The expression +@'object' class-body 'end'@ denotes +a class body. This is the prototype for an object : it lists the +instance variables and methods of an objet of this class. + +A class body is a class value: it is not evaluated at once. Rather, +its components are evaluated each time an object is created. + +In a class body, the pattern @'(' pattern [':' typexpr] ')'@ is +matched against self, therefore providing a binding for self and self +type. Self can only be used in method and initializers. + +Self type cannot be a closed object type, so that the class remains +extensible. + +Since OCaml 4.01, it is an error if the same method or instance +variable name is defined several times in the same class body. + +\subsubsection*{Inheritance} + +\ikwd{inherit\@\texttt{inherit}} + +The inheritance construct @'inherit' class-expr@ allows reusing +methods and instance variables from other classes. The class +expression @class-expr@ must evaluate to a class body. The instance +variables, methods and initializers from this class body are added +into the current class. The addition of a method will override any +previously defined method of the same name. + +\ikwd{as\@\texttt{as}} +An ancestor can be bound by appending @'as' lowercase-ident@ +to the inheritance construct. @lowercase-ident@ is not a true +variable and can only be used to select a method, i.e. in an expression +@lowercase-ident '#' method-name@. This gives access to the +method @method-name@ as it was defined in the parent class even if it is +redefined in the current class. +The scope of this ancestor binding is limited to the current class. +The ancestor method may be called from a subclass but only indirectly. + +\subsubsection*{Instance variable definition} + +\ikwd{val\@\texttt{val}} +\ikwd{mutable\@\texttt{mutable}} + +The definition @'val' ['mutable'] inst-var-name '=' expr@ adds an +instance variable @inst-var-name@ whose initial value is the value of +expression @expr@. +% +The flag @'mutable'@ allows physical modification of this variable by +methods. + +An instance variable can only be used in the methods and +initializers that follow its definition. + +Since version 3.10, redefinitions of a visible instance variable with +the same name do not create a new variable, but are merged, using the +last value for initialization. They must have identical types and +mutability. +However, if an instance variable is hidden by +omitting it from an interface, it will be kept distinct from +other instance variables with the same name. + +\subsubsection*{Virtual instance variable definition} + +\ikwd{val\@\texttt{val}} +\ikwd{mutable\@\texttt{mutable}} + +A variable specification is written @'val' ['mutable'] 'virtual' +inst-var-name ':' typexpr@. It specifies whether the variable is +modifiable, and gives its type. + +Virtual instance variables were added in version 3.10. + +\subsubsection*{Method definition} + +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} + +A method definition is written @'method' method-name '=' expr@. The +definition of a method overrides any previous definition of this +method. The method will be public (that is, not private) if any of +the definition states so. + +A private method, @'method' 'private' method-name '=' expr@, is a +method that can only be invoked on self (from other methods of the +same object, defined in this class or one of its subclasses). This +invocation is performed using the expression +@value-name '#' method-name@, where @value-name@ is directly bound to +self at the beginning of the class definition. Private methods do +not appear in object types. A method may have both public and private +definitions, but as soon as there is a public one, all subsequent +definitions will be made public. + +Methods may have an explicitly polymorphic type, allowing them to be +used polymorphically in programs (even for the same object). The +explicit declaration may be done in one of three ways: (1) by giving an +explicit polymorphic type in the method definition, immediately after +the method name, {\em i.e.} +@'method' ['private'] method-name ':' {{"'" ident}} '.' typexpr '=' +expr@; (2) by a forward declaration of the explicit polymorphic type +through a virtual method definition; (3) by importing such a +declaration through inheritance and/or constraining the type of {\em +self}. + +Some special expressions are available in method bodies for +manipulating instance variables and duplicating self: +\begin{syntax} +expr: + \ldots + | inst-var-name '<-' expr + | '{<' [ inst-var-name '=' expr { ';' inst-var-name '=' expr } [';'] ] '>}' +\end{syntax} + +The expression @inst-var-name '<-' expr@ modifies in-place the current +object by replacing the value associated to @inst-var-name@ by the +value of @expr@. Of course, this instance variable must have been +declared mutable. + +The expression +@'{<' inst-var-name_1 '=' expr_1 ';' \ldots ';' inst-var-name_n '=' expr_n '>}'@ +evaluates to a copy of the current object in which the values of +instance variables @inst-var-name_1, \ldots, inst-var-name_n@ have +been replaced by the values of the corresponding expressions @expr_1, +\ldots, expr_n@. + +\subsubsection*{Virtual method definition} + +\ikwd{method\@\texttt{method}} +\ikwd{private\@\texttt{private}} + +A method specification is written @'method' ['private'] 'virtual' +method-name ':' poly-typexpr@. It specifies whether the method is +public or private, and gives its type. If the method is intended to be +polymorphic, the type must be explicitly polymorphic. + +\subsubsection*{Explicit overriding} + +Since Ocaml 3.12, the keywords @"inherit!"@, @"val!"@ and @"method!"@ +have the same semantics as @"inherit"@, @"val"@ and @"method"@, but +they additionally require the definition they introduce to be +overriding. Namely, @"method!"@ requires @method-name@ to be already +defined in this class, @"val!"@ requires @inst-var-name@ to be already +defined in this class, and @"inherit!"@ requires @class-expr@ to +override some definitions. If no such overriding occurs, an error is +signaled. + +As a side-effect, these 3 keywords avoid the warnings~7 +(method override) and~13 (instance variable override). +Note that warning~7 is disabled by default. + +\subsubsection*{Constraints on type parameters} + +\ikwd{constraint\@\texttt{constraint}} +The construct @'constraint' typexpr_1 '=' typexpr_2@ forces the two +type expressions to be equals. This is typically used to specify type +parameters: in that way they can be bound to specific type +expressions. + +\subsubsection*{Initializers} + +\ikwd{initializer\@\texttt{initializer}} + +A class initializer @'initializer' expr@ specifies an expression that +will be evaluated whenever an object is created from the class, once +all its instance variables have been initialized. + +\subsection{Class definitions} +\label{s:classdef} + +\ikwd{class\@\texttt{class}} +\ikwd{and\@\texttt{and}} + +\begin{syntax} +class-definition: + 'class' class-binding { 'and' class-binding } +; +class-binding: + ['virtual'] ['[' type-parameters ']'] class-name + {parameter} [':' class-type] \\ '=' class-expr +; +type-parameters: + "'" ident { "," "'" ident } +\end{syntax} + +A class definition @'class' class-binding { 'and' class-binding }@ is +recursive. Each @class-binding@ defines a @class-name@ that can be +used in the whole expression except for inheritance. It can also be +used for inheritance, but only in the definitions that follow its own. + +A class binding binds the class name @class-name@ to the value of +expression @class-expr@. It also binds the class type @class-name@ to +the type of the class, and defines two type abbreviations : +@class-name@ and @'#' class-name@. The first one is the type of +objects of this class, while the second is more general as it unifies +with the type of any object belonging to a subclass (see +section~\ref{s:sharp-types}). + +\subsubsection*{Virtual class} + +A class must be flagged virtual if one of its methods is virtual (that +is, appears in the class type, but is not actually defined). +Objects cannot be created from a virtual class. + +\subsubsection*{Type parameters} + +The class type parameters correspond to the ones of the class type and +of the two type abbreviations defined by the class binding. They must +be bound to actual types in the class definition using type +constraints. So that the abbreviations are well-formed, type +variables of the inferred type of the class must either be type +parameters or be bound in the constraint clause. + +\subsection{Class specifications} +\label{s:class-spec} + +\ikwd{class\@\texttt{class}} +\ikwd{and\@\texttt{and}} + +\begin{syntax} +class-specification: + 'class' class-spec { 'and' class-spec } +; +class-spec: + ['virtual'] ['[' type-parameters ']'] class-name ':' + class-type +\end{syntax} + +This is the counterpart in signatures of class definitions. +A class specification matches a class definition if they have the same +type parameters and their types match. + +\subsection{Class type definitions} +\label{s:classtype} + +\ikwd{class\@\texttt{class}} +\ikwd{type\@\texttt{type}} +\ikwd{and\@\texttt{and}} + +\begin{syntax} +classtype-definition: + 'class' 'type' classtype-def + { 'and' classtype-def } +; +classtype-def: + ['virtual'] ['[' type-parameters ']'] class-name '=' class-body-type +\end{syntax} + +A class type definition @'class' class-name '=' class-body-type@ +defines an abbreviation @class-name@ for the class body type +@class-body-type@. As for class definitions, two type abbreviations +@class-name@ and @'#' class-name@ are also defined. The definition can +be parameterized by some type parameters. If any method in the class +type body is virtual, the definition must be flagged @'virtual'@. + +Two class type definitions match if they have the same type parameters +and they expand to matching types. diff --git a/manual/manual/refman/compunit.etex b/manual/manual/refman/compunit.etex new file mode 100644 index 00000000..6c8c09f7 --- /dev/null +++ b/manual/manual/refman/compunit.etex @@ -0,0 +1,42 @@ +\section{Compilation units} +\pdfsection{Compilation units} +%HEVEA\cutname{compunit.html} + +\begin{syntax} +unit-interface: { specification [';;'] } +; +unit-implementation: [ module-items ] +\end{syntax} + +Compilation units bridge the module system and the separate +compilation system. A compilation unit is composed of two parts: an +interface and an implementation. The interface contains a sequence of +specifications, just as the inside of a @'sig' \ldots 'end'@ +signature expression. The implementation contains a sequence of +definitions and expressions, just as the inside of a +@'struct' \ldots 'end'@ module +expression. A compilation unit also has a name @unit-name@, derived +from the names of the files containing the interface and the +implementation (see chapter~\ref{c:camlc} for more details). A +compilation unit behaves roughly as the module definition +\begin{center} +@'module' unit-name ':' 'sig' unit-interface 'end' '=' + 'struct' unit-implementation 'end'@ +\end{center} + +A compilation unit can refer to other compilation units by their +names, as if they were regular modules. For instance, if "U" is a +compilation unit that defines a type "t", other compilation units can +refer to that type under the name "U.t"; they can also refer to "U" as +a whole structure. Except for names of other compilation units, a unit +interface or unit implementation must not have any other free variables. +In other terms, the type-checking and compilation of an interface or +implementation proceeds in the initial environment +\begin{center} +@name_1 ':' 'sig' specification_1 'end' \ldots + name_n ':' 'sig' specification_n 'end'@ +\end{center} +where @name_1 \ldots name_n@ are the names of the other +compilation units available in the search path (see +chapter~\ref{c:camlc} for more details) and @specification_1 \ldots +specification_n@ are their respective interfaces. diff --git a/manual/manual/refman/const.etex b/manual/manual/refman/const.etex new file mode 100644 index 00000000..c503668d --- /dev/null +++ b/manual/manual/refman/const.etex @@ -0,0 +1,35 @@ +\section{Constants} +\pdfsection{Constants} +%HEVEA\cutname{const.html} + +\ikwd{false\@\texttt{false}} +\ikwd{true\@\texttt{true}} +\ikwd{begin\@\texttt{begin}} +\ikwd{end\@\texttt{end}} + +\begin{syntax} +constant: + integer-literal + | float-literal + | char-literal + | string-literal + | constr + | "false" + | "true" + | "("")" + | "begin" "end" + | "[""]" + | "[|""|]" + | "`"tag-name +\end{syntax} +See also the following language extensions: +\hyperref[s:ext-integer]{integer literals for types \texttt{int32}, \texttt{int64} +and \texttt{nativeint}}, \hyperref[s:quoted-strings]{quoted strings} +and \hyperref[s:extension-literals]{extension literals}. + +The syntactic class of constants comprises literals from the four +base types (integers, floating-point numbers, characters, character +strings), and constant constructors from both normal and polymorphic +variants, as well as the special constants @"false"@, @"true"@, @"("")"@, +@"[""]"@, and @"[|""|]"@, which behave like constant constructors, and +@"begin" "end"@, which is equivalent to @'('')'@. diff --git a/manual/manual/refman/expr.etex b/manual/manual/refman/expr.etex new file mode 100644 index 00000000..6e47c03a --- /dev/null +++ b/manual/manual/refman/expr.etex @@ -0,0 +1,998 @@ +\section{Expressions\label{s:value-expr}} +\pdfsection{Expressions} +%HEVEA\cutname{expr.html} +\ikwd{in\@\texttt{in}|see{\texttt{let}}} +\ikwd{and\@\texttt{and}} +\ikwd{rec\@\texttt{rec}|see{\texttt{let}, \texttt{module}}} +\ikwd{let\@\texttt{let}} +\ikwd{try\@\texttt{try}} +\ikwd{function\@\texttt{function}} +\ikwd{fun\@\texttt{fun}} +\ikwd{with\@\texttt{with}} +\ikwd{done\@\texttt{done}|see{\texttt{while}, \texttt{for}}} +\ikwd{do\@\texttt{do}|see{\texttt{while}, \texttt{for}}} +\ikwd{downto\@\texttt{downto}|see{\texttt{for}}} +\ikwd{to\@\texttt{to}|see{\texttt{for}}} +\ikwd{for\@\texttt{for}} +\ikwd{else\@\texttt{else}|see{\texttt{if}}} +\ikwd{then\@\texttt{then}|see{\texttt{if}}} +\ikwd{if\@\texttt{if}} +\ikwd{or\@\texttt{or}} +\ikwd{match\@\texttt{match}} +\ikwd{begin\@\texttt{begin}} +\ikwd{end\@\texttt{end}} +\ikwd{when\@\texttt{when}} +\ikwd{new\@\texttt{new}} +\ikwd{object\@\texttt{object}} +\ikwd{lazy\@\texttt{lazy}} + +\begin{syntax} +expr: + value-path + | constant + | '(' expr ')' + | 'begin' expr 'end' + | '(' expr ':' typexpr ')' + | expr {{',' expr}} + | constr expr + | "`"tag-name expr + | expr '::' expr + | '[' expr { ';' expr } [';'] ']' + | '[|' expr { ';' expr } [';'] '|]' + | '{' field [':' typexpr] ['=' expr]% + { ';' field [':' typexpr] ['=' expr] } [';'] '}' + | '{' expr 'with' field [':' typexpr] ['=' expr]% + { ';' field [':' typexpr] ['=' expr] } [';'] '}' + | expr {{ argument }} + | prefix-symbol expr + | '-' expr + | '-.' expr + | expr infix-op expr + | expr '.' field + | expr '.' field '<-' expr + | expr '.(' expr ')' + | expr '.(' expr ')' '<-' expr + | expr '.[' expr ']' + | expr '.[' expr ']' '<-' expr + | 'if' expr 'then' expr [ 'else' expr ] + | 'while' expr 'do' expr 'done' + | 'for' value-name '=' expr ( 'to' || 'downto' ) expr 'do' expr 'done' + | expr ';' expr + | 'match' expr 'with' pattern-matching + | 'function' pattern-matching + | 'fun' {{ parameter }} [ ':' typexpr ] '->' expr + | 'try' expr 'with' pattern-matching + | 'let' ['rec'] let-binding { 'and' let-binding } 'in' expr + | 'new' class-path + | 'object' class-body 'end' + | expr '#' method-name + | inst-var-name + | inst-var-name '<-' expr + | '(' expr ':>' typexpr ')' + | '(' expr ':' typexpr ':>' typexpr ')' + | '{<' [ inst-var-name '=' expr { ';' inst-var-name '=' expr } [';'] ] '>}' + | 'assert' expr + | 'lazy' expr + | 'let' 'module' module-name { '(' module-name ':' module-type ')' } + [ ':' module-type ] \\ '=' module-expr 'in' expr + | "let" "open" module-path "in" expr + | module-path '.(' expr ')' + | module-path '.[' expr ']' + | module-path '.[|' expr '|]' + | module-path '.{' expr '}' + | module-path '.{<' expr '>}' +; +%BEGIN LATEX +\end{syntax} \begin{syntax} +%END LATEX +argument: + expr + | '~' label-name + | '~' label-name ':' expr + | '?' label-name + | '?' label-name ':' expr +; +%\end{syntax} \begin{syntax} +pattern-matching: + [ '|' ] pattern ['when' expr] '->' expr + { '|' pattern ['when' expr] '->' expr } +; +let-binding: + pattern '=' expr + | value-name { parameter } [':' typexpr] [':>' typexpr] '=' expr + | value-name ':' poly-typexpr '=' expr %since 3.12 +; +parameter: + pattern + | '~' label-name + | '~' '(' label-name [':' typexpr] ')' + | '~' label-name ':' pattern + | '?' label-name + | '?' '(' label-name [':' typexpr] ['=' expr] ')' + | '?' label-name ':' pattern + | '?' label-name ':' '(' pattern [':' typexpr] ['=' expr] ')' +\end{syntax} +See also the following language extensions: +\hyperref[s:object-notations]{object notations}, +\hyperref[s-first-class-modules]{first-class modules}, +\hyperref[s:explicit-overriding-open]{overriding in open statements}, +\hyperref[s:bigarray-access]{syntax for Bigarray access}, +\hyperref[s:attributes]{attributes}, +\hyperref[s:extension-nodes]{extension nodes}, +\hyperref[s:local-exceptions]{local exceptions} +\hyperref[s:index-operators]{extended indexing operators}. + +The table below shows the relative precedences and associativity of +operators and non-closed constructions. The constructions with higher +precedence come first. For infix and prefix symbols, we write +``"*"\ldots'' to mean ``any symbol starting with "*"''. +\ikwd{or\@\texttt{or}}% +\ikwd{if\@\texttt{if}}% +\ikwd{fun\@\texttt{fun}}% +\ikwd{function\@\texttt{function}}% +\ikwd{match\@\texttt{match}}% +\ikwd{try\@\texttt{try}}% +\ikwd{let\@\texttt{let}}% +\ikwd{mod\@\texttt{mod}} +\ikwd{land\@\texttt{land}} +\ikwd{lor\@\texttt{lor}} +\ikwd{lxor\@\texttt{lxor}} +\ikwd{lsl\@\texttt{lsl}} +\ikwd{lsr\@\texttt{lsr}} +\ikwd{asr\@\texttt{asr}} +\begin{tableau}{|l|l|}{Construction or operator}{Associativity} +\entree{prefix-symbol}{--} +\entree{". .( .[ .{" (see section~\ref{s:bigarray-access})}{--} +\entree{"#"\ldots}{--} +\entree{function application, constructor application, tag + application, "assert", + "lazy"}{left} +\entree{"- -." (prefix)}{--} +\entree{"**"\ldots" lsl lsr asr"}{right} +\entree{"*"\ldots" /"\ldots" %"\ldots" mod land lor lxor"}{left} + %% "`"@ident@"`" +\entree{"+"\ldots" -"\ldots}{left} +\entree{"::"}{right} +\entree{{\tt \char64}\ldots " ^"\ldots}{right} +\entree{"="\ldots" <"\ldots" >"\ldots" |"\ldots" &"\ldots" $"\ldots" !="}{left} +\entree{"& &&"}{right} +\entree{"or ||"}{right} +\entree{","}{--} +\entree{"<- :="}{right} +\entree{"if"}{--} +\entree{";"}{right} +\entree{"let match fun function try"}{--} +\end{tableau} + +\subsection{Basic expressions} + +\subsubsection*{Constants} + +An expression consisting in a constant evaluates to this constant. + +\subsubsection*{Value paths} \label{expr:var} + +An expression consisting in an access path evaluates to the value bound to +this path in the current evaluation environment. The path can +be either a value name or an access path to a value component of a module. + +\subsubsection*{Parenthesized expressions} +\ikwd{begin\@\texttt{begin}} +\ikwd{end\@\texttt{end}} + +The expressions @'(' expr ')'@ and @'begin' expr 'end'@ have the same +value as @expr@. The two constructs are semantically equivalent, but it +is good style to use @'begin' \ldots 'end'@ inside control structures: +\begin{alltt} + if \ldots then begin \ldots ; \ldots end else begin \ldots ; \ldots end +\end{alltt} +and @'(' \ldots ')'@ for the other grouping situations. + +Parenthesized expressions can contain a type constraint, as in @'(' +expr ':' typexpr ')'@. This constraint forces the type of @expr@ to be +compatible with @typexpr@. + +Parenthesized expressions can also contain coercions +@'(' expr [':' typexpr] ':>' typexpr')'@ (see +subsection~\ref{s:coercions} below). + + +\subsubsection*{Function application} + +Function application is denoted by juxtaposition of (possibly labeled) +expressions. The expression @expr argument_1 \ldots argument_n@ +evaluates the expression @expr@ and those appearing in @argument_1@ +to @argument_n@. The expression @expr@ must evaluate to a +functional value $f$, which is then applied to the values of +@argument_1, \ldots, argument_n@. + +The order in which the expressions @expr, argument_1, \ldots, +argument_n@ are evaluated is not specified. + +Arguments and parameters are matched according to their respective +labels. Argument order is irrelevant, except among arguments with the +same label, or no label. + +If a parameter is specified as optional (label prefixed by @"?"@) in the +type of @expr@, the corresponding argument will be automatically +wrapped with the constructor "Some", except if the argument itself is +also prefixed by @"?"@, in which case it is passed as is. +% +If a non-labeled argument is passed, and its corresponding parameter +is preceded by one or several optional parameters, then these +parameters are {\em defaulted}, {\em i.e.} the value "None" will be +passed for them. +% +All other missing parameters (without corresponding argument), both +optional and non-optional, will be kept, and the result of the +function will still be a function of these missing parameters to the +body of $f$. + +As a special case, if the function has a known arity, all the +arguments are unlabeled, and their number matches the number of +non-optional parameters, then labels are ignored and non-optional +parameters are matched in their definition order. Optional arguments +are defaulted. + +In all cases but exact match of order and labels, without optional +parameters, the function type should be known at the application +point. This can be ensured by adding a type constraint. Principality +of the derivation can be checked in the "-principal" mode. + +\subsubsection*{Function definition} + +Two syntactic forms are provided to define functions. The first form +is introduced by the keyword "function": +\ikwd{function\@\texttt{function}} + +$$\begin{array}{rlll} +\token{function} & \textsl{pattern}_1 & \token{->} & \textsl{expr}_1 \\ +\token{|} & \ldots \\ +\token{|} & \textsl{pattern}_n & \token{->} & \textsl{expr}_n +\end{array}$$ +This expression evaluates to a functional value with one argument. +When this function is applied to a value \var{v}, this value is +matched against each pattern @pattern_1@ to @pattern_n@. +If one of these matchings succeeds, that is, if the value \var{v} +matches the pattern @pattern_i@ for some \var{i}, +then the expression @expr_i@ associated to the selected pattern +is evaluated, and its value becomes the value of the function +application. The evaluation of @expr_i@ takes place in an +environment enriched by the bindings performed during the matching. + +If several patterns match the argument \var{v}, the one that occurs +first in the function definition is selected. If none of the patterns +matches the argument, the exception "Match_failure" is raised. +% +\index{Matchfailure\@\verb`Match_failure`} + +\medskip + +The other form of function definition is introduced by the keyword "fun": +\ikwd{fun\@\texttt{fun}} +\begin{center} +@"fun" parameter_1 \ldots parameter_n "->" expr@ +\end{center} +This expression is equivalent to: +\begin{center} +@"fun" parameter_1 "->" \ldots "fun" parameter_n "->" expr@ +\end{center} + +An optional type constraint @typexpr@ can be added before "->" to enforce +the type of the result to be compatible with the constraint @typexpr@: +\begin{center} +@"fun" parameter_1 \ldots parameter_n ":" typexpr "->" expr@ +\end{center} +is equivalent to +\begin{center} + @"fun" parameter_1 "->" \ldots "fun" parameter_n "->" % + (expr ":" typexpr )@ +\end{center} +Beware of the small syntactic difference between a type constraint on +the last parameter +\begin{center} + @"fun" parameter_1 \ldots (parameter_n":"typexpr)"->" expr @ +\end{center} +and one on the result +\begin{center} + @"fun" parameter_1 \ldots parameter_n":" typexpr "->" expr @ +\end{center} + +The parameter patterns @"~"lab@ and @"~("lab [":" typ]")"@ +are shorthands for respectively @"~"lab":"lab@ and +@"~"lab":("lab [":" typ]")"@, and similarly for their optional +counterparts. + +A function of the form @"fun" "?" lab ":(" pattern '=' expr_0 ')' '->' +expr@ is equivalent to +\begin{center} +@"fun" "?" lab ":" ident '->' + "let" pattern '=' + "match" ident "with" "Some" ident "->" ident '|' "None" '->' expr_0 + "in" expr@ +\end{center} +where @ident@ +is a fresh variable, except that it is unspecified when @expr_0@ is evaluated. + +After these two transformations, expressions are of the form +\begin{center} +@"fun" [label_1] pattern_1 "->" \ldots "fun" [label_n] pattern_n "->" expr@ +\end{center} +If we ignore labels, which will only be meaningful at function +application, this is equivalent to +\begin{center} +@"function" pattern_1 "->" \ldots "function" pattern_n "->" expr@ +\end{center} +That is, the @"fun"@ expression above evaluates to a curried function +with \var{n} arguments: after applying this function $n$ times to the +values @@v@_1 \ldots @v@_n@, the values will be matched +in parallel against the patterns @pattern_1 \ldots pattern_n@. +If the matching succeeds, the function returns the value of @expr@ in +an environment enriched by the bindings performed during the matchings. +If the matching fails, the exception "Match_failure" is raised. + +\subsubsection*{Guards in pattern-matchings} + +\ikwd{when\@\texttt{when}} +The cases of a pattern matching (in the @"function"@, @"match"@ and +@"try"@ constructs) can include guard expressions, which are +arbitrary boolean expressions that must evaluate to "true" for the +match case to be selected. Guards occur just before the @"->"@ token and +are introduced by the @"when"@ keyword: + +$$\begin{array}{rlll} +\token{function} & \nt{pattern}_1 \; [\token{when} \; \nt{cond}_1] & \token{->} & \nt{expr}_1 \\ +\token{|} & \ldots \\ +\token{|} & \nt{pattern}_n \; [\token{when} \; \nt{cond}_n] & \token{->} & \nt{expr}_n +\end{array}$$ + + +Matching proceeds as described before, except that if the value +matches some pattern @pattern_i@ which has a guard @@cond@_i@, then the +expression @@cond@_i@ is evaluated (in an environment enriched by the +bindings performed during matching). If @@cond@_i@ evaluates to "true", +then @expr_i@ is evaluated and its value returned as the result of the +matching, as usual. But if @@cond@_i@ evaluates to "false", the matching +is resumed against the patterns following @pattern_i@. + +\subsubsection*{Local definitions} \label{s:localdef} + +\ikwd{let\@\texttt{let}} + +The @"let"@ and @"let" "rec"@ constructs bind value names locally. +The construct +\begin{center} +@"let" pattern_1 "=" expr_1 "and" \ldots "and" pattern_n "=" expr_n "in" expr@ +\end{center} +evaluates @expr_1 \ldots expr_n@ in some unspecified order and matches +their values against the patterns @pattern_1 \ldots pattern_n@. If the +matchings succeed, @expr@ is evaluated in the environment enriched by +the bindings performed during matching, and the value of @expr@ is +returned as the value of the whole @"let"@ expression. If one of the +matchings fails, the exception "Match_failure" is raised. +% +\index{Matchfailure\@\verb`Match_failure`} + +An alternate syntax is provided to bind variables to functional +values: instead of writing +\begin{center} +@"let" ident "=" "fun" parameter_1 \ldots parameter_m "->" expr@ +\end{center} +in a @"let"@ expression, one may instead write +\begin{center} +@"let" ident parameter_1 \ldots parameter_m "=" expr@ +\end{center} + +\medskip +\noindent +Recursive definitions of names are introduced by @"let" "rec"@: +\begin{center} +@"let" "rec" pattern_1 "=" expr_1 "and" \ldots "and" pattern_n "=" expr_n + "in" expr@ +\end{center} +The only difference with the @"let"@ construct described above is +that the bindings of names to values performed by the +pattern-matching are considered already performed when the expressions +@expr_1@ to @expr_n@ are evaluated. That is, the expressions @expr_1@ +to @expr_n@ can reference identifiers that are bound by one of the +patterns @pattern_1, \ldots, pattern_n@, and expect them to have the +same value as in @expr@, the body of the @"let" "rec"@ construct. + +The recursive definition is guaranteed to behave as described above if +the expressions @expr_1@ to @expr_n@ are function definitions +(@"fun" \ldots@ or @"function" \ldots@), and the patterns @pattern_1 +\ldots pattern_n@ are just value names, as in: +\begin{center} +@"let" "rec" name_1 "=" "fun" \ldots +"and" \ldots +"and" name_n "=" "fun" \ldots +"in" expr@ +\end{center} +This defines @name_1 \ldots name_n@ as mutually recursive functions +local to @expr@. + +The behavior of other forms of @"let" "rec"@ definitions is +implementation-dependent. The current implementation also supports +a certain class of recursive definitions of non-functional values, +as explained in section~\ref{s:letrecvalues}. +\subsubsection{Explicit polymorphic type annotations} +(Introduced in OCaml 3.12) + +Polymorphic type annotations in @"let"@-definitions behave in a way +similar to polymorphic methods: + +\begin{center} +@"let" pattern_1 ":" typ_1 \ldots typ_n "." typeexpr "=" expr @ +\end{center} + +These annotations explicitly require the defined value to be polymorphic, +and allow one to use this polymorphism in recursive occurrences +(when using @"let" "rec"@). Note however that this is a normal polymorphic +type, unifiable with any instance of itself. + +\subsection{Control structures} + +\subsubsection*{Sequence} + +The expression @expr_1 ";" expr_2@ evaluates @expr_1@ first, then +@expr_2@, and returns the value of @expr_2@. + +\subsubsection*{Conditional} +\ikwd{if\@\texttt{if}} + +The expression @"if" expr_1 "then" expr_2 "else" expr_3@ evaluates to +the value of @expr_2@ if @expr_1@ evaluates to the boolean @"true"@, +and to the value of @expr_3@ if @expr_1@ evaluates to the boolean +@"false"@. + +The @"else" expr_3@ part can be omitted, in which case it defaults to +@"else" "()"@. + +\subsubsection*{Case expression}\ikwd{match\@\texttt{match}} + +The expression +$$\begin{array}{rlll} +\token{match} & \textsl{expr} \\ +\token{with} & \textsl{pattern}_1 & \token{->} & \textsl{expr}_1 \\ +\token{|} & \ldots \\ +\token{|} & \textsl{pattern}_n & \token{->} & \textsl{expr}_n +\end{array}$$ +matches the value of @expr@ against the patterns @pattern_1@ to +@pattern_n@. If the matching against @pattern_i@ succeeds, the +associated expression @expr_i@ is evaluated, and its value becomes the +value of the whole @'match'@ expression. The evaluation of +@expr_i@ takes place in an environment enriched by the bindings +performed during matching. If several patterns match the value of +@expr@, the one that occurs first in the @'match'@ expression is +selected. If none of the patterns match the value of @expr@, the +exception "Match_failure" is raised. +% +\index{Matchfailure\@\verb`Match_failure`} + +\subsubsection*{Boolean operators} + +The expression @expr_1 '&&' expr_2@ evaluates to @'true'@ if both +@expr_1@ and @expr_2@ evaluate to @'true'@; otherwise, it evaluates to +@'false'@. The first component, @expr_1@, is evaluated first. The +second component, @expr_2@, is not evaluated if the first component +evaluates to @'false'@. Hence, the expression @expr_1 '&&' expr_2@ behaves +exactly as +\begin{center} +@'if' expr_1 'then' expr_2 'else' 'false'@. +\end{center} + +The expression @expr_1 '||' expr_2@ evaluates to @'true'@ if one of +the expressions +@expr_1@ and @expr_2@ evaluates to @'true'@; otherwise, it evaluates to +@'false'@. The first component, @expr_1@, is evaluated first. The +second component, @expr_2@, is not evaluated if the first component +evaluates to @'true'@. Hence, the expression @expr_1 '||' expr_2@ behaves +exactly as +\begin{center} +@'if' expr_1 'then' 'true' 'else' expr_2@. +\end{center} + +\ikwd{or\@\texttt{or}} +The boolean operators @'&'@ and @'or'@ are deprecated synonyms for +(respectively) @'&&'@ and @'||'@. + +\subsubsection*{Loops} + +\ikwd{while\@\texttt{while}} +The expression @'while' expr_1 'do' expr_2 'done'@ repeatedly +evaluates @expr_2@ while @expr_1@ evaluates to @'true'@. The loop +condition @expr_1@ is evaluated and tested at the beginning of each +iteration. The whole @'while' \ldots 'done'@ expression evaluates to +the unit value @'()'@. + +\ikwd{for\@\texttt{for}} +The expression @'for' name '=' expr_1 'to' expr_2 'do' expr_3 'done'@ +first evaluates the expressions @expr_1@ and @expr_2@ (the boundaries) +into integer values \var{n} and \var{p}. Then, the loop body @expr_3@ is +repeatedly evaluated in an environment where @name@ is successively +bound to the values + $n$, $n+1$, \ldots, $p-1$, $p$. + The loop body is never evaluated if $n > p$. + + +The expression @'for' name '=' expr_1 'downto' expr_2 'do' expr_3 'done'@ +evaluates similarly, except that @name@ is successively bound to the values + $n$, $n-1$, \ldots, $p+1$, $p$. + The loop body is never evaluated if $n < p$. + + +In both cases, the whole @'for'@ expression evaluates to the unit +value @'()'@. + +\subsubsection*{Exception handling} +\ikwd{try\@\texttt{try}} + +The expression +$$\begin{array}{rlll} +\token{try~} & \textsl{expr} \\ +\token{with} & \textsl{pattern}_1 & \token{->} & \textsl{expr}_1 \\ +\token{|} & \ldots \\ +\token{|} & \textsl{pattern}_n & \token{->} & \textsl{expr}_n +\end{array}$$ +evaluates the expression @expr@ and returns its value if the +evaluation of @expr@ does not raise any exception. If the evaluation +of @expr@ raises an exception, the exception value is matched against +the patterns @pattern_1@ to @pattern_n@. If the matching against +@pattern_i@ succeeds, the associated expression @expr_i@ is evaluated, +and its value becomes the value of the whole @'try'@ expression. The +evaluation of @expr_i@ takes place in an environment enriched by the +bindings performed during matching. If several patterns match the value of +@expr@, the one that occurs first in the @'try'@ expression is +selected. If none of the patterns matches the value of @expr@, the +exception value is raised again, thereby transparently ``passing +through'' the @'try'@ construct. + +\subsection{Operations on data structures} + +\subsubsection*{Products} + +The expression @expr_1 ',' \ldots ',' expr_n@ evaluates to the +\var{n}-tuple of the values of expressions @expr_1@ to @expr_n@. The +evaluation order of the subexpressions is not specified. + +\subsubsection*{Variants} + +The expression @constr expr@ evaluates to the unary variant value +whose constructor is @constr@, and whose argument is the value of +@expr@. Similarly, the expression @constr '(' expr_1 ',' \ldots ',' +expr_n ')'@ evaluates to the n-ary variant value whose constructor is +@constr@ and whose arguments are the values of @expr_1, \ldots, +expr_n@. + +The expression @constr '('expr_1, \ldots, expr_n')'@ evaluates to the +variant value whose constructor is @constr@, and whose arguments are +the values of @expr_1 \ldots expr_n@. + +For lists, some syntactic sugar is provided. The expression +@expr_1 '::' expr_2@ stands for the constructor @'(' '::' ')' @ +applied to the arguments @'(' expr_1 ',' expr_2 ')'@, and therefore +evaluates to the list whose head is the value of @expr_1@ and whose tail +is the value of @expr_2@. The expression @'[' expr_1 ';' \ldots ';' +expr_n ']'@ is equivalent to @expr_1 '::' \ldots '::' expr_n '::' +'[]'@, and therefore evaluates to the list whose elements are the +values of @expr_1@ to @expr_n@. + +\subsubsection*{Polymorphic variants} + +The expression @"`"tag-name expr@ evaluates to the polymorphic variant +value whose tag is @tag-name@, and whose argument is the value of @expr@. + +\subsubsection*{Records} + +The expression @'{' field_1 ['=' expr_1] ';' \ldots ';' field_n ['=' +expr_n ']}'@ evaluates to the record value +$\{ field_1 = v_1; \ldots; field_n = v_n \}$ +where $v_i$ is the value of @expr_i@ for \fromoneto{i}{n}. +A single identifier @field_k@ stands for @field_k '=' field_k@, +and a qualified identifier @module-path '.' field_k@ stands for +@module-path '.' field_k '=' field_k@. +The fields @field_1@ to @field_n@ must all belong to the same record +type; each field of this record type must appear exactly +once in the record expression, though they can appear in any +order. The order in which @expr_1@ to @expr_n@ are evaluated is not +specified. Optional type constraints can be added after each field +@'{' field_1 ':' typexpr_1 '=' expr_1 ';'% + \ldots ';' field_n ':' typexpr_n '=' expr_n '}'@ +to force the type of @field_k@ to be compatible with @typexpr_k@. + +The expression +@"{" expr "with" field_1 ["=" expr_1] ";" \ldots ";" field_n ["=" expr_n] "}"@ +builds a fresh record with fields @field_1 \ldots field_n@ equal to +@expr_1 \ldots expr_n@, and all other fields having the same value as +in the record @expr@. In other terms, it returns a shallow copy of +the record @expr@, except for the fields @field_1 \ldots field_n@, +which are initialized to @expr_1 \ldots expr_n@. As previously, +single identifier @field_k@ stands for @field_k '=' field_k@, +a qualified identifier @module-path '.' field_k@ stands for +@module-path '.' field_k '=' field_k@ and it is +possible to add an optional type constraint on each field being updated +with +@"{" expr "with" field_1 ':' typexpr_1 "=" expr_1 ";" % + \ldots ";" field_n ':' typexpr_n "=" expr_n "}"@. + +The expression @expr_1 '.' field@ evaluates @expr_1@ to a record +value, and returns the value associated to @field@ in this record +value. + +The expression @expr_1 '.' field '<-' expr_2@ evaluates @expr_1@ to a record +value, which is then modified in-place by replacing the value +associated to @field@ in this record by the value of +@expr_2@. This operation is permitted only if @field@ has been +declared @'mutable'@ in the definition of the record type. The whole +expression @expr_1 '.' field '<-' expr_2@ evaluates to the unit value +@'()'@. + +\subsubsection*{Arrays} + +The expression @'[|' expr_1 ';' \ldots ';' expr_n '|]'@ evaluates to +a \var{n}-element array, whose elements are initialized with the values of +@expr_1@ to @expr_n@ respectively. The order in which these +expressions are evaluated is unspecified. + +The expression @expr_1 '.(' expr_2 ')'@ returns the value of element +number @expr_2@ in the array denoted by @expr_1@. The first element +has number 0; the last element has number $n-1$, where \var{n} is the +size of the array. The exception "Invalid_argument" is raised if the +access is out of bounds. + +The expression @expr_1 '.(' expr_2 ')' '<-' expr_3@ modifies in-place +the array denoted by @expr_1@, replacing element number @expr_2@ by +the value of @expr_3@. The exception "Invalid_argument" is raised if +the access is out of bounds. The value of the whole expression is @'()'@. + +\subsubsection*{Strings} + +The expression @expr_1 '.[' expr_2 ']'@ returns the value of character +number @expr_2@ in the string denoted by @expr_1@. The first character +has number 0; the last character has number $n-1$, where \var{n} is the +length of the string. The exception "Invalid_argument" is raised if the +access is out of bounds. + +The expression @expr_1 '.[' expr_2 ']' '<-' expr_3@ modifies in-place +the string denoted by @expr_1@, replacing character number @expr_2@ by +the value of @expr_3@. The exception "Invalid_argument" is raised if +the access is out of bounds. The value of the whole expression is @'()'@. + +{\bf Note:} this possibility is offered only for backward +compatibility with older versions of OCaml and will be removed in a +future version. New code should use byte sequences and the "Bytes.set" +function. + +\subsection{Operators} +\ikwd{mod\@\texttt{mod}} +\ikwd{land\@\texttt{land}} +\ikwd{lor\@\texttt{lor}} +\ikwd{lxor\@\texttt{lxor}} +\ikwd{lsl\@\texttt{lsl}} +\ikwd{lsr\@\texttt{lsr}} +\ikwd{asr\@\texttt{asr}} + +Symbols from the class @infix-symbol@, as well as the keywords +@"*"@, @"+"@, @"-"@, @'-.'@, @"="@, @"!="@, @"<"@, @">"@, @"or"@, @"||"@, +@"&"@, @"&&"@, @":="@, @"mod"@, @"land"@, @"lor"@, @"lxor"@, @"lsl"@, @"lsr"@, +and @"asr"@ can appear in infix position (between two +expressions). Symbols from the class @prefix-symbol@, as well as +the keywords @"-"@ and @"-."@ +can appear in prefix position (in front of an expression). + +Infix and prefix symbols do not have a fixed meaning: they are simply +interpreted as applications of functions bound to the names +corresponding to the symbols. The expression @prefix-symbol expr@ is +interpreted as the application @'(' prefix-symbol ')' +expr@. Similarly, the expression @expr_1 infix-symbol expr_2@ is +interpreted as the application @'(' infix-symbol ')' expr_1 expr_2@. + +The table below lists the symbols defined in the initial environment +and their initial meaning. (See the description of the core +library module "Pervasives" in chapter~\ref{c:corelib} for more +details). Their meaning may be changed at any time using +@"let" "(" infix-op ")" name_1 name_2 "=" \ldots@ + +Note: the operators @'&&'@, @'||'@, and @'~-'@ are handled specially +and it is not advisable to change their meaning. + +The keywords @'-'@ and @'-.'@ can appear both as infix and +prefix operators. When they appear as prefix operators, they are +interpreted respectively as the functions @'(~-)'@ and @'(~-.)'@. + +%% Conversely, a regular function identifier can also be used as an infix +%% operator by enclosing it in backquotes: @expr_1 '`' ident '`' expr_2@ +%% is interpreted as the application @ident expr_1 expr_2@. + +\ikwd{mod\@\texttt{mod}}% +\ikwd{land\@\texttt{land}}% +\ikwd{lor\@\texttt{lor}}% +\ikwd{lxor\@\texttt{lxor}}% +\ikwd{lsl\@\texttt{lsl}}% +\ikwd{lsr\@\texttt{lsr}}% +\ikwd{asr\@\texttt{asr}}% +\begin{tableau}{|l|p{12cm}|}{Operator}{Initial meaning} +\entree{"+"}{Integer addition.} +\entree{"-" (infix)}{Integer subtraction.} +\entree{"~- -" (prefix)}{Integer negation.} +\entree{"*"}{Integer multiplication.} +\entree{"/"}{Integer division. + Raise "Division_by_zero" if second argument is zero.} +\entree{"mod"}{Integer modulus. Raise + "Division_by_zero" if second argument is zero.} +\entree{"land"}{Bitwise logical ``and'' on integers.} +\entree{"lor"}{Bitwise logical ``or'' on integers.} +\entree{"lxor"}{Bitwise logical ``exclusive or'' on integers.} +\entree{"lsl"}{Bitwise logical shift left on integers.} +\entree{"lsr"}{Bitwise logical shift right on integers.} +\entree{"asr"}{Bitwise arithmetic shift right on integers.} +\entree{"+."}{Floating-point addition.} +\entree{"-." (infix)}{Floating-point subtraction.} +\entree{"~-. -." (prefix)}{Floating-point negation.} +\entree{"*."}{Floating-point multiplication.} +\entree{"/."}{Floating-point division.} +\entree{"**"}{Floating-point exponentiation.} +\entree{{\tt\char64} }{List concatenation.} +\entree{"^" }{String concatenation.} +\entree{"!" }{Dereferencing (return the current + contents of a reference).} +\entree{":="}{Reference assignment (update the + reference given as first argument with the value of the second + argument).} +\entree{"=" }{Structural equality test.} +\entree{"<>" }{Structural inequality test.} +\entree{"==" }{Physical equality test.} +\entree{"!=" }{Physical inequality test.} +\entree{"<" }{Test ``less than''.} +\entree{"<=" }{Test ``less than or equal''.} +\entree{">" }{Test ``greater than''.} +\entree{">=" }{Test ``greater than or equal''.} +\entree{"&& &"}{Boolean conjunction.} +\entree{"|| or"}{Boolean disjunction.} +\end{tableau} + +\subsection{Objects} \label{s:objects} + +\subsubsection*{Object creation} + +\ikwd{new\@\texttt{new}} + +When @class-path@ evaluates to a class body, @'new' class-path@ +evaluates to a new object containing the instance variables and +methods of this class. + +When @class-path@ evaluates to a class function, @'new' class-path@ +evaluates to a function expecting the same number of arguments and +returning a new object of this class. + +\subsubsection*{Immediate object creation} + +\ikwd{object\@\texttt{object}} + +Creating directly an object through the @'object' class-body 'end'@ +construct is operationally equivalent to defining locally a @'class' +class-name '=' 'object' class-body 'end'@ ---see sections +\ref{ss:class-body} and following for the syntax of @class-body@--- +and immediately creating a single object from it by @'new' class-name@. + +The typing of immediate objects is slightly different from explicitly +defining a class in two respects. First, the inferred object type may +contain free type variables. Second, since the class body of an +immediate object will never be extended, its self type can be unified +with a closed object type. + +\subsubsection*{Method invocation} + +The expression @expr '#' method-name@ invokes the method +@method-name@ of the object denoted by @expr@. + +If @method-name@ is a polymorphic method, its type should be known at +the invocation site. This is true for instance if @expr@ is the name +of a fresh object (@'let' ident = 'new' class-path \dots @) or if +there is a type constraint. Principality of the derivation can be +checked in the "-principal" mode. + +\subsubsection*{Accessing and modifying instance variables} + +The instance variables of a class are visible only in the body of the +methods defined in the same class or a class that inherits from the +class defining the instance variables. The expression @inst-var-name@ +evaluates to the value of the given instance variable. The expression +@inst-var-name '<-' expr@ assigns the value of @expr@ to the instance +variable @inst-var-name@, which must be mutable. The whole expression +@inst-var-name '<-' expr@ evaluates to @"()"@. + + +\subsubsection*{Object duplication} + +An object can be duplicated using the library function "Oo.copy" +(see +\ifouthtml \ahref{libref/Oo.html}{Module \texttt{Oo}}\else +section~\ref{Oo}\fi). Inside a method, the expression +@ '{<' inst-var-name '=' expr { ';' inst-var-name '=' expr } '>}'@ +returns a copy of self with the given instance variables replaced by +the values of the associated expressions; other instance variables +have the same value in the returned object as in self. + +\subsection{Coercions} \label{s:coercions} + +Expressions whose type contains object or polymorphic variant types +can be explicitly coerced (weakened) to a supertype. +% +The expression @'('expr ':>' typexpr')'@ coerces the expression @expr@ +to type @typexpr@. +% +The expression @'('expr ':' typexpr_1 ':>' typexpr_2')'@ coerces the +expression @expr@ from type @typexpr_1@ to type @typexpr_2@. + +The former operator will sometimes fail to coerce an expression @expr@ +from a type @typ_1@ to a type @typ_2@ +even if type @typ_1@ is a subtype of type +@typ_2@: in the current implementation it only expands two levels of +type abbreviations containing objects and/or polymorphic variants, +keeping only recursion when it is explicit in the class type (for objects). +As an exception to the above algorithm, if both the inferred type of @expr@ +and @typ@ are ground ({\em i.e.} do not contain type variables), the +former operator behaves as the latter one, taking the inferred type of +@expr@ as @typ_1@. In case of failure with the former operator, +the latter one should be used. + +It is only possible to coerce an expression @expr@ from type +@typ_1@ to type @typ_2@, if the type of @expr@ is an instance of +@typ_1@ (like for a type annotation), and @typ_1@ is a subtype +of @typ_2@. The type of the coerced expression is an +instance of @typ_2@. If the types contain variables, +they may be instantiated by the subtyping algorithm, but this is only +done after determining whether @typ_1@ is a potential subtype of +@typ_2@. This means that typing may fail during this latter +unification step, even if some instance of @typ_1@ is a subtype of +some instance of @typ_2@. +% +In the following paragraphs we describe the subtyping relation used. + +\subsubsection*{Object types} + +A fixed object type admits as subtype any object type that includes all +its methods. The types of the methods shall be subtypes of those in +the supertype. Namely, +\begin{center} +@ '<' met_1 ':' typ_1 ';' \dots ';' met_n ':' typ_n '>' @ +\end{center} +is a supertype of +\begin{center} +@ '<' met_1 ':' typ@$'_1$@ ';' \dots ';' met_n ':' typ@$'_n$@ ';' +met@$_{n+1}$@ ':' typ@$'_{n+1}$@ ';' \dots ';' met@$_{n+m}$@ ':' typ@$'_{n+m}$@ +~[';' '..'] '>' @ +\end{center} +which may contain an ellipsis ".." if every @typ_i@ is a supertype of +the corresponding @typ@$'_i$. + +A monomorphic method type can be a supertype of a polymorphic method +type. Namely, if @typ@ is an instance of @typ@$'$, then @ "'"@a@_1 +\dots "'"@a@_n '.' typ@$'$ is a subtype of @typ@. + +Inside a class definition, newly defined types are not available for +subtyping, as the type abbreviations are not yet completely +defined. There is an exception for coercing @@self@@ to the (exact) +type of its class: this is allowed if the type of @@self@@ does not +appear in a contravariant position in the class type, {\em i.e.} if +there are no binary methods. + +\subsubsection*{Polymorphic variant types} + +A polymorphic variant type @typ@ is a subtype of another polymorphic +variant type @typ@$'$ if the upper bound of @typ@ ({\em i.e.} the +maximum set of constructors that may appear in an instance of @typ@) +is included in the lower bound of @typ@$'$, and the types of arguments +for the constructors of @typ@ are subtypes of those in +@typ@$'$. Namely, +\begin{center} +@ "["["<"] "`"C_1 "of" typ_1 "|" \dots "|" "`"C_n "of" typ_n "]" @ +\end{center} +which may be a shrinkable type, is a subtype of +\begin{center} +@ "["[">"] "`"C_1 "of" typ@$'_1$@ "|" \dots "|" "`"C_n "of" typ@$'_n$@ + "|" "`"C@$_{n+1}$@ "of" typ@$'_{n+1}$@ "|" \dots "|" "`"C@$_{n+m}$@ "of" + typ@$'_{n+m}$@ "]" @ +\end{center} +which may be an extensible type, if every @typ_i@ is a subtype of @typ@$'_i$. + +\subsubsection*{Variance} + +Other types do not introduce new subtyping, but they may propagate the +subtyping of their arguments. For instance, @typ_1 "*" typ_2@ is a +subtype of @typ@$'_1$@ "*" typ@$'_2$ when @typ_1@ and @typ_2@ are +respectively subtypes of @typ@$'_1$ and @typ@$'_2$. +For function types, the relation is more subtle: +@typ_1 "->" typ_2@ is a subtype of @typ@$'_1$@~"->" typ@$'_2$ +if @typ_1@ is a supertype of @typ@$'_1$ and @typ_2@ is a +subtype of @typ@$'_2$. For this reason, function types are covariant in +their second argument (like tuples), but contravariant in their first +argument. Mutable types, like "array" or "ref" are neither covariant +nor contravariant, they are nonvariant, that is they do not propagate +subtyping. + +For user-defined types, the variance is automatically inferred: a +parameter is covariant if it has only covariant occurrences, +contravariant if it has only contravariant occurrences, +variance-free if it has no occurrences, and nonvariant otherwise. +A variance-free parameter may change freely through subtyping, it does +not have to be a subtype or a supertype. +% +For abstract and private types, the variance must be given explicitly +(see section~\ref{s:type-defs}), +otherwise the default is nonvariant. This is also the case for +constrained arguments in type definitions. + + +\subsection{Other} + +\subsubsection*{Assertion checking} + + +\ikwd{assert\@\texttt{assert}} + +OCaml supports the @"assert"@ construct to check debugging assertions. +The expression @"assert" expr@ evaluates the expression @expr@ and +returns @"()"@ if @expr@ evaluates to @"true"@. If it evaluates to +@"false"@ the exception +"Assert_failure" is raised with the source file name and the +location of @expr@ as arguments. Assertion +checking can be turned off with the "-noassert" compiler option. In +this case, @expr@ is not evaluated at all. + +As a special case, @"assert false"@ is reduced to +@'raise' '('@"Assert_failure ..."@')'@, which gives it a polymorphic +type. This means that it can be used in place of any expression (for +example as a branch of any pattern-matching). It also means that +the @"assert false"@ ``assertions'' cannot be turned off by the +"-noassert" option. +% +\index{Assertfailure\@\verb`Assert_failure`} + +\subsubsection*{Lazy expressions} +\ikwd{lazy\@\texttt{lazy}} + +The expression @"lazy" expr@ returns a value \var{v} of type "Lazy.t" that +encapsulates the computation of @expr@. The argument @expr@ is not +evaluated at this point in the program. Instead, its evaluation will +be performed the first time the function "Lazy.force" is applied to the value +\var{v}, returning the actual value of @expr@. Subsequent applications +of "Lazy.force" to \var{v} do not evaluate @expr@ again. Applications +of "Lazy.force" may be implicit through pattern matching (see~\ref{s:lazypat}). + +\subsubsection*{Local modules} +\ikwd{let\@\texttt{let}} +\ikwd{module\@\texttt{module}} + +The expression +@"let" "module" module-name "=" module-expr "in" expr@ +locally binds the module expression @module-expr@ to the identifier +@module-name@ during the evaluation of the expression @expr@. +It then returns the value of @expr@. For example: +\begin{verbatim} + let remove_duplicates comparison_fun string_list = + let module StringSet = + Set.Make(struct type t = string + let compare = comparison_fun end) in + StringSet.elements + (List.fold_right StringSet.add string_list StringSet.empty) +\end{verbatim} + +\subsubsection*{Local opens} +\ikwd{let\@\texttt{let}} +\ikwd{module\@\texttt{open}} + +The expressions @"let" "open" module-path "in" expr@ and +@module-path'.('expr')'@ are strictly equivalent. These +constructions locally open the module referred to by the module path +@module-path@ in the respective scope of the expression @expr@. + +When the body of a local open expression is delimited by +@'[' ']'@, @'[|' '|]'@, or @'{' '}'@, the parentheses can be omitted. +For expression, parentheses can also be omitted for @'{<' '>}'@. +For example, @module-path'.['expr']'@ is equivalent to +@module-path'.(['expr'])'@, and @module-path'.[|' expr '|]'@ is +equivalent to @module-path'.([|' expr '|])'@. + +%% \newpage diff --git a/manual/manual/refman/exten.etex b/manual/manual/refman/exten.etex new file mode 100644 index 00000000..080354d8 --- /dev/null +++ b/manual/manual/refman/exten.etex @@ -0,0 +1,2393 @@ +\chapter{Language extensions} \label{c:extensions} +\pdfchapter{Language extensions} +%HEVEA\cutname{extn.html} + +This chapter describes language extensions and convenience features +that are implemented in OCaml, but not described in the +OCaml reference manual. + +\section{Integer literals for types \texttt{int32}, \texttt{int64} + and \texttt{nativeint}} \label{s:ext-integer} + +(Introduced in Objective Caml 3.07) + +\begin{syntax} +constant: ... + | int32-literal + | int64-literal + | nativeint-literal +; +int32-literal: integer-literal 'l' +; +int64-literal: integer-literal 'L' +; +nativeint-literal: integer-literal 'n' +\end{syntax} + +An integer literal can be followed by one of the letters "l", "L" or "n" +to indicate that this integer has type "int32", "int64" or "nativeint" +respectively, instead of the default type "int" for integer literals. +\index{int32\@\verb`int32`} +\index{int64\@\verb`int64`} +\index{nativeint\@\verb`nativeint`} +The library modules "Int32"[\moduleref{Int32}], +"Int64"[\moduleref{Int64}] and "Nativeint"[\moduleref{Nativeint}] +provide operations on these integer types. + +\section{Recursive definitions of values} \label{s:letrecvalues} + +(Introduced in Objective Caml 1.00) + +As mentioned in section~\ref{s:localdef}, the @'let' 'rec'@ binding +construct, in addition to the definition of recursive functions, +also supports a certain class of recursive definitions of +non-functional values, such as +\begin{center} +@"let" "rec" name_1 "=" "1" "::" name_2 +"and" name_2 "=" "2" "::" name_1 +"in" expr@ +\end{center} +which binds @name_1@ to the cyclic list "1::2::1::2::"\ldots, and +@name_2@ to the cyclic list "2::1::2::1::"\ldots +Informally, the class of accepted definitions consists of those +definitions where the defined names occur only inside function +bodies or as argument to a data constructor. + +More precisely, consider the expression: +\begin{center} +@"let" "rec" name_1 "=" expr_1 "and" \ldots "and" name_n "=" expr_n "in" expr@ +\end{center} +It will be accepted if each one of @expr_1 \ldots expr_n@ is +statically constructive with respect to @name_1 \ldots name_n@, +is not immediately linked to any of @name_1 \ldots name_n@, +and is not an array constructor whose arguments have abstract type. + +An expression @@e@@ is said to be {\em statically constructive +with respect to} the variables @name_1 \ldots name_n@ if at least +one of the following conditions is true: +\begin{itemize} +\item @@e@@ has no free occurrence of any of @name_1 \ldots name_n@ +\item @@e@@ is a variable +\item @@e@@ has the form @"fun" \ldots "->" \ldots@ +\item @@e@@ has the form @"function" \ldots "->" \ldots@ +\item @@e@@ has the form @"lazy" "(" \ldots ")"@ +\item @@e@@ has one of the following forms, where each one of + @expr_1 \ldots expr_m@ is statically constructive with respect to + @name_1 \ldots name_n@, and @expr_0@ is statically constructive with + respect to @name_1 \ldots name_n, xname_1 \ldots xname_m@: + \begin{itemize} + \item @"let" ["rec"] xname_1 "=" expr_1 "and" \ldots + "and" xname_m "=" expr_m "in" expr_0@ + \item @"let" "module" \ldots "in" expr_1@ + \item @constr "("expr_1"," \ldots "," expr_m")"@ + \item @"`"tag-name "("expr_1"," \ldots "," expr_m")"@ + \item @"[|" expr_1";" \ldots ";" expr_m "|]"@ + \item @"{" field_1 "=" expr_1";" \ldots ";" field_m = expr_m "}"@ + \item @"{" expr_1 "with" field_2 "=" expr_2";" \ldots ";" + field_m = expr_m "}"@ where @expr_1@ is not immediately + linked to @name_1 \ldots name_n@ + \item @"(" expr_1"," \ldots "," expr_m ")"@ + \item @expr_1";" \ldots ";" expr_m@ + \end{itemize} +\end{itemize} + +An expression @@e@@ is said to be {\em immediately linked to} the variable +@name@ in the following cases: +\begin{itemize} +\item @@e@@ is @name@ +\item @@e@@ has the form @expr_1";" \ldots ";" expr_m@ where @expr_m@ + is immediately linked to @name@ +\item @@e@@ has the form @"let" ["rec"] xname_1 "=" expr_1 "and" \ldots + "and" xname_m "=" expr_m "in" expr_0@ where @expr_0@ is immediately + linked to @name@ or to one of the @xname_i@ such that @expr_i@ + is immediately linked to @name@. +\end{itemize} + +\section{Lazy patterns} \label{s:lazypat} + +\ikwd{lazy\@\texttt{lazy}} + +(Introduced in Objective Caml 3.11) + +\begin{syntax} +pattern: ... + | 'lazy' pattern +\end{syntax} + +The pattern @"lazy" pattern@ matches a value \var{v} of type "Lazy.t", +provided @pattern@ matches the result of forcing \var{v} with +"Lazy.force". A successful match of a pattern containing @"lazy"@ +sub-patterns forces the corresponding parts of the value being matched, even +those that imply no test such as @"lazy" value-name@ or @"lazy" "_"@. +Matching a value with a @pattern-matching@ where some patterns +contain @"lazy"@ sub-patterns may imply forcing parts of the value, +even when the pattern selected in the end has no @"lazy"@ sub-pattern. + +For more information, see the description of module "Lazy" in the +standard library ( +\ifouthtml +\ahref{libref/Lazy.html}{Module \texttt{Lazy}}\else section~\ref{Lazy}\fi). +% +\index{Lazy (module)\@\verb`Lazy` (module)}% +\index{force\@\verb`force`}% + +\section{Recursive modules} \label{s-recursive-modules} +\ikwd{module\@\texttt{module}} +\ikwd{and\@\texttt{and}} + +(Introduced in Objective Caml 3.07) + +% TODO: relaxed syntax + +\begin{syntax} +definition: + ... + | 'module' 'rec' module-name ':' module-type '=' module-expr \\ + { 'and' module-name ':' module-type '=' module-expr } +; +specification: + ... + | 'module' 'rec' module-name ':' module-type + { 'and' module-name':' module-type } +\end{syntax} + +Recursive module definitions, introduced by the @"module rec"@ \ldots +@"and"@ \ldots\ construction, generalize regular module definitions +@'module' module-name '=' module-expr@ and module specifications +@'module' module-name ':' module-type@ by allowing the defining +@module-expr@ and the @module-type@ to refer recursively to the module +identifiers being defined. A typical example of a recursive module +definition is: +\begin{verbatim} + module rec A : sig + type t = Leaf of string | Node of ASet.t + val compare: t -> t -> int + end + = struct + type t = Leaf of string | Node of ASet.t + let compare t1 t2 = + match (t1, t2) with + (Leaf s1, Leaf s2) -> Pervasives.compare s1 s2 + | (Leaf _, Node _) -> 1 + | (Node _, Leaf _) -> -1 + | (Node n1, Node n2) -> ASet.compare n1 n2 + end + and ASet : Set.S with type elt = A.t + = Set.Make(A) +\end{verbatim} +It can be given the following specification: +\begin{verbatim} + module rec A : sig + type t = Leaf of string | Node of ASet.t + val compare: t -> t -> int + end + and ASet : Set.S with type elt = A.t +\end{verbatim} + +This is an experimental extension of OCaml: the class of +recursive definitions accepted, as well as its dynamic semantics are +not final and subject to change in future releases. + +Currently, the compiler requires that all dependency cycles between +the recursively-defined module identifiers go through at least one +``safe'' module. A module is ``safe'' if all value definitions that +it contains have function types @typexpr_1 '->' typexpr_2@. Evaluation of a +recursive module definition proceeds by building initial values for +the safe modules involved, binding all (functional) values to +@'fun' '_' '->' 'raise' @"Undefined_recursive_module". The defining +module expressions are then evaluated, and the initial values +for the safe modules are replaced by the values thus computed. If a +function component of a safe module is applied during this computation +(which corresponds to an ill-founded recursive definition), the +"Undefined_recursive_module" exception is raised at runtime: + +\begin{caml_example}{verbatim} +module rec M: sig val f: unit -> int end = struct let f () = N.x end +and N:sig val x: int end = struct let x = M.f () end +\end{caml_example} + +If there are no safe modules along a dependency cycle, an error is raised + +\begin{caml_example}{verbatim}[error] +module rec M: sig val x: int end = struct let x = N.y end +and N:sig val x: int val y:int end = struct let x = M.x let y = 0 end +\end{caml_example} + +Note that, in the @specification@ case, the @module-type@s must be +parenthesized if they use the @'with' mod-constraint@ construct. + +\section{Private types}\label{s:private-types} +\ikwd{private\@\texttt{private}} + +Private type declarations in module signatures, of the form +"type t = private ...", enable libraries to +reveal some, but not all aspects of the implementation of a type to +clients of the library. In this respect, they strike a middle ground +between abstract type declarations, where no information is revealed +on the type implementation, and data type definitions and type +abbreviations, where all aspects of the type implementation are +publicized. Private type declarations come in three flavors: for +variant and record types (section~\ref{s-private-types-variant}), +for type abbreviations (section~\ref{s-private-types-abbrev}), +and for row types (section~\ref{s-private-rows}). + +\subsection{Private variant and record types} \label{s-private-types-variant} + +(Introduced in Objective Caml 3.07) + +\begin{syntax} +type-representation: + ... + | '=' 'private' [ '|' ] constr-decl { '|' constr-decl } + | '=' 'private' record-decl +\end{syntax} + +Values of a variant or record type declared @"private"@ +can be de-structured normally in pattern-matching or via +the @expr '.' field@ notation for record accesses. However, values of +these types cannot be constructed directly by constructor application +or record construction. Moreover, assignment on a mutable field of a +private record type is not allowed. + +The typical use of private types is in the export signature of a +module, to ensure that construction of values of the private type always +go through the functions provided by the module, while still allowing +pattern-matching outside the defining module. For example: +\begin{verbatim} + module M : sig + type t = private A | B of int + val a : t + val b : int -> t + end + = struct + type t = A | B of int + let a = A + let b n = assert (n > 0); B n + end +\end{verbatim} +Here, the @"private"@ declaration ensures that in any value of type +"M.t", the argument to the "B" constructor is always a positive integer. + +With respect to the variance of their parameters, private types are +handled like abstract types. That is, if a private type has +parameters, their variance is the one explicitly given by prefixing +the parameter by a `"+"' or a `"-"', it is invariant otherwise. + +\subsection{Private type abbreviations} \label{s-private-types-abbrev} + +(Introduced in Objective Caml 3.11) + +\begin{syntax} +type-equation: + ... + | '=' 'private' typexpr +\end{syntax} + +Unlike a regular type abbreviation, a private type abbreviation +declares a type that is distinct from its implementation type @typexpr@. +However, coercions from the type to @typexpr@ are permitted. +Moreover, the compiler ``knows'' the implementation type and can take +advantage of this knowledge to perform type-directed optimizations. + +The following example uses a private type abbreviation to define a +module of nonnegative integers: +\begin{verbatim} + module N : sig + type t = private int + val of_int: int -> t + val to_int: t -> int + end + = struct + type t = int + let of_int n = assert (n >= 0); n + let to_int n = n + end +\end{verbatim} +The type "N.t" is incompatible with "int", ensuring that nonnegative +integers and regular integers are not confused. However, if "x" has +type "N.t", the coercion "(x :> int)" is legal and returns the +underlying integer, just like "N.to_int x". Deep coercions are also +supported: if "l" has type "N.t list", the coercion "(l :> int list)" +returns the list of underlying integers, like "List.map N.to_int l" +but without copying the list "l". + +Note that the coercion @"(" expr ":>" typexpr ")"@ is actually an abbreviated +form, +and will only work in presence of private abbreviations if neither the +type of @expr@ nor @typexpr@ contain any type variables. If they do, +you must use the full form @"(" expr ":" typexpr_1 ":>" typexpr_2 ")"@ where +@typexpr_1@ is the expected type of @expr@. Concretely, this would be "(x : +N.t :> int)" and "(l : N.t list :> int list)" for the above examples. + +\subsection{Private row types} \label{s-private-rows} +\ikwd{private\@\texttt{private}} + +(Introduced in Objective Caml 3.09) + +\begin{syntax} +type-equation: + ... + | '=' 'private' typexpr +\end{syntax} + +Private row types are type abbreviations where part of the +structure of the type is left abstract. Concretely @typexpr@ in the +above should denote either an object type or a polymorphic variant +type, with some possibility of refinement left. If the private +declaration is used in an interface, the corresponding implementation +may either provide a ground instance, or a refined private type. +\begin{verbatim} + module M : sig type c = private < x : int; .. > val o : c end = + struct + class c = object method x = 3 method y = 2 end + let o = new c + end +\end{verbatim} +This declaration does more than hiding the "y" method, it also makes +the type "c" incompatible with any other closed object type, meaning +that only "o" will be of type "c". In that respect it behaves +similarly to private record types. But private row types are +more flexible with respect to incremental refinement. This feature can +be used in combination with functors. +\begin{verbatim} + module F(X : sig type c = private < x : int; .. > end) = + struct + let get_x (o : X.c) = o#x + end + module G(X : sig type c = private < x : int; y : int; .. > end) = + struct + include F(X) + let get_y (o : X.c) = o#y + end +\end{verbatim} + +A polymorphic variant type [t], for example +\begin{verbatim} + type t = [ `A of int | `B of bool ] +\end{verbatim} +can be refined in two ways. A definition [u] may add new field to [t], +and the declaration +\begin{verbatim} + type u = private [> t] +\end{verbatim} +will keep those new fields abstract. Construction of values of type +[u] is possible using the known variants of [t], but any +pattern-matching will require a default case to handle the potential +extra fields. Dually, a declaration [u] may restrict the fields of [t] +through abstraction: the declaration +\begin{verbatim} + type v = private [< t > `A] +\end{verbatim} +corresponds to private variant types. One cannot create a value of the +private type [v], except using the constructors that are explicitly +listed as present, "(`A n)" in this example; yet, when +patter-matching on a [v], one should assume that any of the +constructors of [t] could be present. + +Similarly to abstract types, the variance of type parameters +is not inferred, and must be given explicitly. + + +\section{Local opens for patterns} +\ikwd{let\@\texttt{let}} +\ikwd{open\@\texttt{open}} \label{s:local-opens} + +(Introduced in OCaml 4.04) + +\begin{syntax} +pattern: + ... + | module-path '.(' pattern ')' + | module-path '.[' pattern ']' + | module-path '.[|' pattern '|]' + | module-path '.{' pattern '}' + +\end{syntax} + +For patterns, local opens are limited to the +@module-path'.('pattern')'@ construction. This +construction locally open the module referred to by the module path +@module-path@ in the scope of the pattern @pattern@. + +When the body of a local open pattern is delimited by +@'[' ']'@, @'[|' '|]'@, or @'{' '}'@, the parentheses can be omitted. +For example, @module-path'.['pattern']'@ is equivalent to +@module-path'.(['pattern'])'@, and @module-path'.[|' pattern '|]'@ is +equivalent to @module-path'.([|' pattern '|])'@. + +\section{Object copy short notations} \label{s:object-notations} +\ikwd{with\@\texttt{with}} + +(Introduced in OCaml 4.03) + +\begin{syntax} +expr: + ... + | '{' '<' expr 'with' field ['=' expr] { ';' field ['=' expr] } [';'] '>' '}' +\end{syntax} + +In an object copy expression, +a single identifier @id@ stands for @id '=' id@, and a qualified identifier +@module-path '.' id@ stands for @module-path '.' id '=' id@. +For example, all following methods are equivalent: +\begin{verbatim} + object + val x=0. val y=0. val z=0. + method f_0 x y = {< x; y >} + method f_1 x y = {< x = x; y >} + method f_2 x y = {< x=x ; y = y >} + end +\end{verbatim} + +\section{Locally abstract types} +\ikwd{type\@\texttt{type}} +\ikwd{fun\@\texttt{fun}} \label{s:locally-abstract} + +(Introduced in OCaml 3.12, short syntax added in 4.03) + +\begin{syntax} +parameter: + ... + | '(' "type" {{typeconstr-name}} ')' +\end{syntax} + +The expression @"fun" '(' "type" typeconstr-name ')' "->" expr@ introduces a +type constructor named @typeconstr-name@ which is considered abstract +in the scope of the sub-expression, but then replaced by a fresh type +variable. Note that contrary to what the syntax could suggest, the +expression @"fun" '(' "type" typeconstr-name ')' "->" expr@ itself does not +suspend the evaluation of @expr@ as a regular abstraction would. The +syntax has been chosen to fit nicely in the context of function +declarations, where it is generally used. It is possible to freely mix +regular function parameters with pseudo type parameters, as in: +\begin{caml_example*}{verbatim} + let f = fun (type t) (foo : t list) -> assert false[@ellipsis] +\end{caml_example*} +and even use the alternative syntax for declaring functions: +\begin{caml_example*}{verbatim} + let f (type t) (foo : t list) = assert false[@ellipsis] +\end{caml_example*} +If several locally abstract types need to be introduced, it is possible to use +the syntax +@"fun" '(' "type" typeconstr-name_1 \ldots typeconstr-name_n ')' "->" expr@ +as syntactic sugar for @"fun" '(' "type" typeconstr-name_1 ')' "->" \ldots "->" +"fun" '(' "type" typeconstr-name_n ')' "->" expr@. For instance, +\begin{caml_example*}{verbatim} + let f = fun (type t u v) -> fun (foo : (t * u * v) list) -> assert false[@ellipsis] + let f' (type t u v) (foo : (t * u * v) list) = assert false[@ellipsis] +\end{caml_example} + +This construction is useful because the type constructors it introduces +can be used in places where a type variable is not allowed. For +instance, one can use it to define an exception in a local module +within a polymorphic function. +\begin{verbatim} + let f (type t) () = + let module M = struct exception E of t end in + (fun x -> M.E x), (function M.E x -> Some x | _ -> None) +\end{verbatim} + +Here is another example: +\begin{verbatim} + let sort_uniq (type s) (cmp : s -> s -> int) = + let module S = Set.Make(struct type t = s let compare = cmp end) in + fun l -> + S.elements (List.fold_right S.add l S.empty) +\end{verbatim} + +It is also extremely useful for first-class modules (see +section~\ref{s-first-class-modules}) and generalized algebraic datatypes +(GADTs: see section~\ref{s:gadts}). + +\paragraph{Polymorphic syntax} (Introduced in OCaml 4.00) + +\begin{syntax} +let-binding: + ... + | value-name ':' 'type' {{ typeconstr-name }} '.' typexpr '=' expr +; +class-field: + ... + | 'method' ['private'] method-name ':' 'type' + {{ typeconstr-name }} '.' typexpr '=' expr + | 'method!' ['private'] method-name ':' 'type' + {{ typeconstr-name }} '.' typexpr '=' expr +\end{syntax} + +The @"(type" typeconstr-name")"@ syntax construction by itself does not make +polymorphic the type variable it introduces, but it can be combined +with explicit polymorphic annotations where needed. +The above rule is provided as syntactic sugar to make this easier: +\begin{caml_example*}{verbatim} + let rec f : type t1 t2. t1 * t2 list -> t1 = assert false[@ellipsis] +\end{caml_example*} +\noindent +is automatically expanded into +\begin{caml_example*}{verbatim} + let rec f : 't1 't2. 't1 * 't2 list -> 't1 = + fun (type t1) (type t2) -> ( assert false[@ellipsis] : t1 * t2 list -> t1) +\end{caml_example*} +This syntax can be very useful when defining recursive functions involving +GADTs, see the section~\ref{s:gadts} for a more detailed explanation. + +The same feature is provided for method definitions. + +\section{First-class modules}\label{s-first-class-modules} +\ikwd{module\@\texttt{module}} +\ikwd{val\@\texttt{val}} +\ikwd{with\@\texttt{with}} +\ikwd{and\@\texttt{and}} + +(Introduced in OCaml 3.12; pattern syntax and package type inference +introduced in 4.00; structural comparison of package types introduced in 4.02.; +fewer parens required starting from 4.05) + +\begin{syntax} +typexpr: + ... + | '(''module' package-type')' +; +module-expr: + ... + | '(''val' expr [':' package-type]')' +; +expr: + ... + | '(''module' module-expr [':' package-type]')' +; +pattern: + ... + | '(''module' module-name [':' package-type]')' +; +package-type: + modtype-path + | modtype-path 'with' package-constraint { 'and' package-constraint } +; +package-constraint: + 'type' typeconstr '=' typexpr +; +\end{syntax} + +Modules are typically thought of as static components. This extension +makes it possible to pack a module as a first-class value, which can +later be dynamically unpacked into a module. + +The expression @'(' 'module' module-expr ':' package-type ')'@ converts the +module (structure or functor) denoted by module expression @module-expr@ +to a value of the core language that encapsulates this module. The +type of this core language value is @'(' 'module' package-type ')'@. +The @package-type@ annotation can be omitted if it can be inferred +from the context. + +Conversely, the module expression @'(' 'val' expr ':' package-type ')'@ +evaluates the core language expression @expr@ to a value, which must +have type @'module' package-type@, and extracts the module that was +encapsulated in this value. Again @package-type@ can be omitted if the +type of @expr@ is known. +If the module expression is already parenthesized, like the arguments +of functors are, no additional parens are needed: "Map.Make(val key)". + +The pattern @'(' 'module' module-name ':' package-type ')'@ matches a +package with type @package-type@ and binds it to @module-name@. +It is not allowed in toplevel let bindings. +Again @package-type@ can be omitted if it can be inferred from the +enclosing pattern. + +The @package-type@ syntactic class appearing in the @'(' 'module' +package-type ')'@ type expression and in the annotated forms represents a +subset of module types. +This subset consists of named module types with optional constraints +of a limited form: only non-parametrized types can be specified. + +For type-checking purposes (and starting from OCaml 4.02), package types +are compared using the structural comparison of module types. + +In general, the module expression @'(' "val" expr ":" package-type +')'@ cannot be used in the body of a functor, because this could cause +unsoundness in conjunction with applicative functors. +Since OCaml 4.02, this is relaxed in two ways: +if @package-type@ does not contain nominal type declarations ({\em + i.e.} types that are created with a proper identity), then this +expression can be used anywhere, and even if it contains such types +it can be used inside the body of a generative +functor, described in section~\ref{s:generative-functors}. +It can also be used anywhere in the context of a local module binding +@'let' 'module' module-name '=' '(' "val" expr_1 ":" package-type ')' + "in" expr_2@. + +\paragraph{Basic example} A typical use of first-class modules is to +select at run-time among several implementations of a signature. +Each implementation is a structure that we can encapsulate as a +first-class module, then store in a data structure such as a hash +table: +\begin{caml_example*}{verbatim} + module type DEVICE = sig [@@@ellipsis] end + let devices : (string, (module DEVICE)) Hashtbl.t = Hashtbl.create 17 + + module SVG = struct [@@@ellipsis] end + let _ = Hashtbl.add devices "SVG" (module SVG : DEVICE) + + module PDF = struct [@@@ellipsis] end + let _ = Hashtbl.add devices "PDF" (module PDF: DEVICE) +\end{caml_example*} +We can then select one implementation based on command-line +arguments, for instance: +\begin{verbatim} + module Device = + (val (try Hashtbl.find devices (parse_cmdline()) + with Not_found -> eprintf "Unknown device %s\n"; exit 2) + : DEVICE) +\end{verbatim} +Alternatively, the selection can be performed within a function: +\begin{verbatim} + let draw_using_device device_name picture = + let module Device = + (val (Hashtbl.find devices device_name) : DEVICE) + in + Device.draw picture +\end{verbatim} + +\paragraph{Advanced examples} +With first-class modules, it is possible to parametrize some code over the +implementation of a module without using a functor. + +\begin{verbatim} + let sort (type s) (module Set : Set.S with type elt = s) l = + Set.elements (List.fold_right Set.add l Set.empty) + val sort : (module Set.S with type elt = 'a) -> 'a list -> 'a list +\end{verbatim} + +To use this function, one can wrap the "Set.Make" functor: + +\begin{verbatim} + let make_set (type s) cmp = + let module S = Set.Make(struct + type t = s + let compare = cmp + end) in + (module S : Set.S with type elt = s) + val make_set : ('a -> 'a -> int) -> (module Set.S with type elt = 'a) +\end{verbatim} + +\iffalse +Another advanced use of first-class module is to encode existential +types. In particular, they can be used to simulate generalized +algebraic data types (GADT). To demonstrate this, we first define a type +of witnesses for type equalities: + +\begin{verbatim} + module TypEq : sig + type ('a, 'b) t + val apply: ('a, 'b) t -> 'a -> 'b + val refl: ('a, 'a) t + val sym: ('a, 'b) t -> ('b, 'a) t + end = struct + type ('a, 'b) t = ('a -> 'b) * ('b -> 'a) + let refl = (fun x -> x), (fun x -> x) + let apply (f, _) x = f x + let sym (f, g) = (g, f) + end +\end{verbatim} + +We can then define a parametrized algebraic data type whose +constructors provide some information about the type parameter: + +\begin{verbatim} + module rec Typ : sig + module type PAIR = sig + type t and t1 and t2 + val eq: (t, t1 * t2) TypEq.t + val t1: t1 Typ.typ + val t2: t2 Typ.typ + end + + type 'a typ = + | Int of ('a, int) TypEq.t + | String of ('a, string) TypEq.t + | Pair of (module PAIR with type t = 'a) + end = Typ +\end{verbatim} + +Values of type "'a typ" are supposed to be runtime representations for +the type "'a". The constructors "Int" and "String" are easy: they +directly give a witness of type equality between the parameter "'a" +and the ground types "int" (resp. "string"). The constructor "Pair" is +more complex. One wants to give a witness of type equality between +"'a" and a type of the form "t1 * t2" together with the representations +for "t1" and "t2". However, these two types are unknown. The code above +shows how to use first-class modules to simulate existentials. + +Here is how to construct values of type "'a typ": + +\begin{verbatim} + let int = Typ.Int TypEq.refl + + let str = Typ.String TypEq.refl + + let pair (type s1) (type s2) t1 t2 = + let module P = struct + type t = s1 * s2 + type t1 = s1 + type t2 = s2 + let eq = TypEq.refl + let t1 = t1 + let t2 = t2 + end in + let pair = (module P : Typ.PAIR with type t = s1 * s2) in + Typ.Pair pair +\end{verbatim} + +And finally, here is an example of a polymorphic function that takes the +runtime representation of some type "'a" and a value of the same type, +then pretty-prints the value into a string: + +\begin{verbatim} + open Typ + let rec to_string: 'a. 'a Typ.typ -> 'a -> string = + fun (type s) t x -> + match t with + | Int eq -> string_of_int (TypEq.apply eq x) + | String eq -> Printf.sprintf "%S" (TypEq.apply eq x) + | Pair p -> + let module P = (val p : PAIR with type t = s) in + let (x1, x2) = TypEq.apply P.eq x in + Printf.sprintf "(%s,%s)" (to_string P.t1 x1) (to_string P.t2 x2) +\end{verbatim} + +Note that this function uses an explicit polymorphic annotation to obtain +polymorphic recursion. +\fi + +\section{Recovering the type of a module} \label{s:module-type-of} + +\ikwd{module\@\texttt{module}} +\ikwd{type\@\texttt{type}} +\ikwd{of\@\texttt{of}} +\ikwd{include\@\texttt{include}} + +(Introduced in OCaml 3.12) + +\begin{syntax} +module-type: + ... + | 'module' 'type' 'of' module-expr +\end{syntax} + +The construction @'module' 'type' 'of' module-expr@ expands to the module type +(signature or functor type) inferred for the module expression @module-expr@. +To make this module type reusable in many situations, it is +intentionally not strengthened: abstract types and datatypes are not +explicitly related with the types of the original module. +For the same reason, module aliases in the inferred type are expanded. + +A typical use, in conjunction with the signature-level @'include'@ +construct, is to extend the signature of an existing structure. +In that case, one wants to keep the types equal to types in the +original module. This can done using the following idiom. +\begin{verbatim} + module type MYHASH = sig + include module type of struct include Hashtbl end + val replace: ('a, 'b) t -> 'a -> 'b -> unit + end +\end{verbatim} +The signature "MYHASH" then contains all the fields of the signature +of the module "Hashtbl" (with strengthened type definitions), plus the +new field "replace". An implementation of this signature can be +obtained easily by using the @'include'@ construct again, but this +time at the structure level: +\begin{verbatim} + module MyHash : MYHASH = struct + include Hashtbl + let replace t k v = remove t k; add t k v + end +\end{verbatim} + +Another application where the absence of strengthening comes handy, is +to provide an alternative implementation for an existing module. +\begin{verbatim} + module MySet : module type of Set = struct + ... + end +\end{verbatim} +This idiom guarantees that "Myset" is compatible with Set, but allows +it to represent sets internally in a different way. + +\section{Substituting inside a signature} +\ikwd{with\@\texttt{with}} +\ikwd{module\@\texttt{module}} +\ikwd{type\@\texttt{type}} +\label{s:signature-substitution} + +(Introduced in OCaml 3.12, generalized in 4.06) + +\begin{syntax} +mod-constraint: + ... + | 'type' [type-params] typeconstr-name ':=' typexpr + | 'module' module-path ':=' extended-module-path +\end{syntax} + +A ``destructive'' substitution (@'with' ... ':=' ...@) behaves essentially like +normal signature constraints (@'with' ... '=' ...@), but it additionally removes +the redefined type or module from the signature. + +Prior to OCaml 4.06, there were a number of restrictions: one could only remove +types and modules at the outermost level (not inside submodules), and in the +case of @'with type'@ the definition had to be another type constructor with the +same type parameters. + +A natural application of destructive substitution is merging two +signatures sharing a type name. +\begin{caml_example*}{verbatim} + module type Printable = sig + type t + val print : Format.formatter -> t -> unit + end + module type Comparable = sig + type t + val compare : t -> t -> int + end + module type PrintableComparable = sig + include Printable + include Comparable with type t := t + end +\end{caml_example*} + +One can also use this to completely remove a field: +\begin{caml_example}{verbatim} +module type S = Comparable with type t := int +\end{caml_example} +or to rename one: +\begin{caml_example}{verbatim} +module type S = sig + type u + include Comparable with type t := u +end +\end{caml_example} + +Note that you can also remove manifest types, by substituting with the +same type. +\begin{caml_example}{verbatim} +module type ComparableInt = Comparable with type t = int ;; +module type CompareInt = ComparableInt with type t := int +\end{caml_example} + +\section{Type-level module aliases} +\ikwd{module\@\texttt{module}} +\label{s:module-alias} + +(Introduced in OCaml 4.02) + +\begin{syntax} +specification: + ... + | 'module' module-name '=' module-path +\end{syntax} + +The above specification, inside a signature, only matches a module +definition equal to @module-path@. Conversely, a type-level module +alias can be matched by itself, or by any supertype of the type of the +module it references. + +There are several restrictions on @module-path@: +\begin{enumerate} +\item it should be of the form \(M_0.M_1...M_n\) ({\em i.e.} without + functor applications); +\item inside the body of a functor, \(M_0\) should not be one of the + functor parameters; +\item inside a recursive module definition, \(M_0\) should not be one of + the recursively defined modules. +\end{enumerate} + +Such specifications are also inferred. Namely, when @P@ is a path +satisfying the above constraints, +\begin{caml_eval} +module P = struct end +\end{caml_eval} +\begin{caml_example*}{verbatim} +module N = P +\end{caml_example*} +has type +\caml +\:module N = P +\endcaml + +Type-level module aliases are used when checking module path +equalities. That is, in a context where module name @N@ is known to be +an alias for @P@, not only these two module paths check as equal, but +@F(N)@ and @F(P)@ are also recognized as equal. In the default +compilation mode, this is the only difference with the previous +approach of module aliases having just the same module type as the +module they reference. + +When the compiler flag @'-no-alias-deps'@ is enabled, type-level +module aliases are also exploited to avoid introducing dependencies +between compilation units. Namely, a module alias referring to a +module inside another compilation unit does not introduce a link-time +dependency on that compilation unit, as long as it is not +dereferenced; it still introduces a compile-time dependency if the +interface needs to be read, {\em i.e.} if the module is a submodule +of the compilation unit, or if some type components are referred to. +Additionally, accessing a module alias introduces a link-time +dependency on the compilation unit containing the module referenced by +the alias, rather than the compilation unit containing the alias. +Note that these differences in link-time behavior may be incompatible +with the previous behavior, as some compilation units might not be +extracted from libraries, and their side-effects ignored. + +These weakened dependencies make possible to use module aliases in +place of the @'-pack'@ mechanism. Suppose that you have a library +@'Mylib'@ composed of modules @'A'@ and @'B'@. Using @'-pack'@, one +would issue the command line +\begin{verbatim} + ocamlc -pack a.cmo b.cmo -o mylib.cmo +\end{verbatim} +and as a result obtain a @'Mylib'@ compilation unit, containing +physically @'A'@ and @'B'@ as submodules, and with no dependencies on +their respective compilation units. +Here is a concrete example of a possible alternative approach: +\begin{enumerate} +\item Rename the files containing @'A'@ and @'B'@ to @'Mylib__A'@ and + @'Mylib__B'@. +\item Create a packing interface @'Mylib.ml'@, containing the + following lines. +\begin{verbatim} + module A = Mylib__A + module B = Mylib__B +\end{verbatim} +\item Compile @'Mylib.ml'@ using @'-no-alias-deps'@, and the other + files using @'-no-alias-deps'@ and @'-open' 'Mylib'@ (the last one is + equivalent to adding the line @'open!' 'Mylib'@ at the top of each + file). +\begin{verbatim} + ocamlc -c -no-alias-deps Mylib.ml + ocamlc -c -no-alias-deps -open Mylib Mylib__*.mli Mylib__*.ml +\end{verbatim} +\item Finally, create a library containing all the compilation units, + and export all the compiled interfaces. +\begin{verbatim} + ocamlc -a Mylib*.cmo -o Mylib.cma +\end{verbatim} +\end{enumerate} +This approach lets you access @'A'@ and @'B'@ directly inside the +library, and as @'Mylib.A'@ and @'Mylib.B'@ from outside. +It also has the advantage that @'Mylib'@ is no longer monolithic: if +you use @'Mylib.A'@, only @'Mylib__A'@ will be linked in, not +@'Mylib__B'@. +%Note that in the above @'Mylib.cmo'@ is actually empty, and one could +%name the interface @'Mylib.mli'@, but this would require that all +%clients are compiled with the @'-no-alias-deps'@ flag. + +Note the use of double underscores in @'Mylib__A'@ and +@'Mylib__B'@. These were chosen on purpose; the compiler uses the +following heuristic when printing paths: given a path @'Lib__fooBar'@, +if @'Lib.FooBar'@ exists and is an alias for @'Lib__fooBar'@, then the +compiler will always display @'Lib.FooBar'@ instead of +@'Lib__fooBar'@. This way the long @'Mylib__'@ names stay hidden and +all the user sees is the nicer dot names. This is how the OCaml +standard library is compiled. + +\section{Overriding in open statements}\label{s:explicit-overriding-open} +\ikwd{open.\@\texttt{open\char33}} + +(Introduced in OCaml 4.01) + +\begin{syntax} +definition: + ... + | 'open!' module-path +; +specification: + ... + | 'open!' module-path +; +expr: + ... + | 'let' 'open!' module-path 'in' expr +; +class-body-type: + ... + | 'let' 'open!' module-path 'in' class-body-type +; +class-expr: + ... + | 'let' 'open!' module-path 'in' class-expr +; +\end{syntax} + +Since OCaml 4.01, @"open"@ statements shadowing an existing identifier +(which is later used) trigger the warning 44. Adding a @"!"@ +character after the @"open"@ keyword indicates that such a shadowing is +intentional and should not trigger the warning. + +This is also available (since OCaml 4.06) for local opens in class +expressions and class type expressions. + +\section{Generalized algebraic datatypes} \ikwd{type\@\texttt{type}} +\ikwd{match\@\texttt{match}} \label{s:gadts} + +(Introduced in OCaml 4.00) + +\begin{syntax} +constr-decl: + ... + | constr-name ':' [ constr-args '->' ] typexpr +; +type-param: + ... + | [variance] '_' +\end{syntax} + +Generalized algebraic datatypes, or GADTs, extend usual sum types in +two ways: constraints on type parameters may change depending on the +value constructor, and some type variables may be existentially +quantified. +Adding constraints is done by giving an explicit return type +(the rightmost @typexpr@ in the above syntax), where type parameters +are instantiated. +This return type must use the same type constructor as the type being +defined, and have the same number of parameters. +Variables are made existential when they appear inside a constructor's +argument, but not in its return type. + +Since the use of a return type often eliminates the need to name type +parameters in the left-hand side of a type definition, one can replace +them with anonymous types @"_"@ in that case. + +The constraints associated to each constructor can be recovered +through pattern-matching. +Namely, if the type of the scrutinee of a pattern-matching contains +a locally abstract type, this type can be refined according to the +constructor used. +These extra constraints are only valid inside the corresponding branch +of the pattern-matching. +If a constructor has some existential variables, fresh locally +abstract types are generated, and they must not escape the +scope of this branch. + +\paragraph{Recursive functions} + +Here is a concrete example: +\begin{verbatim} + type _ term = + | Int : int -> int term + | Add : (int -> int -> int) term + | App : ('b -> 'a) term * 'b term -> 'a term + + let rec eval : type a. a term -> a = function + | Int n -> n (* a = int *) + | Add -> (fun x y -> x+y) (* a = int -> int -> int *) + | App(f,x) -> (eval f) (eval x) + (* eval called at types (b->a) and b for fresh b *) + + let two = eval (App (App (Add, Int 1), Int 1)) + val two : int = 2 +\end{verbatim} +It is important to remark that the function "eval" is using the +polymorphic syntax for locally abstract types. When defining a recursive +function that manipulates a GADT, explicit polymorphic recursion should +generally be used. For instance, the following definition fails with a +type error: +\begin{verbatim} + let rec eval (type a) : a term -> a = function + | Int n -> n + | Add -> (fun x y -> x+y) + | App(f,x) -> (eval f) (eval x) +(* ^ + Error: This expression has type ($App_'b -> a) term but an expression was + expected of type 'a + The type constructor $App_'b would escape its scope +*) +\end{verbatim} +In absence of an explicit polymorphic annotation, a monomorphic type +is inferred for the recursive function. If a recursive call occurs +inside the function definition at a type that involves an existential +GADT type variable, this variable flows to the type of the recursive +function, and thus escapes its scope. In the above example, this happens +in the branch "App(f,x)" when "eval" is called with "f" as an argument. +In this branch, the type of "f" is "($App_ 'b-> a)". The prefix "$" in +"$App_ 'b" denotes an existential type named by the compiler +(see~\ref{p:existential-names}). Since the type of "eval" is +"'a term -> 'a", the call "eval f" makes the existential type "$App_'b" +flow to the type variable "'a" and escape its scope. This triggers the +above error. + +\paragraph{Type inference} + +Type inference for GADTs is notoriously hard. +This is due to the fact some types may become ambiguous when escaping +from a branch. +For instance, in the "Int" case above, "n" could have either type "int" +or "a", and they are not equivalent outside of that branch. +As a first approximation, type inference will always work if a +pattern-matching is annotated with types containing no free type +variables (both on the scrutinee and the return type). +This is the case in the above example, thanks to the type annotation +containing only locally abstract types. + +In practice, type inference is a bit more clever than that: type +annotations do not need to be immediately on the pattern-matching, and +the types do not have to be always closed. +As a result, it is usually enough to only annotate functions, as in +the example above. Type annotations are +propagated in two ways: for the scrutinee, they follow the flow of +type inference, in a way similar to polymorphic methods; for the +return type, they follow the structure of the program, they are split +on functions, propagated to all branches of a pattern matching, +and go through tuples, records, and sum types. +Moreover, the notion of ambiguity used is stronger: a type is only +seen as ambiguous if it was mixed with incompatible types (equated by +constraints), without type annotations between them. +For instance, the following program types correctly. +\begin{verbatim} + let rec sum : type a. a term -> _ = fun x -> + let y = + match x with + | Int n -> n + | Add -> 0 + | App(f,x) -> sum f + sum x + in y + 1 + val sum : 'a term -> int = +\end{verbatim} +Here the return type "int" is never mixed with "a", so it is seen as +non-ambiguous, and can be inferred. +When using such partial type annotations we strongly suggest +specifying the "-principal" mode, to check that inference is +principal. + +The exhaustiveness check is aware of GADT constraints, and can +automatically infer that some cases cannot happen. +For instance, the following pattern matching is correctly seen as +exhaustive (the "Add" case cannot happen). +\begin{verbatim} + let get_int : int term -> int = function + | Int n -> n + | App(_,_) -> 0 +\end{verbatim} + + +\paragraph{Refutation cases} (Introduced in OCaml 4.03) + +Usually, the exhaustiveness check only tries to check whether the +cases omitted from the pattern matching are typable or not. +However, you can force it to try harder by adding {\em refutation cases}: +\begin{syntax} +matching-case: + pattern ['when' expr] '->' expr + | pattern '->' '.' +\end{syntax} +In presence of a refutation case, the exhaustiveness check will first +compute the intersection of the pattern with the complement of the +cases preceding it. It then checks whether the resulting patterns can +really match any concrete values by trying to type-check them. +Wild cards in the generated patterns are handled in a special way: if +their type is a variant type with only GADT constructors, then the +pattern is split into the different constructors, in order to check whether +any of them is possible (this splitting is not done for arguments of these +constructors, to avoid non-termination). We also split tuples and +variant types with only one case, since they may contain GADTs inside. +For instance, the following code is deemed exhaustive: + +\begin{verbatim} + type _ t = + | Int : int t + | Bool : bool t + + let deep : (char t * int) option -> char = function + | None -> 'c' + | _ -> . +\end{verbatim} + +Namely, the inferred remaining case is "Some _", which is split into +"Some (Int, _)" and "Some (Bool, _)", which are both untypable because +"deep" expects a non-existing "char t" as the first element of the tuple. +Note that the refutation case could be omitted here, because it is +automatically added when there is only one case in the pattern +matching. + +Another addition is that the redundancy check is now aware of GADTs: a +case will be detected as redundant if it could be replaced by a +refutation case using the same pattern. + +\paragraph{Advanced examples} +The "term" type we have defined above is an {\em indexed} type, where +a type parameter reflects a property of the value contents. +Another use of GADTs is {\em singleton} types, where a GADT value +represents exactly one type. This value can be used as runtime +representation for this type, and a function receiving it can have a +polytypic behavior. + +Here is an example of a polymorphic function that takes the +runtime representation of some type "t" and a value of the same type, +then pretty-prints the value as a string: +\begin{verbatim} + type _ typ = + | Int : int typ + | String : string typ + | Pair : 'a typ * 'b typ -> ('a * 'b) typ + + let rec to_string: type t. t typ -> t -> string = + fun t x -> + match t with + | Int -> string_of_int x + | String -> Printf.sprintf "%S" x + | Pair(t1,t2) -> + let (x1, x2) = x in + Printf.sprintf "(%s,%s)" (to_string t1 x1) (to_string t2 x2) +\end{verbatim} + +Another frequent application of GADTs is equality witnesses. +\begin{verbatim} + type (_,_) eq = Eq : ('a,'a) eq + + let cast : type a b. (a,b) eq -> a -> b = fun Eq x -> x +\end{verbatim} +Here type "eq" has only one constructor, and by matching on it one +adds a local constraint allowing the conversion between "a" and "b". +By building such equality witnesses, one can make equal types which +are syntactically different. + +Here is an example using both singleton types and equality witnesses +to implement dynamic types. +\begin{verbatim} + let rec eq_type : type a b. a typ -> b typ -> (a,b) eq option = + fun a b -> + match a, b with + | Int, Int -> Some Eq + | String, String -> Some Eq + | Pair(a1,a2), Pair(b1,b2) -> + begin match eq_type a1 b1, eq_type a2 b2 with + | Some Eq, Some Eq -> Some Eq + | _ -> None + end + | _ -> None + + type dyn = Dyn : 'a typ * 'a -> dyn + + let get_dyn : type a. a typ -> dyn -> a option = + fun a (Dyn(b,x)) -> + match eq_type a b with + | None -> None + | Some Eq -> Some x +\end{verbatim} + +\paragraph{Existential type names in error messages}% +\label{p:existential-names} +(Updated in OCaml 4.03.0) + +The typing of pattern matching in presence of GADT can generate many +existential types. When necessary, error messages refer to these +existential types using compiler-generated names. Currently, the +compiler generates these names according to the following nomenclature: +\begin{itemize} +\item First, types whose name starts with a "$" are existentials. +\item "$Constr_'a" denotes an existential type introduced for the type +variable "'a" of the GADT constructor "Constr": +\begin{caml_example}{verbatim}[error] +type any = Any : 'name -> any +let escape (Any x) = x +\end{caml_example} +\item "$Constr" denotes an existential type introduced for an anonymous %$ +type variable in the GADT constructor "Constr": +\begin{caml_example}{verbatim}[error] +type any = Any : _ -> any +let escape (Any x) = x +\end{caml_example} +\item "$'a" if the existential variable was unified with the type %$ +variable "'a" during typing: +\begin{caml_example}{verbatim}[error] +type ('arg,'result,'aux) fn = + | Fun: ('a ->'b) -> ('a,'b,unit) fn + | Mem1: ('a ->'b) * 'a * 'b -> ('a, 'b, 'a * 'b) fn + let apply: ('arg,'result, _ ) fn -> 'arg -> 'result = fun f x -> + match f with + | Fun f -> f x + | Mem1 (f,y,fy) -> if x = y then fy else f x +\end{caml_example} +\item "$n" (n a number) is an internally generated existential %$ +which could not be named using one of the previous schemes. +\end{itemize} + +As shown by the last item, the current behavior is imperfect +and may be improved in future versions. + +\paragraph{Equations on non-local abstract types} (Introduced in OCaml +4.04) + +GADT pattern-matching may also add type equations to non-local +abstract types. The behaviour is the same as with local abstract +types. Reusing the above "eq" type, one can write: +\begin{verbatim} + module M : sig type t val x : t val e : (t,int) eq end = struct + type t = int + let x = 33 + let e = Eq + end + + let x : int = let Eq = M.e in M.x +\end{verbatim} + +Of course, not all abstract types can be refined, as this would +contradict the exhaustiveness check. Namely, builtin types (those +defined by the compiler itself, such as "int" or "array"), and +abstract types defined by the local module, are non-instantiable, and +as such cause a type error rather than introduce an equation. + +\section{Syntax for Bigarray access}\label{s:bigarray-access} + +(Introduced in Objective Caml 3.00) + +\begin{syntax} +expr: + ... + | expr '.{' expr { ',' expr } '}' + | expr '.{' expr { ',' expr } '}' '<-' expr +\end{syntax} + +This extension provides syntactic sugar for getting and setting +elements in the arrays provided by the +"Bigarray"[\moduleref{Bigarray}] library. + +The short expressions are translated into calls to functions of the +"Bigarray" module as described in the following table. + +\begin{tableau}{|l|l|}{expression}{translation} +\entree{@expr_0'.{'expr_1'}'@} + {"Bigarray.Array1.get "@expr_0 expr_1@} +\entree{@expr_0'.{'expr_1'}' '<-'expr@} + {"Bigarray.Array1.set "@expr_0 expr_1 expr@} +\entree{@expr_0'.{'expr_1',' expr_2'}'@} + {"Bigarray.Array2.get "@expr_0 expr_1 expr_2@} +\entree{@expr_0'.{'expr_1',' expr_2'}' '<-'expr@} + {"Bigarray.Array2.set "@expr_0 expr_1 expr_2 expr@} +\entree{@expr_0'.{'expr_1',' expr_2',' expr_3'}'@} + {"Bigarray.Array3.get "@expr_0 expr_1 expr_2 expr_3@} +\entree{@expr_0'.{'expr_1',' expr_2',' expr_3'}' '<-'expr@} + {"Bigarray.Array3.set "@expr_0 expr_1 expr_2 expr_3 expr@} +\entree{@expr_0'.{'expr_1',' \ldots',' expr_n'}'@} + {"Bigarray.Genarray.get "@ expr_0 '[|' expr_1',' \ldots ',' + expr_n '|]'@} +\entree{@expr_0'.{'expr_1',' \ldots',' expr_n'}' '<-'expr@} + {"Bigarray.Genarray.set "@ expr_0 '[|' expr_1',' \ldots ',' + expr_n '|]' expr@} +\end{tableau} + +The last two entries are valid for any $n > 3$. + +\section{Attributes}\label{s:attributes} + +\ikwd{when\@\texttt{when}} + +(Introduced in OCaml 4.02, +infix notations for constructs other than expressions added in 4.03) + +Attributes are ``decorations'' of the syntax tree which are mostly +ignored by the type-checker but can be used by external tools. An +attribute is made of an identifier and a payload, which can be a +structure, a type expression (prefixed with ":"), a signature +(prefixed with ":") or a pattern (prefixed with "?") optionally +followed by a "when" clause: + + +\begin{syntax} +attr-id: + lowercase-ident + | capitalized-ident + | attr-id '.' attr-id +; +attr-payload: + [ module-items ] + | ':' typexpr + | ':' [ specification ] + | '?' pattern ['when' expr] +; +\end{syntax} + +The first form of attributes is attached with a postfix notation on +``algebraic'' categories: + +\begin{syntax} +attribute: + '[@' attr-id attr-payload ']' +; +expr: ... + | expr attribute +; +typexpr: ... + | typexpr attribute +; +pattern: ... + | pattern attribute +; +module-expr: ... + | module-expr attribute +; +module-type: ... + | module-type attribute +; +class-expr: ... + | class-expr attribute +; +class-type: ... + | class-type attribute +; +\end{syntax} + +This form of attributes can also be inserted after the @'`'tag-name@ +in polymorphic variant type expressions (@tag-spec-first@, @tag-spec@, +@tag-spec-full@) or after the @method-name@ in @method-type@. + +The same syntactic form is also used to attach attributes to labels and +constructors in type declarations: + +\begin{syntax} +field-decl: + ['mutable'] field-name ':' poly-typexpr {attribute} +; +constr-decl: + (constr-name || '()') [ 'of' constr-args ] {attribute} +; +\end{syntax} + +Note: when a label declaration is followed by a semi-colon, attributes +can also be put after the semi-colon (in which case they are merged to +those specified before). + + +The second form of attributes are attached to ``blocks'' such as type +declarations, class fields, etc: + +\begin{syntax} +item-attribute: + '[@@' attr-id attr-payload ']' +; +typedef: ... + | typedef item-attribute +; +exception-definition: + 'exception' constr-decl + | 'exception' constr-name '=' constr +; +module-items: + [';;'] ( definition || expr { item-attribute } ) { [';;'] definition || ';;' expr { item-attribute } } [';;'] +; +class-binding: ... + | class-binding item-attribute +; +class-spec: ... + | class-spec item-attribute +; +classtype-def: ... + | classtype-def item-attribute +; +definition: + 'let' ['rec'] let-binding { 'and' let-binding } + | 'external' value-name ':' typexpr '=' external-declaration { item-attribute } + | type-definition + | exception-definition { item-attribute } + | class-definition + | classtype-definition + | 'module' module-name { '(' module-name ':' module-type ')' } + [ ':' module-type ] \\ '=' module-expr { item-attribute } + | 'module' 'type' modtype-name '=' module-type { item-attribute } + | 'open' module-path { item-attribute } + | 'include' module-expr { item-attribute } + | 'module' 'rec' module-name ':' module-type '=' \\ + module-expr { item-attribute } \\ + { 'and' module-name ':' module-type '=' module-expr \\ + { item-attribute } } +; +specification: + 'val' value-name ':' typexpr { item-attribute } + | 'external' value-name ':' typexpr '=' external-declaration { item-attribute } + | type-definition + | 'exception' constr-decl { item-attribute } + | class-specification + | classtype-definition + | 'module' module-name ':' module-type { item-attribute } + | 'module' module-name { '(' module-name ':' module-type ')' } + ':' module-type { item-attribute } + | 'module' 'type' modtype-name { item-attribute } + | 'module' 'type' modtype-name '=' module-type { item-attribute } + | 'open' module-path { item-attribute } + | 'include' module-type { item-attribute } +; +class-field-spec: ... + | class-field-spec item-attribute +; +class-field: ... + | class-field item-attribute +; +\end{syntax} + +A third form of attributes appears as stand-alone structure or +signature items in the module or class sub-languages. They are not +attached to any specific node in the syntax tree: + +\begin{syntax} +floating-attribute: + '[@@@' attr-id attr-payload ']' +; +definition: ... + | floating-attribute +; +specification: ... + | floating-attribute +; +class-field-spec: ... + | floating-attribute +; +class-field: ... + | floating-attribute +; +\end{syntax} + +(Note: contrary to what the grammar above describes, @item-attributes@ +cannot be attached to these floating attributes in @class-field-spec@ +and @class-field@.) + + +It is also possible to specify attributes using an infix syntax. For instance: + +\begin{verbatim} +let[@foo] x = 2 in x + 1 === (let x = 2 [@@foo] in x + 1) +begin[@foo][@bar x] ... end === (begin ... end)[@foo][@@bar x] +module[@foo] M = ... === module M = ... [@@foo] +type[@foo] t = T === type t = T [@@foo] +method[@foo] m = ... === method m = ... [@@foo] +\end{verbatim} + +For "let", the attributes are applied to each bindings: + +\begin{verbatim} +let[@foo] x = 2 and y = 3 in x + y === (let x = 2 [@@foo] and y = 3 in x + y) +let[@foo] x = 2 +and[@bar] y = 3 in x + y === (let x = 2 [@@foo] and y = 3 [@bar] in x + y) +\end{verbatim} + + +\subsection{Built-in attributes} +\label{ss:builtin-attributes} + +Some attributes are understood by the type-checker: +\begin{itemize} +\item + ``ocaml.warning'' or ``warning'', with a string literal payload. + This can be used as floating attributes in a + signature/structure/object/object type. The string is parsed and has + the same effect as the "-w" command-line option, in the scope between + the attribute and the end of the current + signature/structure/object/object type. The attribute can also be + attached to any kind of syntactic item which support attributes + (such as an expression, or a type expression) + in which case its scope is limited to that item. + Note that it is not well-defined which scope is used for a specific + warning. This is implementation dependant and can change between versions. + Some warnings are even completely outside the control of ``ocaml.warning'' + (for instance, warnings 1, 2, 14, 29 and 50). + +\item + ``ocaml.warnerror'' or ``warnerror'', with a string literal payload. + Same as ``ocaml.warning'', for the "-warn-error" command-line option. +\item + ``ocaml.deprecated'' or ``deprecated''. + Can be applied to most kind of items in signatures or + structures. When the element is later referenced, a warning (3) is + triggered. If the payload of the attribute is a string literal, + the warning message includes this text. It is also possible + to use this ``ocaml.deprecated'' as a floating attribute + on top of an ``.mli'' file (i.e. before any other non-attribute + item) or on top of an ``.ml'' file without a corresponding + interface; this marks the unit itself as being deprecated. +\item + ``ocaml.deprecated_mutable'' or ``deprecated_mutable''. + Can be applied to a mutable record label. If the label is later + used to modify the field (with ``expr.l <- expr''), a warning (3) + will be triggered. If the payload of the attribute is a string literal, + the warning message includes this text. +\item + ``ocaml.ppwarning'' or ``ppwarning'', in any context, with + a string literal payload. The text is reported as warning (22) + by the compiler (currently, the warning location is the location + of the string payload). This is mostly useful for preprocessors which + need to communicate warnings to the user. This could also be used + to mark explicitly some code location for further inspection. +\item + ``ocaml.warn_on_literal_pattern'' or ``warn_on_literal_pattern'' annotate + constructors in type definition. A warning (52) is then emitted when this + constructor is pattern matched with a constant literal as argument. This + attribute denotes constructors whose argument is purely informative and + may change in the future. Therefore, pattern matching on this argument + with a constant literal is unreliable. For instance, all built-in exception + constructors are marked as ``warn_on_literal_pattern''. + Note that, due to an implementation limitation, this warning (52) is only + triggered for single argument constructor. +\item + ``ocaml.tailcall'' or ``tailcall'' can be applied to function + application in order to check that the call is tailcall optimized. + If it it not the case, a warning (51) is emitted. +\item + ``ocaml.inline'' or ``inline'' take either ``never'', ``always'' + or nothing as payload on a function or functor definition. If no payload + is provided, the default value is ``always''. This payload controls when + applications of the annotated functions should be inlined. +\item + ``ocaml.inlined'' or ``inlined'' can be applied to any function or functor + application to check that the call is inlined by the compiler. If the call + is not inlined, a warning (55) is emitted. +\item + ``ocaml.noalloc'', ``ocaml.unboxed''and ``ocaml.untagged'' or + ``noalloc'', ``unboxed'' and ``untagged'' can be used on external + definitions to obtain finer control over the C-to-OCaml interface. See + \ref{s:C-cheaper-call} for more details. +\item + ``ocaml.immediate'' or ``immediate'' applied on an abstract type mark the type as + having a non-pointer implementation (e.g. ``int'', ``bool'', ``char'' or + enumerated types). Mutation of these immediate types does not activate the + garbage collector's write barrier, which can significantly boost performance in + programs relying heavily on mutable state. +\item + "ocaml.unboxed" or "unboxed" can be used on a type definition if the + type is a single-field record or a concrete type with a single + constructor that has a single argument. It tells the compiler to + optimize the representation of the type by removing the block that + represents the record or the constructor (i.e. a value of this type + is physically equal to its argument). In the case of GADTs, an + additional restriction applies: the argument must not be an + existential variable, represented by an existential type variable, + or an abstract type constructor applied to an existential type + variable. +\item + "ocaml.boxed" or "boxed" can be used on type definitions to mean + the opposite of "ocaml.unboxed": keep the unoptimized + representation of the type. When there is no annotation, the + default is currently "boxed" but it may change in the future. +\end{itemize} + +\begin{verbatim} +module X = struct + [@@@warning "+9"] (* locally enable warning 9 in this structure *) + ... +end + [@@deprecated "Please use module 'Y' instead."] + +let x = begin[@warning "+9"] ... end in .... + +type t = A | B + [@@deprecated "Please use type 's' instead."] + +let f x = + assert (x >= 0) [@ppwarning "TODO: remove this later"]; + +let rec no_op = function + | [] -> () + | _ :: q -> (no_op[@tailcall]) q;; + +let f x = x [@@inline] + +let () = (f[@inlined]) () + +type fragile = + | Int of int [@warn_on_literal_pattern] + | String of string [@warn_on_literal_pattern] + +let f = function +| Int 0 | String "constant" -> () (* trigger warning 52 *) +| _ -> () + +module Immediate: sig + type t [@@immediate] + val x: t ref +end = struct + type t = A | B + let x = ref 0 +end + .... + +\end{verbatim} + + +\section{Extension nodes}\label{s:extension-nodes} + +(Introduced in OCaml 4.02, +infix notations for constructs other than expressions added in 4.03, +infix notation (e1 ;\%ext e2) added in 4.04. +) + +Extension nodes are generic placeholders in the syntax tree. They are +rejected by the type-checker and are intended to be ``expanded'' by external +tools such as "-ppx" rewriters. + +Extension nodes share the same notion of identifier and payload as +attributes~\ref{s:attributes}. + +The first form of extension node is used for ``algebraic'' categories: + +\begin{syntax} +extension: + '[%' attr-id attr-payload ']' +; +expr: ... + | extension +; +typexpr: ... + | extension +; +pattern: ... + | extension +; +module-expr: ... + | extension +; +module-type: ... + | extension +; +class-expr: ... + | extension +; +class-type: ... + | extension +; +\end{syntax} + +A second form of extension node can be used in structures and +signatures, both in the module and object languages: + +\begin{syntax} +item-extension: + '[%%' attr-id attr-payload ']' +; +definition: ... + | item-extension +; +specification: ... + | item-extension +; +class-field-spec: ... + | item-extension +; +class-field: ... + | item-extension +; +\end{syntax} + +An infix form is available for extension nodes when +the payload is of the same kind +(expression with expression, pattern with pattern ...). + +Examples: + +\begin{verbatim} +let%foo x = 2 in x + 1 === [%foo let x = 2 in x + 1] +begin%foo ... end === [%foo begin ... end] +x ;%foo 2 === [%foo x; 2] +module%foo M = .. === [%%foo module M = ... ] +val%foo x : t === [%%foo: val x : t] +\end{verbatim} + +When this form is used together with the infix syntax for attributes, +the attributes are considered to apply to the payload: + +\begin{verbatim} +fun%foo[@bar] x -> x + 1 === [%foo (fun x -> x + 1)[@bar ] ]; +\end{verbatim} + +\subsection{Built-in extension nodes} + +(Introduced in OCaml 4.03) + +Some extension nodes are understood by the compiler itself: +\begin{itemize} + \item + ``ocaml.extension_constructor'' or ``extension_constructor'' + take as payload a constructor from an extensible variant type + (see \ref{s:extensible-variants}) and return its extension + constructor slot. +\end{itemize} + +\begin{caml_example*}{verbatim} +type t = .. +type t += X of int | Y of string +let x = [%extension_constructor X] +let y = [%extension_constructor Y] +\end{caml_example*} +\begin{caml_example}{toplevel} + x <> y;; +\end{caml_example} + +\section{Quoted strings}\label{s:quoted-strings} + +(Introduced in OCaml 4.02) + +Quoted strings "{foo|...|foo}" provide a different lexical syntax to +write string literals in OCaml code. They are useful to represent +strings of arbitrary content without escaping -- as long as the +delimiter you chose (here "|foo}") does not occur in the string +itself. + +\begin{syntax} +string-literal: ... + | '{' quoted-string-id '|' ........ '|' quoted-string-id '}' +; +quoted-string-id: + { 'a'...'z' || '_' } +; +\end{syntax} + +The opening delimiter has the form "{id|" where "id" is a (possibly +empty) sequence of lowercase letters and underscores. The +corresponding closing delimiter is "|id}" (with the same +identifier). Unlike regular OCaml string literals, quoted +strings do not interpret any character in a special way. + +Example: + +\begin{verbatim} +String.length {|\"|} (* returns 2 *) +String.length {foo|\"|foo} (* returns 2 *) +\end{verbatim} + +Quoted strings are interesting in particular in conjunction to +extension nodes "[%foo ...]" (see \ref{s:extension-nodes}) to embed +foreign syntax fragments to be interpreted by a preprocessor and +turned into OCaml code: you can use "[%sql {|...|}]" for example to +represent arbitrary SQL statements -- assuming you have a ppx-rewriter +that recognizes the "%sql" extension -- without requiring escaping +quotes. + +Note that the non-extension form, for example "{sql|...|sql}", should +not be used for this purpose, as the user cannot see in the code that +this string literal has a different semantics than they expect, and +giving a semantics to a specific delimiter limits the freedom to +change the delimiter to avoid escaping issues. + +\section{Exception cases in pattern matching}\label{s:exception-match} + +(Introduced in OCaml 4.02) + +A new form of exception patterns is allowed, only as a toplevel +pattern under a "match"..."with" pattern-matching (other occurrences +are rejected by the type-checker). + +\begin{syntax} +pattern: ... + | 'exception' pattern +; +\end{syntax} + +Cases with such a toplevel pattern are called ``exception cases'', +as opposed to regular ``value cases''. Exception cases are applied +when the evaluation of the matched expression raises an exception. +The exception value is then matched against all the exception cases +and re-raised if none of them accept the exception (as for a +"try"..."with" block). Since the bodies of all exception and value +cases is outside the scope of the exception handler, they are all +considered to be in tail-position: if the "match"..."with" block +itself is in tail position in the current function, any function call +in tail position in one of the case bodies results in an actual tail +call. + +It is an error if all cases are exception cases in a given pattern +matching. + +\section{Extensible variant types}\label{s:extensible-variants} + +(Introduced in OCaml 4.02) + +\begin{syntax} +type-representation: + ... + | '=' '..' +; +specification: + ... + | 'type' [type-params] typeconstr type-extension-spec +; +definition: + ... + | 'type' [type-params] typeconstr type-extension-def +; +type-extension-spec: '+=' ['private'] ['|'] constr-decl { '|' constr-decl } +; +type-extension-def: '+=' ['private'] ['|'] constr-def { '|' constr-def } +; +constr-def: + constr-decl + | constr-name '=' constr +; +\end{syntax} + +Extensible variant types are variant types which can be extended with +new variant constructors. Extensible variant types are defined using +"..". New variant constructors are added using "+=". +\begin{verbatim} + type attr = .. + + type attr += Str of string + + type attr += + | Int of int + | Float of float +\end{verbatim} + +Pattern matching on an extensible variant type requires a default case +to handle unknown variant constructors: +\begin{verbatim} + let to_string = function + | Str s -> s + | Int i -> string_of_int i + | Float f -> string_of_float f + | _ -> "?" +\end{verbatim} + +A preexisting example of an extensible variant type is the built-in +"exn" type used for exceptions. Indeed, exception constructors can be +declared using the type extension syntax: +\begin{verbatim} + type exn += Exc of int +\end{verbatim} + +Extensible variant constructors can be rebound to a different name. This +allows exporting variants from another module. +\begin{verbatim} + type Expr.attr += Str = Expr.Str +\end{verbatim} + +Extensible variant constructors can be declared "private". As with +regular variants, this prevents them from being constructed directly by +constructor application while still allowing them to be de-structured in +pattern-matching. +\begin{verbatim} + module Bool : sig + type attr += private Bool of int + val bool : bool -> attr + end = struct + type attr += Bool of int + let bool p = if p then Bool 1 else Bool 0 + end +\end{verbatim} + +\subsection{Private extensible variant types} + +(Introduced in OCaml 4.06) + +\begin{syntax} +type-representation: + ... + | '=' 'private' '..' +; +\end{syntax} + +Extensible variant types can be declared "private". This prevents new +constructors from being declared directly, but allows extension +constructors to be referred to in interfaces. +\begin{verbatim} + module Msg : sig + type t = private .. + module MkConstr (X : sig type t end) : sig + type t += C of X.t + end + end = struct + type t = .. + module MkConstr (X : sig type t end) = struct + type t += C of X.t + end + end +\end{verbatim} + +\section{Generative functors}\label{s:generative-functors} + +(Introduced in OCaml 4.02) + +\begin{syntax} +module-expr: + ... + | 'functor' '()' '->' module-expr + | module-expr '()' +; +definition: + ... + | 'module' module-name { '(' module-name ':' module-type ')' || '()' } + [ ':' module-type ] \\ '=' module-expr +; +module-type: + ... + | 'functor' '()' '->' module-type +; +specification: + ... + | 'module' module-name { '(' module-name ':' module-type ')' || '()' } + ':' module-type +; +\end{syntax} + +A generative functor takes a unit "()" argument. +In order to use it, one must necessarily apply it to this unit argument, +ensuring that all type components in the result of the functor behave +in a generative way, {\em i.e.} they are different from types obtained +by other applications of the same functor. +This is equivalent to taking an argument of signature "sig end", and always +applying to "struct end", but not to some defined module (in the +latter case, applying twice to the same module would return identical +types). + +As a side-effect of this generativity, one is allowed to unpack +first-class modules in the body of generative functors. + +\section{Extension-only syntax} +(Introduced in OCaml 4.02.2, extended in 4.03) + +Some syntactic constructions are accepted during parsing and rejected +during type checking. These syntactic constructions can therefore not +be used directly in vanilla OCaml. However, "-ppx" rewriters and other +external tools can exploit this parser leniency to extend the language +with these new syntactic constructions by rewriting them to +vanilla constructions. +\subsection{Extension operators} \label{s:ext-ops} +(Introduced in OCaml 4.02.2) +\begin{syntax} +infix-symbol: + ... + | "#" {operator-chars} "#" {operator-char '|' "#"} +; +\end{syntax} + +Operator names starting with a "#" character and containing more than +one "#" character are reserved for extensions. + +\subsection{Extension literals} \label{s:extension-literals} +(Introduced in OCaml 4.03) +\begin{syntax} +float-literal: + ... + | ["-"] ("0"\ldots"9") { "0"\ldots"9"||"_" } ["." { "0"\ldots"9"||"_" }] + [("e"||"E") ["+"||"-"] ("0"\ldots"9") { "0"\ldots"9"||"_" }] + ["g"\ldots"z"||"G"\ldots"Z"] + | ["-"] ("0x"||"0X") + ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" }\\ + ["." { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" }] + [("p"||"P") ["+"||"-"] ("0"\ldots"9") { "0"\ldots"9"||"_" }] + ["g"\ldots"z"||"G"\ldots"Z"] +; +int-literal: + ... + | ["-"] ("0"\ldots"9") { "0"\ldots"9" || "_" }["g"\ldots"z"||"G"\ldots"Z"] + | ["-"] ("0x"||"0X") ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" } + ["g"\ldots"z"||"G"\ldots"Z"] + | ["-"] ("0o"||"0O") ("0"\ldots"7") { "0"\ldots"7"||"_" } + ["g"\ldots"z"||"G"\ldots"Z"] + | ["-"] ("0b"||"0B") ("0"\ldots"1") { "0"\ldots"1"||"_" } + ["g"\ldots"z"||"G"\ldots"Z"] +; +\end{syntax} +Int and float literals followed by an one-letter identifier in the +range @["g".."z"||"G".."Z"]@ are extension-only literals. + +\section{Inline records} \label{s:inline-records} +(Introduced in OCaml 4.03) +\begin{syntax} + constr-args: + ... + | record-decl +; +\end{syntax} + +The arguments of a sum-type constructors can now be defined using the +same syntax as records. Mutable and polymorphic fields are allowed. +GADT syntax is supported. Attributes can be specified on individual +fields. + +Syntactically, building or matching constructors with such an inline +record argument is similar to working with a unary constructor whose +unique argument is a declared record type. A pattern can bind +the inline record as a pseudo-value, but the record cannot escape the +scope of the binding and can only be used with the dot-notation to +extract or modify fields or to build new constructor values. + +\begin{verbatim} +type t = + | Point of {width: int; mutable x: float; mutable y: float} + | ... + +let v = Point {width = 10; x = 0.; y = 0.} + +let scale l = function + | Point p -> Point {p with x = l *. p.x; y = l *. p.y} + | .... + +let print = function + | Point {x; y; _} -> Printf.printf "%f/%f" x y + | .... + +let reset = function + | Point p -> p.x <- 0.; p.y <- 0. + | ... + +let invalid = function + | Point p -> p (* INVALID *) + | ... +\end{verbatim} + + +\section{Local exceptions} +\ikwd{let\@\texttt{let}} +\ikwd{exception\@\texttt{exception}} \label{s:local-exceptions} + +(Introduced in OCaml 4.04) + +It is possible to define local exceptions in expressions: + +\begin{syntax} +expr: + ... + | "let" "exception" constr-decl "in" expr +\end{syntax} + + +The syntactic scope of the exception constructor is the inner +expression, but nothing prevents exception values created with this +constructor from escaping this scope. Two executions of the definition +above result in two incompatible exception constructors (as for any +exception definition). + + +\section{Documentation comments} +(Introduced in OCaml 4.03) + +Comments which start with "**" are treated specially by the +compiler. They are automatically converted during parsing into +attributes (see \ref{s:attributes}) to allow tools to process them as +documentation. + +Such comments can take three forms: {\em floating comments}, {\em item +comments} and {\em label comments}. Any comment starting with "**" which +does not match one of these forms will cause the compiler to emit +warning 50. + +Comments which start with "**" are also used by the ocamldoc +documentation generator (see \ref{c:ocamldoc}). The three comment forms +recognised by the compiler are a subset of the forms accepted by +ocamldoc (see \ref{s:ocamldoc-comments}). + +\subsection{Floating comments} + +Comments surrounded by blank lines that appear within structures, +signatures, classes or class types are converted into +@floating-attribute@s. For example: + +\begin{verbatim} +type t = T + +(** Now some definitions for [t] *) + +let mkT = T +\end{verbatim} + +will be converted to: + +\begin{verbatim} +type t = T + +[@@@ocaml.text " Now some definitions for [t] "] + +let mkT = T +\end{verbatim} + +\subsection{Item comments} + +Comments which appear {\em immediately before} or {\em immediately +after} a structure item, signature item, class item or class type item +are converted into @item-attribute@s. Immediately before or immediately +after means that there must be no blank lines, ";;", or other +documentation comments between them. For example: + +\begin{verbatim} +type t = T +(** A description of [t] *) + +\end{verbatim} + +or + +\begin{verbatim} + +(** A description of [t] *) +type t = T +\end{verbatim} + +will be converted to: + +\begin{verbatim} +type t = T +[@@ocaml.doc " A description of [t] "] +\end{verbatim} + +Note that, if a comment appears immediately next to multiple items, +as in: + +\begin{verbatim} +type t = T +(** An ambiguous comment *) +type s = S +\end{verbatim} + +then it will be attached to both items: + +\begin{verbatim} +type t = T +[@@ocaml.doc " An ambiguous comment "] +type s = S +[@@ocaml.doc " An ambiguous comment "] +\end{verbatim} + +and the compiler will emit warning 50. + +\subsection{Label comments} + +Comments which appear {\em immediately after} a labelled argument, +record field, variant constructor, object method or polymorphic variant +constructor are are converted into @attribute@s. Immediately +after means that there must be no blank lines or other documentation +comments between them. For example: + +\begin{verbatim} +type t1 = lbl:int (** Labelled argument *) -> unit + +type t2 = { + fld: int; (** Record field *) + fld2: float; +} + +type t3 = + | Cstr of string (** Variant constructor *) + | Cstr2 of string + +type t4 = < meth: int * int; (** Object method *) > + +type t5 = [ + `PCstr (** Polymorphic variant constructor *) +] +\end{verbatim} + +will be converted to: + +\begin{verbatim} +type t1 = lbl:(int [@ocaml.doc " Labelled argument "]) -> unit + +type t2 = { + fld: int [@ocaml.doc " Record field "]; + fld2: float; +} + +type t3 = + | Cstr of string [@ocaml.doc " Variant constructor "] + | Cstr2 of string + +type t4 = < meth : int * int [@ocaml.doc " Object method "] > + +type t5 = [ + `PCstr [@ocaml.doc " Polymorphic variant constructor "] +] +\end{verbatim} + +Note that label comments take precedence over item comments, so: + +\begin{verbatim} +type t = T of string +(** Attaches to T not t *) +\end{verbatim} + +will be converted to: + +\begin{verbatim} +type t = T of string [@ocaml.doc " Attaches to T not t "] +\end{verbatim} + +whilst: + +\begin{verbatim} +type t = T of string +(** Attaches to T not t *) +(** Attaches to t *) +\end{verbatim} + +will be converted to: + +\begin{verbatim} +type t = T of string [@ocaml.doc " Attaches to T not t "] +[@@ocaml.doc " Attaches to t "] +\end{verbatim} + +In the absence of meaningful comment on the last constructor of +a type, an empty comment~"(**)" can be used instead: + +\begin{verbatim} +type t = T of string +(**) +(** Attaches to t *) +\end{verbatim} + +will be converted directly to + +\begin{verbatim} +type t = T of string +[@@ocaml.doc " Attaches to t "] +\end{verbatim} + +\section{Extended indexing operators \label{s:index-operators} } +(Introduced in 4.06) + +\begin{syntax} + +dot-ext: + | ('!'||'$'||'%'||'&'||'*'||'+'||'-'||'/'||':'||'='||'>'||'?'||'@'||'^'||'|'||'~') { operator-char } +; +expr: + ... + | expr '.' [module-path '.'] dot-ext ( '(' expr ')' || '[' expr ']' || '{' expr '}' ) [ '<-' expr ] +; +operator-name: + ... + | '.' dot-ext ('()' || '[]' || '{}') ['<-'] +; +\end{syntax} + + +This extension provides syntactic sugar for getting and setting elements +for user-defined indexed types. For instance, we can define python-like +dictionaries with +\begin{caml_example*}{verbatim} +module Dict = struct +include Hashtbl +let ( .%{} ) tabl index = find tabl index +let ( .%{}<- ) tabl index value = add tabl index value +end +let dict = + let dict = Dict.create 10 in + let () = + dict.Dict.%{"one"} <- 1; + let open Dict in + dict.%{"two"} <- 2 in + dict +\end{caml_example*} +\begin{caml_example}{toplevel} +dict.Dict.%{"one"};; +let open Dict in dict.%{"two"};; +\end{caml_example} + +\section{Empty variant types\label{s:empty-variants} } +(Introduced in 4.07.0) + +\begin{syntax} +type-representation: + ... + | '=' '|' +\end{syntax} +This extension allows user to define empty variants. +Empty variant type can be eliminated by refutation case of pattern matching. +\begin{caml_example*}{verbatim} +type t = | +let f (x: t) = match x with _ -> . +\end{caml_example*} diff --git a/manual/manual/refman/lex.etex b/manual/manual/refman/lex.etex new file mode 100644 index 00000000..f1ac3ea1 --- /dev/null +++ b/manual/manual/refman/lex.etex @@ -0,0 +1,300 @@ +\section{Lexical conventions} +\pdfsection{Lexical conventions} +%HEVEA\cutname{lex.html} +\subsubsection*{Blanks} + +The following characters are considered as blanks: space, +horizontal tabulation, carriage return, line feed and form feed. Blanks are +ignored, but they separate adjacent identifiers, literals and +keywords that would otherwise be confused as one single identifier, +literal or keyword. + +\subsubsection*{Comments} + +Comments are introduced by the two characters @"(*"@, with no +intervening blanks, and terminated by the characters @"*)"@, with +no intervening blanks. Comments are treated as blank characters. +Comments do not occur inside string or character literals. Nested +comments are handled correctly. + +\subsubsection*{Identifiers} + +\begin{syntax} +ident: ( letter || "_" ) { letter || "0" \ldots "9" || "_" || "'" } ; +capitalized-ident: ("A" \ldots "Z") { letter || "0" \ldots "9" || "_" || "'" } ; +lowercase-ident: + ("a" \ldots "z" || "_") { letter || "0" \ldots "9" || "_" || "'" } ; +letter: "A" \ldots "Z" || "a" \ldots "z" +\end{syntax} + +Identifiers are sequences of letters, digits, "_" (the underscore +character), and "'" (the single quote), starting with a +letter or an underscore. +Letters contain at least the 52 lowercase and uppercase +letters from the ASCII set. The current implementation +also recognizes as letters some characters from the ISO +8859-1 set (characters 192--214 and 216--222 as uppercase letters; +characters 223--246 and 248--255 as lowercase letters). This +feature is deprecated and should be avoided for future compatibility. + +All characters in an identifier are +meaningful. The current implementation accepts identifiers up to +16000000 characters in length. + +In many places, OCaml makes a distinction between capitalized +identifiers and identifiers that begin with a lowercase letter. The +underscore character is considered a lowercase letter for this +purpose. + +\subsubsection*{Integer literals} + +\begin{syntax} +integer-literal: + ["-"] ("0"\ldots"9") { "0"\ldots"9" || "_" } + | ["-"] ("0x"||"0X") ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" } + | ["-"] ("0o"||"0O") ("0"\ldots"7") { "0"\ldots"7"||"_" } + | ["-"] ("0b"||"0B") ("0"\ldots"1") { "0"\ldots"1"||"_" } +\end{syntax} + +An integer literal is a sequence of one or more digits, optionally +preceded by a minus sign. By default, integer literals are in decimal +(radix 10). The following prefixes select a different radix: +\begin{tableau}{|l|l|}{Prefix}{Radix} +\entree{"0x", "0X"}{hexadecimal (radix 16)} +\entree{"0o", "0O"}{octal (radix 8)} +\entree{"0b", "0B"}{binary (radix 2)} +\end{tableau} +(The initial @"0"@ is the digit zero; the @"O"@ for octal is the letter O.) +The interpretation of integer literals that fall outside the range of +representable integer values is undefined. + +For convenience and readability, underscore characters (@"_"@) are accepted +(and ignored) within integer literals. + +\subsubsection*{Floating-point literals} + +\begin{syntax} +float-literal: + ["-"] ("0"\ldots"9") { "0"\ldots"9"||"_" } ["." { "0"\ldots"9"||"_" }] + [("e"||"E") ["+"||"-"] ("0"\ldots"9") { "0"\ldots"9"||"_" }] + | ["-"] ("0x"||"0X") + ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" } \\ + ["." { "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f"||"_" }] + [("p"||"P") ["+"||"-"] ("0"\ldots"9") { "0"\ldots"9"||"_" }] +\end{syntax} + +Floating-point decimal literals consist in an integer part, a +fractional part and +an exponent part. The integer part is a sequence of one or more +digits, optionally preceded by a minus sign. The fractional part is a +decimal point followed by zero, one or more digits. +The exponent part is the character @"e"@ or @"E"@ followed by an +optional @"+"@ or @"-"@ sign, followed by one or more digits. It is +interpreted as a power of 10. +The fractional part or the exponent part can be omitted but not both, to +avoid ambiguity with integer literals. +The interpretation of floating-point literals that fall outside the +range of representable floating-point values is undefined. + +Floating-point hexadecimal literals are denoted with the @"0x"@ or @"0X"@ +prefix. The syntax is similar to that of floating-point decimal +literals, with the following differences. +The integer part and the fractional part use hexadecimal +digits. The exponent part starts with the character @"p"@ or @"P"@. +It is written in decimal and interpreted as a power of 2. + +For convenience and readability, underscore characters (@"_"@) are accepted +(and ignored) within floating-point literals. + +\subsubsection*{Character literals} +\label{s:characterliteral} + +\begin{syntax} +char-literal: + "'" regular-char "'" + | "'" escape-sequence "'" +; +escape-sequence: + "\" ( "\" || '"' || "'" || "n" || "t" || "b" || "r" || space ) + | "\" ("0"\ldots"9") ("0"\ldots"9") ("0"\ldots"9") + | "\x" ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + ("0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f") + | "\o" ("0"\ldots"3") ("0"\ldots"7") ("0"\ldots"7") +\end{syntax} + +Character literals are delimited by @"'"@ (single quote) characters. +The two single quotes enclose either one character different from +@"'"@ and @'\'@, or one of the escape sequences below: +\begin{tableau}{|l|l|}{Sequence}{Character denoted} +\entree{"\\\\"}{backslash ("\\")} +\entree{"\\\""}{double quote ("\"")} +\entree{"\\'"}{single quote ("'")} +\entree{"\\n"}{linefeed (LF)} +\entree{"\\r"}{carriage return (CR)} +\entree{"\\t"}{horizontal tabulation (TAB)} +\entree{"\\b"}{backspace (BS)} +\entree{"\\"\var{space}}{space (SPC)} +\entree{"\\"\var{ddd}}{the character with ASCII code \var{ddd} in decimal} +\entree{"\\x"\var{hh}}{the character with ASCII code \var{hh} in hexadecimal} +\entree{"\\o"\var{ooo}}{the character with ASCII code \var{ooo} in octal} +\end{tableau} + +\subsubsection*{String literals} +\label{s:stringliteral} + +\begin{syntax} +string-literal: + '"' { string-character } '"' +; +string-character: + regular-string-char + | escape-sequence + | "\u{" {{ "0"\ldots"9"||"A"\ldots"F"||"a"\ldots"f" }} "}" + | '\' newline { space || tab } +\end{syntax} + +String literals are delimited by @'"'@ (double quote) characters. +The two double quotes enclose a sequence of either characters +different from @'"'@ and @'\'@, or escape sequences from the +table given above for character literals, or a Unicode character +escape sequence. + +A Unicode character escape sequence is substituted by the UTF-8 +encoding of the specified Unicode scalar value. The Unicode scalar +value, an integer in the ranges 0x0000...0xD7FF or 0xE000...0x10FFFF, +is defined using 1 to 6 hexadecimal digits; leading zeros are allowed. + +To allow splitting long string literals across lines, the sequence +"\\"\var{newline}~\var{spaces-or-tabs} (a backslash at the end of a line +followed by any number of spaces and horizontal tabulations at the +beginning of the next line) is ignored inside string literals. + +The current implementation places practically no restrictions on the +length of string literals. + +\subsubsection*{Naming labels} +\label{s:labelname} + +To avoid ambiguities, naming labels in expressions cannot just be defined +syntactically as the sequence of the three tokens "~", @ident@ and +":", and have to be defined at the lexical level. + +\begin{syntax} +label-name: lowercase-ident +; +label: "~" label-name ":" +; +optlabel: "?" label-name ":" +\end{syntax} + +Naming labels come in two flavours: @label@ for normal arguments and +@optlabel@ for optional ones. They are simply distinguished by their +first character, either "~" or "?". + +Despite @label@ and @optlabel@ being lexical entities in expressions, +their expansions @'~' label-name ':'@ and @'?' label-name ':'@ will be +used in grammars, for the sake of readability. Note also that inside +type expressions, this expansion can be taken literally, {\em i.e.} +there are really 3 tokens, with optional blanks between them. + +\subsubsection*{Prefix and infix symbols} + +%% || '`' lowercase-ident '`' + +\begin{syntax} +infix-symbol: + ('=' || '<' || '>' || '@' || '^' || '|' || '&' || + '+' || '-' || '*' || '/' || '$' || '%') { operator-char } + | "#" {{ operator-char }} +; +prefix-symbol: + '!' { operator-char } + | ('?' || '~') {{ operator-char }} +; +operator-char: + '!' || '$' || '%' || '&' || '*' || '+' || '-' || '.' || + '/' || ':' || '<' || '=' || '>' || '?' || '@' || + '^' || '|' || '~' +\end{syntax} +See also the following language extensions: +\hyperref[s:ext-ops]{extension operators} and +\hyperref[s:index-operators]{extended indexing operators}. + +Sequences of ``operator characters'', such as "<=>" or "!!", +are read as a single token from the @infix-symbol@ or @prefix-symbol@ +class. These symbols are parsed as prefix and infix operators inside +expressions, but otherwise behave like normal identifiers. +%% Identifiers starting with a lowercase letter and enclosed +%% between backquote characters @'`' lowercase-ident '`'@ are also parsed +%% as infix operators. + +\subsubsection*{Keywords} + +The identifiers below are reserved as keywords, and cannot be employed +otherwise: +\begin{verbatim} + and as assert asr begin class + constraint do done downto else end + exception external false for fun function + functor if in include inherit initializer + land lazy let lor lsl lsr + lxor match method mod module mutable + new nonrec object of open or + private rec sig struct then to + true try type val virtual when + while with +\end{verbatim} +% +\goodbreak% +% +The following character sequences are also keywords: +% +%% FIXME the token >] is not used anywhere in the syntax +% +\begin{alltt} +" != # & && ' ( ) * + , -" +" -. -> . .. : :: := :> ; ;; <" +" <- = > >] >} ? [ [< [> [| ]" +" _ ` { {< | |] || } ~" +\end{alltt} +% +Note that the following identifiers are keywords of the Camlp4 +extensions and should be avoided for compatibility reasons. +% +\begin{verbatim} + parser value $ $$ $: <: << >> ?? +\end{verbatim} + +\subsubsection*{Ambiguities} + +Lexical ambiguities are resolved according to the ``longest match'' +rule: when a character sequence can be decomposed into two tokens in +several different ways, the decomposition retained is the one with the +longest first token. + +\subsubsection*{Line number directives} + +\begin{syntax} +linenum-directive: + '#' {{"0" \ldots "9"}} + | '#' {{"0" \ldots "9"}} '"' { string-character } '"' +\end{syntax} + +Preprocessors that generate OCaml source code can insert line number +directives in their output so that error messages produced by the +compiler contain line numbers and file names referring to the source +file before preprocessing, instead of after preprocessing. +A line number directive is composed of a @"#"@ (sharp sign), followed by +a positive integer (the source line number), optionally followed by a +character string (the source file name). +Line number directives are treated as blanks during lexical +analysis. + +% FIXME spaces and tabs are allowed before and after the number +% FIXME ``string-character'' is inaccurate: everything is allowed except +% CR, LF, and doublequote; moreover, backslash escapes are not +% interpreted (especially backslash-doublequote) +% FIXME any number of random characters are allowed (and ignored) at the +% end of the line, except CR and LF. diff --git a/manual/manual/refman/modtypes.etex b/manual/manual/refman/modtypes.etex new file mode 100644 index 00000000..cbcbaab5 --- /dev/null +++ b/manual/manual/refman/modtypes.etex @@ -0,0 +1,303 @@ +\section{Module types (module specifications)} +\pdfsection{Module types (module specifications)} +%HEVEA\cutname{modtypes.html} + +Module types are the module-level equivalent of type expressions: they +specify the general shape and type properties of modules. + +\ikwd{sig\@\texttt{sig}} +\ikwd{end\@\texttt{end}} +\ikwd{functor\@\texttt{functor}} +\ikwd{with\@\texttt{with}} +\ikwd{and\@\texttt{and}} +\ikwd{val\@\texttt{val}} +\ikwd{external\@\texttt{external}} +\ikwd{type\@\texttt{type}} +\ikwd{exception\@\texttt{exception}} +\ikwd{class\@\texttt{class}} +\ikwd{module\@\texttt{module}} +\ikwd{open\@\texttt{open}} +\ikwd{include\@\texttt{include}} + +\begin{syntax} +module-type: + modtype-path + | 'sig' { specification [';;'] } 'end' + | 'functor' '(' module-name ':' module-type ')' '->' module-type + | module-type '->' module-type + | module-type 'with' mod-constraint { 'and' mod-constraint } + | '(' module-type ')' +; +mod-constraint: + 'type' [type-params] typeconstr type-equation { type-constraint } + | 'module' module-path '=' extended-module-path +; +%BEGIN LATEX +\end{syntax} +\begin{syntax} +%END LATEX +specification: + 'val' value-name ':' typexpr + | 'external' value-name ':' typexpr '=' external-declaration + | type-definition + | 'exception' constr-decl + | class-specification + | classtype-definition + | 'module' module-name ':' module-type + | 'module' module-name { '(' module-name ':' module-type ')' } + ':' module-type + | 'module' 'type' modtype-name + | 'module' 'type' modtype-name '=' module-type + | 'open' module-path + | 'include' module-type +\end{syntax} +See also the following language extensions: +\hyperref[s:module-type-of]{recovering the type of a module}, +\hyperref[s:signature-substitution]{substitution inside a signature}, +\hyperref[s:module-alias]{type-level module aliases}, +\hyperref[s:attributes]{attributes}, +\hyperref[s:extension-nodes]{extension nodes} and +\hyperref[s:generative-functors]{generative functors}. + +\subsection{Simple module types} + +The expression @modtype-path@ is equivalent to the module type bound +to the name @modtype-path@. +The expression @'(' module-type ')'@ denotes the same type as +@module-type@. + +\subsection{Signatures} + +\ikwd{sig\@\texttt{sig}} +\ikwd{end\@\texttt{end}} + +Signatures are type specifications for structures. Signatures +@'sig' \ldots 'end'@ are collections of type specifications for value +names, type names, exceptions, module names and module type names. A +structure will match a signature if the structure provides definitions +(implementations) for all the names specified in the signature (and +possibly more), and these definitions meet the type requirements given +in the signature. + +An optional @";;"@ is allowed after each specification in a +signature. It serves as a syntactic separator with no semantic +meaning. + +\subsubsection*{Value specifications} + +\ikwd{val\@\texttt{val}} + +A specification of a value component in a signature is written +@'val' value-name ':' typexpr@, where @value-name@ is the name of the +value and @typexpr@ its expected type. + +\ikwd{external\@\texttt{external}} + +The form @'external' value-name ':' typexpr '=' external-declaration@ +is similar, except that it requires in addition the name to be +implemented as the external function specified in @external-declaration@ +(see chapter~\ref{c:intf-c}). + +\subsubsection*{Type specifications} + +\ikwd{type\@\texttt{type}} + +A specification of one or several type components in a signature is +written @'type' typedef { 'and' typedef }@ and consists of a sequence +of mutually recursive definitions of type names. + +Each type definition in the signature specifies an optional type +equation @'=' typexpr@ and an optional type representation +@'=' constr-decl \ldots@ or @'=' '{' field-decl \ldots '}'@. +The implementation of the type name in a matching structure must +be compatible with the type expression specified in the equation (if +given), and have the specified representation (if given). Conversely, +users of that signature will be able to rely on the type equation +or type representation, if given. More precisely, we have the +following four situations: + +\begin{description} +\item[Abstract type: no equation, no representation.] ~ \\ +Names that are defined as abstract types in a signature can be +implemented in a matching structure by any kind of type definition +(provided it has the same number of type parameters). The exact +implementation of the type will be hidden to the users of the +structure. In particular, if the type is implemented as a variant type +or record type, the associated constructors and fields will not be +accessible to the users; if the type is implemented as an +abbreviation, the type equality between the type name and the +right-hand side of the abbreviation will be hidden from the users of the +structure. Users of the structure consider that type as incompatible +with any other type: a fresh type has been generated. + +\item[Type abbreviation: an equation @'=' typexpr@, no representation.] ~ \\ +The type name must be implemented by a type compatible with @typexpr@. +All users of the structure know that the type name is +compatible with @typexpr@. + +\item[New variant type or record type: no equation, a representation.] ~ \\ +The type name must be implemented by a variant type or record type +with exactly the constructors or fields specified. All users of the +structure have access to the constructors or fields, and can use them +to create or inspect values of that type. However, users of the +structure consider that type as incompatible with any other type: a +fresh type has been generated. + +\item[Re-exported variant type or record type: an equation, +a representation.] ~ \\ +This case combines the previous two: the representation of the type is +made visible to all users, and no fresh type is generated. +\end{description} + +\subsubsection*{Exception specification} + +\ikwd{exception\@\texttt{exception}} + +The specification @'exception' constr-decl@ in a signature requires the +matching structure to provide an exception with the name and arguments +specified in the definition, and makes the exception available to all +users of the structure. + +\subsubsection*{Class specifications} + +\ikwd{class\@\texttt{class}} + +A specification of one or several classes in a signature is written +@'class' class-spec { 'and' class-spec }@ and consists of a sequence +of mutually recursive definitions of class names. + +Class specifications are described more precisely in +section~\ref{s:class-spec}. + +\subsubsection*{Class type specifications} + +\ikwd{class\@\texttt{class}} +\ikwd{type\@\texttt{type}} + +A specification of one or several classe types in a signature is +written @'class' 'type' classtype-def@ @{ 'and' classtype-def }@ and +consists of a sequence of mutually recursive definitions of class type +names. Class type specifications are described more precisely in +section~\ref{s:classtype}. + +\subsubsection*{Module specifications} + +\ikwd{module\@\texttt{module}} + +A specification of a module component in a signature is written +@'module' module-name ':' module-type@, where @module-name@ is the +name of the module component and @module-type@ its expected type. +Modules can be nested arbitrarily; in particular, functors can appear +as components of structures and functor types as components of +signatures. + +For specifying a module component that is a functor, one may write +\begin{center} +@'module' module-name '(' name_1 ':' module-type_1 ')' + \ldots '(' name_n ':' module-type_n ')' + ':' module-type@ +\end{center} +instead of +\begin{center} +@'module' module-name ':' + 'functor' '(' name_1 ':' module-type_1 ')' '->' \ldots + '->' module-type@ +\end{center} + +\subsubsection*{Module type specifications} + +\ikwd{type\@\texttt{type}} +\ikwd{module\@\texttt{module}} + +A module type component of a signature can be specified either as a +manifest module type or as an abstract module type. + +An abstract module type specification +@'module' 'type' modtype-name@ allows the name @modtype-name@ to be +implemented by any module type in a matching signature, but hides the +implementation of the module type to all users of the signature. + +A manifest module type specification +@'module' 'type' modtype-name '=' module-type@ +requires the name @modtype-name@ to be implemented by the module type +@module-type@ in a matching signature, but makes the equality between +@modtype-name@ and @module-type@ apparent to all users of the signature. + +\subsubsection{Opening a module path} + +\ikwd{open\@\texttt{open}} + +The expression @'open' module-path@ in a signature does not specify +any components. It simply affects the parsing of the following items +of the signature, allowing components of the module denoted by +@module-path@ to be referred to by their simple names @name@ instead of +path accesses @module-path '.' name@. The scope of the @"open"@ +stops at the end of the signature expression. + +\subsubsection{Including a signature} + +\ikwd{include\@\texttt{include}} + +The expression @'include' module-type@ in a signature performs textual +inclusion of the components of the signature denoted by @module-type@. +It behaves as if the components of the included signature were copied +at the location of the @'include'@. The @module-type@ argument must +refer to a module type that is a signature, not a functor type. + +\subsection{Functor types} + +\ikwd{functor\@\texttt{functor}} + +The module type expression +@'functor' '(' module-name ':' module-type_1 ')' '->' module-type_2@ +is the type of functors (functions from modules to modules) that take +as argument a module of type @module-type_1@ and return as result a +module of type @module-type_2@. The module type @module-type_2@ can +use the name @module-name@ to refer to type components of the actual +argument of the functor. If the type @module-type_2@ does not +depend on type components of @module-name@, the module type expression +can be simplified with the alternative short syntax +@ module-type_1 '->' module-type_2 @. +No restrictions are placed on the type of the functor argument; in +particular, a functor may take another functor as argument +(``higher-order'' functor). + +\subsection{The "with" operator} + +\ikwd{with\@\texttt{with}} + +Assuming @module-type@ denotes a signature, the expression +@module-type 'with' mod-constraint@ @{ 'and' mod-constraint }@ denotes +the same signature where type equations have been added to some of the +type specifications, as described by the constraints following the +"with" keyword. The constraint @'type' [type-parameters] typeconstr +'=' typexpr@ adds the type equation @'=' typexpr@ to the specification +of the type component named @typeconstr@ of the constrained signature. +The constraint @'module' module-path '=' extended-module-path@ adds +type equations to all type components of the sub-structure denoted by +@module-path@, making them equivalent to the corresponding type +components of the structure denoted by @extended-module-path@. + +For instance, if the module type name "S" is bound to the signature +\begin{verbatim} + sig type t module M: (sig type u end) end +\end{verbatim} +then "S with type t=int" denotes the signature +\begin{verbatim} + sig type t=int module M: (sig type u end) end +\end{verbatim} +and "S with module M = N" denotes the signature +\begin{verbatim} + sig type t module M: (sig type u=N.u end) end +\end{verbatim} +A functor taking two arguments of type "S" that share their "t" component +is written +\begin{verbatim} + functor (A: S) (B: S with type t = A.t) ... +\end{verbatim} + +Constraints are added left to right. After each constraint has been +applied, the resulting signature must be a subtype of the signature +before the constraint was applied. Thus, the @'with'@ operator can +only add information on the type components of a signature, but never +remove information. diff --git a/manual/manual/refman/modules.etex b/manual/manual/refman/modules.etex new file mode 100644 index 00000000..431ad83d --- /dev/null +++ b/manual/manual/refman/modules.etex @@ -0,0 +1,239 @@ +\section{Module\label{s:module-expr} expressions (module implementations)} +\pdfsection{Module expressions (module implementations)} +%HEVEA\cutname{modules.html} + +Module expressions are the module-level equivalent of value +expressions: they evaluate to modules, thus providing implementations +for the specifications expressed in module types. + +\ikwd{struct\@\texttt{struct}} +\ikwd{end\@\texttt{end}} +\ikwd{functor\@\texttt{functor}} +\ikwd{let\@\texttt{let}} +\ikwd{and\@\texttt{and}} +\ikwd{external\@\texttt{external}} +\ikwd{type\@\texttt{type}} +\ikwd{exception\@\texttt{exception}} +\ikwd{class\@\texttt{class}} +\ikwd{module\@\texttt{module}} +\ikwd{open\@\texttt{open}} +\ikwd{include\@\texttt{include}} + +\begin{syntax} +module-expr: + module-path + | 'struct' [ module-items ] 'end' + | 'functor' '(' module-name ':' module-type ')' '->' module-expr + | module-expr '(' module-expr ')' + | '(' module-expr ')' + | '(' module-expr ':' module-type ')' +; +module-items: + {';;'} ( definition || expr ) { {';;'} ( definition || ';;' expr) } {';;'} +; +%\end{syntax} \begin{syntax} +definition: + 'let' ['rec'] let-binding { 'and' let-binding } + | 'external' value-name ':' typexpr '=' external-declaration + | type-definition + | exception-definition + | class-definition + | classtype-definition + | 'module' module-name { '(' module-name ':' module-type ')' } + [ ':' module-type ] \\ '=' module-expr + | 'module' 'type' modtype-name '=' module-type + | 'open' module-path + | 'include' module-expr +\end{syntax} +See also the following language extensions: +\hyperref[s-recursive-modules]{recursive modules}, +\hyperref[s-first-class-modules]{first-class modules}, +\hyperref[s:explicit-overriding-open]{overriding in open statements}, +\hyperref[s:attributes]{attributes}, +\hyperref[s:extension-nodes]{extension nodes} and +\hyperref[s:generative-functors]{generative functors}. + +\subsection{Simple module expressions} + +The expression @module-path@ evaluates to the module bound to the name +@module-path@. + +The expression @'(' module-expr ')'@ evaluates to the same module as +@module-expr@. + +The expression @'(' module-expr ':' module-type ')'@ checks that the +type of @module-expr@ is a subtype of @module-type@, that is, that all +components specified in @module-type@ are implemented in +@module-expr@, and their implementation meets the requirements given +in @module-type@. In other terms, it checks that the implementation +@module-expr@ meets the type specification @module-type@. The whole +expression evaluates to the same module as @module-expr@, except that +all components not specified in @module-type@ are hidden and can no +longer be accessed. + +\subsection{Structures} + +\ikwd{struct\@\texttt{struct}} +\ikwd{end\@\texttt{end}} + +Structures @'struct' \ldots 'end'@ are collections of definitions for +value names, type names, exceptions, module names and module type +names. The definitions are evaluated in the order in which they appear +in the structure. The scopes of the bindings performed by the +definitions extend to the end of the structure. As a consequence, a +definition may refer to names bound by earlier definitions in the same +structure. + +For compatibility with toplevel phrases (chapter~\ref{c:camllight}), +optional @";;"@ are allowed after and before each definition in a structure. These +@";;"@ have no semantic meanings. Similarly, an @expr@ preceded by ";;" is allowed as +a component of a structure. It is equivalent to @'let' '_' '=' expr@, i.e. @expr@ is +evaluated for its side-effects but is not bound to any identifier. If @expr@ is +the first component of a structure, the preceding ";;" can be omitted. + +\subsubsection*{Value definitions} + +\ikwd{let\@\texttt{let}} + +A value definition @'let' ['rec'] let-binding { 'and' let-binding }@ +bind value names in the same way as a @'let' \ldots 'in' \ldots@ expression +(see section~\ref{s:localdef}). The value names appearing in the +left-hand sides of the bindings are bound to the corresponding values +in the right-hand sides. + +\ikwd{external\@\texttt{external}} + +A value definition @'external' value-name ':' typexpr '=' external-declaration@ +implements @value-name@ as the external function specified in +@external-declaration@ (see chapter~\ref{c:intf-c}). + +\subsubsection*{Type definitions} + +\ikwd{type\@\texttt{type}} + +A definition of one or several type components is written +@'type' typedef { 'and' typedef }@ and consists of a sequence +of mutually recursive definitions of type names. + +\subsubsection*{Exception definitions} + +\ikwd{exception\@\texttt{exception}} + +Exceptions are defined with the syntax @'exception' constr-decl@ +or @'exception' constr-name '=' constr@. + +\subsubsection*{Class definitions} + +\ikwd{class\@\texttt{class}} + +A definition of one or several classes is written @'class' +class-binding { 'and' class-binding }@ and consists of a sequence of +mutually recursive definitions of class names. Class definitions are +described more precisely in section~\ref{s:classdef}. + +\subsubsection*{Class type definitions} + +\ikwd{class\@\texttt{class}} +\ikwd{type\@\texttt{type}} + +A definition of one or several classes is written +@'class' 'type' classtype-def { 'and' classtype-def }@ and consists of +a sequence of mutually recursive definitions of class type names. +Class type definitions are described more precisely in +section~\ref{s:classtype}. + +\subsubsection*{Module definitions} + +\ikwd{module\@\texttt{module}} + +The basic form for defining a module component is +@'module' module-name '=' module-expr@, which evaluates @module-expr@ and binds +the result to the name @module-name@. + +One can write +\begin{center} +@'module' module-name ':' module-type '=' module-expr@ +\end{center} +instead of +\begin{center} +@'module' module-name '=' '(' module-expr ':' module-type ')'@. +\end{center} +Another derived form is +\begin{center} +@'module' module-name '(' name_1 ':' module-type_1 ')' \ldots + '(' name_n ':' module-type_n ')' '=' module-expr@ +\end{center} +which is equivalent to +\begin{center} +@'module' module-name '=' + 'functor' '(' name_1 ':' module-type_1 ')' '->' \ldots + '->' module-expr@ +\end{center} + +\subsubsection*{Module type definitions} + +\ikwd{type\@\texttt{type}} +\ikwd{module\@\texttt{module}} + +A definition for a module type is written +@'module' 'type' modtype-name '=' module-type@. +It binds the name @modtype-name@ to the module type denoted by the +expression @module-type@. + +\subsubsection*{Opening a module path} + +\ikwd{open\@\texttt{open}} + +The expression @'open' module-path@ in a structure does not define any +components nor perform any bindings. It simply affects the parsing of +the following items of the structure, allowing components of the +module denoted by @module-path@ to be referred to by their simple names +@name@ instead of path accesses @module-path '.' name@. The scope of +the @"open"@ stops at the end of the structure expression. + +\subsubsection*{Including the components of another structure} + +\ikwd{include\@\texttt{include}} + +The expression @'include' module-expr@ in a structure re-exports in +the current structure all definitions of the structure denoted by +@module-expr@. For instance, if the identifier "S" is bound to the +module +\begin{verbatim} + struct type t = int let x = 2 end +\end{verbatim} +the module expression +\begin{verbatim} + struct include S let y = (x + 1 : t) end +\end{verbatim} +is equivalent to the module expression +\begin{verbatim} + struct type t = S.t let x = S.x let y = (x + 1 : t) end +\end{verbatim} +The difference between @'open'@ and @'include'@ is that @'open'@ +simply provides short names for the components of the opened +structure, without defining any components of the current structure, +while @'include'@ also adds definitions for the components of the +included structure. + +\subsection{Functors} + +\subsubsection*{Functor definition} + +\ikwd{functor\@\texttt{functor}} + +The expression @'functor' '(' module-name ':' module-type ')' '->' +module-expr@ evaluates to a functor that takes as argument modules of +the type @module-type_1@, binds @module-name@ to these modules, +evaluates @module-expr@ in the extended environment, and returns the +resulting modules as results. No restrictions are placed on the type of the +functor argument; in particular, a functor may take another functor as +argument (``higher-order'' functor). + +\subsubsection*{Functor application} + +The expression @module-expr_1 '(' module-expr_2 ')'@ evaluates +@module-expr_1@ to a functor and @module-expr_2@ to a module, and +applies the former to the latter. The type of @module-expr_2@ must +match the type expected for the arguments of the functor @module-expr_1@. + diff --git a/manual/manual/refman/names.etex b/manual/manual/refman/names.etex new file mode 100644 index 00000000..4f85eed4 --- /dev/null +++ b/manual/manual/refman/names.etex @@ -0,0 +1,151 @@ +\section{Names} \label{s:names} +\pdfsection{Names} +%HEVEA\cutname{names.html} + +Identifiers are used to give names to several classes of language +objects and refer to these objects by name later: +\begin{itemize} +\item value names (syntactic class @value-name@), +\item value constructors and exception constructors (class @constr-name@), +\item labels (@label-name@, defined in section~\ref{s:labelname}), +\item polymorphic variant tags (@tag-name@), +\item type constructors (@typeconstr-name@), +\item record fields (@field-name@), +\item class names (@class-name@), +\item method names (@method-name@), +\item instance variable names (@inst-var-name@), +\item module names (@module-name@), +\item module type names (@modtype-name@). +\end{itemize} +These eleven name spaces are distinguished both by the context and by the +capitalization of the identifier: whether the first letter of the +identifier is in lowercase (written @lowercase-ident@ below) or in +uppercase (written @capitalized-ident@). Underscore is considered a +lowercase letter for this purpose. + +\subsubsection*{Naming objects} +\ikwd{mod\@\texttt{mod}} +\ikwd{land\@\texttt{land}} +\ikwd{lor\@\texttt{lor}} +\ikwd{lxor\@\texttt{lxor}} +\ikwd{lsl\@\texttt{lsl}} +\ikwd{lsr\@\texttt{lsr}} +\ikwd{asr\@\texttt{asr}} + +\begin{syntax} +value-name: + lowercase-ident + | '(' operator-name ')' +; +operator-name: + prefix-symbol || infix-op +; +infix-op: + infix-symbol + | '*' || '+' || '-' || '-.' || '=' || '!=' || '<' || '>' || 'or' || '||' + || '&' || '&&' || ':=' + | 'mod' || 'land' || 'lor' || 'lxor' || 'lsl' || 'lsr' || 'asr' +; +constr-name: + capitalized-ident +; +tag-name: + capitalized-ident +; +typeconstr-name: + lowercase-ident +; +field-name: + lowercase-ident +; +module-name: + capitalized-ident +; +modtype-name: + ident +; +class-name: + lowercase-ident +; +inst-var-name: + lowercase-ident +; +method-name: + lowercase-ident +\end{syntax} +See also the following language extension: +\hyperref[s:index-operators]{extended indexing operators}. + +As shown above, prefix and infix symbols as well as some keywords can +be used as value names, provided they are written between parentheses. +The capitalization rules are summarized in the table below. + +\begin{tableau}{|l|l|}{Name space}{Case of first letter} +\entree{Values}{lowercase} +\entree{Constructors}{uppercase} +\entree{Labels}{lowercase} +\entree{Polymorphic variant tags}{uppercase} +\entree{Exceptions}{uppercase} +\entree{Type constructors}{lowercase} +\entree{Record fields}{lowercase} +\entree{Classes}{lowercase} +\entree{Instance variables}{lowercase} +\entree{Methods}{lowercase} +\entree{Modules}{uppercase} +\entree{Module types}{any} +\end{tableau} + +{\it Note on polymorphic variant tags:\/} the current implementation accepts +lowercase variant tags in addition to capitalized variant tags, but we +suggest you avoid lowercase variant tags for portability and +compatibility with future OCaml versions. + +\subsubsection*{Referring to named objects} + +\begin{syntax} +value-path: + [ module-path '.' ] value-name +; +constr: + [ module-path '.' ] constr-name +; +typeconstr: + [ extended-module-path '.' ] typeconstr-name +; +field: + [ module-path '.' ] field-name +; +modtype-path: + [ extended-module-path '.' ] modtype-name +; +class-path: + [ module-path '.' ] class-name +; +classtype-path: + [ extended-module-path '.' ] class-name +; +module-path: + module-name { '.' module-name } +; +extended-module-path: + extended-module-name { '.' extended-module-name } +; +extended-module-name: + module-name { '(' extended-module-path ')' } +\end{syntax} + +A named object can be referred to either by its name (following the +usual static scoping rules for names) or by an access path @prefix '.' name@, +where @prefix@ designates a module and @name@ is the name of an object +defined in that module. The first component of the path, @prefix@, is +either a simple module name or an access path @name_1 '.' name_2 \ldots@, +in case the defining module is itself nested inside other modules. +For referring to type constructors, module types, or class types, +the @prefix@ can +also contain simple functor applications (as in the syntactic class +@extended-module-path@ above) in case the defining module is the +result of a functor application. + +Label names, tag names, method names and instance variable names need +not be qualified: the former three are global labels, while the latter +are local to a class. diff --git a/manual/manual/refman/patterns.etex b/manual/manual/refman/patterns.etex new file mode 100644 index 00000000..8abdce5e --- /dev/null +++ b/manual/manual/refman/patterns.etex @@ -0,0 +1,178 @@ +\section{Patterns} +\pdfsection{Patterns} +\ikwd{as\@\texttt{as}} +%HEVEA\cutname{patterns.html} +\begin{syntax} +pattern: + value-name + | '_' + | constant + | pattern 'as' value-name + | '(' pattern ')' + | '(' pattern ':' typexpr ')' + | pattern '|' pattern + | constr pattern + | "`"tag-name pattern + | "#"typeconstr + | pattern {{ ',' pattern }} + | '{' field [':' typexpr] ['=' pattern]% + { ';' field [':' typexpr] ['=' pattern] } [';' '_' ] [ ';' ] '}' + | '[' pattern { ';' pattern } [ ';' ] ']' + | pattern '::' pattern + | '[|' pattern { ';' pattern } [ ';' ] '|]' + | char-literal '..' char-literal +\end{syntax} +See also the following language extensions: \hyperref[s:lazypat]{lazy patterns}, +\hyperref[s:local-opens]{local opens}, +\hyperref[s-first-class-modules]{first-class modules}, +\hyperref[s:attributes]{attributes}, +\hyperref[s:extension-nodes]{extension nodes} and +\hyperref[s:exception-match]{exception cases in pattern matching}. + +The table below shows the relative precedences and associativity of +operators and non-closed pattern constructions. The constructions with +higher precedences come first. +\ikwd{as\@\texttt{as}} +\begin{tableau}{|l|l|}{Operator}{Associativity} +\entree{".."}{--} +\entree{"lazy" (see section~\ref{s:lazypat})}{--} +\entree{Constructor application, Tag application}{right} +\entree{"::"}{right} +\entree{","}{--} +\entree{"|"}{left} +\entree{"as"}{--} +\end{tableau} + +Patterns are templates that allow selecting data structures of a +given shape, and binding identifiers to components of the data +structure. This selection operation is called pattern matching; its +outcome is either ``this value does not match this pattern'', or +``this value matches this pattern, resulting in the following bindings +of names to values''. + +\subsubsection*{Variable patterns} + +A pattern that consists in a value name matches any value, +binding the name to the value. The pattern @"_"@ also matches +any value, but does not bind any name. + +Patterns are {\em linear\/}: a variable cannot be bound several times by +a given pattern. In particular, there is no way to test for equality +between two parts of a data structure using only a pattern (but +@"when"@ guards can be used for this purpose). + +\subsubsection*{Constant patterns} + +A pattern consisting in a constant matches the values that +are equal to this constant. + +%% FIXME for negative numbers, blanks are allowed between the minus +%% sign and the first digit. + +\subsubsection*{Alias patterns} +\ikwd{as\@\texttt{as}} + +The pattern @pattern_1 "as" value-name@ matches the same values as +@pattern_1@. If the matching against @pattern_1@ is successful, +the name @value-name@ is bound to the matched value, in addition to the +bindings performed by the matching against @pattern_1@. + +\subsubsection*{Parenthesized patterns} + +The pattern @"(" pattern_1 ")"@ matches the same values as +@pattern_1@. A type constraint can appear in a +parenthesized pattern, as in @"(" pattern_1 ":" typexpr ")"@. This +constraint forces the type of @pattern_1@ to be compatible with +@typexpr@. + +\subsubsection*{``Or'' patterns} + +The pattern @pattern_1 "|" pattern_2@ represents the logical ``or'' of +the two patterns @pattern_1@ and @pattern_2@. A value matches +@pattern_1 "|" pattern_2@ if it matches @pattern_1@ or +@pattern_2@. The two sub-patterns @pattern_1@ and @pattern_2@ +must bind exactly the same identifiers to values having the same types. +Matching is performed from left to right. +More precisely, +in case some value~$v$ matches @pattern_1 "|" pattern_2@, the bindings +performed are those of @pattern_1@ when $v$ matches @pattern_1@. +Otherwise, value~$v$ matches @pattern_2@ whose bindings are performed. + + +\subsubsection*{Variant patterns} + +The pattern @constr '(' pattern_1 ',' \ldots ',' pattern_n ')'@ matches +all variants whose +constructor is equal to @constr@, and whose arguments match +@pattern_1 \ldots pattern_n@. It is a type error if $n$ is not the +number of arguments expected by the constructor. + +The pattern @constr '_'@ matches all variants whose constructor is +@constr@. + +The pattern @pattern_1 "::" pattern_2@ matches non-empty lists whose +heads match @pattern_1@, and whose tails match @pattern_2@. + +The pattern @"[" pattern_1 ";" \ldots ";" pattern_n "]"@ matches lists +of length $n$ whose elements match @pattern_1@ \ldots @pattern_n@, +respectively. This pattern behaves like +@pattern_1 "::" \ldots "::" pattern_n "::" "[]"@. + +\subsubsection*{Polymorphic variant patterns} + +The pattern @"`"tag-name pattern_1@ matches all polymorphic variants +whose tag is equal to @tag-name@, and whose argument matches +@pattern_1@. + +\subsubsection*{Polymorphic variant abbreviation patterns} + +If the type @["('a,'b,"\ldots")"] typeconstr = "[" "`"tag-name_1 typexpr_1 "|" +\ldots "|" "`"tag-name_n typexpr_n"]"@ is defined, then the pattern @"#"typeconstr@ +is a shorthand for the following or-pattern: +@"(" "`"tag-name_1"(_" ":" typexpr_1")" "|" \ldots "|" "`"tag-name_n"(_" +":" typexpr_n"))"@. It matches all values of type @"[<" typeconstr "]"@. + +\subsubsection*{Tuple patterns} + +The pattern @pattern_1 "," \ldots "," pattern_n@ matches $n$-tuples +whose components match the patterns @pattern_1@ through @pattern_n@. That +is, the pattern matches the tuple values $(v_1, \ldots, v_n)$ such that +@pattern_i@ matches $v_i$ for \fromoneto{i}{n}. + +\subsubsection*{Record patterns} + +The pattern @"{" field_1 ["=" pattern_1] ";" \ldots ";" field_n ["=" +pattern_n] "}"@ matches records that define at least the fields +@field_1@ through @field_n@, and such that the value associated to +@field_i@ matches the pattern @pattern_i@, for \fromoneto{i}{n}. +A single identifier @field_k@ stands for @field_k '=' field_k @, +and a single qualified identifier @module-path '.' field_k@ stands +for @module-path '.' field_k '=' field_k @. +The record value can define more fields than @field_1@ \ldots +@field_n@; the values associated to these extra fields are not taken +into account for matching. Optionally, a record pattern can be terminated +by @';' '_'@ to convey the fact that not all fields of the record type are +listed in the record pattern and that it is intentional. +Optional type constraints can be added field by field with +@"{" field_1 ":" typexpr_1 "=" pattern_1 ";"% +\ldots ";"field_n ":" typexpr_n "=" pattern_n "}"@ to force the type +of @field_k@ to be compatible with @typexpr_k@. + + +\subsubsection*{Array patterns} + +The pattern @"[|" pattern_1 ";" \ldots ";" pattern_n "|]"@ +matches arrays of length $n$ such that the $i$-th array element +matches the pattern @pattern_i@, for \fromoneto{i}{n}. + +\subsubsection*{Range patterns} + +The pattern +@"'" @c@ "'" ".." "'" @d@ "'"@ is a shorthand for the pattern +\begin{center} +@"'" @c@ "'" "|" "'" @c@_1 "'" "|" "'" @c@_2 "'" "|" \ldots + "|" "'" @c@_n "'" "|" "'" @d@ "'"@ +\end{center} +where \nth{c}{1}, \nth{c}{2}, \ldots, \nth{c}{n} are the characters +that occur between \var{c} and \var{d} in the ASCII character set. For +instance, the pattern "'0'"@'..'@"'9'" matches all characters that are digits. diff --git a/manual/manual/refman/refman.etex b/manual/manual/refman/refman.etex new file mode 100644 index 00000000..a7daea02 --- /dev/null +++ b/manual/manual/refman/refman.etex @@ -0,0 +1,48 @@ +\chapter{The OCaml language} \label{c:refman} +\pdfchapterfold{-12}{Reference manual for the OCaml language} +%HEVEA\cutname{language.html} + +%better html output that way, sniff. +%HEVEA\subsection*{Foreword} +%BEGIN LATEX +\section*{Foreword} +%END LATEX + +This document is intended as a reference manual for the OCaml +language. It lists the language constructs, and gives their precise +syntax and informal semantics. It is by no means a tutorial +introduction to the language: there is not a single example. A good +working knowledge of OCaml is assumed. + +No attempt has been made at mathematical rigor: words are employed +with their intuitive meaning, without further definition. As a +consequence, the typing rules have been left out, by lack of the +mathematical framework required to express them, while they are +definitely part of a full formal definition of the language. + + +\subsection*{Notations} + +The syntax of the language is given in BNF-like notation. Terminal +symbols are set in typewriter font (@'like' 'this'@). +Non-terminal symbols are set in italic font (@like that@). +Square brackets @[\ldots]@ denote optional components. Curly brackets +@{\ldots}@ denotes zero, one or several repetitions of the enclosed +components. Curly brackets with a trailing plus sign @{{\ldots}}@ +denote one or several repetitions of the enclosed components. +Parentheses @(\ldots)@ denote grouping. + +%HEVEA\cutdef{section} +\input{lex} +\input{values} +\input{names} +\input{types} +\input{const} +\input{patterns} +\input{expr} +\input{typedecl} +\input{classes} +\input{modtypes} +\input{modules} +\input{compunit} +%HEVEA\cutend diff --git a/manual/manual/refman/typedecl.etex b/manual/manual/refman/typedecl.etex new file mode 100644 index 00000000..9961f182 --- /dev/null +++ b/manual/manual/refman/typedecl.etex @@ -0,0 +1,226 @@ +\section{Type and exception definitions} +%HEVEA\cutname{typedecl.html}% +\pdfsection{Type and exception definitions} + +\subsection{Type definitions} +\label{s:type-defs} + +Type definitions bind type constructors to data types: either +variant types, record types, type abbreviations, or abstract data +types. They also bind the value constructors and record fields +associated with the definition. + +\ikwd{type\@\texttt{type}} +\ikwd{and\@\texttt{and}} +\ikwd{nonrec\@\texttt{nonrec}} +\ikwd{of\@\texttt{of}} + +\begin{syntax} +type-definition: + 'type' ['nonrec'] typedef { 'and' typedef } +; +typedef: + [type-params] typeconstr-name type-information +; +type-information: + [type-equation] [type-representation] { type-constraint } +; +type-equation: + '=' typexpr +; +type-representation: + '=' ['|'] constr-decl { '|' constr-decl } + | '=' record-decl + | '=' '|' +; +type-params: + type-param + | '(' type-param { "," type-param } ')' +; +type-param: + [variance] "'" ident +; +variance: + '+' + | '-' +; +record-decl: + '{' field-decl { ';' field-decl } [';'] '}' +; +constr-decl: + (constr-name || '[]' || '(::)') [ 'of' constr-args ] +; +constr-args: + typexpr { '*' typexpr } +; +field-decl: + ['mutable'] field-name ':' poly-typexpr +; +type-constraint: + 'constraint' "'" ident '=' typexpr +\end{syntax} +\ikwd{mutable\@\texttt{mutable}} +\ikwd{constraint\@\texttt{constraint}} +See also the following language extensions: +\hyperref[s:private-types]{private types}, +\hyperref[s:gadts]{generalized algebraic datatypes}, +\hyperref[s:attributes]{attributes}, +\hyperref[s:extension-nodes]{extension nodes}, +\hyperref[s:extensible-variants]{extensible variant types} and +\hyperref[s:inline-records]{inline records}. + +Type definitions are introduced by the "type" keyword, and +consist in one or several simple definitions, possibly mutually +recursive, separated by the "and" keyword. Each simple definition +defines one type constructor. + +A simple definition consists in a lowercase identifier, possibly +preceded by one or several type parameters, and followed by an +optional type equation, then an optional type representation, and then +a constraint clause. The identifier is the name of the type +constructor being defined. + +In the right-hand side of type definitions, references to one of the +type constructor name being defined are considered as recursive, +unless "type" is followed by "nonrec". The "nonrec" keyword was +introduced in OCaml 4.02.2. + +The optional type parameters are either one type variable @"'" ident@, +for type constructors with one parameter, or a list of type variables +@"('"ident_1,\ldots,"'"ident_n")"@, for type constructors with several +parameters. Each type parameter may be prefixed by a variance +constraint @"+"@ (resp. @"-"@) indicating that the parameter is +covariant (resp. contravariant). These type parameters can appear in +the type expressions of the right-hand side of the definition, +optionally restricted by a variance constraint ; {\em i.e.\/} a +covariant parameter may only appear on the right side of a functional +arrow (more precisely, follow the left branch of an even number of +arrows), and a contravariant parameter only the left side (left branch of +an odd number of arrows). If the type has a representation or +an equation, and the parameter is free ({\em i.e.\/} not bound via a +type constraint to a constructed type), its variance constraint is +checked but subtyping {\em etc.\/} will use the inferred variance of the +parameter, which may be less restrictive; otherwise ({\em i.e.\/} for abstract +types or non-free parameters), the variance must be given explicitly, +and the parameter is invariant if no variance is given. + +The optional type equation @'=' typexpr@ makes the defined type +equivalent to the type expression @typexpr@: +one can be substituted for the other during typing. +If no type equation is given, a new type is generated: the defined type +is incompatible with any other type. + +The optional type representation describes the data structure +representing the defined type, by giving the list of associated +constructors (if it is a variant type) or associated fields (if it is +a record type). If no type representation is given, nothing is +assumed on the structure of the type besides what is stated in the +optional type equation. + +The type representation @'=' ['|'] constr-decl { '|' constr-decl }@ +describes a variant type. The constructor declarations +@constr-decl_1, \ldots, constr-decl_n@ describe the constructors +associated to this variant type. The constructor +declaration @constr-name 'of' typexpr_1 '*' \ldots '*' typexpr_n@ +declares the name @constr-name@ as a non-constant constructor, whose +arguments have types @typexpr_1@ \ldots @typexpr_n@. +The constructor declaration @constr-name@ +declares the name @constr-name@ as a constant +constructor. Constructor names must be capitalized. + +The type representation @'=' '{' field-decl { ';' field-decl } [';'] '}'@ +describes a record type. The field declarations @field-decl_1, \ldots, +field-decl_n@ describe the fields associated to this record type. +The field declaration @field-name ':' poly-typexpr@ declares +@field-name@ as a field whose argument has type @poly-typexpr@. +The field declaration @'mutable' field-name ':' poly-typexpr@ +\ikwd{mutable\@\texttt{mutable}} +behaves similarly; in addition, it allows physical modification of +this field. +Immutable fields are covariant, mutable fields are non-variant. +Both mutable and immutable fields may have explicitly polymorphic +types. The polymorphism of the contents is statically checked whenever +a record value is created or modified. Extracted values may have their +types instantiated. + +The two components of a type definition, the optional equation and the +optional representation, can be combined independently, giving +rise to four typical situations: + +\begin{description} +\item[Abstract type: no equation, no representation.] ~\\ +When appearing in a module signature, this definition specifies +nothing on the type constructor, besides its number of parameters: +its representation is hidden and it is assumed incompatible with any +other type. + +\item[Type abbreviation: an equation, no representation.] ~\\ +This defines the type constructor as an abbreviation for the type +expression on the right of the @'='@ sign. + +\item[New variant type or record type: no equation, a representation.] ~\\ +This generates a new type constructor and defines associated +constructors or fields, through which values of that type can be +directly built or inspected. + +\item[Re-exported variant type or record type: an equation, +a representation.] ~\\ +In this case, the type constructor is defined as an abbreviation for +the type expression given in the equation, but in addition the +constructors or fields given in the representation remain attached to +the defined type constructor. The type expression in the equation part +must agree with the representation: it must be of the same kind +(record or variant) and have exactly the same constructors or fields, +in the same order, with the same arguments. +\end{description} + +The type variables appearing as type parameters can optionally be +prefixed by "+" or "-" to indicate that the type constructor is +covariant or contravariant with respect to this parameter. This +variance information is used to decide subtyping relations when +checking the validity of @":>"@ coercions (see section \ref{s:coercions}). + +For instance, "type +'a t" declares "t" as an abstract type that is +covariant in its parameter; this means that if the type $\tau$ is a +subtype of the type $\sigma$, then $\tau " t"$ is a subtype of $\sigma +" t"$. Similarly, "type -'a t" declares that the abstract type "t" is +contravariant in its parameter: if $\tau$ is a subtype of $\sigma$, then +$\sigma " t"$ is a subtype of $\tau " t"$. If no "+" or "-" variance +annotation is given, the type constructor is assumed non-variant in the +corresponding parameter. For instance, the abstract type declaration +"type 'a t" means that $\tau " t"$ is neither a subtype nor a +supertype of $\sigma " t"$ if $\tau$ is subtype of $\sigma$. + +The variance indicated by the "+" and "-" annotations on parameters +is enforced only for abstract and private types, or when there are +type constraints. +Otherwise, for abbreviations, variant and record types without type +constraints, the variance properties of the type constructor +are inferred from its definition, and the variance annotations are +only checked for conformance with the definition. + +\ikwd{constraint\@\texttt{constraint}} +The construct @ 'constraint' "'" ident '=' typexpr @ allows the +specification of +type parameters. Any actual type argument corresponding to the type +parameter @ident@ has to be an instance of @typexpr@ (more precisely, +@ident@ and @typexpr@ are unified). Type variables of @typexpr@ can +appear in the type equation and the type declaration. + +\subsection{Exception definitions} \label{s:excdef} +\ikwd{exception\@\texttt{exception}} + +\begin{syntax} +exception-definition: + 'exception' constr-decl + | 'exception' constr-name '=' constr +\end{syntax} + +Exception definitions add new constructors to the built-in variant +type \verb"exn" of exception values. The constructors are declared as +for a definition of a variant type. + +The form @'exception' constr-decl@ +generates a new exception, distinct from all other exceptions in the system. +The form @'exception' constr-name '=' constr@ +gives an alternate name to an existing exception. diff --git a/manual/manual/refman/types.etex b/manual/manual/refman/types.etex new file mode 100644 index 00000000..231a1f87 --- /dev/null +++ b/manual/manual/refman/types.etex @@ -0,0 +1,243 @@ +\section{Type expressions} +\pdfsection{Type expressions} +%HEVEA\cutname{types.html} +\ikwd{as\@\texttt{as}} + +\begin{syntax} +typexpr: + "'" ident + | "_" + | '(' typexpr ')' + | [['?']label-name':'] typexpr '->' typexpr + | typexpr {{ '*' typexpr }} + | typeconstr + | typexpr typeconstr + | '(' typexpr { ',' typexpr } ')' typeconstr + | typexpr 'as' "'" ident + | polymorphic-variant-type + | '<' ['..'] '>' + | '<' method-type { ';' method-type } [';' || ';' '..'] '>' + | '#' class-path + | typexpr '#' class-path + | '(' typexpr { ',' typexpr } ')' '#' class-path +; +poly-typexpr: + typexpr + | {{ "'" ident }} '.' typexpr +; +method-type: + method-name ':' poly-typexpr +\end{syntax} +See also the following language extensions: +\hyperref[s-first-class-modules]{first-class modules}, +\hyperref[s:attributes]{attributes} and +\hyperref[s:extension-nodes]{extension nodes}. + +The table below shows the relative precedences and associativity of +operators and non-closed type constructions. The constructions with +higher precedences come first. +\ikwd{as\@\texttt{as}} +\begin{tableau}{|l|l|}{Operator}{Associativity} +\entree{Type constructor application}{--} +\entree{"#"}{--} +\entree{"*"}{--} +\entree{"->"}{right} +\entree{"as"}{--} +\end{tableau} + +Type expressions denote types in definitions of data types as well as +in type constraints over patterns and expressions. + +\subsubsection*{Type variables} + +The type expression @"'" ident@ stands for the type variable named +@ident@. The type expression @"_"@ stands for either an anonymous type +variable or anonymous type parameters. In data type definitions, type +variables are names for the data type parameters. In type constraints, +they represent unspecified types that can be instantiated by any type +to satisfy the type constraint. In general the scope of a named type +variable is the whole top-level phrase where it appears, and it can +only be generalized when leaving this scope. Anonymous variables have +no such restriction. In the following cases, the scope of named type +variables is restricted to the type expression where they appear: +1) for universal (explicitly polymorphic) type variables; +2) for type variables that only appear in public method specifications +(as those variables will be made universal, as described in +section~\ref{sec-methspec}); +3) for variables used as aliases, when the type they are aliased to +would be invalid in the scope of the enclosing definition ({\it i.e.} +when it contains free universal type variables, or locally +defined types.) + +\subsubsection*{Parenthesized types} + +The type expression @"(" typexpr ")"@ denotes the same type as +@typexpr@. + +\subsubsection*{Function types} + +The type expression @typexpr_1 '->' typexpr_2@ denotes the type of +functions mapping arguments of type @typexpr_1@ to results of type +@typexpr_2@. + +@label-name ':' typexpr_1 '->' typexpr_2@ denotes the same function type, but +the argument is labeled @label@. + +@'?' label-name ':' typexpr_1 '->' typexpr_2@ denotes the type of functions +mapping an optional labeled argument of type @typexpr_1@ to results of +type @typexpr_2@. That is, the physical type of the function will be +@typexpr_1 "option" '->' typexpr_2@. + +\subsubsection*{Tuple types} + +The type expression @typexpr_1 '*' \ldots '*' typexpr_n@ +denotes the type of tuples whose elements belong to types @typexpr_1, +\ldots typexpr_n@ respectively. + +\subsubsection*{Constructed types} + +Type constructors with no parameter, as in @typeconstr@, are type +expressions. + +The type expression @typexpr typeconstr@, where @typeconstr@ is a type +constructor with one parameter, denotes the application of the unary type +constructor @typeconstr@ to the type @typexpr@. + +The type expression @(typexpr_1,\ldots,typexpr_n) typeconstr@, where +@typeconstr@ is a type constructor with $n$ parameters, denotes the +application of the $n$-ary type constructor @typeconstr@ to the types +@typexpr_1@ through @typexpr_n@. + +In the type expression @ "_" typeconstr @, the anonymous type expression +@ "_" @ stands in for anonymous type parameters and is equivalent to +@ ("_", \ldots,"_") @ with as many repetitions of "_" as the arity of +@typeconstr@. + +\subsubsection*{Aliased and recursive types} + +\ikwd{as\@\texttt{as}} + +The type expression @typexpr 'as' "'" ident@ denotes the same type as +@typexpr@, and also binds the type variable @ident@ to type @typexpr@ both +in @typexpr@ and in other types. In general the scope of an alias is +the same as for a named type variable, and covers the whole enclosing +definition. If the type variable +@ident@ actually occurs in @typexpr@, a recursive type is created. Recursive +types for which there exists a recursive path that does not contain +an object or polymorphic variant type constructor are rejected, except +when the "-rectypes" mode is selected. + +If @"'" ident@ denotes an explicit polymorphic variable, and @typexpr@ +denotes either an object or polymorphic variant type, the row variable +of @typexpr@ is captured by @"'" ident@, and quantified upon. + +\subsubsection*{Polymorphic variant types} +\ikwd{of\@\texttt{of}} + +\begin{syntax} +polymorphic-variant-type: + '[' tag-spec-first { '|' tag-spec } ']' + | '[>' [ tag-spec ] { '|' tag-spec } ']' + | '[<' ['|'] tag-spec-full { '|' tag-spec-full } + [ '>' {{ '`'tag-name }} ] ']' +; +%\end{syntax} \begin{syntax} +tag-spec-first: + '`'tag-name [ 'of' typexpr ] + | [ typexpr ] '|' tag-spec +; +tag-spec: + '`'tag-name [ 'of' typexpr ] + | typexpr +; +tag-spec-full: + '`'tag-name [ 'of' ['&'] typexpr { '&' typexpr } ] + | typexpr +\end{syntax} + +Polymorphic variant types describe the values a polymorphic variant +may take. + +The first case is an exact variant type: all possible tags are +known, with their associated types, and they can all be present. +Its structure is fully known. + +The second case is an open variant type, describing a polymorphic +variant value: it gives the list of all tags the value could take, +with their associated types. This type is still compatible with a +variant type containing more tags. A special case is the unknown +type, which does not define any tag, and is compatible with any +variant type. + +The third case is a closed variant type. It gives information about +all the possible tags and their associated types, and which tags are +known to potentially appear in values. The exact variant type (first +case) is +just an abbreviation for a closed variant type where all possible tags +are also potentially present. + +In all three cases, tags may be either specified directly in the +@'`'tag-name ["of" typexpr]@ form, or indirectly through a type +expression, which must expand to an +exact variant type, whose tag specifications are inserted in its +place. + +Full specifications of variant tags are only used for non-exact closed +types. They can be understood as a conjunctive type for the argument: +it is intended to have all the types enumerated in the +specification. + +Such conjunctive constraints may be unsatisfiable. In such a case the +corresponding tag may not be used in a value of this type. This +does not mean that the whole type is not valid: one can still use +other available tags. +Conjunctive constraints are mainly intended as output from the type +checker. When they are used in source programs, unsolvable constraints +may cause early failures. + +\subsubsection*{Object types} + +An object type +@'<' [method-type { ';' method-type }] '>'@ +is a record of method types. + +Each method may have an explicit polymorphic type: @{{ "'" ident }} +'.' typexpr@. Explicit polymorphic variables have a local scope, and +an explicit polymorphic type can only be unified to an +equivalent one, where only the order and names of polymorphic +variables may change. + +The type @'<' {method-type ';'} '..' '>'@ is the +type of an object whose method names and types are described by +@method-type_1, \ldots, method-type_n@, and possibly some other +methods represented by the ellipsis. This ellipsis actually is +a special kind of type variable (called {\em row variable} in the +literature) that stands for any number of extra method types. + +\subsubsection*{\#-types} +\label{s:sharp-types} + +The type @'#' class-path@ is a special kind of abbreviation. This +abbreviation unifies with the type of any object belonging to a subclass +of class @class-path@. +% +It is handled in a special way as it usually hides a type variable (an +ellipsis, representing the methods that may be added in a subclass). +In particular, it vanishes when the ellipsis gets instantiated. +% +Each type expression @'#' class-path@ defines a new type variable, so +type @'#' class-path '->' '#' class-path@ is usually not the same as +type @('#' class-path 'as' "'" ident) '->' "'" ident@. +% + +Use of \#-types to abbreviate polymorphic variant types is deprecated. +If @@t@@ is an exact variant type then @"#"@t@@ translates to @"[<" @t@"]"@, +and @"#"@t@"[>" "`"tag_1 \dots"`"tag_k"]"@ translates to +@"[<" @t@ ">" "`"tag_1 \dots"`"tag_k"]"@ + +\subsubsection*{Variant and record types} + +There are no type expressions describing (defined) variant types nor +record types, since those are always named, i.e. defined before use +and referred to by name. Type definitions are described in +section~\ref{s:type-defs}. diff --git a/manual/manual/refman/values.etex b/manual/manual/refman/values.etex new file mode 100644 index 00000000..d5d01f0f --- /dev/null +++ b/manual/manual/refman/values.etex @@ -0,0 +1,97 @@ +\section{Values} +\pdfsection{Values} +%HEVEA\cutname{values.html} + +This section describes the kinds of values that are manipulated by +OCaml programs. + +\subsection{Base values} + +\subsubsection*{Integer numbers} + +Integer values are integer numbers from $-2^{30}$ to $2^{30}-1$, that +is $-1073741824$ to $1073741823$. The implementation may support a +wider range of integer values: on 64-bit platforms, the current +implementation supports integers ranging from $-2^{62}$ to $2^{62}-1$. + +\subsubsection*{Floating-point numbers} + +Floating-point values are numbers in floating-point representation. +The current implementation uses double-precision floating-point +numbers conforming to the IEEE 754 standard, with 53 bits of mantissa +and an exponent ranging from $-1022$ to $1023$. + +\subsubsection*{Characters} + +Character values are represented as 8-bit integers between 0 and 255. +Character codes between 0 and 127 are interpreted following the ASCII +standard. The current implementation interprets character codes +between 128 and 255 following the ISO 8859-1 standard. + +\subsubsection*{Character strings} \label{s:string-val} + +String values are finite sequences of characters. The current +implementation supports strings containing up to $2^{24} - 5$ +characters (16777211 characters); on 64-bit platforms, the limit is +$2^{57} - 9$. + +\subsection{Tuples} + +Tuples of values are written @'('@v@_1',' \ldots',' @v@_n')'@, standing for the +$n$-tuple of values @@v@_1@ to @@v@_n@. The current implementation +supports tuple of up to $2^{22} - 1$ elements (4194303 elements). + +\subsection{Records} + +Record values are labeled tuples of values. The record value written +@'{' field_1 '=' @v@_1';' \ldots';' field_n '=' @v@_n '}'@ associates the value +@@v@_i@ to the record field @field_i@, for $i = 1 \ldots n$. The current +implementation supports records with up to $2^{22} - 1$ fields +(4194303 fields). + +\subsection{Arrays} + +Arrays are finite, variable-sized sequences of values of the same +type. The current implementation supports arrays containing up to +$2^{22} - 1$ elements (4194303 elements) unless the elements are +floating-point numbers (2097151 elements in this case); on 64-bit +platforms, the limit is $2^{54} - 1$ for all arrays. + +\subsection{Variant values} + +Variant values are either a constant constructor, or a non-constant +constructor applied to a number of values. The former case is written +@constr@; the latter case is written @constr '('@v@_1',' ... ',' @v@_n +')'@, where the @@v@_i@ are said to be the arguments of the non-constant +constructor @constr@. The parentheses may be omitted if there is only +one argument. + +The following constants are treated like built-in constant +constructors: +\begin{tableau}{|l|l|}{Constant}{Constructor} +\entree{"false"}{the boolean false} +\entree{"true"}{the boolean true} +\entree{"()"}{the ``unit'' value} +\entree{"[]"}{the empty list} +\end{tableau} + +The current implementation limits each variant type to have at most +246 non-constant constructors and $2^{30}-1$ constant constructors. + +\subsection{Polymorphic variants} + +Polymorphic variants are an alternate form of variant values, not +belonging explicitly to a predefined variant type, and following +specific typing rules. They can be either constant, written +@"`"tag-name@, or non-constant, written @"`"tag-name'('@v@')'@. + +\subsection{Functions} + +Functional values are mappings from values to values. + +\subsection{Objects} + +Objects are composed of a hidden internal state which is a +record of instance variables, and a set of methods for accessing and +modifying these variables. The structure of an object is described by +the toplevel class that created it. diff --git a/manual/manual/style.css b/manual/manual/style.css new file mode 100644 index 00000000..8711a22e --- /dev/null +++ b/manual/manual/style.css @@ -0,0 +1,80 @@ +/* fira-sans-regular - latin */ +@font-face { + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Fira Sans Regular'), local('FiraSans-Regular'), + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('/pub/docs/manual-ocaml/fonts/fira-sans-v8-latin-regular.svg#FiraSans') format('svg'); /* Legacy iOS */ +} + + +a:visited {color : #416DFF; text-decoration : none; } +a:link {color : #416DFF; text-decoration : none; } +a:hover {color : Black; text-decoration : underline; } +a:active {color : Black; text-decoration : underline; } +.keyword { font-weight : bold ; color : Red } +.keywordsign { color : #C04600 } +.comment { color : Green } +.constructor { color : Blue } +.type { color : #5C6585 } +.string { color : Maroon } +.warning { color : Red ; font-weight : bold } +.info { margin-left : 3em; margin-right : 3em } +.code { color : #465F91 ; } +h1 { font-size : 2rem ; text-align: center; } + +h2, h3, h4, h5, h6, div.h7, div.h8, div.h9 { + font-size: 1.75rem; + border: 1px solid #000; + margin-top: 20px; + margin-bottom: 2px; + text-align: center; + padding: 8px; + font-family: "Fira Sans", sans-serif; + font-weight: normal; +} +h1 { + font-family: "Fira Sans", sans-serif; + padding: 10px; +} + +h2 { background-color: #90BDFF; } +h3 { background-color: #90DDFF; } +h4 { background-color: #90EDFF; } +h5 { background-color: #90FDFF; } +h6 { background-color: #90BDFF; } +div.h7 { background-color: #90DDFF; } +div.h8 { background-color: #F0FFFF; } +div.h9 { background-color: #FFFFFF; } + +.typetable { border-style : hidden } +.indextable { border-style : hidden } +.paramstable { border-style : hidden ; padding: 5pt 5pt} +body { + background-color : #f7f7f7; + font-size: 1rem; + max-width: 800px; + width: 85%; + margin: auto; + padding-bottom: 30px; +} +td { + font-size: 1rem; +} +.navbar { /* previous - up - next */ + position: absolute; + left: 10px; + top: 10px; +} +tr { background-color : #f7f7f7 } +td.typefieldcomment { background-color : #f7f7f7 } +pre { margin-bottom: 4px; white-space: pre-wrap; } +div.sig_block {margin-left: 2em} +ul.info-attributes { list-style: none; margin: 0; padding: 0; } +div.info > p:first-child{ margin-top:0; } +div.info-desc > p:first-child { margin-top:0; margin-bottom:0; } diff --git a/manual/manual/texstuff/.cvsignore b/manual/manual/texstuff/.cvsignore new file mode 100644 index 00000000..84eade83 --- /dev/null +++ b/manual/manual/texstuff/.cvsignore @@ -0,0 +1,13 @@ +*.aux +*.dvi +*.idx +*.ilg +*.ind +*.log +*.toc +*.ipr +*.txt +*.pdf +*.ps +pdfmanual.out +manual.out diff --git a/manual/manual/texstuff/.gitignore b/manual/manual/texstuff/.gitignore new file mode 100644 index 00000000..84eade83 --- /dev/null +++ b/manual/manual/texstuff/.gitignore @@ -0,0 +1,13 @@ +*.aux +*.dvi +*.idx +*.ilg +*.ind +*.log +*.toc +*.ipr +*.txt +*.pdf +*.ps +pdfmanual.out +manual.out diff --git a/manual/manual/textman/.cvsignore b/manual/manual/textman/.cvsignore new file mode 100644 index 00000000..72475845 --- /dev/null +++ b/manual/manual/textman/.cvsignore @@ -0,0 +1,5 @@ +manual.txt +manual.hmanual.kwd +*.haux +*.hind +*.htoc diff --git a/manual/manual/textman/.gitignore b/manual/manual/textman/.gitignore new file mode 100644 index 00000000..72475845 --- /dev/null +++ b/manual/manual/textman/.gitignore @@ -0,0 +1,5 @@ +manual.txt +manual.hmanual.kwd +*.haux +*.hind +*.htoc diff --git a/manual/manual/tutorials/.cvsignore b/manual/manual/tutorials/.cvsignore new file mode 100644 index 00000000..81ccbe71 --- /dev/null +++ b/manual/manual/tutorials/.cvsignore @@ -0,0 +1,2 @@ +*.tex +*.htex diff --git a/manual/manual/tutorials/.gitignore b/manual/manual/tutorials/.gitignore new file mode 100644 index 00000000..81ccbe71 --- /dev/null +++ b/manual/manual/tutorials/.gitignore @@ -0,0 +1,2 @@ +*.tex +*.htex diff --git a/manual/manual/tutorials/Makefile b/manual/manual/tutorials/Makefile new file mode 100644 index 00000000..b454374d --- /dev/null +++ b/manual/manual/tutorials/Makefile @@ -0,0 +1,31 @@ +FILES= coreexamples.tex lablexamples.tex objectexamples.tex moduleexamples.tex\ +advexamples.tex polymorphism.tex + +TOPDIR=../../.. +include $(TOPDIR)/Makefile.tools + +LD_PATH="$(TOPDIR)/otherlibs/str:$(TOPDIR)/otherlibs/unix" + +CAMLLATEX=$(SET_LD_PATH) $(OCAMLRUN) ../../tools/caml-tex2 +TEXQUOTE=../../tools/texquote2 + +ALLFILES=$(FILES) + +etex-files: $(ALLFILES) +all: $(ALLFILES) + +clean: + rm -f $(ALLFILES) + +.SUFFIXES: +.SUFFIXES: .etex .tex + +.etex.tex: + @$(CAMLLATEX) -caml "TERM=norepeat $(OCAML)" -n 80 -v false\ + -o $*.caml_tex_error.tex $*.etex\ + && mv $*.caml_tex_error.tex $*.gen.tex\ + && $(TEXQUOTE) < $*.gen.tex > $*.texquote_error.tex\ + && mv $*.texquote_error.tex $*.tex\ + || printf "Failure when generating %s\n" $*.tex + +$(ALLFILES): ../../tools/caml-tex2 $(TEXQUOTE) diff --git a/manual/manual/tutorials/advexamples.etex b/manual/manual/tutorials/advexamples.etex new file mode 100644 index 00000000..2be639d5 --- /dev/null +++ b/manual/manual/tutorials/advexamples.etex @@ -0,0 +1,647 @@ +\chapter{Advanced examples with classes and modules} +\pdfchapterfold{-3}{Tutorial: Advanced examples with classes and modules} +%HEVEA\cutname{advexamples.html} +\label{c:advexamples} + +{\it (Chapter written by Didier Rémy)} + +\bigskip + +\noindent + +In this chapter, we show some larger examples using objects, classes +and modules. We review many of the object features simultaneously on +the example of a bank account. We show how modules taken from the +standard library can be expressed as classes. Lastly, we describe a +programming pattern known as {\em virtual types} through the example +of window managers. + +\section{Extended example: bank accounts} +\pdfsection{Extended example: bank accounts} +\label{ss:bank-accounts} + +In this section, we illustrate most aspects of Object and inheritance +by refining, debugging, and specializing the following +initial naive definition of a simple bank account. (We reuse the +module "Euro" defined at the end of chapter~\ref{c:objectexamples}.) +\begin{caml_eval} +module type MONEY = + sig + type t + class c : float -> + object ('a) + val repr : t + method value : t + method print : unit + method times : float -> 'a + method leq : 'a -> bool + method plus : 'a -> 'a + end + end;; +module Euro : MONEY = + struct + type t = float + class c x = + object (self : 'a) + val repr = x + method value = repr + method print = print_float repr + method times k = {< repr = k *. x >} + method leq (p : 'a) = repr <= p#value + method plus (p : 'a) = {< repr = x +. p#value >} + end + end;; +\end{caml_eval} +\begin{caml_example}{toplevel} +let euro = new Euro.c;; +let zero = euro 0.;; +let neg x = x#times (-1.);; +class account = + object + val mutable balance = zero + method balance = balance + method deposit x = balance <- balance # plus x + method withdraw x = + if x#leq balance then (balance <- balance # plus (neg x); x) else zero + end;; +let c = new account in c # deposit (euro 100.); c # withdraw (euro 50.);; +\end{caml_example} +We now refine this definition with a method to compute interest. +\begin{caml_example}{toplevel} +class account_with_interests = + object (self) + inherit account + method private interest = self # deposit (self # balance # times 0.03) + end;; +\end{caml_example} +We make the method "interest" private, since clearly it should not be +called freely from the outside. Here, it is only made accessible to subclasses +that will manage monthly or yearly updates of the account. + +We should soon fix a bug in the current definition: the deposit method can +be used for withdrawing money by depositing negative amounts. We can +fix this directly: +\begin{caml_example}{toplevel} +class safe_account = + object + inherit account + method deposit x = if zero#leq x then balance <- balance#plus x + end;; +\end{caml_example} +However, the bug might be fixed more safely by the following definition: +\begin{caml_example}{toplevel} +class safe_account = + object + inherit account as unsafe + method deposit x = + if zero#leq x then unsafe # deposit x + else raise (Invalid_argument "deposit") + end;; +\end{caml_example} +In particular, this does not require the knowledge of the implementation of +the method "deposit". + +To keep track of operations, we extend the class with a mutable field +"history" and a private method "trace" to add an operation in the +log. Then each method to be traced is redefined. +\begin{caml_example}{toplevel} +type 'a operation = Deposit of 'a | Retrieval of 'a;; +class account_with_history = + object (self) + inherit safe_account as super + val mutable history = [] + method private trace x = history <- x :: history + method deposit x = self#trace (Deposit x); super#deposit x + method withdraw x = self#trace (Retrieval x); super#withdraw x + method history = List.rev history + end;; +\end{caml_example} +%% \label{ss:bank:initializer} +One may wish to open an account and simultaneously deposit some initial +amount. Although the initial implementation did not address this +requirement, it can be achieved by using an initializer. +\begin{caml_example}{toplevel} +class account_with_deposit x = + object + inherit account_with_history + initializer balance <- x + end;; +\end{caml_example} +A better alternative is: +\begin{caml_example}{toplevel} +class account_with_deposit x = + object (self) + inherit account_with_history + initializer self#deposit x + end;; +\end{caml_example} +Indeed, the latter is safer since the call to "deposit" will automatically +benefit from safety checks and from the trace. +Let's test it: +\begin{caml_example}{toplevel} +let ccp = new account_with_deposit (euro 100.) in +let _balance = ccp#withdraw (euro 50.) in +ccp#history;; +\end{caml_example} +Closing an account can be done with the following polymorphic function: +\begin{caml_example}{toplevel} +let close c = c#withdraw c#balance;; +\end{caml_example} +Of course, this applies to all sorts of accounts. + +Finally, we gather several versions of the account into a module "Account" +abstracted over some currency. +\begin{caml_example*}{toplevel} +let today () = (01,01,2000) (* an approximation *) +module Account (M:MONEY) = + struct + type m = M.c + let m = new M.c + let zero = m 0. + + class bank = + object (self) + val mutable balance = zero + method balance = balance + val mutable history = [] + method private trace x = history <- x::history + method deposit x = + self#trace (Deposit x); + if zero#leq x then balance <- balance # plus x + else raise (Invalid_argument "deposit") + method withdraw x = + if x#leq balance then + (balance <- balance # plus (neg x); self#trace (Retrieval x); x) + else zero + method history = List.rev history + end + + class type client_view = + object + method deposit : m -> unit + method history : m operation list + method withdraw : m -> m + method balance : m + end + + class virtual check_client x = + let y = if (m 100.)#leq x then x + else raise (Failure "Insufficient initial deposit") in + object (self) + initializer self#deposit y + method virtual deposit: m -> unit + end + + module Client (B : sig class bank : client_view end) = + struct + class account x : client_view = + object + inherit B.bank + inherit check_client x + end + + let discount x = + let c = new account x in + if today() < (1998,10,30) then c # deposit (m 100.); c + end + end;; +\end{caml_example*} +This shows the use of modules to group several class definitions that can in +fact be thought of as a single unit. This unit would be provided by a bank +for both internal and external uses. +This is implemented as a functor that abstracts over the currency so that +the same code can be used to provide accounts in different currencies. + +The class "bank" is the {\em real} implementation of the bank account (it +could have been inlined). This is the one that will be used for further +extensions, refinements, etc. Conversely, the client will only be given the client view. +\begin{caml_example*}{toplevel} +module Euro_account = Account(Euro);; +module Client = Euro_account.Client (Euro_account);; +new Client.account (new Euro.c 100.);; +\end{caml_example*} +Hence, the clients do not have direct access to the "balance", nor the +"history" of their own accounts. Their only way to change their balance is +to deposit or withdraw money. It is important to give the clients +a class and not just the ability to create accounts (such as the +promotional "discount" account), so that they can +personalize their account. +For instance, a client may refine the "deposit" and "withdraw" methods +so as to do his own financial bookkeeping, automatically. On the +other hand, the function "discount" is given as such, with no +possibility for further personalization. + +It is important to provide the client's view as a functor +"Client" so that client accounts can still be built after a possible +specialization of the "bank". +The functor "Client" may remain unchanged and be passed +the new definition to initialize a client's view of the extended account. +\begin{caml_example*}{toplevel} +module Investment_account (M : MONEY) = + struct + type m = M.c + module A = Account(M) + + class bank = + object + inherit A.bank as super + method deposit x = + if (new M.c 1000.)#leq x then + print_string "Would you like to invest?"; + super#deposit x + end + + module Client = A.Client + end;; +\end{caml_example*} +\begin{caml_eval} +module Euro_account = Investment_account (Euro);; +module Client = Euro_account.Client (Euro_account);; +new Client.account (new Euro.c 100.);; +\end{caml_eval} +The functor "Client" may also be redefined when some new features of the +account can be given to the client. +\begin{caml_example*}{toplevel} +module Internet_account (M : MONEY) = + struct + type m = M.c + module A = Account(M) + + class bank = + object + inherit A.bank + method mail s = print_string s + end + + class type client_view = + object + method deposit : m -> unit + method history : m operation list + method withdraw : m -> m + method balance : m + method mail : string -> unit + end + + module Client (B : sig class bank : client_view end) = + struct + class account x : client_view = + object + inherit B.bank + inherit A.check_client x + end + end + end;; +\end{caml_example*} +\begin{caml_eval} +module Euro_account = Internet_account (Euro);; +module Client = Euro_account.Client (Euro_account);; +new Client.account (new Euro.c 100.);; +\end{caml_eval} + + +\section{Simple modules as classes} +\pdfsection{Simple modules as classes} +\label{ss:modules-as-classes} + +One may wonder whether it is possible to treat primitive types such as +integers and strings as objects. Although this is usually uninteresting +for integers or strings, there may be some situations where +this is desirable. The class "money" above is such an example. +We show here how to do it for strings. + +\subsection{Strings} +\label{module:string} + +A naive definition of strings as objects could be: +\begin{caml_example}{toplevel} +class ostring s = + object + method get n = String.get s n + method print = print_string s + method escaped = new ostring (String.escaped s) + end;; +\end{caml_example} +However, the method "escaped" returns an object of the class "ostring", +and not an object of the current class. Hence, if the class is further +extended, the method "escaped" will only return an object of the parent +class. +\begin{caml_example}{toplevel} +class sub_string s = + object + inherit ostring s + method sub start len = new sub_string (String.sub s start len) + end;; +\end{caml_example} +As seen in section \ref{ss:binary-methods}, the solution is to use +functional update instead. We need to create an instance variable +containing the representation "s" of the string. +\begin{caml_example}{toplevel} +class better_string s = + object + val repr = s + method get n = String.get repr n + method print = print_string repr + method escaped = {< repr = String.escaped repr >} + method sub start len = {< repr = String.sub s start len >} + end;; +\end{caml_example} +As shown in the inferred type, the methods "escaped" and "sub" now return +objects of the same type as the one of the class. + +Another difficulty is the implementation of the method "concat". +In order to concatenate a string with another string of the same class, +one must be able to access the instance variable externally. Thus, a method +"repr" returning s must be defined. Here is the correct definition of +strings: +\begin{caml_example}{toplevel} +class ostring s = + object (self : 'mytype) + val repr = s + method repr = repr + method get n = String.get repr n + method print = print_string repr + method escaped = {< repr = String.escaped repr >} + method sub start len = {< repr = String.sub s start len >} + method concat (t : 'mytype) = {< repr = repr ^ t#repr >} + end;; +\end{caml_example} +Another constructor of the class string can be defined to return a new +string of a given length: +\begin{caml_example}{toplevel} +class cstring n = ostring (String.make n ' ');; +\end{caml_example} +Here, exposing the representation of strings is probably harmless. We do +could also hide the representation of strings as we hid the currency in the +class "money" of section~\ref{ss:friends}. + +\subsubsection{Stacks} +\label{module:stack} + +There is sometimes an alternative between using modules or classes for +parametric data types. +Indeed, there are situations when the two approaches are quite similar. +For instance, a stack can be straightforwardly implemented as a class: +\begin{caml_example}{toplevel} +exception Empty;; +class ['a] stack = + object + val mutable l = ([] : 'a list) + method push x = l <- x::l + method pop = match l with [] -> raise Empty | a::l' -> l <- l'; a + method clear = l <- [] + method length = List.length l + end;; +\end{caml_example} +However, writing a method for iterating over a stack is more +problematic. A method "fold" would have type +"('b -> 'a -> 'b) -> 'b -> 'b". Here "'a" is the parameter of the stack. +The parameter "'b" is not related to the class "'a stack" but to the +argument that will be passed to the method "fold". +%The intuition is that method "fold" should be polymorphic, i.e. of type +%"All ('a) ('b -> 'a -> 'b) -> 'b -> 'b". +A naive approach is to make "'b" an extra parameter of class "stack": +\begin{caml_example}{toplevel} +class ['a, 'b] stack2 = + object + inherit ['a] stack + method fold f (x : 'b) = List.fold_left f x l + end;; +\end{caml_example} +However, the method "fold" of a given object can only be +applied to functions that all have the same type: +\begin{caml_example}{toplevel} +let s = new stack2;; +s#fold ( + ) 0;; +s;; +\end{caml_example} +A better solution is to use polymorphic methods, which were +introduced in OCaml version 3.05. Polymorphic methods makes +it possible to treat the type variable "'b" in the type of "fold" as +universally quantified, giving "fold" the polymorphic type +"Forall 'b. ('b -> 'a -> 'b) -> 'b -> 'b". +An explicit type declaration on the method "fold" is required, since +the type checker cannot infer the polymorphic type by itself. +\begin{caml_example}{toplevel} +class ['a] stack3 = + object + inherit ['a] stack + method fold : 'b. ('b -> 'a -> 'b) -> 'b -> 'b + = fun f x -> List.fold_left f x l + end;; +\end{caml_example} + +% However, the nice correspondence between the implementations of stacks as +% modules or classes is a very particular case. + +% XXX Maps + +\subsection{Hashtbl} +\label{module:hashtbl} + +A simplified version of object-oriented hash tables should have the +following class type. +\begin{caml_example}{toplevel} +class type ['a, 'b] hash_table = + object + method find : 'a -> 'b + method add : 'a -> 'b -> unit + end;; +\end{caml_example} +A simple implementation, which is quite reasonable for small hash tables is +to use an association list: +\begin{caml_example}{toplevel} +class ['a, 'b] small_hashtbl : ['a, 'b] hash_table = + object + val mutable table = [] + method find key = List.assoc key table + method add key valeur = table <- (key, valeur) :: table + end;; +\end{caml_example} +A better implementation, and one that scales up better, is to use a +true hash table\ldots\ whose elements are small hash tables! +\begin{caml_example}{toplevel} +class ['a, 'b] hashtbl size : ['a, 'b] hash_table = + object (self) + val table = Array.init size (fun i -> new small_hashtbl) + method private hash key = + (Hashtbl.hash key) mod (Array.length table) + method find key = table.(self#hash key) # find key + method add key = table.(self#hash key) # add key + end;; +\end{caml_example} + +% problem + +% solution + +\subsection{Sets} +\label{module:set} + +Implementing sets leads to another difficulty. Indeed, the method +"union" needs to be able to access the internal representation of +another object of the same class. + +This is another instance of friend functions as seen in section +\ref{ss:friends}. Indeed, this is the same mechanism used in the module +"Set" in the absence of objects. + +In the object-oriented version of sets, we only need to add an additional +method "tag" to return the representation of a set. Since sets are +parametric in the type of elements, the method "tag" has a parametric type +"'a tag", concrete within +the module definition but abstract in its signature. +From outside, it will then be guaranteed that two objects with a method "tag" +of the same type will share the same representation. +\begin{caml_example*}{toplevel} +module type SET = + sig + type 'a tag + class ['a] c : + object ('b) + method is_empty : bool + method mem : 'a -> bool + method add : 'a -> 'b + method union : 'b -> 'b + method iter : ('a -> unit) -> unit + method tag : 'a tag + end + end;; +module Set : SET = + struct + let rec merge l1 l2 = + match l1 with + [] -> l2 + | h1 :: t1 -> + match l2 with + [] -> l1 + | h2 :: t2 -> + if h1 < h2 then h1 :: merge t1 l2 + else if h1 > h2 then h2 :: merge l1 t2 + else merge t1 l2 + type 'a tag = 'a list + class ['a] c = + object (_ : 'b) + val repr = ([] : 'a list) + method is_empty = (repr = []) + method mem x = List.exists (( = ) x) repr + method add x = {< repr = merge [x] repr >} + method union (s : 'b) = {< repr = merge repr s#tag >} + method iter (f : 'a -> unit) = List.iter f repr + method tag = repr + end + end;; +\end{caml_example*} + +\section{The subject/observer pattern} +\pdfsection{The subject/observer pattern} +\label{ss:subject-observer} + +The following example, known as the subject/observer pattern, is often +presented in the literature as a difficult inheritance problem with +inter-connected classes. +The general pattern amounts to the definition a pair of two +classes that recursively interact with one another. + +The class "observer" has a distinguished method "notify" that requires +two arguments, a subject and an event to execute an action. +\begin{caml_example}{toplevel} +class virtual ['subject, 'event] observer = + object + method virtual notify : 'subject -> 'event -> unit + end;; +\end{caml_example} +The class "subject" remembers a list of observers in an instance variable, +and has a distinguished method "notify_observers" to broadcast the message +"notify" to all observers with a particular event "e". +\begin{caml_example}{toplevel} +class ['observer, 'event] subject = + object (self) + val mutable observers = ([]:'observer list) + method add_observer obs = observers <- (obs :: observers) + method notify_observers (e : 'event) = + List.iter (fun x -> x#notify self e) observers + end;; +\end{caml_example} +The difficulty usually lies in defining instances of the pattern above +by inheritance. This can be done in a natural and obvious manner in +OCaml, as shown on the following example manipulating windows. +\begin{caml_example}{toplevel} +type event = Raise | Resize | Move;; +let string_of_event = function + Raise -> "Raise" | Resize -> "Resize" | Move -> "Move";; +let count = ref 0;; +class ['observer] window_subject = + let id = count := succ !count; !count in + object (self) + inherit ['observer, event] subject + val mutable position = 0 + method identity = id + method move x = position <- position + x; self#notify_observers Move + method draw = Printf.printf "{Position = %d}\n" position; + end;; +class ['subject] window_observer = + object + inherit ['subject, event] observer + method notify s e = s#draw + end;; +\end{caml_example} +As can be expected, the type of "window" is recursive. +\begin{caml_example}{toplevel} +let window = new window_subject;; +\end{caml_example} +However, the two classes of "window_subject" and "window_observer" are not +mutually recursive. +\begin{caml_example}{toplevel} +let window_observer = new window_observer;; +window#add_observer window_observer;; +window#move 1;; +\end{caml_example} + +Classes "window_observer" and "window_subject" can still be extended by +inheritance. For instance, one may enrich the "subject" with new +behaviors and refine the behavior of the observer. +\begin{caml_example}{toplevel} +class ['observer] richer_window_subject = + object (self) + inherit ['observer] window_subject + val mutable size = 1 + method resize x = size <- size + x; self#notify_observers Resize + val mutable top = false + method raise = top <- true; self#notify_observers Raise + method draw = Printf.printf "{Position = %d; Size = %d}\n" position size; + end;; +class ['subject] richer_window_observer = + object + inherit ['subject] window_observer as super + method notify s e = if e <> Raise then s#raise; super#notify s e + end;; +\end{caml_example} +We can also create a different kind of observer: +\begin{caml_example}{toplevel} +class ['subject] trace_observer = + object + inherit ['subject, event] observer + method notify s e = + Printf.printf + "\n" s#identity (string_of_event e) + end;; +\end{caml_example} +and attach several observers to the same object: +\begin{caml_example}{toplevel} +let window = new richer_window_subject;; +window#add_observer (new richer_window_observer);; +window#add_observer (new trace_observer);; +window#move 1; window#resize 2;; +\end{caml_example} + +%\subsection{Classes used as modules with inheritance} +% +% to be filled for next release... +% +% an example of stateless objects used to provide inheritance in modules +% + + +% LocalWords: objectexamples bsection init caml val int Oo succ incr ref +% LocalWords: typecheck leq bool cp eval sig struct ABSPOINT Abspoint iter neg +% LocalWords: accu mem rec repr Euro euro ccp inlined ostring len concat OCaml diff --git a/manual/manual/tutorials/coreexamples.etex b/manual/manual/tutorials/coreexamples.etex new file mode 100644 index 00000000..396265b0 --- /dev/null +++ b/manual/manual/tutorials/coreexamples.etex @@ -0,0 +1,761 @@ +\chapter{The core language} \label{c:core-xamples} +\pdfchapterfold{-9}{Tutorial: The core language} +%HEVEA\cutname{coreexamples.html} + +This part of the manual is a tutorial introduction to the +OCaml language. A good familiarity with programming in a conventional +languages (say, C or Java) is assumed, but no prior exposure to +functional languages is required. The present chapter introduces the +core language. Chapter~\ref{c:moduleexamples} deals with the +module system, chapter~\ref{c:objectexamples} with the +object-oriented features, chapter~\ref{c:labl-examples} with +extensions to the core language (labeled arguments and polymorphic +variants), and chapter~\ref{c:advexamples} gives some advanced examples. + +\section{Basics} +\pdfsection{Basics} + +For this overview of OCaml, we use the interactive system, which +is started by running "ocaml" from the Unix shell, or by launching the +"OCamlwin.exe" application under Windows. This tutorial is presented +as the transcript of a session with the interactive system: +lines starting with "#" represent user input; the system responses are +printed below, without a leading "#". + +Under the interactive system, the user types OCaml phrases terminated +by ";;" in response to the "#" prompt, and the system compiles them +on the fly, executes them, and prints the outcome of evaluation. +Phrases are either simple expressions, or "let" definitions of +identifiers (either values or functions). +\begin{caml_example}{toplevel} +1+2*3;; +let pi = 4.0 *. atan 1.0;; +let square x = x *. x;; +square (sin pi) +. square (cos pi);; +\end{caml_example} +The OCaml system computes both the value and the type for +each phrase. Even function parameters need no explicit type declaration: +the system infers their types from their usage in the +function. Notice also that integers and floating-point numbers are +distinct types, with distinct operators: "+" and "*" operate on +integers, but "+." and "*." operate on floats. +\begin{caml_example}{toplevel}[error] +1.0 * 2;; +\end{caml_example} + +Recursive functions are defined with the "let rec" binding: +\begin{caml_example}{toplevel} +let rec fib n = + if n < 2 then n else fib (n-1) + fib (n-2);; +fib 10;; +\end{caml_example} + +\section{Data types} +\pdfsection{Data types} + +In addition to integers and floating-point numbers, OCaml offers the +usual basic data types: booleans, characters, and immutable character strings. +\begin{caml_example}{toplevel} +(1 < 2) = false;; +'a';; +"Hello world";; +\end{caml_example} + +Predefined data structures include tuples, arrays, and lists. There are also +general mechanisms for defining your own data structures, such as records and +variants, which will be covered in more detail later; for now, we concentrate +on lists. Lists are either given in extension as a bracketed list of +semicolon-separated elements, or built from the empty list "[]" +(pronounce ``nil'') by adding elements in front using the "::" +(``cons'') operator. +\begin{caml_example}{toplevel} +let l = ["is"; "a"; "tale"; "told"; "etc."];; +"Life" :: l;; +\end{caml_example} +As with all other OCaml data structures, lists do not need to be +explicitly allocated and deallocated from memory: all memory +management is entirely automatic in OCaml. Similarly, there is no +explicit handling of pointers: the OCaml compiler silently introduces +pointers where necessary. + +As with most OCaml data structures, inspecting and destructuring lists +is performed by pattern-matching. List patterns have exactly the same +form as list expressions, with identifiers representing unspecified +parts of the list. As an example, here is insertion sort on a list: +\begin{caml_example}{toplevel} +let rec sort lst = + match lst with + [] -> [] + | head :: tail -> insert head (sort tail) +and insert elt lst = + match lst with + [] -> [elt] + | head :: tail -> if elt <= head then elt :: lst else head :: insert elt tail +;; +sort l;; +\end{caml_example} + +The type inferred for "sort", "'a list -> 'a list", means that "sort" +can actually apply to lists of any type, and returns a list of the +same type. The type "'a" is a {\em type variable}, and stands for any +given type. The reason why "sort" can apply to lists of any type is +that the comparisons ("=", "<=", etc.) are {\em polymorphic} in OCaml: +they operate between any two values of the same type. This makes +"sort" itself polymorphic over all list types. +\begin{caml_example}{toplevel} +sort [6;2;5;3];; +sort [3.14; 2.718];; +\end{caml_example} + +The "sort" function above does not modify its input list: it builds +and returns a new list containing the same elements as the input list, +in ascending order. There is actually no way in OCaml to modify +a list in-place once it is built: we say that lists are {\em immutable} +data structures. Most OCaml data structures are immutable, but a few +(most notably arrays) are {\em mutable}, meaning that they can be +modified in-place at any time. + +The OCaml notation for the type of a function with multiple arguments is \\ +"arg1_type -> arg2_type -> ... -> return_type". For example, +the type inferred for "insert", "'a -> 'a list -> 'a list", means that "insert" +takes two arguments, an element of any type "'a" and a list with elements of +the same type "'a" and returns a list of the same type. +\section{Functions as values} +\pdfsection{Functions as values} + +OCaml is a functional language: functions in the full mathematical +sense are supported and can be passed around freely just as any other +piece of data. For instance, here is a "deriv" function that takes any +float function as argument and returns an approximation of its +derivative function: +\begin{caml_example}{toplevel} +let deriv f dx = function x -> (f (x +. dx) -. f x) /. dx;; +let sin' = deriv sin 1e-6;; +sin' pi;; +\end{caml_example} +Even function composition is definable: +\begin{caml_example}{toplevel} +let compose f g = function x -> f (g x);; +let cos2 = compose square cos;; +\end{caml_example} + +Functions that take other functions as arguments are called +``functionals'', or ``higher-order functions''. Functionals are +especially useful to provide iterators or similar generic operations +over a data structure. For instance, the standard OCaml library +provides a "List.map" functional that applies a given function to each +element of a list, and returns the list of the results: +\begin{caml_example}{toplevel} +List.map (function n -> n * 2 + 1) [0;1;2;3;4];; +\end{caml_example} +This functional, along with a number of other list and array +functionals, is predefined because it is often useful, but there is +nothing magic with it: it can easily be defined as follows. +\begin{caml_example}{toplevel} +let rec map f l = + match l with + [] -> [] + | hd :: tl -> f hd :: map f tl;; +\end{caml_example} + +\section{Records and variants} +\pdfsection{Records and variants} +\label{s:tut-recvariants} + +User-defined data structures include records and variants. Both are +defined with the "type" declaration. Here, we declare a record type to +represent rational numbers. +\begin{caml_example}{toplevel} +type ratio = {num: int; denom: int};; +let add_ratio r1 r2 = + {num = r1.num * r2.denom + r2.num * r1.denom; + denom = r1.denom * r2.denom};; +add_ratio {num=1; denom=3} {num=2; denom=5};; +\end{caml_example} +Record fields can also be accessed through pattern-matching: +\begin{caml_example}{toplevel} +let integer_part r = + match r with + {num=num; denom=denom} -> num / denom;; +\end{caml_example} +Since there is only one case in this pattern matching, it +is safe to expand directly the argument "r" in a record pattern: +\begin{caml_example}{toplevel} +let integer_part {num=num; denom=denom} = num / denom;; +\end{caml_example} +Unneeded fields can be omitted: +\begin{caml_example}{toplevel} +let get_denom {denom=denom} = denom;; +\end{caml_example} +Optionally, missing fields can be made explicit by ending the list of +fields with a trailing wildcard "_":: +\begin{caml_example}{toplevel} +let get_num {num=num; _ } = num;; +\end{caml_example} +When both sides of the "=" sign are the same, it is possible to avoid +repeating the field name by eliding the "=field" part: +\begin{caml_example}{toplevel} +let integer_part {num; denom} = num / denom;; +\end{caml_example} +This short notation for fields also works when constructing records: +\begin{caml_example}{toplevel} +let ratio num denom = {num; denom};; +\end{caml_example} +At last, it is possible to update few fields of a record at once: +\begin{caml_example}{toplevel} + let integer_product integer ratio = { ratio with num = integer * ratio.num };; +\end{caml_example} +With this functional update notation, the record on the left-hand side +of "with" is copied except for the fields on the right-hand side which +are updated. + +The declaration of a variant type lists all possible forms for values +of that type. Each case is identified by a name, called a constructor, +which serves both for constructing values of the variant type and +inspecting them by pattern-matching. Constructor names are capitalized +to distinguish them from variable names (which must start with a +lowercase letter). For instance, here is a variant +type for doing mixed arithmetic (integers and floats): +\begin{caml_example}{toplevel} +type number = Int of int | Float of float | Error;; +\end{caml_example} +This declaration expresses that a value of type "number" is either an +integer, a floating-point number, or the constant "Error" representing +the result of an invalid operation (e.g. a division by zero). + +Enumerated types are a special case of variant types, where all +alternatives are constants: +\begin{caml_example}{toplevel} +type sign = Positive | Negative;; +let sign_int n = if n >= 0 then Positive else Negative;; +\end{caml_example} + +To define arithmetic operations for the "number" type, we use +pattern-matching on the two numbers involved: +\begin{caml_example}{toplevel} +let add_num n1 n2 = + match (n1, n2) with + (Int i1, Int i2) -> + (* Check for overflow of integer addition *) + if sign_int i1 = sign_int i2 && sign_int (i1 + i2) <> sign_int i1 + then Float(float i1 +. float i2) + else Int(i1 + i2) + | (Int i1, Float f2) -> Float(float i1 +. f2) + | (Float f1, Int i2) -> Float(f1 +. float i2) + | (Float f1, Float f2) -> Float(f1 +. f2) + | (Error, _) -> Error + | (_, Error) -> Error;; +add_num (Int 123) (Float 3.14159);; +\end{caml_example} + +Another interesting example of variant type is the built-in +"'a option" type which represents either a value of type "'a" or an +absence of value: +\begin{caml_example}{toplevel} +type 'a option = Some of 'a | None;; +\end{caml_example} +This type is particularly useful when defining function that can +fail in common situations, for instance +\begin{caml_example}{toplevel} +let safe_square_root x = if x > 0. then Some(sqrt x) else None;; +\end{caml_example} + +The most common usage of variant types is to describe recursive data +structures. Consider for example the type of binary trees: +\begin{caml_example}{toplevel} +type 'a btree = Empty | Node of 'a * 'a btree * 'a btree;; +\end{caml_example} +This definition reads as follows: a binary tree containing values of +type "'a" (an arbitrary type) is either empty, or is a node containing +one value of type "'a" and two subtrees also containing values of type +"'a", that is, two "'a btree". + +Operations on binary trees are naturally expressed as recursive functions +following the same structure as the type definition itself. For +instance, here are functions performing lookup and insertion in +ordered binary trees (elements increase from left to right): +\begin{caml_example}{toplevel} +let rec member x btree = + match btree with + Empty -> false + | Node(y, left, right) -> + if x = y then true else + if x < y then member x left else member x right;; +let rec insert x btree = + match btree with + Empty -> Node(x, Empty, Empty) + | Node(y, left, right) -> + if x <= y then Node(y, insert x left, right) + else Node(y, left, insert x right);; +\end{caml_example} + + +\subsection{Record and variant disambiguation} +( This subsection can be skipped on the first reading ) + +Astute readers may have wondered what happens when two or more record +fields or constructors share the same name + +\begin{caml_example*}{toplevel} +type first_record = { x:int; y:int; z:int } +type middle_record = { x:int; z:int } +type last_record = { x:int };; +type first_variant = A | B | C +type last_variant = A;; +\end{caml_example*} + +The answer is that when confronted with multiple options, OCaml tries to +use locally available information to disambiguate between the various fields +and constructors. First, if the type of the record or variant is known, +OCaml can pick unambiguously the corresponding field or constructor. +For instance: + +\begin{caml_example}{toplevel} +let look_at_x_then_z (r:first_record) = + let x = r.x in + x + r.z;; +let permute (x:first_variant) = match x with + | A -> (B:first_variant) + | B -> A + | C -> C;; +type wrapped = First of first_record +let f (First r) = r, r.x;; +\end{caml_example} + +In the first example, "(r:first_record)" is an explicit annotation +telling OCaml that the type of "r" is "first_record". With this +annotation, Ocaml knows that "r.x" refers to the "x" field of the first +record type. Similarly, the type annotation in the second example makes +it clear to OCaml that the constructors "A", "B" and "C" come from the +first variant type. Contrarily, in the last example, OCaml has inferred +by itself that the type of "r" can only be "first_record" and there are +no needs for explicit type annotations. + +Those explicit type annotations can in fact be used anywhere. +Most of the time they are unnecessary, but they are useful to guide +disambiguation, to debug unexpected type errors, or combined with some +of the more advanced features of OCaml described in later chapters. + +Secondly, for records, OCaml can also deduce the right record type by +looking at the whole set of fields used in a expression or pattern: +\begin{caml_example}{toplevel} +let project_and_rotate {x;y; _ } = { x= - y; y = x ; z = 0} ;; +\end{caml_example} +Since the fields "x" and "y" can only appear simultaneously in the first +record type, OCaml infers that the type of "project_and_rotate" is +"first_record -> first_record". + +In last resort, if there is not enough information to disambiguate between +different fields or constructors, Ocaml picks the last defined type +amongst all locally valid choices: + +\begin{caml_example}{toplevel} +let look_at_xz {x;z} = x;; +\end{caml_example} + +Here, OCaml has inferred that the possible choices for the type of +"{x;z}" are "first_record" and "middle_record", since the type +"last_record" has no field "z". Ocaml then picks the type "middle_record" +as the last defined type between the two possibilities. + +Beware that this last resort disambiguation is local: once Ocaml has +chosen a disambiguation, it sticks to this choice, even if it leads to +an ulterior type error: + +\begin{caml_example}{toplevel}[error] +let look_at_x_then_y r = + let x = r.x in (* Ocaml deduces [r: last_record] *) + x + r.y;; +let is_a_or_b x = match x with + | A -> true (* OCaml infers [x: last_variant] *) + | B -> true;; +\end{caml_example} + +Moreover, being the last defined type is a quite unstable position that +may change surreptitiously after adding or moving around a type +definition, or after opening a module (see chapter \ref{c:moduleexamples}). +Consequently, adding explicit type annotations to guide disambiguation is +more robust than relying on the last defined type disambiguation. + +\section{Imperative features} +\pdfsection{Imperative features} + +Though all examples so far were written in purely applicative style, +OCaml is also equipped with full imperative features. This includes the +usual "while" and "for" loops, as well as mutable data structures such +as arrays. Arrays are either created by listing semicolon-separated element +values between "[|" and "|]" brackets, or allocated and initialized with the +"Array.make" function, then filled up later by assignments. For instance, the +function below sums two vectors (represented as float arrays) componentwise. +\begin{caml_example}{toplevel} +let add_vect v1 v2 = + let len = min (Array.length v1) (Array.length v2) in + let res = Array.make len 0.0 in + for i = 0 to len - 1 do + res.(i) <- v1.(i) +. v2.(i) + done; + res;; +add_vect [| 1.0; 2.0 |] [| 3.0; 4.0 |];; +\end{caml_example} + +Record fields can also be modified by assignment, provided they are +declared "mutable" in the definition of the record type: +\begin{caml_example}{toplevel} +type mutable_point = { mutable x: float; mutable y: float };; +let translate p dx dy = + p.x <- p.x +. dx; p.y <- p.y +. dy;; +let mypoint = { x = 0.0; y = 0.0 };; +translate mypoint 1.0 2.0;; +mypoint;; +\end{caml_example} + +OCaml has no built-in notion of variable -- identifiers whose current +value can be changed by assignment. (The "let" binding is not an +assignment, it introduces a new identifier with a new scope.) +However, the standard library provides references, which are mutable +indirection cells, with operators "!" to fetch +the current contents of the reference and ":=" to assign the contents. +Variables can then be emulated by "let"-binding a reference. For +instance, here is an in-place insertion sort over arrays: +\begin{caml_example}{toplevel} +let insertion_sort a = + for i = 1 to Array.length a - 1 do + let val_i = a.(i) in + let j = ref i in + while !j > 0 && val_i < a.(!j - 1) do + a.(!j) <- a.(!j - 1); + j := !j - 1 + done; + a.(!j) <- val_i + done;; +\end{caml_example} + +References are also useful to write functions that maintain a current +state between two calls to the function. For instance, the following +pseudo-random number generator keeps the last returned number in a +reference: +\begin{caml_example}{toplevel} +let current_rand = ref 0;; +let random () = + current_rand := !current_rand * 25713 + 1345; + !current_rand;; +\end{caml_example} + +Again, there is nothing magical with references: they are implemented as +a single-field mutable record, as follows. +\begin{caml_example}{toplevel} +type 'a ref = { mutable contents: 'a };; +let ( ! ) r = r.contents;; +let ( := ) r newval = r.contents <- newval;; +\end{caml_example} + +In some special cases, you may need to store a polymorphic function in +a data structure, keeping its polymorphism. Doing this requires +user-provided type annotations, since polymorphism is only introduced +automatically for global definitions. However, you can explicitly give +polymorphic types to record fields. +\begin{caml_example}{toplevel} +type idref = { mutable id: 'a. 'a -> 'a };; +let r = {id = fun x -> x};; +let g s = (s.id 1, s.id true);; +r.id <- (fun x -> print_string "called id\n"; x);; +g r;; +\end{caml_example} + +\section{Exceptions} +\pdfsection{Exceptions} + +OCaml provides exceptions for signalling and handling exceptional +conditions. Exceptions can also be used as a general-purpose non-local +control structure, although this should not be overused since it can +make the code harder to understand. Exceptions are declared with the +"exception" construct, and signalled with the "raise" operator. For instance, +the function below for taking the head of a list uses an exception to +signal the case where an empty list is given. +\begin{caml_example}{toplevel} +exception Empty_list;; +let head l = + match l with + [] -> raise Empty_list + | hd :: tl -> hd;; +head [1;2];; +head [];; +\end{caml_example} + +Exceptions are used throughout the standard library to signal cases +where the library functions cannot complete normally. For instance, +the "List.assoc" function, which returns the data associated with a +given key in a list of (key, data) pairs, raises the predefined +exception "Not_found" when the key does not appear in the list: +\begin{caml_example}{toplevel} +List.assoc 1 [(0, "zero"); (1, "one")];; +List.assoc 2 [(0, "zero"); (1, "one")];; +\end{caml_example} + +Exceptions can be trapped with the "try"\ldots"with" construct: +\begin{caml_example}{toplevel} +let name_of_binary_digit digit = + try + List.assoc digit [0, "zero"; 1, "one"] + with Not_found -> + "not a binary digit";; +name_of_binary_digit 0;; +name_of_binary_digit (-1);; +\end{caml_example} + +The "with" part does pattern matching on the +exception value with the same syntax and behavior as "match". Thus, +several exceptions can be caught by one +"try"\ldots"with" construct. Also, finalization can be performed by +trapping all exceptions, performing the finalization, then re-raising +the exception: +\begin{caml_example}{toplevel} +let temporarily_set_reference ref newval funct = + let oldval = !ref in + try + ref := newval; + let res = funct () in + ref := oldval; + res + with x -> + ref := oldval; + raise x;; +\end{caml_example} + +\section{Symbolic processing of expressions} +\pdfsection{Symbolic processing of expressions} + +We finish this introduction with a more complete example +representative of the use of OCaml for symbolic processing: formal +manipulations of arithmetic expressions containing variables. The +following variant type describes the expressions we shall manipulate: +\begin{caml_example}{toplevel} +type expression = + Const of float + | Var of string + | Sum of expression * expression (* e1 + e2 *) + | Diff of expression * expression (* e1 - e2 *) + | Prod of expression * expression (* e1 * e2 *) + | Quot of expression * expression (* e1 / e2 *) +;; +\end{caml_example} + +We first define a function to evaluate an expression given an +environment that maps variable names to their values. For simplicity, +the environment is represented as an association list. +\begin{caml_example}{toplevel} +exception Unbound_variable of string;; +let rec eval env exp = + match exp with + Const c -> c + | Var v -> + (try List.assoc v env with Not_found -> raise (Unbound_variable v)) + | Sum(f, g) -> eval env f +. eval env g + | Diff(f, g) -> eval env f -. eval env g + | Prod(f, g) -> eval env f *. eval env g + | Quot(f, g) -> eval env f /. eval env g;; +eval [("x", 1.0); ("y", 3.14)] (Prod(Sum(Var "x", Const 2.0), Var "y"));; +\end{caml_example} + +Now for a real symbolic processing, we define the derivative of an +expression with respect to a variable "dv": +\begin{caml_example}{toplevel} +let rec deriv exp dv = + match exp with + Const c -> Const 0.0 + | Var v -> if v = dv then Const 1.0 else Const 0.0 + | Sum(f, g) -> Sum(deriv f dv, deriv g dv) + | Diff(f, g) -> Diff(deriv f dv, deriv g dv) + | Prod(f, g) -> Sum(Prod(f, deriv g dv), Prod(deriv f dv, g)) + | Quot(f, g) -> Quot(Diff(Prod(deriv f dv, g), Prod(f, deriv g dv)), + Prod(g, g)) +;; +deriv (Quot(Const 1.0, Var "x")) "x";; +\end{caml_example} + +\section{Pretty-printing} +\pdfsection{Pretty-printing} + +As shown in the examples above, the internal representation (also +called {\em abstract syntax\/}) of expressions quickly becomes hard to +read and write as the expressions get larger. We need a printer and a +parser to go back and forth between the abstract syntax and the {\em +concrete syntax}, which in the case of expressions is the familiar +algebraic notation (e.g. "2*x+1"). + +For the printing function, we take into account the usual precedence +rules (i.e. "*" binds tighter than "+") to avoid printing unnecessary +parentheses. To this end, we maintain the current operator precedence +and print parentheses around an operator only if its precedence is +less than the current precedence. +\begin{caml_example}{toplevel} +let print_expr exp = + (* Local function definitions *) + let open_paren prec op_prec = + if prec > op_prec then print_string "(" in + let close_paren prec op_prec = + if prec > op_prec then print_string ")" in + let rec print prec exp = (* prec is the current precedence *) + match exp with + Const c -> print_float c + | Var v -> print_string v + | Sum(f, g) -> + open_paren prec 0; + print 0 f; print_string " + "; print 0 g; + close_paren prec 0 + | Diff(f, g) -> + open_paren prec 0; + print 0 f; print_string " - "; print 1 g; + close_paren prec 0 + | Prod(f, g) -> + open_paren prec 2; + print 2 f; print_string " * "; print 2 g; + close_paren prec 2 + | Quot(f, g) -> + open_paren prec 2; + print 2 f; print_string " / "; print 3 g; + close_paren prec 2 + in print 0 exp;; +let e = Sum(Prod(Const 2.0, Var "x"), Const 1.0);; +print_expr e; print_newline ();; +print_expr (deriv e "x"); print_newline ();; +\end{caml_example} + +%%%%%%%%%%% Should be moved to the camlp4 documentation. +%% Parsing (transforming concrete syntax into abstract syntax) is usually +%% more delicate. OCaml offers several tools to help write parsers: +%% on the one hand, OCaml versions of the lexer generator Lex and the +%% parser generator Yacc (see chapter~\ref{c:ocamlyacc}), which handle +%% LALR(1) languages using push-down automata; on the other hand, a +%% predefined type of streams (of characters or tokens) and +%% pattern-matching over streams, which facilitate the writing of +%% recursive-descent parsers for LL(1) languages. An example using +%% "ocamllex" and "ocamlyacc" is given in +%% chapter~\ref{c:ocamlyacc}. Here, we will use stream parsers. +%% The syntactic support for stream parsers is provided by the Camlp4 +%% preprocessor, which can be loaded into the interactive toplevel via +%% the "#load" directives below. +%% +%% \begin{caml_example} +%% #load "dynlink.cma";; +%% #load "camlp4o.cma";; +%% open Genlex;; +%% let lexer = make_lexer ["("; ")"; "+"; "-"; "*"; "/"];; +%% \end{caml_example} +%% For the lexical analysis phase (transformation of the input text into +%% a stream of tokens), we use a ``generic'' lexer provided in the +%% standard library module "Genlex". The "make_lexer" function takes a +%% list of keywords and returns a lexing function that ``tokenizes'' an +%% input stream of characters. Tokens are either identifiers, keywords, +%% or literals (integer, floats, characters, strings). Whitespace and +%% comments are skipped. +%% \begin{caml_example} +%% let token_stream = lexer (Stream.of_string "1.0 +x");; +%% Stream.next token_stream;; +%% Stream.next token_stream;; +%% Stream.next token_stream;; +%% \end{caml_example} +%% +%% The parser itself operates by pattern-matching on the stream of +%% tokens. As usual with recursive descent parsers, we use several +%% intermediate parsing functions to reflect the precedence and +%% associativity of operators. Pattern-matching over streams is more +%% powerful than on regular data structures, as it allows recursive calls +%% to parsing functions inside the patterns, for matching sub-components of +%% the input stream. See the Camlp4 documentation for more details. +%% +%% %Already said above +%% %In order to use stream parsers at toplevel, we must first load the +%% %"camlp4" preprocessor. +%% %\begin{caml_example} +%% %#load"camlp4o.cma";; +%% %\end{caml_example} +%% %Then we are ready to define our parser. +%% \begin{caml_example}{toplevel} +%% let rec parse_expr = parser +%% [< e1 = parse_mult; e = parse_more_adds e1 >] -> e +%% and parse_more_adds e1 = parser +%% [< 'Kwd "+"; e2 = parse_mult; e = parse_more_adds (Sum(e1, e2)) >] -> e +%% | [< 'Kwd "-"; e2 = parse_mult; e = parse_more_adds (Diff(e1, e2)) >] -> e +%% | [< >] -> e1 +%% and parse_mult = parser +%% [< e1 = parse_simple; e = parse_more_mults e1 >] -> e +%% and parse_more_mults e1 = parser +%% [< 'Kwd "*"; e2 = parse_simple; e = parse_more_mults (Prod(e1, e2)) >] -> e +%% | [< 'Kwd "/"; e2 = parse_simple; e = parse_more_mults (Quot(e1, e2)) >] -> e +%% | [< >] -> e1 +%% and parse_simple = parser +%% [< 'Ident s >] -> Var s +%% | [< 'Int i >] -> Const(float i) +%% | [< 'Float f >] -> Const f +%% | [< 'Kwd "("; e = parse_expr; 'Kwd ")" >] -> e;; +%% let parse_expression = parser [< e = parse_expr; _ = Stream.empty >] -> e;; +%% \end{caml_example} +%% +%% Composing the lexer and parser, we finally obtain a function to read +%% an expression from a character string: +%% \begin{caml_example} +%% let read_expression s = parse_expression (lexer (Stream.of_string s));; +%% read_expression "2*(x+y)";; +%% \end{caml_example} +%% A small puzzle: why do we get different results in the following two +%% examples? +%% \begin{caml_example} +%% read_expression "x - 1";; +%% read_expression "x-1";; +%% \end{caml_example} +%% Answer: the generic lexer provided by "Genlex" recognizes negative +%% integer literals as one integer token. Hence, "x-1" is read as +%% the token "Ident \"x\"" followed by the token "Int(-1)"; this sequence +%% does not match any of the parser rules. On the other hand, +%% the second space in "x - 1" causes the lexer to return the three +%% expected tokens: "Ident \"x\"", then "Kwd \"-\"", then "Int(1)". + +\section{Standalone OCaml programs} +\pdfsection{Standalone OCaml programs} + +All examples given so far were executed under the interactive system. +OCaml code can also be compiled separately and executed +non-interactively using the batch compilers "ocamlc" and "ocamlopt". +The source code must be put in a file with extension ".ml". It +consists of a sequence of phrases, which will be evaluated at runtime +in their order of appearance in the source file. Unlike in interactive +mode, types and values are not printed automatically; the program must +call printing functions explicitly to produce some output. The ";;" used +in the interactive examples is not required in +source files created for use with OCaml compilers, but can be helpful +to mark the end of a top-level expression unambiguously even when +there are syntax errors. +Here is a +sample standalone program to print Fibonacci numbers: +\begin{verbatim} +(* File fib.ml *) +let rec fib n = + if n < 2 then 1 else fib (n-1) + fib (n-2);; +let main () = + let arg = int_of_string Sys.argv.(1) in + print_int (fib arg); + print_newline (); + exit 0;; +main ();; +\end{verbatim} +"Sys.argv" is an array of strings containing the command-line +parameters. "Sys.argv.(1)" is thus the first command-line parameter. +The program above is compiled and executed with the following shell +commands: +\begin{verbatim} +$ ocamlc -o fib fib.ml +$ ./fib 10 +89 +$ ./fib 20 +10946 +\end{verbatim} + +More complex standalone OCaml programs are typically composed of +multiple source files, and can link with precompiled libraries. +Chapters~\ref{c:camlc} and~\ref{c:nativecomp} explain how to use the +batch compilers "ocamlc" and "ocamlopt". Recompilation of +multi-file OCaml projects can be automated using third-party +build systems, such as the +\href{https://github.com/ocaml/ocamlbuild/}{ocamlbuild} +compilation manager. diff --git a/manual/manual/tutorials/lablexamples.etex b/manual/manual/tutorials/lablexamples.etex new file mode 100644 index 00000000..d4ceef17 --- /dev/null +++ b/manual/manual/tutorials/lablexamples.etex @@ -0,0 +1,491 @@ +\chapter{Labels and variants} \label{c:labl-examples} +\pdfchapterfold{-2}{Tutorial: Labels and variants} +%HEVEA\cutname{lablexamples.html} +{\it (Chapter written by Jacques Garrigue)} + +\bigskip + +\noindent This chapter gives an overview of the new features in +OCaml 3: labels, and polymorphic variants. + +\section{Labels} +\pdfsection{Labels} + +If you have a look at modules ending in "Labels" in the standard +library, you will see that function types have annotations you did not +have in the functions you defined yourself. + +\begin{caml_example}{toplevel} +ListLabels.map;; +StringLabels.sub;; +\end{caml_example} + +Such annotations of the form "name:" are called {\em labels}. They are +meant to document the code, allow more checking, and give more +flexibility to function application. +You can give such names to arguments in your programs, by prefixing them +with a tilde "~". + +\begin{caml_example}{toplevel} +let f ~x ~y = x - y;; +let x = 3 and y = 2 in f ~x ~y;; +\end{caml_example} + +When you want to use distinct names for the variable and the label +appearing in the type, you can use a naming label of the form +"~name:". This also applies when the argument is not a variable. + +\begin{caml_example}{toplevel} +let f ~x:x1 ~y:y1 = x1 - y1;; +f ~x:3 ~y:2;; +\end{caml_example} + +Labels obey the same rules as other identifiers in OCaml, that is you +cannot use a reserved keyword (like "in" or "to") as label. + +Formal parameters and arguments are matched according to their +respective labels\footnote{This correspond to the commuting label mode +of Objective Caml 3.00 through 3.02, with some additional flexibility +on total applications. The so-called classic mode ("-nolabels" +options) is now deprecated for normal use.}, the absence of label +being interpreted as the empty label. +% +This allows commuting arguments in applications. One can also +partially apply a function on any argument, creating a new function of +the remaining parameters. + +\begin{caml_example}{toplevel} +let f ~x ~y = x - y;; +f ~y:2 ~x:3;; +ListLabels.fold_left;; +ListLabels.fold_left [1;2;3] ~init:0 ~f:( + );; +ListLabels.fold_left ~init:0;; +\end{caml_example} + +If several arguments of a function bear the same label (or no label), +they will not commute among themselves, and order matters. But they +can still commute with other arguments. + +\begin{caml_example}{toplevel} +let hline ~x:x1 ~x:x2 ~y = (x1, x2, y);; +hline ~x:3 ~y:2 ~x:5;; +\end{caml_example} + +As an exception to the above parameter matching rules, if an +application is total (omitting all optional arguments), labels may be +omitted. +In practice, many applications are total, so that labels can often be +omitted. +\begin{caml_example}{toplevel} +f 3 2;; +ListLabels.map succ [1;2;3];; +\end{caml_example} +But beware that functions like "ListLabels.fold_left" whose result +type is a type variable will never be considered as totally applied. +\begin{caml_example}{toplevel}[error] +ListLabels.fold_left ( + ) 0 [1;2;3];; +\end{caml_example} + +When a function is passed as an argument to a higher-order function, +labels must match in both types. Neither adding nor removing labels +are allowed. +\begin{caml_example}{toplevel} +let h g = g ~x:3 ~y:2;; +h f;; +h ( + ) [@@expect error];; +\end{caml_example} +Note that when you don't need an argument, you can still use a wildcard +pattern, but you must prefix it with the label. +\begin{caml_example}{toplevel} +h (fun ~x:_ ~y -> y+1);; +\end{caml_example} + +\subsection{Optional arguments} + +An interesting feature of labeled arguments is that they can be made +optional. For optional parameters, the question mark "?" replaces the +tilde "~" of non-optional ones, and the label is also prefixed by "?" +in the function type. +Default values may be given for such optional parameters. + +\begin{caml_example}{toplevel} +let bump ?(step = 1) x = x + step;; +bump 2;; +bump ~step:3 2;; +\end{caml_example} + +A function taking some optional arguments must also take at least one +non-optional argument. The criterion for deciding whether an optional +argument has been omitted is the non-labeled application of an +argument appearing after this optional argument in the function type. +Note that if that argument is labeled, you will only be able to +eliminate optional arguments through the special case for total +applications. + +\begin{caml_example}{toplevel} +let test ?(x = 0) ?(y = 0) () ?(z = 0) () = (x, y, z);; +test ();; +test ~x:2 () ~z:3 ();; +\end{caml_example} + +Optional parameters may also commute with non-optional or unlabeled +ones, as long as they are applied simultaneously. By nature, optional +arguments do not commute with unlabeled arguments applied +independently. +\begin{caml_example}{toplevel} +test ~y:2 ~x:3 () ();; +test () () ~z:1 ~y:2 ~x:3;; +(test () ()) ~z:1 [@@expect error];; +\end{caml_example} +Here "(test () ())" is already "(0,0,0)" and cannot be further +applied. + +Optional arguments are actually implemented as option types. If +you do not give a default value, you have access to their internal +representation, "type 'a option = None | Some of 'a". You can then +provide different behaviors when an argument is present or not. + +\begin{caml_example}{toplevel} +let bump ?step x = + match step with + | None -> x * 2 + | Some y -> x + y +;; +\end{caml_example} + +It may also be useful to relay an optional argument from a function +call to another. This can be done by prefixing the applied argument +with "?". This question mark disables the wrapping of optional +argument in an option type. + +\begin{caml_example}{toplevel} +let test2 ?x ?y () = test ?x ?y () ();; +test2 ?x:None;; +\end{caml_example} + +\subsection{Labels and type inference} +\label{ss:label-inference} + +While they provide an increased comfort for writing function +applications, labels and optional arguments have the pitfall that they +cannot be inferred as completely as the rest of the language. + +You can see it in the following two examples. +\begin{caml_example}{toplevel} +let h' g = g ~y:2 ~x:3;; +h' f [@@expect error];; +let bump_it bump x = + bump ~step:2 x;; +bump_it bump 1 [@@expect error];; +\end{caml_example} +The first case is simple: "g" is passed "~y" and then "~x", but "f" +expects "~x" and then "~y". This is correctly handled if we know the +type of "g" to be "x:int -> y:int -> int" in advance, but otherwise +this causes the above type clash. The simplest workaround is to apply +formal parameters in a standard order. + +The second example is more subtle: while we intended the argument +"bump" to be of type "?step:int -> int -> int", it is inferred as +"step:int -> int -> 'a". +% +These two types being incompatible (internally normal and optional +arguments are different), a type error occurs when applying "bump_it" +to the real "bump". + +We will not try here to explain in detail how type inference works. +One must just understand that there is not enough information in the +above program to deduce the correct type of "g" or "bump". That is, +there is no way to know whether an argument is optional or not, or +which is the correct order, by looking only at how a function is +applied. The strategy used by the compiler is to assume that there are +no optional arguments, and that applications are done in the right +order. + +The right way to solve this problem for optional parameters is to add +a type annotation to the argument "bump". +\begin{caml_example}{toplevel} +let bump_it (bump : ?step:int -> int -> int) x = + bump ~step:2 x;; +bump_it bump 1;; +\end{caml_example} +In practice, such problems appear mostly when using objects whose +methods have optional arguments, so that writing the type of object +arguments is often a good idea. + +Normally the compiler generates a type error if you attempt to pass to +a function a parameter whose type is different from the expected one. +However, in the specific case where the expected type is a non-labeled +function type, and the argument is a function expecting optional +parameters, the compiler will attempt to transform the argument to +have it match the expected type, by passing "None" for all optional +parameters. + +\begin{caml_example}{toplevel} +let twice f (x : int) = f(f x);; +twice bump 2;; +\end{caml_example} + +This transformation is coherent with the intended semantics, +including side-effects. That is, if the application of optional +parameters shall produce side-effects, these are delayed until the +received function is really applied to an argument. + +\subsection{Suggestions for labeling} + +Like for names, choosing labels for functions is not an easy task. A +good labeling is a labeling which + +\begin{itemize} +\item makes programs more readable, +\item is easy to remember, +\item when possible, allows useful partial applications. +\end{itemize} + +We explain here the rules we applied when labeling OCaml +libraries. + +To speak in an ``object-oriented'' way, one can consider that each +function has a main argument, its {\em object}, and other arguments +related with its action, the {\em parameters}. To permit the +combination of functions through functionals in commuting label mode, the +object will not be labeled. Its role is clear from the function +itself. The parameters are labeled with names reminding of +their nature or their role. The best labels combine nature and +role. When this is not possible the role is to be preferred, since the +nature will +often be given by the type itself. Obscure abbreviations should be +avoided. +\begin{alltt} +"ListLabels.map : f:('a -> 'b) -> 'a list -> 'b list" +UnixLabels.write : file_descr -> buf:bytes -> pos:int -> len:int -> unit +\end{alltt} + +When there are several objects of same nature and role, they are all +left unlabeled. +\begin{alltt} +"ListLabels.iter2 : f:('a -> 'b -> 'c) -> 'a list -> 'b list -> unit" +\end{alltt} + +When there is no preferable object, all arguments are labeled. +\begin{alltt} +BytesLabels.blit : + src:bytes -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit +\end{alltt} + +However, when there is only one argument, it is often left unlabeled. +\begin{alltt} +BytesLabels.create : int -> bytes +\end{alltt} +This principle also applies to functions of several arguments whose +return type is a type variable, as long as the role of each argument +is not ambiguous. Labeling such functions may lead to awkward error +messages when one attempts to omit labels in an application, as we +have seen with "ListLabels.fold_left". + +Here are some of the label names you will find throughout the +libraries. + +\begin{tableau}{|l|l|}{Label}{Meaning} +\entree{"f:"}{a function to be applied} +\entree{"pos:"}{a position in a string, array or byte sequence} +\entree{"len:"}{a length} +\entree{"buf:"}{a byte sequence or string used as buffer} +\entree{"src:"}{the source of an operation} +\entree{"dst:"}{the destination of an operation} +\entree{"init:"}{the initial value for an iterator} +\entree{"cmp:"}{a comparison function, {\it e.g.} "Pervasives.compare"} +\entree{"mode:"}{an operation mode or a flag list} +\end{tableau} + +All these are only suggestions, but keep in mind that the +choice of labels is essential for readability. Bizarre choices will +make the program harder to maintain. + +In the ideal, the right function name with right labels should be +enough to understand the function's meaning. Since one can get this +information with OCamlBrowser or the "ocaml" toplevel, the documentation +is only used when a more detailed specification is needed. + +\begin{caml_eval} +#label false;; +\end{caml_eval} + + +\section{Polymorphic variants} +\pdfsection{Polymorphic variants} + +Variants as presented in section~\ref{s:tut-recvariants} are a +powerful tool to build data structures and algorithms. However they +sometimes lack flexibility when used in modular programming. This is +due to the fact that every constructor is assigned to a unique type +when defined and used. Even if the same name appears in the definition +of multiple types, the constructor itself belongs to only one type. +Therefore, one cannot decide that a given constructor belongs to +multiple types, or consider a value of some type to belong to some +other type with more constructors. + +With polymorphic variants, this original assumption is removed. That +is, a variant tag does not belong to any type in particular, the type +system will just check that it is an admissible value according to its +use. You need not define a type before using a variant tag. A variant +type will be inferred independently for each of its uses. + +\subsection*{Basic use} + +In programs, polymorphic variants work like usual ones. You just have +to prefix their names with a backquote character "`". +\begin{caml_example}{toplevel} +[`On; `Off];; +`Number 1;; +let f = function `On -> 1 | `Off -> 0 | `Number n -> n;; +List.map f [`On; `Off];; +\end{caml_example} +"[>`Off|`On] list" means that to match this list, you should at +least be able to match "`Off" and "`On", without argument. +"[<`On|`Off|`Number of int]" means that "f" may be applied to "`Off", +"`On" (both without argument), or "`Number" $n$ where +$n$ is an integer. +The ">" and "<" inside the variant types show that they may still be +refined, either by defining more tags or by allowing less. As such, they +contain an implicit type variable. Because each of the variant types +appears only once in the whole type, their implicit type variables are +not shown. + +The above variant types were polymorphic, allowing further refinement. +When writing type annotations, one will most often describe fixed +variant types, that is types that cannot be refined. This is +also the case for type abbreviations. Such types do not contain "<" or +">", but just an enumeration of the tags and their associated types, +just like in a normal datatype definition. +\begin{caml_example}{toplevel} +type 'a vlist = [`Nil | `Cons of 'a * 'a vlist];; +let rec map f : 'a vlist -> 'b vlist = function + | `Nil -> `Nil + | `Cons(a, l) -> `Cons(f a, map f l) +;; +\end{caml_example} + +\subsection*{Advanced use} + +Type-checking polymorphic variants is a subtle thing, and some +expressions may result in more complex type information. + +\begin{caml_example}{toplevel} +let f = function `A -> `C | `B -> `D | x -> x;; +f `E;; +\end{caml_example} +Here we are seeing two phenomena. First, since this matching is open +(the last case catches any tag), we obtain the type "[> `A | `B]" +rather than "[< `A | `B]" in a closed matching. Then, since "x" is +returned as is, input and return types are identical. The notation "as +'a" denotes such type sharing. If we apply "f" to yet another tag +"`E", it gets added to the list. + +\begin{caml_example}{toplevel} +let f1 = function `A x -> x = 1 | `B -> true | `C -> false +let f2 = function `A x -> x = "a" | `B -> true ;; +let f x = f1 x && f2 x;; +\end{caml_example} +Here "f1" and "f2" both accept the variant tags "`A" and "`B", but the +argument of "`A" is "int" for "f1" and "string" for "f2". In "f"'s +type "`C", only accepted by "f1", disappears, but both argument types +appear for "`A" as "int & string". This means that if we +pass the variant tag "`A" to "f", its argument should be {\em both} +"int" and "string". Since there is no such value, "f" cannot be +applied to "`A", and "`B" is the only accepted input. + +Even if a value has a fixed variant type, one can still give it a +larger type through coercions. Coercions are normally written with +both the source type and the destination type, but in simple cases the +source type may be omitted. +\begin{caml_example}{toplevel} +type 'a wlist = [`Nil | `Cons of 'a * 'a wlist | `Snoc of 'a wlist * 'a];; +let wlist_of_vlist l = (l : 'a vlist :> 'a wlist);; +let open_vlist l = (l : 'a vlist :> [> 'a vlist]);; +fun x -> (x :> [`A|`B|`C]);; +\end{caml_example} + +You may also selectively coerce values through pattern matching. +\begin{caml_example}{toplevel} +let split_cases = function + | `Nil | `Cons _ as x -> `A x + | `Snoc _ as x -> `B x +;; +\end{caml_example} +When an or-pattern composed of variant tags is wrapped inside an +alias-pattern, the alias is given a type containing only the tags +enumerated in the or-pattern. This allows for many useful idioms, like +incremental definition of functions. + +\begin{caml_example}{toplevel} +let num x = `Num x +let eval1 eval (`Num x) = x +let rec eval x = eval1 eval x ;; +let plus x y = `Plus(x,y) +let eval2 eval = function + | `Plus(x,y) -> eval x + eval y + | `Num _ as x -> eval1 eval x +let rec eval x = eval2 eval x ;; +\end{caml_example} + +To make this even more comfortable, you may use type definitions as +abbreviations for or-patterns. That is, if you have defined "type +myvariant = [`Tag1 of int | `Tag2 of bool]", then the pattern "#myvariant" is +equivalent to writing "(`Tag1(_ : int) | `Tag2(_ : bool))". +\begin{caml_eval} +type myvariant = [`Tag1 of int | `Tag2 of bool];; +\end{caml_eval} + +Such abbreviations may be used alone, +\begin{caml_example}{toplevel} +let f = function + | #myvariant -> "myvariant" + | `Tag3 -> "Tag3";; +\end{caml_example} +or combined with with aliases. +\begin{caml_example}{toplevel} +let g1 = function `Tag1 _ -> "Tag1" | `Tag2 _ -> "Tag2";; +let g = function + | #myvariant as x -> g1 x + | `Tag3 -> "Tag3";; +\end{caml_example} + +\subsection{Weaknesses of polymorphic variants} + +After seeing the power of polymorphic variants, one may wonder why +they were added to core language variants, rather than replacing them. + +The answer is twofold. One first aspect is that while being pretty +efficient, the lack of static type information allows for less +optimizations, and makes polymorphic variants slightly heavier than +core language ones. However noticeable differences would only +appear on huge data structures. + +More important is the fact that polymorphic variants, while being +type-safe, result in a weaker type discipline. That is, core language +variants do actually much more than ensuring type-safety, they also +check that you use only declared constructors, that all constructors +present in a data-structure are compatible, and they enforce typing +constraints to their parameters. + +For this reason, you must be more careful about making types explicit +when you use polymorphic variants. When you write a library, this is +easy since you can describe exact types in interfaces, but for simple +programs you are probably better off with core language variants. + +Beware also that some idioms make trivial errors very hard to find. +For instance, the following code is probably wrong but the compiler +has no way to see it. +\begin{caml_example}{toplevel} +type abc = [`A | `B | `C] ;; +let f = function + | `As -> "A" + | #abc -> "other" ;; +let f : abc -> string = f ;; +\end{caml_example} +You can avoid such risks by annotating the definition itself. +\begin{caml_example}{toplevel}[error] +let f : abc -> string = function + | `As -> "A" + | #abc -> "other" ;; +\end{caml_example} diff --git a/manual/manual/tutorials/moduleexamples.etex b/manual/manual/tutorials/moduleexamples.etex new file mode 100644 index 00000000..a9a4f648 --- /dev/null +++ b/manual/manual/tutorials/moduleexamples.etex @@ -0,0 +1,385 @@ +\chapter{The module system} \label{c:moduleexamples} +\pdfchapterfold{-5}{Tutorial: The module system} +%HEVEA\cutname{moduleexamples.html} + +This chapter introduces the module system of OCaml. + +\section{Structures} +\pdfsection{Structures} + +A primary motivation for modules is to package together related +definitions (such as the definitions of a data type and associated +operations over that type) and enforce a consistent naming scheme for +these definitions. This avoids running out of names or accidentally +confusing names. Such a package is called a {\em structure} and +is introduced by the "struct"\ldots"end" construct, which contains an +arbitrary sequence of definitions. The structure is usually given a +name with the "module" binding. Here is for instance a structure +packaging together a type of priority queues and their operations: +\begin{caml_example}{toplevel} +module PrioQueue = + struct + type priority = int + type 'a queue = Empty | Node of priority * 'a * 'a queue * 'a queue + let empty = Empty + let rec insert queue prio elt = + match queue with + Empty -> Node(prio, elt, Empty, Empty) + | Node(p, e, left, right) -> + if prio <= p + then Node(prio, elt, insert right p e, left) + else Node(p, e, insert right prio elt, left) + exception Queue_is_empty + let rec remove_top = function + Empty -> raise Queue_is_empty + | Node(prio, elt, left, Empty) -> left + | Node(prio, elt, Empty, right) -> right + | Node(prio, elt, (Node(lprio, lelt, _, _) as left), + (Node(rprio, relt, _, _) as right)) -> + if lprio <= rprio + then Node(lprio, lelt, remove_top left, right) + else Node(rprio, relt, left, remove_top right) + let extract = function + Empty -> raise Queue_is_empty + | Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue) + end;; +\end{caml_example} +Outside the structure, its components can be referred to using the +``dot notation'', that is, identifiers qualified by a structure name. +For instance, "PrioQueue.insert" is the function "insert" defined +inside the structure "PrioQueue" and "PrioQueue.queue" is the type +"queue" defined in "PrioQueue". +\begin{caml_example}{toplevel} +PrioQueue.insert PrioQueue.empty 1 "hello";; +\end{caml_example} + +Another possibility is to open the module, which brings all +identifiers defined inside the module in the scope of the current +structure. + +\begin{caml_example}{toplevel} + open PrioQueue;; + insert empty 1 "hello";; +\end{caml_example} + +Opening a module enables lighter access to its components, at the +cost of making it harder to identify in which module a identifier +has been defined. In particular, opened modules can shadow +identifiers present in the current scope, potentially leading +to confusing errors: + +\begin{caml_example}{toplevel} + let empty = [] + open PrioQueue;; + let x = 1 :: empty [@@expect error];; +\end{caml_example} + + +A partial solution to this conundrum is to open modules locally, +making the components of the module available only in the +concerned expression. This can also make the code easier to read +-- the open statement is closer to where it is used-- and to refactor +-- the code fragment is more self-contained. +Two constructions are available for this purpose: +\begin{caml_example}{toplevel} + let open PrioQueue in + insert empty 1 "hello";; +\end{caml_example} +and +\begin{caml_example}{toplevel} + PrioQueue.(insert empty 1 "hello");; +\end{caml_example} +In the second form, when the body of a local open is itself delimited +by parentheses, braces or bracket, the parentheses of the local open +can be omitted. For instance, +\begin{caml_example}{toplevel} + PrioQueue.[empty] = PrioQueue.([empty]);; + PrioQueue.[|empty|] = PrioQueue.([|empty|]);; + PrioQueue.{ contents = empty } = PrioQueue.({ contents = empty });; +\end{caml_example} +becomes +\begin{caml_example}{toplevel} + PrioQueue.[insert empty 1 "hello"];; +\end{caml_example} + +It is also possible to copy the components of a module inside +another module by using an "include" statement. This can be +particularly useful to extend existing modules. As an illustration, +we could add functions that returns an optional value rather than +an exception when the priority queue is empty. +\begin{caml_example}{toplevel} + module PrioQueueOpt = + struct + include PrioQueue + + let remove_top_opt x = + try Some(remove_top x) with Queue_is_empty -> None + + let extract_opt x = + try Some(extract x) with Queue_is_empty -> None + end;; +\end{caml_example} + +\section{Signatures} +\pdfsection{Signatures} + +Signatures are interfaces for structures. A signature specifies +which components of a structure are accessible from the outside, and +with which type. It can be used to hide some components of a structure +(e.g. local function definitions) or export some components with a +restricted type. For instance, the signature below specifies the three +priority queue operations "empty", "insert" and "extract", but not the +auxiliary function "remove_top". Similarly, it makes the "queue" type +abstract (by not providing its actual representation as a concrete type). +\begin{caml_example}{toplevel} +module type PRIOQUEUE = + sig + type priority = int (* still concrete *) + type 'a queue (* now abstract *) + val empty : 'a queue + val insert : 'a queue -> int -> 'a -> 'a queue + val extract : 'a queue -> int * 'a * 'a queue + exception Queue_is_empty + end;; +\end{caml_example} +Restricting the "PrioQueue" structure by this signature results in +another view of the "PrioQueue" structure where the "remove_top" +function is not accessible and the actual representation of priority +queues is hidden: +\begin{caml_example}{toplevel} +module AbstractPrioQueue = (PrioQueue : PRIOQUEUE);; +AbstractPrioQueue.remove_top [@@expect error];; +AbstractPrioQueue.insert AbstractPrioQueue.empty 1 "hello";; +\end{caml_example} +The restriction can also be performed during the definition of the +structure, as in +\begin{verbatim} +module PrioQueue = (struct ... end : PRIOQUEUE);; +\end{verbatim} +An alternate syntax is provided for the above: +\begin{verbatim} +module PrioQueue : PRIOQUEUE = struct ... end;; +\end{verbatim} + +Like for modules, it is possible to include a signature to copy +its components inside the current signature. For instance, we +can extend the PRIOQUEUE signature with the "extract_opt" +function: + +\begin{caml_example}{toplevel} +module type PRIOQUEUE_WITH_OPT = + sig + include PRIOQUEUE + val extract_opt : 'a queue -> (int * 'a * 'a queue) option + end;; +\end{caml_example} + + +\section{Functors} +\pdfsection{Functors} + +Functors are ``functions'' from modules to modules. Functors let you create +parameterized modules and then provide other modules as parameter(s) to get +a specific implementation. For instance, a "Set" module implementing sets +as sorted lists could be parameterized to work with any module that provides +an element type and a comparison function "compare" (such as "OrderedString"): + +\begin{caml_example}{toplevel} +type comparison = Less | Equal | Greater;; +module type ORDERED_TYPE = + sig + type t + val compare: t -> t -> comparison + end;; +module Set = + functor (Elt: ORDERED_TYPE) -> + struct + type element = Elt.t + type set = element list + let empty = [] + let rec add x s = + match s with + [] -> [x] + | hd::tl -> + match Elt.compare x hd with + Equal -> s (* x is already in s *) + | Less -> x :: s (* x is smaller than all elements of s *) + | Greater -> hd :: add x tl + let rec member x s = + match s with + [] -> false + | hd::tl -> + match Elt.compare x hd with + Equal -> true (* x belongs to s *) + | Less -> false (* x is smaller than all elements of s *) + | Greater -> member x tl + end;; +\end{caml_example} +By applying the "Set" functor to a structure implementing an ordered +type, we obtain set operations for this type: +\begin{caml_example}{toplevel} +module OrderedString = + struct + type t = string + let compare x y = if x = y then Equal else if x < y then Less else Greater + end;; +module StringSet = Set(OrderedString);; +StringSet.member "bar" (StringSet.add "foo" StringSet.empty);; +\end{caml_example} + +\section{Functors and type abstraction} +\pdfsection{Functors and type abstraction} + +As in the "PrioQueue" example, it would be good style to hide the +actual implementation of the type "set", so that users of the +structure will not rely on sets being lists, and we can switch later +to another, more efficient representation of sets without breaking +their code. This can be achieved by restricting "Set" by a suitable +functor signature: +\begin{caml_example}{toplevel} +module type SETFUNCTOR = + functor (Elt: ORDERED_TYPE) -> + sig + type element = Elt.t (* concrete *) + type set (* abstract *) + val empty : set + val add : element -> set -> set + val member : element -> set -> bool + end;; +module AbstractSet = (Set : SETFUNCTOR);; +module AbstractStringSet = AbstractSet(OrderedString);; +AbstractStringSet.add "gee" AbstractStringSet.empty;; +\end{caml_example} + +In an attempt to write the type constraint above more elegantly, +one may wish to name the signature of the structure +returned by the functor, then use that signature in the constraint: +\begin{caml_example}{toplevel} +module type SET = + sig + type element + type set + val empty : set + val add : element -> set -> set + val member : element -> set -> bool + end;; +module WrongSet = (Set : functor(Elt: ORDERED_TYPE) -> SET);; +module WrongStringSet = WrongSet(OrderedString);; +WrongStringSet.add "gee" WrongStringSet.empty [@@expect error];; +\end{caml_example} +The problem here is that "SET" specifies the type "element" +abstractly, so that the type equality between "element" in the result +of the functor and "t" in its argument is forgotten. Consequently, +"WrongStringSet.element" is not the same type as "string", and the +operations of "WrongStringSet" cannot be applied to strings. +As demonstrated above, it is important that the type "element" in the +signature "SET" be declared equal to "Elt.t"; unfortunately, this is +impossible above since "SET" is defined in a context where "Elt" does +not exist. To overcome this difficulty, OCaml provides a +"with type" construct over signatures that allows enriching a signature +with extra type equalities: +\begin{caml_example}{toplevel} +module AbstractSet2 = + (Set : functor(Elt: ORDERED_TYPE) -> (SET with type element = Elt.t));; +\end{caml_example} + +As in the case of simple structures, an alternate syntax is provided +for defining functors and restricting their result: +\begin{verbatim} +module AbstractSet2(Elt: ORDERED_TYPE) : (SET with type element = Elt.t) = + struct ... end;; +\end{verbatim} + +Abstracting a type component in a functor result is a powerful +technique that provides a high degree of type safety, as we now +illustrate. Consider an ordering over character strings that is +different from the standard ordering implemented in the +"OrderedString" structure. For instance, we compare strings without +distinguishing upper and lower case. +\begin{caml_example}{toplevel} +module NoCaseString = + struct + type t = string + let compare s1 s2 = + OrderedString.compare (String.lowercase_ascii s1) (String.lowercase_ascii s2) + end;; +module NoCaseStringSet = AbstractSet(NoCaseString);; +NoCaseStringSet.add "FOO" AbstractStringSet.empty [@@expect error];; +\end{caml_example} +Note that the two types "AbstractStringSet.set" and +"NoCaseStringSet.set" are not compatible, and values of these +two types do not match. This is the correct behavior: even though both +set types contain elements of the same type (strings), they are built +upon different orderings of that type, and different invariants need +to be maintained by the operations (being strictly increasing for the +standard ordering and for the case-insensitive ordering). Applying +operations from "AbstractStringSet" to values of type +"NoCaseStringSet.set" could give incorrect results, or build +lists that violate the invariants of "NoCaseStringSet". + +\section{Modules and separate compilation} +\pdfsection{Modules and separate compilation} + +All examples of modules so far have been given in the context of the +interactive system. However, modules are most useful for large, +batch-compiled programs. For these programs, it is a practical +necessity to split the source into several files, called compilation +units, that can be compiled separately, thus minimizing recompilation +after changes. + +In OCaml, compilation units are special cases of structures +and signatures, and the relationship between the units can be +explained easily in terms of the module system. A compilation unit \var{A} +comprises two files: +\begin{itemize} +\item the implementation file \var{A}".ml", which contains a sequence +of definitions, analogous to the inside of a "struct"\ldots"end" +construct; +\item the interface file \var{A}".mli", which contains a sequence of +specifications, analogous to the inside of a "sig"\ldots"end" +construct. +\end{itemize} +These two files together define a structure named \var{A} as if +the following definition was entered at top-level: +\begin{alltt} +module \var{A}: sig (* \hbox{contents of file} \var{A}.mli *) end + = struct (* \hbox{contents of file} \var{A}.ml *) end;; +\end{alltt} +The files that define the compilation units can be compiled separately +using the "ocamlc -c" command (the "-c" option means ``compile only, do +not try to link''); this produces compiled interface files (with +extension ".cmi") and compiled object code files (with extension +".cmo"). When all units have been compiled, their ".cmo" files are +linked together using the "ocamlc" command. For instance, the following +commands compile and link a program composed of two compilation units +"Aux" and "Main": +\begin{verbatim} +$ ocamlc -c Aux.mli # produces aux.cmi +$ ocamlc -c Aux.ml # produces aux.cmo +$ ocamlc -c Main.mli # produces main.cmi +$ ocamlc -c Main.ml # produces main.cmo +$ ocamlc -o theprogram Aux.cmo Main.cmo +\end{verbatim} +The program behaves exactly as if the following phrases were entered +at top-level: +\begin{alltt} +module Aux: sig (* \rminalltt{contents of} Aux.mli *) end + = struct (* \rminalltt{contents of} Aux.ml *) end;; +module Main: sig (* \rminalltt{contents of} Main.mli *) end + = struct (* \rminalltt{contents of} Main.ml *) end;; +\end{alltt} +In particular, "Main" can refer to "Aux": the definitions and +declarations contained in "Main.ml" and "Main.mli" can refer to +definition in "Aux.ml", using the "Aux."\var{ident} notation, provided +these definitions are exported in "Aux.mli". + +The order in which the ".cmo" files are given to "ocamlc" during the +linking phase determines the order in which the module definitions +occur. Hence, in the example above, "Aux" appears first and "Main" can +refer to it, but "Aux" cannot refer to "Main". + +Note that only top-level structures can be mapped to +separately-compiled files, but neither functors nor module types. +However, all module-class objects can appear as components of a +structure, so the solution is to put the functor or module type +inside a structure, which can then be mapped to a file. diff --git a/manual/manual/tutorials/objectexamples.etex b/manual/manual/tutorials/objectexamples.etex new file mode 100644 index 00000000..9166c3cd --- /dev/null +++ b/manual/manual/tutorials/objectexamples.etex @@ -0,0 +1,1293 @@ +\chapter{Objects in OCaml} +\label{c:objectexamples} +\pdfchapterfold{-15}{Tutorial: Objects in OCaml} +%HEVEA\cutname{objectexamples.html} +{\it (Chapter written by J\'er\^ome Vouillon, Didier R\'emy and Jacques Garrigue)} + +\bigskip + +\noindent This chapter gives an overview of the object-oriented features of +OCaml. + +Note that the relationship between object, class and type in OCaml is +different than in mainstream object-oriented languages such as Java and +C++, so you shouldn't assume that similar keywords mean the same thing. +Object-oriented features are used much less frequently in OCaml than +in those languages. OCaml has alternatives that are often more appropriate, +such as modules and functors. Indeed, many OCaml programs do not use objects +at all. + + +\begin{htmlonly} + +\ref{ss:classes-and-objects} Classes and objects \\ +\ref{ss:immediate-objects} Immediate objects \\ +\ref{ss:reference-to-self} Reference to self \\ +\ref{ss:initializers} Initializers \\ +\ref{ss:virtual-methods} Virtual methods \\ +\ref{ss:private-methods} Private methods \\ +\ref{ss:class-interfaces} Class interfaces \\ +\ref{ss:inheritance} Inheritance \\ +\ref{ss:multiple-inheritance} Multiple inheritance \\ +\ref{ss:parameterized-classes} Parameterized classes \\ +\ref{ss:polymorphic-methods} Polymorphic methods \\ +\ref{ss:using-coercions} Using coercions \\ +\ref{ss:functional-objects} Functional objects \\ +\ref{ss:cloning-objects} Cloning objects \\ +\ref{ss:recursive-classes} Recursive classes \\ +\ref{ss:binary-methods} Binary methods \\ +\ref{ss:friends} Friends \\ + +%%\ref{s:advanced-examples} {\bf Advanced examples} +%% +%%\ref{ss:bank-accounts} An extended example of bank accounts \\ +%%\ref{ss:modules-as-classes} Simple modules as classes: +%% \ref{module:string} Strings +%% \ref{module:stack} Stacks +%% \ref{module:hashtbl} Hash tables +%% \ref{module:set} Sets \\ +%%\ref{ss:subject-observer} The subject/observer pattern \\ + +\end{htmlonly} + +\section{Classes and objects} +\pdfsection{Classes and objects} +\label{ss:classes-and-objects} + +The class "point" below defines one instance variable "x" and two methods +"get_x" and "move". The initial value of the instance variable is "0". +The variable "x" is declared mutable, so the method "move" can change +its value. +\begin{caml_example}{toplevel} +class point = + object + val mutable x = 0 + method get_x = x + method move d = x <- x + d + end;; +\end{caml_example} + +We now create a new point "p", instance of the "point" class. +\begin{caml_example}{toplevel} +let p = new point;; +\end{caml_example} +Note that the type of "p" is "point". This is an abbreviation +automatically defined by the class definition above. It stands for the +object type " unit>", listing the methods +of class "point" along with their types. + +We now invoke some methods of "p": +\begin{caml_example}{toplevel} +p#get_x;; +p#move 3;; +p#get_x;; +\end{caml_example} + +The evaluation of the body of a class only takes place at object +creation time. Therefore, in the following example, the instance +variable "x" is initialized to different values for two different +objects. +\begin{caml_example}{toplevel} +let x0 = ref 0;; +class point = + object + val mutable x = incr x0; !x0 + method get_x = x + method move d = x <- x + d + end;; +new point#get_x;; +new point#get_x;; +\end{caml_example} + +The class "point" can also be abstracted over the initial values of +the "x" coordinate. +\begin{caml_example}{toplevel} +class point = fun x_init -> + object + val mutable x = x_init + method get_x = x + method move d = x <- x + d + end;; +\end{caml_example} +Like in function definitions, the definition above can be +abbreviated as: +\begin{caml_example}{toplevel} +class point x_init = + object + val mutable x = x_init + method get_x = x + method move d = x <- x + d + end;; +\end{caml_example} +An instance of the class "point" is now a function that expects an +initial parameter to create a point object: +\begin{caml_example}{toplevel} +new point;; +let p = new point 7;; +\end{caml_example} +The parameter "x_init" is, of course, visible in the whole body of the +definition, including methods. For instance, the method "get_offset" +in the class below returns the position of the object relative to its +initial position. +\begin{caml_example}{toplevel} +class point x_init = + object + val mutable x = x_init + method get_x = x + method get_offset = x - x_init + method move d = x <- x + d + end;; +\end{caml_example} +%Instance variables can only be used inside methods. For instance it would +%not be possible to define +%\begin{caml_example}{toplevel} +%class point x_init = +% object +% val mutable x = x_init +% val origin = x +% method get_offset = x - origin +% method move d = x <- x + d +% end;; +%\end{caml_example} +Expressions can be evaluated and bound before defining the object body +of the class. This is useful to enforce invariants. For instance, +points can be automatically adjusted to the nearest point on a grid, +as follows: +\begin{caml_example}{toplevel} +class adjusted_point x_init = + let origin = (x_init / 10) * 10 in + object + val mutable x = origin + method get_x = x + method get_offset = x - origin + method move d = x <- x + d + end;; +\end{caml_example} +(One could also raise an exception if the "x_init" coordinate is not +on the grid.) In fact, the same effect could here be obtained by +calling the definition of class "point" with the value of the +"origin". +\begin{caml_example}{toplevel} +class adjusted_point x_init = point ((x_init / 10) * 10);; +\end{caml_example} +An alternate solution would have been to define the adjustment in +a special allocation function: +\begin{caml_example}{toplevel} +let new_adjusted_point x_init = new point ((x_init / 10) * 10);; +\end{caml_example} +However, the former pattern is generally more appropriate, since +the code for adjustment is part of the definition of the class and will be +inherited. + +This ability provides class constructors as can be found in other +languages. Several constructors can be defined this way to build objects of +the same class but with different initialization patterns; an +alternative is to use initializers, as described below in section +\ref{ss:initializers}. + +\section{Immediate objects} +\pdfsection{Immediate objects} +\label{ss:immediate-objects} + +There is another, more direct way to create an object: create it +without going through a class. + +The syntax is exactly the same as for class expressions, but the +result is a single object rather than a class. All the constructs +described in the rest of this section also apply to immediate objects. +\begin{caml_example}{toplevel} +let p = + object + val mutable x = 0 + method get_x = x + method move d = x <- x + d + end;; +p#get_x;; +p#move 3;; +p#get_x;; +\end{caml_example} + +Unlike classes, which cannot be defined inside an expression, +immediate objects can appear anywhere, using variables from their +environment. +\begin{caml_example}{toplevel} +let minmax x y = + if x < y then object method min = x method max = y end + else object method min = y method max = x end;; +\end{caml_example} + +Immediate objects have two weaknesses compared to classes: their types +are not abbreviated, and you cannot inherit from them. But these two +weaknesses can be advantages in some situations, as we will see +in sections \ref{ss:reference-to-self} and \ref{ss:parameterized-classes}. + +\section{Reference to self} +\pdfsection{Reference to self} +\label{ss:reference-to-self} + +A method or an initializer can invoke methods on self (that is, +the current object). For that, self must be explicitly bound, here to +the variable "s" ("s" could be any identifier, even though we will +often choose the name "self".) +\begin{caml_example}{toplevel} +class printable_point x_init = + object (s) + val mutable x = x_init + method get_x = x + method move d = x <- x + d + method print = print_int s#get_x + end;; +let p = new printable_point 7;; +p#print;; +\end{caml_example} +Dynamically, the variable "s" is bound at the invocation of a method. In +particular, when the class "printable_point" is inherited, the variable +"s" will be correctly bound to the object of the subclass. + +A common problem with self is that, as its type may be extended in +subclasses, you cannot fix it in advance. Here is a simple example. +\begin{caml_example}{toplevel} +let ints = ref [];; +class my_int = + object (self) + method n = 1 + method register = ints := self :: !ints + end [@@expect error];; +\end{caml_example} +You can ignore the first two lines of the error message. What matters +is the last one: putting self into an external reference would make it +impossible to extend it through inheritance. +We will see in section \ref{ss:using-coercions} a workaround to this +problem. +Note however that, since immediate objects are not extensible, the +problem does not occur with them. +\begin{caml_example}{toplevel} +let my_int = + object (self) + method n = 1 + method register = ints := self :: !ints + end;; +\end{caml_example} + +\section{Initializers} +\pdfsection{Initializers} +\label{ss:initializers} + +Let-bindings within class definitions are evaluated before the object +is constructed. It is also possible to evaluate an expression +immediately after the object has been built. Such code is written as +an anonymous hidden method called an initializer. Therefore, it can +access self and the instance variables. +\begin{caml_example}{toplevel} +class printable_point x_init = + let origin = (x_init / 10) * 10 in + object (self) + val mutable x = origin + method get_x = x + method move d = x <- x + d + method print = print_int self#get_x + initializer print_string "new point at "; self#print; print_newline () + end;; +let p = new printable_point 17;; +\end{caml_example} +Initializers cannot be overridden. On the contrary, all initializers are +evaluated sequentially. +Initializers are particularly useful to enforce invariants. +Another example can be seen in section \ref{ss:bank-accounts}. + + +\section{Virtual methods} +\pdfsection{Virtual methods and variables} +\label{ss:virtual-methods} + +It is possible to declare a method without actually defining it, using +the keyword "virtual". This method will be provided later in +subclasses. A class containing virtual methods must be flagged +"virtual", and cannot be instantiated (that is, no object of this class +can be created). It still defines type abbreviations (treating virtual methods +as other methods.) +\begin{caml_example}{toplevel} +class virtual abstract_point x_init = + object (self) + method virtual get_x : int + method get_offset = self#get_x - x_init + method virtual move : int -> unit + end;; +class point x_init = + object + inherit abstract_point x_init + val mutable x = x_init + method get_x = x + method move d = x <- x + d + end;; +\end{caml_example} + +Instance variables can also be declared as virtual, with the same effect +as with methods. +\begin{caml_example}{toplevel} +class virtual abstract_point2 = + object + val mutable virtual x : int + method move d = x <- x + d + end;; +class point2 x_init = + object + inherit abstract_point2 + val mutable x = x_init + method get_offset = x - x_init + end;; +\end{caml_example} + +\section{Private methods} +\pdfsection{Private methods} +\label{ss:private-methods} + +Private methods are methods that do not appear in object interfaces. +They can only be invoked from other methods of the same object. +\begin{caml_example}{toplevel} +class restricted_point x_init = + object (self) + val mutable x = x_init + method get_x = x + method private move d = x <- x + d + method bump = self#move 1 + end;; +let p = new restricted_point 0;; +p#move 10 [@@expect error] ;; +p#bump;; +\end{caml_example} +Note that this is not the same thing as private and protected methods +in Java or C++, which can be called from other objects of the same +class. This is a direct consequence of the independence between types +and classes in OCaml: two unrelated classes may produce +objects of the same type, and there is no way at the type level to +ensure that an object comes from a specific class. However a possible +encoding of friend methods is given in section \ref{ss:friends}. + +Private methods are inherited (they are by default visible in subclasses), +unless they are hidden by signature matching, as described below. + +Private methods can be made public in a subclass. +\begin{caml_example}{toplevel} +class point_again x = + object (self) + inherit restricted_point x + method virtual move : _ + end;; +\end{caml_example} +The annotation "virtual" here is only used to mention a method without +providing its definition. Since we didn't add the "private" +annotation, this makes the method public, keeping the original +definition. + +An alternative definition is +\begin{caml_example}{toplevel} +class point_again x = + object (self : < move : _; ..> ) + inherit restricted_point x + end;; +\end{caml_example} +The constraint on self's type is requiring a public "move" method, and +this is sufficient to override "private". + +One could think that a private method should remain private in a subclass. +However, since the method is visible in a subclass, it is always possible +to pick its code and define a method of the same name that runs that +code, so yet another (heavier) solution would be: +\begin{caml_example}{toplevel} +class point_again x = + object + inherit restricted_point x as super + method move = super#move + end;; +\end{caml_example} + +Of course, private methods can also be virtual. Then, the keywords must +appear in this order "method private virtual". + +\section{Class interfaces} +\pdfsection{Class interfaces} +\label{ss:class-interfaces} + + +%XXX Differentiate class type and class interface ? + +Class interfaces are inferred from class definitions. They may also +be defined directly and used to restrict the type of a class. Like class +declarations, they also define a new type abbreviation. +\begin{caml_example}{toplevel} +class type restricted_point_type = + object + method get_x : int + method bump : unit +end;; +fun (x : restricted_point_type) -> x;; +\end{caml_example} +In addition to program documentation, class interfaces can be used to +constrain the type of a class. Both concrete instance variables and concrete +private methods can be hidden by a class type constraint. Public +methods and virtual members, however, cannot. +\begin{caml_example}{toplevel} +class restricted_point' x = (restricted_point x : restricted_point_type);; +\end{caml_example} +Or, equivalently: +\begin{caml_example}{toplevel} +class restricted_point' = (restricted_point : int -> restricted_point_type);; +\end{caml_example} +The interface of a class can also be specified in a module +signature, and used to restrict the inferred signature of a module. +\begin{caml_example}{toplevel} +module type POINT = sig + class restricted_point' : int -> + object + method get_x : int + method bump : unit + end +end;; +module Point : POINT = struct + class restricted_point' = restricted_point +end;; +\end{caml_example} + +\section{Inheritance} +\pdfsection{Inheritance} +\label{ss:inheritance} + +We illustrate inheritance by defining a class of colored points that +inherits from the class of points. This class has all instance +variables and all methods of class "point", plus a new instance +variable "c" and a new method "color". +\begin{caml_example}{toplevel} +class colored_point x (c : string) = + object + inherit point x + val c = c + method color = c + end;; +let p' = new colored_point 5 "red";; +p'#get_x, p'#color;; +\end{caml_example} +A point and a colored point have incompatible types, since a point has +no method "color". However, the function "get_x" below is a generic +function applying method "get_x" to any object "p" that has this +method (and possibly some others, which are represented by an ellipsis +in the type). Thus, it applies to both points and colored points. +\begin{caml_example}{toplevel} +let get_succ_x p = p#get_x + 1;; +get_succ_x p + get_succ_x p';; +\end{caml_example} +Methods need not be declared previously, as shown by the example: +\begin{caml_example}{toplevel} +let set_x p = p#set_x;; +let incr p = set_x p (get_succ_x p);; +\end{caml_example} + +\section{Multiple inheritance} +\pdfsection{Multiple inheritance} +\label{ss:multiple-inheritance} + +Multiple inheritance is allowed. Only the last definition of a method +is kept: the redefinition in a subclass of a method that was visible in +the parent class overrides the definition in the parent class. +Previous definitions of a method can be reused by binding the related +ancestor. Below, "super" is bound to the ancestor "printable_point". +The name "super" is a pseudo value identifier that can only be used to +invoke a super-class method, as in "super#print". +\begin{caml_example}{toplevel} +class printable_colored_point y c = + object (self) + val c = c + method color = c + inherit printable_point y as super + method! print = + print_string "("; + super#print; + print_string ", "; + print_string (self#color); + print_string ")" + end;; +let p' = new printable_colored_point 17 "red";; +p'#print;; +\end{caml_example} +A private method that has been hidden in the parent class is no longer +visible, and is thus not overridden. Since initializers are treated as +private methods, all initializers along the class hierarchy are evaluated, +in the order they are introduced. + +Note that for clarity's sake, the method "print" is explicitly marked as +overriding another definition by annotating the "method" keyword with +an exclamation mark "!". If the method "print" were not overriding the +"print" method of "printable_point", the compiler would raise an error: +\begin{caml_example}{toplevel}[error] + object + method! m = () + end;; +\end{caml_example} + +This explicit overriding annotation also works +for "val" and "inherit": +\begin{caml_example}{toplevel} +class another_printable_colored_point y c c' = + object (self) + inherit printable_point y + inherit! printable_colored_point y c + val! c = c' + end;; +\end{caml_example} + +\section{Parameterized classes} +\pdfsection{Parameterized classes} +\label{ss:parameterized-classes} + +Reference cells can be implemented as objects. +The naive definition fails to typecheck: +\begin{caml_example}{toplevel}[error] +class oref x_init = + object + val mutable x = x_init + method get = x + method set y = x <- y + end;; +\end{caml_example} +The reason is that at least one of the methods has a polymorphic type +(here, the type of the value stored in the reference cell), thus +either the class should be parametric, or the method type should be +constrained to a monomorphic type. A monomorphic instance of the class could +be defined by: +\begin{caml_example}{toplevel} +class oref (x_init:int) = + object + val mutable x = x_init + method get = x + method set y = x <- y + end;; +\end{caml_example} +Note that since immediate objects do not define a class type, they have +no such restriction. +\begin{caml_example}{toplevel} +let new_oref x_init = + object + val mutable x = x_init + method get = x + method set y = x <- y + end;; +\end{caml_example} +On the other hand, a class for polymorphic references must explicitly +list the type parameters in its declaration. Class type parameters are +listed between "[" and "]". The type parameters must also be +bound somewhere in the class body by a type constraint. +\begin{caml_example}{toplevel} +class ['a] oref x_init = + object + val mutable x = (x_init : 'a) + method get = x + method set y = x <- y + end;; +let r = new oref 1 in r#set 2; (r#get);; +\end{caml_example} +The type parameter in the declaration may actually be constrained in the +body of the class definition. In the class type, the actual value of +the type parameter is displayed in the "constraint" clause. +\begin{caml_example}{toplevel} +class ['a] oref_succ (x_init:'a) = + object + val mutable x = x_init + 1 + method get = x + method set y = x <- y + end;; +\end{caml_example} +Let us consider a more complex example: define a circle, whose center +may be any kind of point. We put an additional type +constraint in method "move", since no free variables must remain +unaccounted for by the class type parameters. +\begin{caml_example}{toplevel} +class ['a] circle (c : 'a) = + object + val mutable center = c + method center = center + method set_center c = center <- c + method move = (center#move : int -> unit) + end;; +\end{caml_example} +An alternate definition of "circle", using a "constraint" clause in +the class definition, is shown below. The type "#point" used below in +the "constraint" clause is an abbreviation produced by the definition +of class "point". This abbreviation unifies with the type of any +object belonging to a subclass of class "point". It actually expands to +"< get_x : int; move : int -> unit; .. >". This leads to the following +alternate definition of "circle", which has slightly stronger +constraints on its argument, as we now expect "center" to have a +method "get_x". +\begin{caml_example}{toplevel} +class ['a] circle (c : 'a) = + object + constraint 'a = #point + val mutable center = c + method center = center + method set_center c = center <- c + method move = center#move + end;; +\end{caml_example} +The class "colored_circle" is a specialized version of class +"circle" that requires the type of the center to unify with +"#colored_point", and adds a method "color". Note that when specializing a +parameterized class, the instance of type parameter must always be +explicitly given. It is again written between "[" and "]". +\begin{caml_example}{toplevel} +class ['a] colored_circle c = + object + constraint 'a = #colored_point + inherit ['a] circle c + method color = center#color + end;; +\end{caml_example} + +\section{Polymorphic methods} +\pdfsection{Polymorphic methods} +\label{ss:polymorphic-methods} + +While parameterized classes may be polymorphic in their contents, they +are not enough to allow polymorphism of method use. + +A classical example is defining an iterator. +\begin{caml_example}{toplevel} +List.fold_left;; +class ['a] intlist (l : int list) = + object + method empty = (l = []) + method fold f (accu : 'a) = List.fold_left f accu l + end;; +\end{caml_example} +At first look, we seem to have a polymorphic iterator, however this +does not work in practice. +\begin{caml_example}{toplevel} +let l = new intlist [1; 2; 3];; +l#fold (fun x y -> x+y) 0;; +l;; +l#fold (fun s x -> s ^ string_of_int x ^ " ") "" [@@expect error];; +\end{caml_example} +Our iterator works, as shows its first use for summation. However, +since objects themselves are not polymorphic (only their constructors +are), using the "fold" method fixes its type for this individual object. +Our next attempt to use it as a string iterator fails. + +The problem here is that quantification was wrongly located: it is +not the class we want to be polymorphic, but the "fold" method. +This can be achieved by giving an explicitly polymorphic type in the +method definition. +\begin{caml_example}{toplevel} +class intlist (l : int list) = + object + method empty = (l = []) + method fold : 'a. ('a -> int -> 'a) -> 'a -> 'a = + fun f accu -> List.fold_left f accu l + end;; +let l = new intlist [1; 2; 3];; +l#fold (fun x y -> x+y) 0;; +l#fold (fun s x -> s ^ string_of_int x ^ " ") "";; +\end{caml_example} +As you can see in the class type shown by the compiler, while +polymorphic method types must be fully explicit in class definitions +(appearing immediately after the method name), quantified type +variables can be left implicit in class descriptions. Why require types +to be explicit? The problem is that "(int -> int -> int) -> int -> +int" would also be a valid type for "fold", and it happens to be +incompatible with the polymorphic type we gave (automatic +instantiation only works for toplevel types variables, not for inner +quantifiers, where it becomes an undecidable problem.) So the compiler +cannot choose between those two types, and must be helped. + +However, the type can be completely omitted in the class definition if +it is already known, through inheritance or type constraints on self. +Here is an example of method overriding. +\begin{caml_example*}{toplevel} +class intlist_rev l = + object + inherit intlist l + method! fold f accu = List.fold_left f accu (List.rev l) + end;; +\end{caml_example*} +The following idiom separates description and definition. +\begin{caml_example*}{toplevel} +class type ['a] iterator = + object method fold : ('b -> 'a -> 'b) -> 'b -> 'b end;; +class intlist l = + object (self : int #iterator) + method empty = (l = []) + method fold f accu = List.fold_left f accu l + end;; +\end{caml_example*} +Note here the "(self : int #iterator)" idiom, which ensures that this +object implements the interface "iterator". + +Polymorphic methods are called in exactly the same way as normal +methods, but you should be aware of some limitations of type +inference. Namely, a polymorphic method can only be called if its +type is known at the call site. Otherwise, the method will be assumed +to be monomorphic, and given an incompatible type. +\begin{caml_example}{toplevel} +let sum lst = lst#fold (fun x y -> x+y) 0;; +sum l [@@expect error];; +\end{caml_example} +The workaround is easy: you should put a type constraint on the +parameter. +\begin{caml_example}{toplevel} +let sum (lst : _ #iterator) = lst#fold (fun x y -> x+y) 0;; +\end{caml_example} +Of course the constraint may also be an explicit method type. +Only occurences of quantified variables are required. +\begin{caml_example}{toplevel} +let sum lst = + (lst : < fold : 'a. ('a -> _ -> 'a) -> 'a -> 'a; .. >)#fold (+) 0;; +\end{caml_example} + +Another use of polymorphic methods is to allow some form of implicit +subtyping in method arguments. We have already seen in section +\ref{ss:inheritance} how some functions may be polymorphic in the +class of their argument. This can be extended to methods. +\begin{caml_example}{toplevel} +class type point0 = object method get_x : int end;; +class distance_point x = + object + inherit point x + method distance : 'a. (#point0 as 'a) -> int = + fun other -> abs (other#get_x - x) + end;; +let p = new distance_point 3 in +(p#distance (new point 8), p#distance (new colored_point 1 "blue"));; +\end{caml_example} +Note here the special syntax "(#point0 as 'a)" we have to use to +quantify the extensible part of "#point0". As for the variable binder, +it can be omitted in class specifications. If you want polymorphism +inside object field it must be quantified independently. +\begin{caml_example}{toplevel} +class multi_poly = + object + method m1 : 'a. (< n1 : 'b. 'b -> 'b; .. > as 'a) -> _ = + fun o -> o#n1 true, o#n1 "hello" + method m2 : 'a 'b. (< n2 : 'b -> bool; .. > as 'a) -> 'b -> _ = + fun o x -> o#n2 x + end;; +\end{caml_example} +In method "m1", "o" must be an object with at least a method "n1", +itself polymorphic. In method "m2", the argument of "n2" and "x" must +have the same type, which is quantified at the same level as "'a". + +\section{Using coercions} +\pdfsection{Using coercions} +\label{ss:using-coercions} + +Subtyping is never implicit. There are, however, two ways to perform +subtyping. The most general construction is fully explicit: both the +domain and the codomain of the type coercion must be given. + +We have seen that points and colored points have incompatible types. +For instance, they cannot be mixed in the same list. However, a +colored point can be coerced to a point, hiding its "color" method: +\begin{caml_example}{toplevel} +let colored_point_to_point cp = (cp : colored_point :> point);; +let p = new point 3 and q = new colored_point 4 "blue";; +let l = [p; (colored_point_to_point q)];; +\end{caml_example} +An object of type "t" can be seen as an object of type "t'" +only if "t" is a subtype of "t'". For instance, a point cannot be +seen as a colored point. +\begin{caml_example}{toplevel}[error] +(p : point :> colored_point);; +\end{caml_example} +Indeed, narrowing coercions without runtime checks would be unsafe. +Runtime type checks might raise exceptions, and they would require +the presence of type information at runtime, which is not the case in +the OCaml system. +For these reasons, there is no such operation available in the language. + +Be aware that subtyping and inheritance are not related. Inheritance is a +syntactic relation between classes while subtyping is a semantic relation +between types. For instance, the class of colored points could have been +defined directly, without inheriting from the class of points; the type of +colored points would remain unchanged and thus still be a subtype of +points. +% Conversely, the class "int_comparable" inherits from class +%"comparable", but type "int_comparable" is not a subtype of "comparable". +%\begin{caml_example}{toplevel} +%function x -> (x : int_comparable :> comparable);; +%\end{caml_example} + +The domain of a coercion can often be omitted. For instance, one can +define: +\begin{caml_example}{toplevel} +let to_point cp = (cp :> point);; +\end{caml_example} +In this case, the function "colored_point_to_point" is an instance of the +function "to_point". This is not always true, however. The fully +explicit coercion is more precise and is sometimes unavoidable. +Consider, for example, the following class: +\begin{caml_example}{toplevel} +class c0 = object method m = {< >} method n = 0 end;; +\end{caml_example} +The object type "c0" is an abbreviation for " as 'a". +Consider now the type declaration: +\begin{caml_example}{toplevel} +class type c1 = object method m : c1 end;; +\end{caml_example} +The object type "c1" is an abbreviation for the type " as 'a". +The coercion from an object of type "c0" to an object of type "c1" is +correct: +\begin{caml_example}{toplevel} +fun (x:c0) -> (x : c0 :> c1);; +\end{caml_example} +%%% FIXME come up with a better example. +% However, the domain of the coercion cannot be omitted here: +% \begin{caml_example}{toplevel} +% fun (x:c0) -> (x :> c1);; +% \end{caml_example} +However, the domain of the coercion cannot always be omitted. +In that case, the solution is to use the explicit form. +% +Sometimes, a change in the class-type definition can also solve the problem +\begin{caml_example}{toplevel} +class type c2 = object ('a) method m : 'a end;; +fun (x:c0) -> (x :> c2);; +\end{caml_example} +While class types "c1" and "c2" are different, both object types +"c1" and "c2" expand to the same object type (same method names and types). +Yet, when the domain of a coercion is left implicit and its co-domain +is an abbreviation of a known class type, then the class type, rather +than the object type, is used to derive the coercion function. This +allows leaving the domain implicit in most cases when coercing form a +subclass to its superclass. +% +The type of a coercion can always be seen as below: +\begin{caml_example}{toplevel} +let to_c1 x = (x :> c1);; +let to_c2 x = (x :> c2);; +\end{caml_example} +Note the difference between these two coercions: in the case of "to_c2", +the type +"#c2 = < m : 'a; .. > as 'a" is polymorphically recursive (according +to the explicit recursion in the class type of "c2"); hence the +success of applying this coercion to an object of class "c0". +On the other hand, in the first case, "c1" was only expanded and +unrolled twice to obtain "< m : < m : c1; .. >; .. >" (remember "#c1 = +< m : c1; .. >"), without introducing recursion. +You may also note that the type of "to_c2" is "#c2 -> c2" while +the type of "to_c1" is more general than "#c1 -> c1". This is not always true, +since there are class types for which some instances of "#c" are not subtypes +of "c", as explained in section~\ref{ss:binary-methods}. Yet, for +parameterless classes the coercion "(_ :> c)" is always more general than +"(_ : #c :> c)". +%If a class type exposes the type of self through one of its parameters, this +%is no longer true. Here is a counter-example. +%\begin{caml_example}{toplevel} +%class type ['a] c = object ('a) method m : 'a end;; +%let to_c x = (x :> _ c);; +%\end{caml_example} + + +A common problem may occur when one tries to define a coercion to a +class "c" while defining class "c". The problem is due to the type +abbreviation not being completely defined yet, and so its subtypes are not +clearly known. Then, a coercion "(_ :> c)" or "(_ : #c :> c)" is taken to be +the identity function, as in +\begin{caml_example}{toplevel} +function x -> (x :> 'a);; +\end{caml_example} +As a consequence, if the coercion is applied to "self", as in the +following example, the type of "self" is unified with the closed type +"c" (a closed object type is an object type without ellipsis). This +would constrain the type of self be closed and is thus rejected. +Indeed, the type of self cannot be closed: this would prevent any +further extension of the class. Therefore, a type error is generated +when the unification of this type with another type would result in a +closed object type. +\begin{caml_example}{toplevel}[error] +class c = object method m = 1 end +and d = object (self) + inherit c + method n = 2 + method as_c = (self :> c) +end;; +\end{caml_example} +However, the most common instance of this problem, coercing self to +its current class, is detected as a special case by the type checker, +and properly typed. +\begin{caml_example}{toplevel} +class c = object (self) method m = (self :> c) end;; +\end{caml_example} +This allows the following idiom, keeping a list of all objects +belonging to a class or its subclasses: +\begin{caml_example}{toplevel} +let all_c = ref [];; +class c (m : int) = + object (self) + method m = m + initializer all_c := (self :> c) :: !all_c + end;; +\end{caml_example} +This idiom can in turn be used to retrieve an object whose type has +been weakened: +\begin{caml_example}{toplevel} +let rec lookup_obj obj = function [] -> raise Not_found + | obj' :: l -> + if (obj :> < >) = (obj' :> < >) then obj' else lookup_obj obj l ;; +let lookup_c obj = lookup_obj obj !all_c;; +\end{caml_example} +The type "< m : int >" we see here is just the expansion of "c", due +to the use of a reference; we have succeeded in getting back an object +of type "c". + +\medskip +The previous coercion problem can often be avoided by first +defining the abbreviation, using a class type: +\begin{caml_example}{toplevel} +class type c' = object method m : int end;; +class c : c' = object method m = 1 end +and d = object (self) + inherit c + method n = 2 + method as_c = (self :> c') +end;; +\end{caml_example} +It is also possible to use a virtual class. Inheriting from this class +simultaneously forces all methods of "c" to have the same +type as the methods of "c'". +\begin{caml_example}{toplevel} +class virtual c' = object method virtual m : int end;; +class c = object (self) inherit c' method m = 1 end;; +\end{caml_example} +One could think of defining the type abbreviation directly: +\begin{caml_example*}{toplevel} +type c' = ;; +\end{caml_example*} +However, the abbreviation "#c'" cannot be defined directly in a similar way. +It can only be defined by a class or a class-type definition. +This is because a "#"-abbreviation carries an implicit anonymous +variable ".." that cannot be explicitly named. +The closer you get to it is: +\begin{caml_example*}{toplevel} +type 'a c'_class = 'a constraint 'a = < m : int; .. >;; +\end{caml_example*} +with an extra type variable capturing the open object type. + +\section{Functional objects} +\pdfsection{Functional objects} +\label{ss:functional-objects} + +It is possible to write a version of class "point" without assignments +on the instance variables. The override construct "{< ... >}" returns a copy of +``self'' (that is, the current object), possibly changing the value of +some instance variables. +\begin{caml_example}{toplevel} +class functional_point y = + object + val x = y + method get_x = x + method move d = {< x = x + d >} + end;; +let p = new functional_point 7;; +p#get_x;; +(p#move 3)#get_x;; +p#get_x;; +\end{caml_example} +Note that the type abbreviation "functional_point" is recursive, which can +be seen in the class type of "functional_point": the type of self is "'a" +and "'a" appears inside the type of the method "move". + +The above definition of "functional_point" is not equivalent +to the following: +\begin{caml_example}{toplevel} +class bad_functional_point y = + object + val x = y + method get_x = x + method move d = new bad_functional_point (x+d) + end;; +\end{caml_example} +While objects of either class will behave the same, objects of their +subclasses will be different. In a subclass of "bad_functional_point", +the method "move" will +keep returning an object of the parent class. On the contrary, in a +subclass of "functional_point", the method "move" will return an +object of the subclass. + +Functional update is often used in conjunction with binary methods +as illustrated in section \ref{module:string}. + +\section{Cloning objects} +\pdfsection{Cloning objects} +\label{ss:cloning-objects} + +Objects can also be cloned, whether they are functional or imperative. +The library function "Oo.copy" makes a shallow copy of an object. That is, +it returns a new object that has the same methods and instance +variables as its argument. The +instance variables are copied but their contents are shared. +Assigning a new value to an instance variable of the copy (using a method +call) will not affect instance variables of the original, and conversely. +A deeper assignment (for example if the instance variable is a reference cell) +will of course affect both the original and the copy. + +The type of "Oo.copy" is the following: +\begin{caml_example}{toplevel} +Oo.copy;; +\end{caml_example} +The keyword "as" in that type binds the type variable "'a" to +the object type "< .. >". Therefore, "Oo.copy" takes an object with +any methods (represented by the ellipsis), and returns an object of +the same type. The type of "Oo.copy" is different from type "< .. > -> +< .. >" as each ellipsis represents a different set of methods. +Ellipsis actually behaves as a type variable. +\begin{caml_example}{toplevel} +let p = new point 5;; +let q = Oo.copy p;; +q#move 7; (p#get_x, q#get_x);; +\end{caml_example} +In fact, "Oo.copy p" will behave as "p#copy" assuming that a public +method "copy" with body "{< >}" has been defined in the class of "p". + +Objects can be compared using the generic comparison functions "=" and "<>". +Two objects are equal if and only if they are physically equal. In +particular, an object and its copy are not equal. +\begin{caml_example}{toplevel} +let q = Oo.copy p;; +p = q, p = p;; +\end{caml_example} +Other generic comparisons such as ("<", "<=", ...) can also be used on +objects. The +relation "<" defines an unspecified but strict ordering on objects. The +ordering relationship between two objects is fixed once for all after the +two objects have been created and it is not affected by mutation of fields. + +Cloning and override have a non empty intersection. +They are interchangeable when used within an object and without +overriding any field: +\begin{caml_example}{toplevel} +class copy = + object + method copy = {< >} + end;; +class copy = + object (self) + method copy = Oo.copy self + end;; +\end{caml_example} +Only the override can be used to actually override fields, and +only the "Oo.copy" primitive can be used externally. + +Cloning can also be used to provide facilities for saving and +restoring the state of objects. +\begin{caml_example}{toplevel} +class backup = + object (self : 'mytype) + val mutable copy = None + method save = copy <- Some {< copy = None >} + method restore = match copy with Some x -> x | None -> self + end;; +\end{caml_example} +The above definition will only backup one level. +The backup facility can be added to any class by using multiple inheritance. +\begin{caml_example}{toplevel} +class ['a] backup_ref x = object inherit ['a] oref x inherit backup end;; +let rec get p n = if n = 0 then p # get else get (p # restore) (n-1);; +let p = new backup_ref 0 in +p # save; p # set 1; p # save; p # set 2; +[get p 0; get p 1; get p 2; get p 3; get p 4];; +\end{caml_example} +We can define a variant of backup that retains all copies. (We also +add a method "clear" to manually erase all copies.) +\begin{caml_example}{toplevel} +class backup = + object (self : 'mytype) + val mutable copy = None + method save = copy <- Some {< >} + method restore = match copy with Some x -> x | None -> self + method clear = copy <- None + end;; +\end{caml_example} +\begin{caml_example}{toplevel} +class ['a] backup_ref x = object inherit ['a] oref x inherit backup end;; +let p = new backup_ref 0 in +p # save; p # set 1; p # save; p # set 2; +[get p 0; get p 1; get p 2; get p 3; get p 4];; +\end{caml_example} + + + +\section{Recursive classes} +\pdfsection{Recursive classes} +\label{ss:recursive-classes} + +Recursive classes can be used to define objects whose types are +mutually recursive. +\begin{caml_example}{toplevel} +class window = + object + val mutable top_widget = (None : widget option) + method top_widget = top_widget + end +and widget (w : window) = + object + val window = w + method window = window + end;; +\end{caml_example} +Although their types are mutually recursive, the classes "widget" and +"window" are themselves independent. + + +\section{Binary methods} +\pdfsection{Binary methods} +\label{ss:binary-methods} + +A binary method is a method which takes an argument of the same type +as self. The class "comparable" below is a template for classes with a +binary method "leq" of type "'a -> bool" where the type variable "'a" +is bound to the type of self. Therefore, "#comparable" expands to "< +leq : 'a -> bool; .. > as 'a". We see here that the binder "as" also +allows writing recursive types. +\begin{caml_example}{toplevel} +class virtual comparable = + object (_ : 'a) + method virtual leq : 'a -> bool + end;; +\end{caml_example} +We then define a subclass "money" of "comparable". The class "money" +simply wraps floats as comparable objects. We will extend it below with +more operations. We have to use a type constraint on the class parameter "x" +because the primitive "<=" is a polymorphic function in +OCaml. The "inherit" clause ensures that the type of objects +of this class is an instance of "#comparable". +\begin{caml_example}{toplevel} +class money (x : float) = + object + inherit comparable + val repr = x + method value = repr + method leq p = repr <= p#value + end;; +\end{caml_example} +% not explained: mutability can be hidden +Note that the type "money" is not a subtype of type +"comparable", as the self type appears in contravariant position +in the type of method "leq". +Indeed, an object "m" of class "money" has a method "leq" +that expects an argument of type "money" since it accesses +its "value" method. Considering "m" of type "comparable" would allow a +call to method "leq" on "m" with an argument that does not have a method +"value", which would be an error. + +Similarly, the type "money2" below is not a subtype of type "money". +\begin{caml_example}{toplevel} +class money2 x = + object + inherit money x + method times k = {< repr = k *. repr >} + end;; +\end{caml_example} +It is however possible to define functions that manipulate objects of +type either "money" or "money2": the function "min" +will return the minimum of any two objects whose type unifies with +"#comparable". The type of "min" is not the same as "#comparable -> +#comparable -> #comparable", as the abbreviation "#comparable" hides a +type variable (an ellipsis). Each occurrence of this abbreviation +generates a new variable. +\begin{caml_example}{toplevel} +let min (x : #comparable) y = + if x#leq y then x else y;; +\end{caml_example} +This function can be applied to objects of type "money" +or "money2". +\begin{caml_example}{toplevel} +(min (new money 1.3) (new money 3.1))#value;; +(min (new money2 5.0) (new money2 3.14))#value;; +\end{caml_example} + +More examples of binary methods can be found in sections +\ref{module:string} and \ref{module:set}. + +Note the use of override for method "times". +Writing "new money2 (k *. repr)" instead of "{< repr = k *. repr >}" +would not behave well with inheritance: in a subclass "money3" of "money2" +the "times" method would return an object of class "money2" but not of class +"money3" as would be expected. + +The class "money" could naturally carry another binary method. Here is a +direct definition: +\begin{caml_example}{toplevel} +class money x = + object (self : 'a) + val repr = x + method value = repr + method print = print_float repr + method times k = {< repr = k *. x >} + method leq (p : 'a) = repr <= p#value + method plus (p : 'a) = {< repr = x +. p#value >} + end;; +\end{caml_example} + +\section{Friends} +\pdfsection{Friends} +\label{ss:friends} + +The above class "money" reveals a problem that often occurs with binary +methods. In order to interact with other objects of the same class, the +representation of "money" objects must be revealed, using a method such as +"value". If we remove all binary methods (here "plus" and "leq"), +the representation can easily be hidden inside objects by removing the method +"value" as well. However, this is not possible as soon as some binary +method requires access to the representation of objects of the same +class (other than self). +\begin{caml_example}{toplevel} +class safe_money x = + object (self : 'a) + val repr = x + method print = print_float repr + method times k = {< repr = k *. x >} + end;; +\end{caml_example} +Here, the representation of the object is known only to a particular object. +To make it available to other objects of the same class, we are forced to +make it available to the whole world. However we can easily restrict the +visibility of the representation using the module system. +\begin{caml_example*}{toplevel} +module type MONEY = + sig + type t + class c : float -> + object ('a) + val repr : t + method value : t + method print : unit + method times : float -> 'a + method leq : 'a -> bool + method plus : 'a -> 'a + end + end;; +module Euro : MONEY = + struct + type t = float + class c x = + object (self : 'a) + val repr = x + method value = repr + method print = print_float repr + method times k = {< repr = k *. x >} + method leq (p : 'a) = repr <= p#value + method plus (p : 'a) = {< repr = x +. p#value >} + end + end;; +\end{caml_example*} +Another example of friend functions may be found in section +\ref{module:set}. These examples occur when a group of objects (here +objects of the same class) and functions should see each others internal +representation, while their representation should be hidden from the +outside. The solution is always to define all friends in the same module, +give access to the representation and use a signature constraint to make the +representation abstract outside the module. + + + +% LocalWords: typecheck monomorphic uncaptured Subtyping subtyping leq repr Oo +% LocalWords: val sig bool Euro struct OCaml Vouillon Didier int ref incr init +% LocalWords: succ mytype rec + diff --git a/manual/manual/tutorials/polymorphism.etex b/manual/manual/tutorials/polymorphism.etex new file mode 100644 index 00000000..5402ec36 --- /dev/null +++ b/manual/manual/tutorials/polymorphism.etex @@ -0,0 +1,477 @@ + +\chapter{Polymorphism and its limitations}% +\label{c:polymorphism} +\pdfchapterfold{0}{Tutorial: Polymorphism limitations} +%HEVEA\cutname{polymorphism.html} + +\bigskip + +\noindent This chapter covers more advanced questions related to the +limitations of polymorphic functions and types. There are some situations +in OCaml where the type inferred by the type checker may be less generic +than expected. Such non-genericity can stem either from interactions +between side-effect and typing or the difficulties of implicit polymorphic +recursion and higher-rank polymorphism. + +This chapter details each of these situations and, if it is possible, +how to recover genericity. + +\section{Weak polymorphism and mutation} +\subsection{Weakly polymorphic types} +\label{ss:weaktypes} +Maybe the most frequent examples of non-genericity derive from the +interactions between polymorphic types and mutation. A simple example +appears when typing the following expression +\begin{caml_example}{toplevel} +let store = ref None ;; +\end{caml_example} +Since the type of "None" is "'a option" and the function "ref" has type +"'b -> 'b ref", a natural deduction for the type of "store" would be +"'a option ref". However, the inferred type, "'_weak1 option ref", is +different. Type variables whose name starts with a "_weak" prefix like +"'_weak1" are weakly polymorphic type variables, sometimes shortened as +weak type variables. +A weak type variable is a placeholder for a single type that is currently +unknown. Once the specific type "t" behind the placeholder type "'_weak1" +is known, all occurrences of "'_weak1" will be replaced by "t". For instance, +we can define another option reference and store an "int" inside: +\begin{caml_example}{toplevel} +let another_store = ref None ;; +another_store := Some 0; +another_store ;; +\end{caml_example} +After storing an "int" inside "another_store", the type of "another_store" has +been updated from "'_weak2 option ref" to "int option ref". +This distinction between weakly and generic polymorphic type variable protects +OCaml programs from unsoundness and runtime errors. To understand from where +unsoundness might come, consider this simple function which swaps a value "x" +with the value stored inside a "store" reference, if there is such value: +\begin{caml_example}{toplevel} +let swap store x = match !store with + | None -> store := Some x; x + | Some y -> store := Some x; y;; +\end{caml_example} +We can apply this function to our store +\begin{caml_example}{toplevel} +let one = swap store 1 +let one_again = swap store 2 +let two = swap store 3;; +\end{caml_example} +After these three swaps the stored value is "3". Everything is fine up to +now. We can then try to swap "3" with a more interesting value, for +instance a function: +\begin{caml_example}{toplevel}[error] +let error = swap store (fun x -> x);; +\end{caml_example} +At this point, the type checker rightfully complains that it is not +possible to swap an integer and a function, and that an "int" should always +be traded for another "int". Furthermore, the type checker prevents us to +change manually the type of the value stored by "store": +\begin{caml_example}{toplevel}[error] +store := Some (fun x -> x);; +\end{caml_example} +Indeed, looking at the type of store, we see that the weak type "'_weak1" has +been replaced by the type "int" +\begin{caml_example}{toplevel} +store;; +\end{caml_example} +Therefore, after placing an "int" in "store", we cannot use it to store any +value other than an "int". More generally, weak types protect the program from +undue mutation of values with a polymorphic type. + +%todo: fix indentation in pdfmanual +Moreover, weak types cannot appear in the signature of toplevel modules: +types must be known at compilation time. Otherwise, different compilation +units could replace the weak type with different and incompatible types. +For this reason, compiling the following small piece of code +\begin{verbatim} +let option_ref = ref None +\end{verbatim} +yields a compilation error +\begin{verbatim} +Error: The type of this expression, '_weak1 option ref, + contains type variables that cannot be generalized +\end{verbatim} +To solve this error, it is enough to add an explicit type annotation to +specify the type at declaration time: +\begin{verbatim} +let option_ref: int option ref = ref None +\end{verbatim} +This is in any case a good practice for such global mutable variables. +Otherwise, they will pick out the type of first use. If there is a mistake +at this point, this can result in confusing type errors when later, correct +uses are flagged as errors. + +\subsection{The value restriction}\label{ss:valuerestriction} + +Identifying the exact context in which polymorphic types should be +replaced by weak types in a modular way is a difficult question. Indeed +the type system must handle the possibility that functions may hide persistent +mutable states. For instance, the following function uses an internal reference +to implement a delayed identity function +\begin{caml_example}{toplevel} +let make_fake_id () = + let store = ref None in + fun x -> swap store x ;; +let fake_id = make_fake_id();; +\end{caml_example} +It would be unsound to apply this "fake_id" function to values with different +types. The function "fake_id" is therefore rightfully assigned the type +"'_weak3 -> '_weak3" rather than "'a -> 'a". At the same time, it ought to +be possible to use a local mutable state without impacting the type of a +function. +%todo: add an example? + +To circumvent these dual difficulties, the type checker considers that any value +returned by a function might rely on persistent mutable states behind the scene +and should be given a weak type. This restriction on the type of mutable +values and the results of function application is called the value restriction. +Note that this value restriction is conservative: there are situations where the +value restriction is too cautious and gives a weak type to a value that could be +safely generalized to a polymorphic type: +\begin{caml_example}{toplevel} +let not_id = (fun x -> x) (fun x -> x);; +\end{caml_example} +Quite often, this happens when defining function using higher order function. +To avoid this problem, a solution is to add an explicit argument to the +function: +\begin{caml_example}{toplevel} +let id_again = fun x -> (fun x -> x) (fun x -> x) x;; +\end{caml_example} +With this argument, "id_again" is seen as a function definition by the type +checker and can therefore be generalized. This kind of manipulation is called +eta-expansion in lambda calculus and is sometimes referred under this name. + +\subsection{The relaxed value restriction} + +There is another partial solution to the problem of unnecessary weak type, +which is implemented directly within the type checker. Briefly, it is possible +to prove that weak types that only appear as type parameters in covariant +positions --also called positive positions-- can be safely generalized to +polymorphic types. For instance, the type "'a list" is covariant in "'a": +\begin{caml_example}{toplevel} + let f () = [];; + let empty = f ();; +\end{caml_example} +Remark that the type inferred for "empty" is "'a list" and not "'_weak5 list" +that should have occurred with the value restriction since "f ()" is a +function application. + +The value restriction combined with this generalization for covariant type +parameters is called the relaxed value restriction. + +%question: is here the best place for describing variance? +\subsection{Variance and value restriction} +Variance describes how type constructors behave with respect to subtyping. +Consider for instance a pair of type "x" and "xy" with "x" a subtype of "xy", +denoted "x :> xy": +\begin{caml_example}{toplevel} + type x = [ `X ];; + type xy = [ `X | `Y ];; +\end{caml_example} +As "x" is a subtype of "xy", we can convert a value of type "x" +to a value of type "xy": +\begin{caml_example}{toplevel} + let x:x = `X;; + let x' = ( x :> xy);; +\end{caml_example} +Similarly, if we have a value of type "x list", we can convert it to a value +of type "xy list", since we could convert each element one by one: +\begin{caml_example}{toplevel} + let l:x list = [`X; `X];; + let l' = ( l :> xy list);; +\end{caml_example} +In other words, "x :> xy" implies that "x list :> xy list", therefore +the type constructor "'a list" is covariant (it preserves subtyping) +in its parameter "'a". + +Contrarily, if we have a function that can handle values of type "xy" +\begin{caml_example}{toplevel} + let f: xy -> unit = function + | `X -> () + | `Y -> ();; +\end{caml_example} +it can also handle values of type "x": +\begin{caml_example}{toplevel} + let f' = (f :> x -> unit);; +\end{caml_example} +Note that we can rewrite the type of "f" and "f'" as +\begin{caml_example}{toplevel} + type 'a proc = 'a -> unit + let f' = (f: xy proc :> x proc);; +\end{caml_example} +In this case, we have "x :> xy" implies "xy proc :> x proc". Notice +that the second subtyping relation reverse the order of "x" and "xy": +the type constructor "'a proc" is contravariant in its parameter "'a". +More generally, the function type constructor "'a -> 'b" is covariant in +its return type "'b" and contravariant in its argument type "'a". + +A type constructor can also be invariant in some of its type parameters, +neither covariant nor contravariant. A typical example is a reference: +\begin{caml_example}{toplevel} + let x: x ref = ref `X;; +\end{caml_example} +If we were able to coerce "x" to the type "xy ref" as a variable "xy", +we could use "xy" to store the value "`Y" inside the reference and then use +the "x" value to read this content as a value of type "x", +which would break the type system. + +More generally, as soon as a type variable appears in a position describing +mutable state it becomes invariant. As a corollary, covariant variables will +never denote mutable locations and can be safely generalized. +For a better description, interested readers can consult the original +article by Jacques Garrigue on +\url{http://www.math.nagoya-u.ac.jp/~garrigue/papers/morepoly-long.pdf} + +Together, the relaxed value restriction and type parameter covariance +help to avoid eta-expansion in many situations. + +\subsection{Abstract data types} +Moreover, when the type definitions are exposed, the type checker +is able to infer variance information on its own and one can benefit from +the relaxed value restriction even unknowingly. However, this is not the case +anymore when defining new abstract types. As an illustration, we can define a +module type collection as: +\begin{caml_example}{toplevel} +module type COLLECTION = sig + type 'a t + val empty: unit -> 'a t +end + +module Implementation = struct + type 'a t = 'a list + let empty ()= [] +end;; + +module List2: COLLECTION = Implementation;; +\end{caml_example} + +In this situation, when coercing the module "List2" to the module type +"COLLECTION", the type checker forgets that "'a List2.t" was covariant +in "'a". Consequently, the relaxed value restriction does not apply anymore: + +\begin{caml_example}{toplevel} + List2.empty ();; +\end{caml_example} + +To keep the relaxed value restriction, we need to declare the abstract type +"'a COLLECTION.t" as covariant in "'a": +\begin{caml_example}{toplevel} +module type COLLECTION = sig + type +'a t + val empty: unit -> 'a t +end + +module List2: COLLECTION = Implementation;; +\end{caml_example} + +We then recover polymorphism: + +\begin{caml_example}{toplevel} + List2.empty ();; +\end{caml_example} + +\section{Polymorphic recursion}\label{s:polymorphic-recursion} + +The second major class of non-genericity is directly related to the problem +of type inference for polymorphic functions. In some circumstances, the type +inferred by OCaml might be not general enough to allow the definition of +some recursive functions, in particular for recursive function acting on +non-regular algebraic data type. + +With a regular polymorphic algebraic data type, the type parameters of +the type constructor are constant within the definition of the type. For +instance, we can look at arbitrarily nested list defined as: +\begin{caml_example}{toplevel} + type 'a regular_nested = List of 'a list | Nested of 'a regular_nested list + let l = Nested[ List [1]; Nested [List[2;3]]; Nested[Nested[]] ];; +\end{caml_example} +Note that the type constructor "regular_nested" always appears as +"'a regular_nested" in the definition above, with the same parameter +"'a". Equipped with this type, one can compute a maximal depth with +a classic recursive function +\begin{caml_example}{toplevel} + let rec maximal_depth = function + | List _ -> 1 + | Nested [] -> 0 + | Nested (a::q) -> 1 + max (maximal_depth a) (maximal_depth (Nested q));; +\end{caml_example} + +Non-regular recursive algebraic data types correspond to polymorphic algebraic +data types whose parameter types vary between the left and right side of +the type definition. For instance, it might be interesting to define a datatype +that ensures that all lists are nested at the same depth: +\begin{caml_example}{toplevel} + type 'a nested = List of 'a list | Nested of 'a list nested;; +\end{caml_example} +Intuitively, a value of type "'a nested" is a list of list \dots of list of +elements "a" with "k" nested list. We can then adapt the "maximal_depth" +function defined on "regular_depth" into a "depth" function that computes this +"k". As a first try, we may define +\begin{caml_example}{toplevel}[error] +let rec depth = function + | List _ -> 1 + | Nested n -> 1 + depth n;; +\end{caml_example} +The type error here comes from the fact that during the definition of "depth", +the type checker first assigns to "depth" the type "'a -> 'b ". +When typing the pattern matching, "'a -> 'b" becomes "'a nested -> 'b", then +"'a nested -> int" once the "List" branch is typed. +However, when typing the application "depth n" in the "Nested" branch, +the type checker encounters a problem: "depth n" is applied to +"'a list nested", it must therefore have the type +"'a list nested -> 'b". Unifying this constraint with the previous one +leads to the impossible constraint "'a list nested = 'a nested". +In other words, within its definition, the recursive function "depth" is +applied to values of type "'a t" with different types "'a" due to the +non-regularity of the type constructor "nested". This creates a problem because +the type checker had introduced a new type variable "'a" only at the +\emph{definition} of the function "depth" whereas, here, we need a +different type variable for every \emph{application} of the function "depth". + +\subsection{Explicitly polymorphic annotations} +The solution of this conundrum is to use an explicitly polymorphic type +annotation for the type "'a": +\begin{caml_example}{toplevel} +let rec depth: 'a. 'a nested -> int = function + | List _ -> 1 + | Nested n -> 1 + depth n;; +depth ( Nested(List [ [7]; [8] ]) );; +\end{caml_example} +In the type of "depth", "'a.'a nested -> int", the type variable "'a" +is universally quantified. In other words, "'a.'a nested -> int" reads as +``for all type "'a", "depth" maps "'a nested" values to integers''. +Whereas the standard type "'a nested -> int" can be interpreted +as ``let be a type variable "'a", then "depth" maps "'a nested" values +to integers''. There are two major differences with these two type +expressions. First, the explicit polymorphic annotation indicates to the +type checker that it needs to introduce a new type variable every times +the function "depth" is applied. This solves our problem with the definition +of the function "depth". + +Second, it also notifies the type checker that the type of the function should +be polymorphic. Indeed, without explicit polymorphic type annotation, the +following type annotation is perfectly valid +\begin{caml_example}{toplevel} + let sum: 'a -> 'b -> 'c = fun x y -> x + y;; +\end{caml_example} +since "'a","'b" and "'c" denote type variables that may or may not be +polymorphic. Whereas, it is an error to unify an explicitly polymorphic type +with a non-polymorphic type: +\begin{caml_example}{toplevel}[error] + let sum: 'a 'b 'c. 'a -> 'b -> 'c = fun x y -> x + y;; +\end{caml_example} + +An important remark here is that it is not needed to explicit fully +the type of "depth": it is sufficient to add annotations only for the +universally quantified type variables: +\begin{caml_example}{toplevel} +let rec depth: 'a. 'a nested -> _ = function + | List _ -> 1 + | Nested n -> 1 + depth n;; +depth ( Nested(List [ [7]; [8] ]) );; +\end{caml_example} + +%todo: add a paragraph on the interaction with locally abstract type + +\subsection{More examples} +With explicit polymorphic annotations, it becomes possible to implement +any recursive function that depends only on the structure of the nested +lists and not on the type of the elements. For instance, a more complex +example would be to compute the total number of elements of the nested +lists: +\begin{caml_example}{toplevel} + let len nested = + let map_and_sum f = List.fold_left (fun acc x -> acc + f x) 0 in + let rec len: 'a. ('a list -> int ) -> 'a nested -> int = + fun nested_len n -> + match n with + | List l -> nested_len l + | Nested n -> len (map_and_sum nested_len) n + in + len List.length nested;; +len (Nested(Nested(List [ [ [1;2]; [3] ]; [ []; [4]; [5;6;7]]; [[]] ])));; +\end{caml_example} + +Similarly, it may be necessary to use more than one explicitly +polymorphic type variables, like for computing the nested list of +list lengths of the nested list: +\begin{caml_example}{toplevel} +let shape n = + let rec shape: 'a 'b. ('a nested -> int nested) -> + ('b list list -> 'a list) -> 'b nested -> int nested + = fun nest nested_shape -> + function + | List l -> raise + (Invalid_argument "shape requires nested_list of depth greater than 1") + | Nested (List l) -> nest @@ List (nested_shape l) + | Nested n -> + let nested_shape = List.map nested_shape in + let nest x = nest (Nested x) in + shape nest nested_shape n in + shape (fun n -> n ) (fun l -> List.map List.length l ) n;; + +shape (Nested(Nested(List [ [ [1;2]; [3] ]; [ []; [4]; [5;6;7]]; [[]] ])));; +\end{caml_example} + +\section{Higher-rank polymorphic functions} + +Explicit polymorphic annotations are however not sufficient to cover all +the cases where the inferred type of a function is less general than +expected. A similar problem arises when using polymorphic functions as arguments +of higher-order functions. For instance, we may want to compute the average +depth or length of two nested lists: +\begin{caml_example}{toplevel} + let average_depth x y = (depth x + depth y) / 2;; + let average_len x y = (len x + len y) / 2;; + let one = average_len (List [2]) (List [[]]);; +\end{caml_example} +It would be natural to factorize these two definitions as: +\begin{caml_example}{toplevel} + let average f x y = (f x + f y) / 2;; +\end{caml_example} +However, the type of "average len" is less generic than the type of +"average_len", since it requires the type of the first and second argument to +be the same: +\begin{caml_example}{toplevel} + average_len (List [2]) (List [[]]);; + average len (List [2]) (List [[]])[@@expect error];; +\end{caml_example} + +As previously with polymorphic recursion, the problem stems from the fact that +type variables are introduced only at the start of the "let" definitions. When +we compute both "f x" and "f y", the type of "x" and "y" are unified together. +To avoid this unification, we need to indicate to the type checker +that f is polymorphic in its first argument. In some sense, we would want +"average" to have type +\begin{verbatim} +val average: ('a. 'a nested -> int) -> 'a nested -> 'b nested -> int +\end{verbatim} +Note that this syntax is not valid within OCaml: "average" has an universally +quantified type "'a" inside the type of one of its argument whereas for +polymorphic recursion the universally quantified type was introduced before +the rest of the type. This position of the universally quantified type means +that "average" is a second-rank polymorphic function. This kind of higher-rank +functions is not directly supported by OCaml: type inference for second-rank +polymorphic function and beyond is undecidable; therefore using this kind of +higher-rank functions requires to handle manually these universally quantified +types. + +In OCaml, there are two ways to introduce this kind of explicit universally +quantified types: universally quantified record fields, +\begin{caml_example}{toplevel} + type 'a nested_reduction = { f:'elt. 'elt nested -> 'a };; + let boxed_len = { f = len };; +\end{caml_example} +and universally quantified object methods: +\begin{caml_example}{toplevel} + let obj_len = object method f:'a. 'a nested -> 'b = len end;; +\end{caml_example} +To solve our problem, we can therefore use either the record solution: +\begin{caml_example}{toplevel} + let average nsm x y = (nsm.f x + nsm.f y) / 2 ;; +\end{caml_example} +or the object one: +\begin{caml_example}{toplevel} + let average (obj: _ > ) x y = (obj#f x + obj#f y) / 2 ;; +\end{caml_example} diff --git a/manual/styles/altindex.sty b/manual/styles/altindex.sty new file mode 100644 index 00000000..d236e714 --- /dev/null +++ b/manual/styles/altindex.sty @@ -0,0 +1,39 @@ +%% An attempt to have several index files +%% +%% Defines \altindex{filename}{word to index} +%% and \makealtindex{filename} +%% +%% It is possible to define a macro for each index as follows: +%% \newcommand{\myindex}{\altindex{myindexfile}} +%% +%% This code is not really clean, there are still a number of things +%% that I don't understand... but it works. + +%% \makealtindex{filename} opens filename.idx for writing. + +\def\makealtindex#1{\if@filesw + \expandafter\newwrite\csname @#1altindexfile\endcsname + \immediate\openout\expandafter\csname @#1altindexfile\endcsname=#1.idx + \typeout{Writing alternate index file #1.idx}\fi} + +%% \@wraltindex makes the assumes that a trailing `\fi' will get bound +%% to #2. So, it `eats' it as second parameter and reinserts it. +%% Quick and dirty, I know... +%% Writes the index entry #3 into #1. + +\def\@wraltindex#1#2#3{\let\thepage\relax + \xdef\@gtempa{\write#1{\string + \indexentry{#3}{\thepage}}}\fi\endgroup\@gtempa + \if@nobreak \ifvmode\nobreak\fi\fi\@esphack} + +%% \altindex{filename}{index entry} does nothing if +%% \@altindexfile is \relax (i.e. filename.idx not open). +%% Otherwise, writes the index entry, and closes the whole stuff (some +%% groups, and some \if). + +\def\altindex#1{\@bsphack\begingroup + \def\protect##1{\string##1\space}\@sanitize + \@ifundefined{@#1altindexfile}% + {\endgroup\@esphack}% + {\@wraltindex{\expandafter\csname @#1altindexfile\endcsname}} +} diff --git a/manual/styles/caml-sl.sty b/manual/styles/caml-sl.sty new file mode 100644 index 00000000..6bcfefe8 --- /dev/null +++ b/manual/styles/caml-sl.sty @@ -0,0 +1,61 @@ +% CAML style option, for use with the caml-latex filter. + +\typeout{Document Style option `caml-sl' <7 Apr 92>.} +\newcommand{\hash}{\#} +{\catcode`\^^M=\active % + \gdef\@camlinputline#1^^M{\normalsize\tt\hash{} #1\par} % + \gdef\@camloutputline#1^^M{\small\ttfamily\slshape#1\par} } % +\def\@camlblankline{\medskip} +\chardef\@camlbackslash="5C +\def\@bunderline{\setbox0\hbox\bgroup\let\par\@parinunderline} + +\def \@parinunderline {\futurelet \@next \@@parinunderline} +\def \@@parinunderline {\ifx \@next \? \let \@do \@@par@inunderline \else \let \@do \@@@parinunderline \fi \@do} +\def \@@par@inunderline #1{\@eunderline\@oldpar\?\@bunderline} +\def \@@@parinunderline {\@eunderline\@oldpar\@bunderline} +\def\@eunderline{\egroup\underline{\box0}} +\def\@camlnoop{} + +\def\caml{ + \bgroup + \parindent 0pt + \parskip 0pt + \let\do\@makeother\dospecials + \catcode13=\active % 13 = ^M = CR + \catcode92=0 % 92 = \ + \catcode32=\active % 32 = SPC + \frenchspacing + \@vobeyspaces + \let\@oldpar\par + \let\?\@camlinputline + \let\:\@camloutputline + \let\;\@camlblankline + \let\<\@bunderline + \let\>\@eunderline + \let\\\@camlbackslash + \let\-\@camlnoop +} + +\def\endcaml{ + \egroup + \addvspace{\medskipamount} +} + +% Caml-example related command +\def\camlexample#1{ + \ifnum\pdfstrcmp{#1}{toplevel}=0 + \renewcommand{\hash}{\#} + \else + \renewcommand{\hash}{} + \fi + \begin{flushleft} +} +\def\endcamlexample{\end{flushleft}\renewcommand{\hash}{\#}} +\def\camlinput{} +\def\endcamlinput{} +\def\camloutput{} +\def\endcamloutput{} +\def\camlerror{} +\def\endcamlerror{} +\def\camlwarn{} +\def\endcamlwarn{} diff --git a/manual/styles/caml.sty b/manual/styles/caml.sty new file mode 100644 index 00000000..3f5753ca --- /dev/null +++ b/manual/styles/caml.sty @@ -0,0 +1,31 @@ +% CAML style option, for use with the caml-latex filter. + +\typeout{Document Style option `caml' <7 Apr 92>.} + +{\catcode`\^^M=\active % + \gdef\@camlinputline#1^^M{\tt\##1\par} % + \gdef\@camloutputline#1^^M{\tt#1\par} } % +\def\@camlblankline{\medskip} +\chardef\@camlbackslash="5C + +\def\caml{ + \bgroup + \flushleft + \parindent 0pt + \parskip 0pt + \let\do\@makeother\dospecials + \catcode`\^^M=\active + \catcode`\\=0 + \catcode`\ \active + \frenchspacing + \@vobeyspaces + \let\?\@camlinputline + \let\:\@camloutputline + \let\;\@camlblankline + \let\\\@camlbackslash +} + +\def\endcaml{ + \endflushleft + \egroup\noindent +} diff --git a/manual/styles/doc.tfm b/manual/styles/doc.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/docbf.tfm b/manual/styles/docbf.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/docit.tfm b/manual/styles/docit.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/docmi.tfm b/manual/styles/docmi.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/docrm.tfm b/manual/styles/docrm.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/doctt.tfm b/manual/styles/doctt.tfm new file mode 100644 index 0000000000000000000000000000000000000000..d010f29eddf7b88418cd59ffefac0d790ae182ea GIT binary patch literal 772 zcmb7?ze)o^5XQgF!MVvnJc5mKK7gI&1#Ltlq>+Pg2x5`iE?Q_In8LWQ+CIgmAb--sDrtDil2?}5N| z=0m8HZW2?XzT^|%e;Sd0jW{M2M7v6j^!}_fdbD3wEuBx^!peCq8f9quyFQDD``Dkr z9wu3zrs5=*)PJAfr5}KYp1ZQD?n5~H*Kor=+>>{>{Uhjj6?)?Zx^)5Fn}B|5Ko2L8 zFP4$-1Squ5;ROxuH=mDpW_WgMOle?@`2wh4#Wf;^+MR{!Od}V*!U?wE9G1DKSx1o= S=h)uE-`=sYJ)7=Dcl!ny2aYrV literal 0 HcmV?d00001 diff --git a/manual/styles/fullpage.sty b/manual/styles/fullpage.sty new file mode 100644 index 00000000..6ecbeb76 --- /dev/null +++ b/manual/styles/fullpage.sty @@ -0,0 +1,2 @@ +\marginparwidth 0pt \oddsidemargin 0pt \evensidemargin 0pt \marginparsep 0pt +\topmargin 0pt \textwidth 6.5in \textheight 8.5 in diff --git a/manual/styles/html.sty b/manual/styles/html.sty new file mode 100644 index 00000000..6a9e9253 --- /dev/null +++ b/manual/styles/html.sty @@ -0,0 +1,222 @@ +% LaTeX2HTML Version 0.6.4 : html.sty +% +% This file contains definitions of LaTeX commands which are +% processed in a special way by the translator. +% For example, there are commands for embedding external hypertext links, +% for cross-references between documents or for including +% raw HTML. +% This file includes the comments.sty file v2.0 by Victor Eijkhout +% In most cases these commands do nothing when processed by LaTeX. + +% Modifications: +% +% nd = Nikos Drakos +% jz = Jelle van Zeijl + +% jz 22-APR-94 - Added support for htmlref +% nd - Created + + + +% Exit if the style file is already loaded +% (suggested by Lee Shombert +\ifx \htmlstyloaded\relax \endinput\else\let\htmlstyloaded\relax\fi + +%%% LINKS TO EXTERNAL DOCUMENTS +% +% This can be used to provide links to arbitrary documents. +% The first argumment should be the text that is going to be +% highlighted and the second argument a URL. +% The hyperlink will appear as a hyperlink in the HTML +% document and as a footnote in the dvi or ps files. +% +\newcommand{\htmladdnormallinkfoot}[2]{ #1\footnote{#2}} + +% This is an alternative definition of the command above which +% will ignore the URL in the dvi or ps files. +\newcommand{\htmladdnormallink}[2]{ #1 } + +% This command takes as argument a URL pointing to an image. +% The image will be embedded in the HTML document but will +% be ignored in the dvi and ps files. +% +\newcommand{\htmladdimg}[1]{ } + +%%% CROSS-REFERENCES BETWEEN (LOCAL OR REMOTE) DOCUMENTS +% +% This can be used to refer to symbolic labels in other Latex +% documents that have already been processed by the translator. +% The arguments should be: +% #1 : the URL to the directory containing the external document +% #2 : the path to the labels.pl file of the external document. +% If the external document lives on a remote machine then labels.pl +% must be copied on the local machine. +% +%e.g. \externallabels{http://cbl.leeds.ac.uk/nikos/WWW/doc/tex2html/latex2html} +% {/usr/cblelca/nikos/tmp/labels.pl} +% The arguments are ignored in the dvi and ps files. +% +\newcommand{\externallabels}[2]{ } + +% This complements the \externallabels command above. The argument +% should be a label defined in another latex document and will be +% ignored in the dvi and ps files. +% +\newcommand{\externalref}[1]{ } + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Comment.sty version 2.0, 19 June 1992 +% selectively in/exclude pieces of text: the user can define new +% comment versions, and each is controlled separately. +% This style can be used with plain TeX or LaTeX, and probably +% most other packages too. +% +% Examples of use in LaTeX and TeX follow \endinput +% +% Author +% Victor Eijkhout +% Department of Computer Science +% University Tennessee at Knoxville +% 104 Ayres Hall +% Knoxville, TN 37996 +% USA +% +% eijkhout@cs.utk.edu +% +% Usage: all text included in between +% \comment ... \endcomment +% or \begin{comment} ... \end{comment} +% is discarded. The closing command should appear on a line +% of its own. No starting spaces, nothing after it. +% This environment should work with arbitrary amounts +% of comment. +% +% Other 'comment' environments are defined by +% and are selected/deselected with +% \includecomment{versiona} +% \excludecoment{versionb} +% +% These environments are used as +% \versiona ... \endversiona +% or \begin{versiona} ... \end{versiona} +% with the closing command again on a line of its own. +% +% Basic approach: +% to comment something out, scoop up every line in verbatim mode +% as macro argument, then throw it away. +% For inclusions, both the opening and closing comands +% are defined as noop +% +% Changed \next to \html@next to prevent clashes with other sty files +% (mike@emn.fr) +% Changed \html@next to \htmlnext so the \makeatletter and +% \makeatother commands could be removed (they were cuasing other +% style files - changebar.sty - to crash) (nikos@cbl.leeds.ac.uk) + + +\def\makeinnocent#1{\catcode`#1=12 } +\def\csarg#1#2{\expandafter#1\csname#2\endcsname} + +\def\ThrowAwayComment#1{\begingroup + \def\CurrentComment{#1}% + \let\do\makeinnocent \dospecials + \makeinnocent\^^L% and whatever other special cases + \endlinechar`\^^M \catcode`\^^M=12 \xComment} +{\catcode`\^^M=12 \endlinechar=-1 % + \gdef\xComment#1^^M{\def\test{#1} + \csarg\ifx{PlainEnd\CurrentComment Test}\test + \let\htmlnext\endgroup + \else \csarg\ifx{LaLaEnd\CurrentComment Test}\test + \edef\htmlnext{\endgroup\noexpand\end{\CurrentComment}} + \else \let\htmlnext\xComment + \fi \fi \htmlnext} +} + +\def\includecomment + #1{\expandafter\def\csname#1\endcsname{}% + \expandafter\def\csname end#1\endcsname{}} +\def\excludecomment + #1{\expandafter\def\csname#1\endcsname{\ThrowAwayComment{#1}}% + {\escapechar=-1\relax + \csarg\xdef{PlainEnd#1Test}{\string\\end#1}% + \csarg\xdef{LaLaEnd#1Test}{\string\\end\string\{#1\string\}}% + }} + +\excludecomment{comment} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% RAW HTML +% +% Enclose raw HTML between a \begin{rawhtml} and \end{rawhtml}. +% The html environment ignores its body +% +\excludecomment{rawhtml} + +%%% HTML ONLY +% +% Enclose LaTeX constructs which will only appear in the +% HTML output and will be ignored by LaTeX with +% \begin{htmlonly} and \end{htmlonly} +% +\excludecomment{htmlonly} + +%%% LaTeX ONLY +% Enclose LaTeX constructs which will only appear in the +% DVI output and will be ignored by latex2html with +%\begin{latexonly} and \end{latexonly} +% +\newenvironment{latexonly}{}{} + +%%% HYPERREF +% Suggested by Eric M. Carol +% Similar to \ref but accepts conditional text. +% The first argument is HTML text which will become ``hyperized'' +% (underlined). +% The second and third arguments are text which will appear only in the paper +% version (DVI file), enclosing the fourth argument which is a reference to a label. +% +%e.g. \hyperref{using the tracer}{using the tracer (see Section}{)}{trace} +% where there is a corresponding \label{trace} +% +\newcommand{\hyperref}[4]{#2\ref{#4}#3} + +%%% HTMLREF +% Reference in HTML version only. +% Mix between \htmladdnormallink and \hyperref. +% First arg is text for in both versions, second is label for use in HTML +% version. +\newcommand{\htmlref}[2]{#1} + +%%% HTMLIMAGE +% This command can be used inside any environment that is converted +% into an inlined image (eg a "figure" environment) in order to change +% the way the image will be translated. The argument of \htmlimage +% is really a string of options separated by commas ie +% [scale=],[external],[thumbnail= +% The scale option allows control over the size of the final image. +% The ``external'' option will cause the image not to be inlined +% (images are inlined by default). External images will be accessible +% via a hypertext link. +% The ``thumbnail'' option will cause a small inlined image to be +% placed in the caption. The size of the thumbnail depends on the +% reduction factor. The use of the ``thumbnail'' option implies +% the ``external'' option. +% +% Example: +% \htmlimage{scale=1.5,external,thumbnail=0.2} +% will cause a small thumbnail image 1/5th of the original size to be +% placed in the final document, pointing to an external image 1.5 +% times bigger than the original. +% +\newcommand{\htmlimage}[1]{} + +%%% HTMLADDTONAVIGATION +% This command appends its argument to the buttons in the navigation +% panel. It is ignored by LaTeX. +% +% Example: +% \htmladdtonavigation{\htmladdnormallink +% {\htmladdimg{http://server/path/to/gif}} +% {http://server/path}} +\newcommand{\htmladdtonavigation}[1]{} diff --git a/manual/styles/isolatin.sty b/manual/styles/isolatin.sty new file mode 100644 index 00000000..9a685097 --- /dev/null +++ b/manual/styles/isolatin.sty @@ -0,0 +1,174 @@ +% 1-Jun-1992 +% +% File bases on iso1ibm.tex Version 1.0 of May, 9 1990 +\message{ISO-latin-1 input coding, version 0.9 of 1-Jun-1992.} +% +% For input of 8 bits character. +% This allows reading ISO-8859 Latin-1 codes. +% +\chardef \atcode = \the \catcode `\@ +\catcode `\@ = 11 +% +\catcode160=13 \def^^a0{{\bf?}} % 160 '240, "a0 +\catcode161=13 \def^^a1{!`} % 161 '241, "a1 +\catcode162=13 \def^^a2{{\bf?}} % 162 '242, "a2 +\catcode163=13 \def^^a3{\pounds{}} % 163 '243, "a3 +\catcode164=13 \def^^a4{{\bf?}} % 164 '244, "a4 +\catcode165=13 \def^^a5{{\bf?}} % 165 '245, "a5 +\catcode166=13 \def^^a6{$\vert$} % 166 '246, "a6 +\catcode167=13 \def^^a7{\S{}} % 167 '247, "a7 \S{} ISO-1, +\catcode168=13 \def^^a8{\"{ }} % 168 '250, "a8 +\catcode169=13 \def^^a9{\copyright{}}% 169, '251, "a9 +\catcode170=13 \def^^aa{{\bf?}} % 170 '252, "aa +\catcode171=13 % 171 '253, "ab, +\@ifundefined{lguill}{\def^^ab{$<<$}}{\def^^ab{\lguill}} +\catcode172=13 \def^^ac{{\bf?}} % 172 '254, "ac +\catcode173=13 \def^^ad{{\bf?}} % 173 '255 "ad +\catcode174=13 \def^^ae{{\bf?}} % 174 '256, "ae +\catcode175=13 \def^^af{{\bf?}} % 175 '257, "af +\catcode176=13 \def^^b0{{\bf?}} % 176 '260, "b0 ?? \No +\catcode177=13 \def^^b1{$\pm$} % 177 '261, "b1 ISO-1 plus-minus +\catcode178=13 \def^^b2{${}^2$} % 178, '262, "b2 +\catcode179=13 \def^^b3{${}^3$} % 179, '263, "b3 +\catcode180=13 \def^^b4{\'{ }} % 180, '264, "b4 +\catcode181=13 \def^^b5{{\bf?}} % 181, '265, "b5 +\catcode182=13 \def^^b6{\P{}} % 182, '266, "b6 +\catcode183=13 \def^^b7{$\cdot$} % 183, '267, "b7 +\catcode184=13 \def^^b8{\c{ }} % 184, '270, "b8 +\catcode185=13 \def^^b9{${}^1$} % 185, '271, "b9 +\catcode186=13 \def^^ba{{\bf?}} % 186, '272, "ba +\catcode187=13 % 187, '273, "bb +\@ifundefined{rguill}{\def^^bb{$>>$}}{\def^^bb{\rguill}} +\catcode188=13 \def^^bc{$\frac 1 4$} % 188, '274, "bc +\catcode189=13 \def^^bd{$\frac 1 2$} % 189, '275, "bd +\catcode190=13 \def^^be{$\frac 3 4$} % 190, '276, "be +\catcode191=13 \def^^bf{?`} % 191, '277, "bf +\catcode192=13 \def^^c0{\`A} % 192, '300, "c0 +\@ifundefined{@grave@A@grave@}{\def^^c0{\`A}}{\let^^c0=\@grave@A@grave@} +\catcode193=13 \def^^c1{\'A} % 193, '301, "c1 +\@ifundefined{@acute@A@acute@}{\def^^c1{\'A}}{\let^^c1=\@acute@A@acute@} +\catcode194=13 \def^^c2{\^A} % 194, '302, "c2 +\@ifundefined{@circflx@A@circflx@}{\def^^c2{\^A}}{\let^^c2=\@circflx@A@circflx@} +\catcode195=13 \def^^c3{\~A} % 195, '303, "c3 +\@ifundefined{@tileda@A@tilda@}{\def^^c3{\~A}}{\let^^c3=\@tileda@A@tilda@} +\catcode196=13 \def^^c4{\"A} % 196, '304, "c4 +\@ifundefined{@Umlaut@A@Umlaut@}{\def^^c4{\"A}}{\let^^c4=\@Umlaut@A@Umlaut@} +\catcode197=13 \def^^c5{\AA{}} % 197, '305, "c5 +\@ifundefined{@A@A@}{\def^^c5{\AA{}}}{\let^^c5=\@A@A@} +\catcode198=13 \def^^c6{\AE{}} % 198, '306, "c6 +\@ifundefined{@A@E@}{\def^^c6{\AE{}}}{\let^^c6=\@A@E@} +\catcode199=13 \def^^c7{\c{C}} % 199, '307, "c7 +\@ifundefined{@cedilla@C@cedilla}{\def^^c7{\c{C}}}{\let^^c7=\@cedilla@C@cedilla} +\catcode200=13 \def^^c8{\`E} % 200, '310, "c8 +\@ifundefined{@grave@E@grave@}{\def^^c8{\`E}}{\let^^c8=\@grave@E@grave@} +\catcode201=13 \def^^c9{\'E} % 201, '311, "c9 +\@ifundefined{@acute@E@acute@}{\def^^c9{\'E}}{\let^^c9=\@acute@E@acute@} +\catcode202=13 \def^^ca{\^E} % 202, '312, "ca +\@ifundefined{@circflx@E@circflx@}{\def^^ca{\^E}}{\let^^ca=\@circflx@E@circflx@} +\catcode203=13 \def^^cb{{\"E}} % 203, '313, "cb +\@ifundefined{@Umlaut@E@Umlaut@}{\def^^cb{\"E}}{\let^^cb=\@Umlaut@E@Umlaut@} +\catcode204=13 \def^^cc{\`I} % 204, '314, "cc +\@ifundefined{@grave@I@grave@}{\def^^cc{\`I}}{\let^^cc=\@grave@I@grave@} +\catcode205=13 \def^^cd{\'I} % 205, '315, "cd +\@ifundefined{@acute@I@acute@}{\def^^cd{\'I}}{\let^^cd=\@acute@I@acute@} +\catcode206=13 \def^^ce{\^I} % 206, '316, "ce +\@ifundefined{@circflx@I@circflx@}{\def^^ce{\^I}}{\let^^ce=\@circflx@I@circflx@} +\catcode207=13 \def^^cf{{\"I}} % 207, '317, "cf +\@ifundefined{@Umlaut@I@Umlaut@}{\def^^cf{\"I}}{\let^^cf=\@Umlaut@I@Umlaut@} +\catcode208=13 \def^^d0{\rlap{\raise0.3ex\hbox{--}}D} % 208, '320, "d0 +\@ifundefined{@Eth@}{}{\let^^d0=\@Eth@} +\catcode209=13 \def^^d1{¥} % 209, '321, "d1 +\@ifundefined{@tileda@N@tilda@}{\def^^d1{\~N}}{\let^^d1\@tileda@N@tilda@} +\catcode210=13 \def^^d2{\`O} % 210, '322, "d2 +\@ifundefined{@grave@O@grave@}{\def^^d2{\`O}}{\let^^d2=\@grave@O@grave@} +\catcode211=13 \def^^d3{\'O} % 211, '323, "d3 +\@ifundefined{@acute@O@acute@}{\def^^d3{\'O}}{\let^^d3\@acute@O@acute@} +\catcode212=13 \def^^d4{\^O} % 212, '324, "d4 +\@ifundefined{@circflx@O@circflx@}{\def^^d4{\^O}}{\let^^d4=\@circflx@O@circflx@} +\catcode213=13 \def^^d5{\~O} % 213, '325, "d5 +\@ifundefined{@tileda@O@tilda@}{\def^^d5{\~O}}{\let^^d5\@tileda@O@tilda@} +\catcode214=13 \def^^d6{\"O} % 214, '326, "d6 +\@ifundefined{@Umlaut@O@Umlaut@}{\def^^d6{\"O}}{\let^^d6=\@Umlaut@O@Umlaut@} +\catcode215=13 \def^^d7{$\times$}% 215, '327, "d7 +\catcode216=13 \def^^d8{\O{}} % 216, '330, "d8 +\@ifundefined{@OOO@}{\def^^d8{\O{}}}{\let^^d8=\@OOO@} +\catcode217=13 \def^^d9{\`U} % 217, '331, "d9 +\@ifundefined{@grave@U@grave@}{\def^^d9{\`U}}{\let^^d9=\@grave@U@grave@} +\catcode218=13 \def^^da{\'U} % 218, '332, "da +\@ifundefined{@acute@U@acute@}{\def^^da{\'U}}{\let^^da=\@acute@U@acute@} +\catcode219=13 \def^^db{\^U} % 219, '333, "db +\@ifundefined{@circflx@U@circflx@}{\def^^db{\^U}}{\let^^db=\@circflx@U@circflx@} +\catcode220=13 \def^^dc{\"U} % 220, '334, "dc +\@ifundefined{@Umlaut@U@Umlaut@}{\def^^dc{\"U}}{\let^^dc=\@Umlaut@U@Umlaut@} +\catcode221=13 \def^^dd{{\'Y}} % 221, '335, "dd +\@ifundefined{@acute@Y@acute@}{\def^^dd{\'Y}}{\let^^dd=\@acute@Y@acute@} +\catcode222=13 \def^^de{\lower 0.7ex \hbox{l}\hskip-1ex\relax b} % 222, '336, "de +\@ifundefined{@Thorn@}{}{\let^^de=\@Thorn@} +\catcode223=13 \def^^df{\ss{}} % 223, '337, "df +\@ifundefined{@sss@}{\def^^df{\ss{}}}{\let^^df=\@sss@} +\catcode224=13 \def^^e0{\`a} % 224, '340, "e0 +\@ifundefined{@grave@a@grave@}{\def^^e0{\`a}}{\let^^e0=\@grave@a@grave@} +\catcode225=13 \def^^e1{\'a} % 225, '341, "e1 +\@ifundefined{@acute@a@acute@}{\def^^e1{\'a}}{\let^^e1=\@acute@a@acute@} +\catcode226=13 \def^^e2{\^a} % 226, '342, "e2 +\@ifundefined{@circflx@a@circflx@}{\def^^e2{\^a}}{\let^^e2=\@circflx@a@circflx@} +\catcode227=13 \def^^e3{\~a} % 227, '343, "e3 +\@ifundefined{@tileda@a@tilda@}{\def^^e3{\~a}}{\let^^e3=\@tileda@a@tilda@} +\catcode228=13 \def^^e4{\"a} % 228, '344, "e4 +\@ifundefined{@Umlaut@a@Umlaut@}{\def^^e4{\"a}}{\let^^e4=\@Umlaut@a@Umlaut@} +\catcode229=13 \def^^e5{\aa{}} % 229, '345, "e5 +\@ifundefined{@a@a@}{\def^^e5{\aa{}}}{\let^^e5=\@a@a@} +\catcode230=13 \def^^e6{\ae{}} % 230, '346, "e6 +\@ifundefined{@a@e@}{\def^^e6{\ae{}}}{\let^^e6=\@a@e@} +\catcode231=13 \def^^e7{\c{c}} % 231, '347, "e7 +\@ifundefined{@cedilla@c@cedilla}{\def^^e7{\c{c}}}{\let^^e7=\@cedilla@c@cedilla} +\catcode232=13 \def^^e8{\`e} % 232, '350, "e8 +\@ifundefined{@grave@e@grave@}{\def^^e8{\`e}}{\let^^e8=\@grave@e@grave@} +\catcode233=13 \def^^e9{\'e} % 233, '351, "e9 +\@ifundefined{@acute@e@acute@}{\def^^e9{\'e}}{\let^^e9=\@acute@e@acute@} +\catcode234=13 \def^^ea{\^e} % 234, '352, "ea +\@ifundefined{@circflx@e@circflx@}{\def^^ea{\^e}}{\let^^ea=\@circflx@e@circflx@} +\catcode235=13 \def^^eb{\"e} % 235, '353, "eb +\@ifundefined{@Umlaut@e@Umlaut@}{\def^^eb{\"e}}{\let^^eb=\@Umlaut@e@Umlaut@} +\catcode236=13 \def^^ec{\`{\i}} % 236, '354, "ec +\@ifundefined{@grave@i@grave@}{\def^^ec{\`{\i}}}{\let^^ec=\@grave@i@grave@} +\catcode237=13 \def^^ed{\'{\i}} % 237, '355, "ed +\@ifundefined{@acute@i@acute@}{\def^^ed{\'{\i}}}{\let^^ed=\@acute@i@acute@} +\catcode238=13 \def^^ee{\^{\i}} % 238, '356, "ee +\@ifundefined{@circflx@i@circflx@}{\def^^ee{\^{\i}}}{\let^^ee=\@circflx@i@circflx@} +\catcode239=13 \def^^ef{\"{\i}} % 239, '357, "ef +\@ifundefined{@Umlaut@i@Umlaut@}{\def^^ef{\"{\i}}}{\let^^ef=\@Umlaut@i@Umlaut@} +\catcode240=13 \def^^f0{$\partial$} % 240, '360, "f0 +\@ifundefined{@eth@}{\def^^f0{$\partial$}}{\let^^f0=\@eth@} +\catcode241=13 \def^^f1{\~n} % 241, '361, "f1 +\@ifundefined{@tileda@n@tilda@}{\def^^f1{\~n}}{\let^^f1\@tileda@n@tilda@} +\catcode242=13 \def^^f2{\`o} % 242, '362, "f2 +\@ifundefined{@grave@o@grave@}{\def^^f2{\`o}}{\let^^f2=\@grave@o@grave@} +\catcode243=13 \def^^f3{\'o} % 243, '363, "f3 +\@ifundefined{@acute@o@acute@}{\def^^f3{\'o}}{\let^^f3\@acute@o@acute@} +\catcode244=13 \def^^f4{\^o} % 244, '364, "f4 +\@ifundefined{@circflx@o@circflx@}{\def^^f4{\^o}}{\let^^f4=\@circflx@o@circflx@} +\catcode245=13 \def^^f5{\~o} % 245, '365, "f5 +\@ifundefined{@tileda@o@tilda@}{\def^^f5{\~o}}{\let^^f5\@tileda@o@tilda@} +\catcode246=13 \def^^f6{\"o} % 246, '366, "f6 +\@ifundefined{@Umlaut@o@Umlaut@}{\def^^f6{\"o}}{\let^^f6=\@Umlaut@o@Umlaut@} +\catcode247=13 \def^^f7{$\div$} % 247, '367, "f7 +\catcode248=13 \def^^f8{\o{}} % 248, '370, "f8 +\@ifundefined{@ooo@}{\def^^f8{\o{}}}{\let^^f8=\@ooo@} +\catcode249=13 \def^^f9{\`u} % 249, '371, "f9 +\@ifundefined{@grave@u@grave@}{\def^^f9{\`u}}{\let^^f9=\@grave@u@grave@} +\catcode250=13 \def^^fa{\'u} % 250, '372, "fa +\@ifundefined{@acute@u@acute@}{\def^^fa{\'u}}{\let^^fa=\@acute@u@acute@} +\catcode251=13 \def^^fb{\^u} % 251, '373, "fb +\@ifundefined{@circflx@u@circflx@}{\def^^fb{\^u}}{\let^^fb=\@circflx@u@circflx@} +\catcode252=13 \def^^fc{\"u} % 252, '374, "fc +\@ifundefined{@Umlaut@u@Umlaut@}{\def^^fc{\"u}}{\let^^fc=\@Umlaut@u@Umlaut@} +\catcode253=13 \def^^fd{\'y} % 253, '375, "fd +\@ifundefined{@acute@y@acute@}{\def^^fd{\'y}}{\let^^fd=\@acute@y@acute@} +\catcode254=13 \def^^fe{\lower 0.8ex\hbox{l}\hskip-1ex\relax b} % 254, '376, "fe +\@ifundefined{@thorn@}{}{\let^^fe=\@thorn@} +\catcode255=13 \def^^ff{\"y} % 255, '377, "ff +\@ifundefined{@Umlaut@y@Umlaut@}{\def^^ff{\"y}}{\let^^ff=\@Umlaut@y@Umlaut@} +\catcode `\@ = \the \atcode +\endinput +% End of iso-latin-1.tex diff --git a/manual/styles/multicols.sty b/manual/styles/multicols.sty new file mode 100644 index 00000000..2d945488 --- /dev/null +++ b/manual/styles/multicols.sty @@ -0,0 +1,176 @@ +% Save file as: MULTICOLS.STY Source: FILESERV@SHSU.BITNET +% multicols.sty version 1.0 +% Allows for multiple column typesetting +% From TUGboat, voulme 10 (1989), No. 3 +% +% Frank Mittelback +% Electronic Data Systems +% (Deutschland) GmbH +% Eisenstrasse 56 +% D-6090 Russelsheim +% Federal Republic of Germany +% Bitnet: pzf5hz@drueds2 +% +% Variables: +% \premulticols - If the space left on the page is less than this, a new +% page is started before the multiple columns. Otherwise, a \vskip +% of \multicolsep is added. +% \postmulticols - analogous to \premulticols +% \columnseprule - the width of the rule separating the columns. +% +% Commands: +% \raggedcolumns - don't align bottom lines of columns +% \flushcolumns - align bottom lines (default) +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\@ifundefined{mult@cols}{}{\endinput} + +\def\multicols#1{\col@number#1\relax + \ifnum\col@number<\@ne + \@warning{Using '\number\col@number' columns doesn't seem a good idea.^^J + I therefore use two columns instead}% + \col@number\tw@ \fi + \@ifnextchar[\mult@cols{\mult@cols[]}} + +\def\mult@cols[#1]{\@ifnextchar[% + {\mult@@cols{#1}}% + {\mult@@cols{#1}[\premulticols]}} + +\def\mult@@cols#1[#2]{% + \enough@room#2% + #1\par\addvspace\multicolsep + \begingroup + \prepare@multicols\ignorespaces} + +\def\enough@room#1{\par \penalty\z@ + \page@free \pagegoal + \advance \page@free -\pagetotal + \ifdim \page@free <#1\newpage \fi} + +\def\prepare@multicols{% + \output{\global\setbox\partial@page + \vbox{\unvbox\@cclv}}\eject + \vbadness9999 \hbadness5000 + \tolerance\multicoltolerance + \doublecol@number\col@number + \multiply\doublecol@number\tw@ + \advance\baselineskip\multicolbaselineskip + \advance\@colroom-\ht\partial@page + \vsize\col@number\@colroom + \advance\vsize\c@collectmore\baselineskip + \hsize\columnwidth \advance\hsize\columnsep + \advance\hsize-\col@number\columnsep + \divide\hsize\col@number + \linewidth\hsize + \output{\multi@columnout}% + \multiply\count\footins\col@number + \multiply\skip \footins\col@number + \reinsert@footnotes} + +\def\endmulticols{\par\penalty\z@ + \output{\balance@columns}\eject + \endgroup \reinsert@footnotes + \global\c@unbalance\z@ + \enough@room\postmulticols + \addvspace\multicolsep} + +\newcount\c@unbalance \c@unbalance = 0 +\newcount\c@collectmore \c@collectmore = 0 +\newcount\col@number +\newcount\doublecol@number +\newcount\multicoltolerance \multicoltolerance = 9999 +\newdimen\page@free +\newdimen\premulticols \premulticols = 50pt +\newdimen\postmulticols \postmulticols = 20pt +\newskip\multicolsep \multicolsep = 12pt plus 4pt minus 3pt +\newskip\multicolbaselineskip \multicolbaselineskip=0pt +\newbox\partial@page + +\def\process@cols#1#2{\count@#1\relax + \loop #2% + \advance\count@\tw@ + \ifnum\count@<\doublecol@number + \repeat} + +\def\page@sofar{\unvbox\partial@page + \process@cols\z@{\wd\count@\hsize}% + \hbox to\textwidth{% + \process@cols\tw@{\box\count@ + \hss\vrule\@width\columnseprule\hss}% + \box\z@}} + +\def\reinsert@footnotes{\ifvoid\footins\else + \insert\footins{\unvbox\footins}\fi} + +\def\multi@columnout{% + \ifnum\outputpenalty <-\@Mi + \speci@ls \else + \splittopskip\topskip + \splitmaxdepth\maxdepth + \dimen@\@colroom + \divide\skip\footins\col@number + \ifvoid\footins \else + \advance\dimen@-\skip\footins + \advance\dimen@-\ht\footins \fi + \process@cols\tw@{\setbox\count@ + \vsplit\@cclv to\dimen@}% + \setbox\z@\vsplit\@cclv to\dimen@ + \ifvoid\@cclv \else + \unvbox\@cclv + \penalty\outputpenalty + \fi + \setbox\@cclv\vbox{\page@sofar}% + \@makecol\@outputpage + \global\@colroom\@colht + \process@deferreds + \global\vsize\col@number\@colroom + \global\advance\vsize + \c@collectmore\baselineskip + \multiply\skip\footins\col@number\fi} + +\def\speci@ls{% + \typeout{floats and marginpars not allowed inside `multicols' environment}% + \unvbox\@cclv\reinsert@footnotes + \gdef\@currlist{}} + +\def\process@deferreds{% + \@floatplacement + \begingroup + \let\@tempb\@deferlist + \gdef\@deferlist{}% + \let\@elt\@scolelt + \@tempb \endgroup} + +\newif\ifshr@nking + +\def\raggedcolumns{% + \@bsphack\shr@nkingtrue\@esphack} +\def\flushcolumns{% + \@bsphack\shr@nkingfale\@esphack} + +\def\balance@columns{% + \splittopskip\topskip + \splitmaxdepth\maxdepth + \setbox\z@\vbox{\unvbox\@cclv}\dimen@\ht\z@ + \advance\dimen@\col@number\topskip + \advance\dimen@-\col@number\baselineskip + \divide\dimen@\col@number + \advance\dimen@\c@unbalance\baselineskip + {\vbadness\@M \loop + {\process@cols\@ne{\global\setbox\count@\box\voidb@x}}% + \global\setbox\@ne\copy\z@ + {\process@cols\thr@@{\global\setbox\count@\vsplit\@ne to\dimen@}}% + \ifshr@nking \global\setbox\thr@@\vbox{\unvbox\thr@@}% + \fi + \ifdim\ht\@ne >\ht\thr@@ + \global\advance\dimen@\p@ + \repeat}% + \dimen@\ht\thr@@ + \process@cols\z@{\@tempcnta\count@ + \advance\@tempcnta\@ne + \setbox\count@\vtop to\dimen@ + {\unvbox\@tempcnta + \ifshr@nking\vfill\fi}}% + \global\vsize\@colroom + \global\advance\vsize\ht\partial@page + \page@sofar} diff --git a/manual/styles/multind.sty b/manual/styles/multind.sty new file mode 100644 index 00000000..ef91c28d --- /dev/null +++ b/manual/styles/multind.sty @@ -0,0 +1,65 @@ +% indexes document style option for producing multiple indexes +% for use with the modified bbok style, CHbook.sty +% Written by F.W. Long, Version 1.1, 12 August 1991. + +% Modified by F.W. Long, Version 1.1a, 29 August 1991 +% to get the index heading correctly spaced. + +% Modified by F.W. Long, Version 1.1b, 31 August 1991 +% to remove the abbreviation \ix (which should be in the document, not here). + +% Modified \makeindex and \index commands to allow multiple indexes +% in both cases the first parameter is the index name. +% They now work more like \@starttoc and \addcontentsline. +% \index is no longer defined inside \makeindex but determines +% whether the appropriate file is defined before writing to it. + +\def\makeindex#1{\begingroup + \makeatletter + \if@filesw \expandafter\newwrite\csname #1@idxfile\endcsname + \expandafter\immediate\openout \csname #1@idxfile\endcsname #1.idx\relax + \typeout{Writing index file #1.idx }\fi \endgroup} + +\def\index#1{\@bsphack\begingroup + \def\protect##1{\string##1\space}\@sanitize + \@wrindex{#1}} + +% \@wrindex now checks that the appropriate file is defined. + +\def\@wrindex#1#2{\let\thepage\relax + \xdef\@gtempa{\@ifundefined{#1@idxfile}{}{\expandafter + \write\csname #1@idxfile\endcsname{\string + \indexentry{#2}{\thepage}}}}\endgroup\@gtempa + \if@nobreak \ifvmode\nobreak\fi\fi\@esphack} + +% Modified \printindex command to allow multiple indexes. +% This now takes over much of the work of \theindex. +% Again, the first parameter is the index name. +% The second parameter is the index title (as printed). + +\newif\if@restonecol +\def\printindex#1#2{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi + \columnseprule \z@ \columnsep 35pt + \newpage \twocolumn[{\Large\bf #2 \vskip4ex}] + \markright{\uppercase{#2}} + \addcontentsline{toc}{section}{#2} + \@input{#1.ind}} + +% The following index commands are taken from book.sty. +% \theindex is modified to not start a chapter. + +\def\theindex{\parindent\z@ + \parskip\z@ plus .3pt\relax\let\item\@idxitem} +\def\@idxitem{\par\hangindent 40pt} +\def\subitem{\par\hangindent 40pt \hspace*{20pt}} +\def\subsubitem{\par\hangindent 40pt \hspace*{30pt}} +\def\endtheindex{\if@restonecol\onecolumn\else\clearpage\fi} +\def\indexspace{\par \vskip 10pt plus 5pt minus 3pt\relax} + +% the command \ix allows an abbreviation for the general index + +%\def\ix#1{#1\index{general}{#1}} + +% define the \see command from makeidx.sty + +\def\see#1#2{{\em see\/} #1} diff --git a/manual/styles/ocamldoc.hva b/manual/styles/ocamldoc.hva new file mode 100644 index 00000000..58b7bb12 --- /dev/null +++ b/manual/styles/ocamldoc.hva @@ -0,0 +1,20 @@ +\usepackage{alltt} +\newenvironment{ocamldoccode}{\begin{alltt}}{\end{alltt}} +\newenvironment{ocamldocdescription}{\begin{quote}}{\end{quote}} +\newenvironment{ocamldoccomment}{\begin{quote}}{\end{quote}} + + +\newenvironment{ocamldocindent}{\list{}{}\item\relax}{\endlist} +\newenvironment{ocamldocsigend} + {\noindent\quad\texttt{sig}\ocamldocindent} + {\endocamldocindent + \noindent\quad\texttt{end}\medskip} +\newenvironment{ocamldocobjectend} + {\noindent\quad\texttt{object}\ocamldocindent} + {\endocamldocindent + \noindent\quad\texttt{end}\medskip} + +\newcommand{\moduleref}[1]{\ifhtml\ahref{libref/#1.html}{\texttt{#1}}\fi} + +# For processing .tex generated by ocamldoc (for text manual) +\newcommand{\ocamldocvspace}[1]{\vspace{#1}} \ No newline at end of file diff --git a/manual/styles/ocamldoc.sty b/manual/styles/ocamldoc.sty new file mode 100644 index 00000000..b176c9b1 --- /dev/null +++ b/manual/styles/ocamldoc.sty @@ -0,0 +1,75 @@ + +%% Support macros for LaTeX documentation generated by ocamldoc. +%% This file is in the public domain; do what you want with it. + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{ocamldoc} + [2001/12/04 v1.0 ocamldoc support] + +\newenvironment{ocamldoccode}{% + \bgroup + \leftskip\@totalleftmargin + \rightskip\z@skip + \parindent\z@ + \parfillskip\@flushglue + \parskip\z@skip + %\noindent + \@@par\smallskip + \@tempswafalse + \def\par{% + \if@tempswa + \leavevmode\null\@@par\penalty\interlinepenalty + \else + \@tempswatrue + \ifhmode\@@par\penalty\interlinepenalty\fi + \fi} + \obeylines + \verbatim@font + \let\org@prime~% + \@noligs + \let\org@dospecials\dospecials + \g@remfrom@specials{\\} + \g@remfrom@specials{\{} + \g@remfrom@specials{\}} + \let\do\@makeother + \dospecials + \let\dospecials\org@dospecials + \frenchspacing\@vobeyspaces + \everypar \expandafter{\the\everypar \unpenalty}} +{\egroup\par} + +\def\g@remfrom@specials#1{% + \def\@new@specials{} + \def\@remove##1{% + \ifx##1#1\else + \g@addto@macro\@new@specials{\do ##1}\fi} + \let\do\@remove\dospecials + \let\dospecials\@new@specials + } + +\newenvironment{ocamldocdescription} +{\list{}{\rightmargin0pt \topsep0pt}\raggedright\item\noindent\relax\ignorespaces} +{\endlist\medskip} + +\newenvironment{ocamldoccomment} +{\list{}{\leftmargin 2\leftmargini \rightmargin0pt \topsep0pt}\raggedright\item\noindent\relax} +{\endlist} + +\let \ocamldocparagraph \paragraph +\def \paragraph #1{\ocamldocparagraph {#1}\noindent} +\let \ocamldocsubparagraph \subparagraph +\def \subparagraph #1{\ocamldocsubparagraph {#1}\noindent} + +\let\ocamldocvspace\vspace + +\newenvironment{ocamldocindent}{\list{}{}\item\relax}{\endlist} +\newenvironment{ocamldocsigend} + {\noindent\quad\texttt{sig}\ocamldocindent} + {\endocamldocindent\vskip -\lastskip + \noindent\quad\texttt{end}\medskip} +\newenvironment{ocamldocobjectend} + {\noindent\quad\texttt{object}\ocamldocindent} + {\endocamldocindent\vskip -\lastskip + \noindent\quad\texttt{end}\medskip} + +\endinput diff --git a/manual/styles/plaintext.sty b/manual/styles/plaintext.sty new file mode 100644 index 00000000..2d1b366c --- /dev/null +++ b/manual/styles/plaintext.sty @@ -0,0 +1,268 @@ +% Plain text style file. + +\typeout{Style option Plaintext} + +% Version from John Pavel's dvidoc.sty, March 1987 +% Heavily hacked by Xavier Leroy, June 1993. + +% Redefine all fonts to be the "doc" pseudo-font, with fixed spacing. +% Since rm, tt and mi have different character encodings, we keep +% several copies of the doc font, with different names, so that dvi2txt +% can select the right encoding according to the name. Also, we use +% different names for boldface and italics, so that dvi2txt can select +% the right style whenever possible. + +\def\sl{\rm} +\def\sc{\rm} + +\def\vpt{} +\def\vipt{} +\def\viipt{} +\def\viiipt{} +\def\ixpt{} +\def\xipt{} +\def\xiipt{} +\def\xivpt{} +\def\xviipt{} +\def\xxpt{} +\def\xxvpt{} + +%%% for i in fiv six sev egt nin ten elv twl frtn svnt twty twfv; do +%%% echo "\\font\\${i}rm = docrm" +%%% echo "\\font\\${i}mi = docmi" +%%% echo "\\font\\${i}sy = cmsy10" +%%% echo "\\font\\${i}it = docit" +%%% echo "\\font\\${i}bf = docbf" +%%% echo "\\font\\${i}tt = doctt" +%%% echo "\\font\\${i}sf = docrm" +%%% done + +\font\fivrm = docrm +\font\fivmi = docmi +\font\fivsy = cmsy10 +\font\fivit = docit +\font\fivbf = docbf +\font\fivtt = doctt +\font\fivsf = docrm +\font\sixrm = docrm +\font\sixmi = docmi +\font\sixsy = cmsy10 +\font\sixit = docit +\font\sixbf = docbf +\font\sixtt = doctt +\font\sixsf = docrm +\font\sevrm = docrm +\font\sevmi = docmi +\font\sevsy = cmsy10 +\font\sevit = docit +\font\sevbf = docbf +\font\sevtt = doctt +\font\sevsf = docrm +\font\egtrm = docrm +\font\egtmi = docmi +\font\egtsy = cmsy10 +\font\egtit = docit +\font\egtbf = docbf +\font\egttt = doctt +\font\egtsf = docrm +\font\ninrm = docrm +\font\ninmi = docmi +\font\ninsy = cmsy10 +\font\ninit = docit +\font\ninbf = docbf +\font\nintt = doctt +\font\ninsf = docrm +\font\tenrm = docrm +\font\tenmi = docmi +\font\tensy = cmsy10 +\font\tenit = docit +\font\tenbf = docbf +\font\tentt = doctt +\font\tensf = docrm +\font\elvrm = docrm +\font\elvmi = docmi +\font\elvsy = cmsy10 +\font\elvit = docit +\font\elvbf = docbf +\font\elvtt = doctt +\font\elvsf = docrm +\font\twlrm = docrm +\font\twlmi = docmi +\font\twlsy = cmsy10 +\font\twlit = docit +\font\twlbf = docbf +\font\twltt = doctt +\font\twlsf = docrm +\font\frtnrm = docrm +\font\frtnmi = docmi +\font\frtnsy = cmsy10 +\font\frtnit = docit +\font\frtnbf = docbf +\font\frtntt = doctt +\font\frtnsf = docrm +\font\svtnrm = docrm +\font\svtnmi = docmi +\font\svtnsy = cmsy10 +\font\svtnit = docit +\font\svtnbf = docbf +\font\svtntt = doctt +\font\svtnsf = docrm +\font\twtyrm = docrm +\font\twtymi = docmi +\font\twtysy = cmsy10 +\font\twtyit = docit +\font\twtybf = docbf +\font\twtytt = doctt +\font\twtysf = docrm +\font\twfvrm = docrm +\font\twfvmi = docmi +\font\twfvsy = cmsy10 +\font\twfvit = docit +\font\twfvbf = docbf +\font\twfvtt = doctt +\font\twfvsf = docrm + +\rm + +% Dimensions + +\hsize 78 em % 78 characters per line so fit any screen +\textwidth 78 em +\raggedright % Do not try to align on the right +\parindent=2em % Two blanks for paragraph indentation +\def\enspace{\kern 1em} \def\enskip{\hskip 1em\relax} + +% Vertical skips may best be multiples of \baselineskip +\baselineskip=12pt % 6 lines per inch +\normalbaselineskip=\baselineskip +\vsize 58\baselineskip % 58 lines per page +\textheight 58\baselineskip +\voffset=0pt +\parskip=0pt +\smallskipamount=0pt +\medskipamount= \baselineskip +\bigskipamount=2\baselineskip +\raggedbottom % do not try to align the page bottom + +% By default itemize is done with bullets, which don't look good. + +\def\labelitemi{-} +\def\labelitemii{-} +\def\labelitemiii{-} +\def\labelitemiv{-} + +% Fix up table of contents. Default latex uses fractional spacing between +% the section number and title. This comes out as no space in the doc file +% so we add a space to numberline, and expand tempdima by one em to allow +% for it. Also, go out of math mode for the dot in the leader. Dots in +% math mode turn out to be colons! +% +\def\@dottedtocline#1#2#3#4#5{\ifnum #1>\c@tocdepth \else + \vskip \z@ plus .2pt + {\hangindent #2\relax \rightskip \@tocrmarg \parfillskip -\rightskip + \parindent #2\relax\@afterindenttrue + \interlinepenalty\@M + \leavevmode + \@tempdima #3\relax + \addtolength\@tempdima{1em} + #4\nobreak\leaders\hbox to 2em{\hss.\hss}\hfill \nobreak \hbox to\@pnumwidth{\hfil\rm #5}\par}\fi} +\def\numberline#1{\advance\hangindent\@tempdima \hbox to\@tempdima{#1\hfil}\ } +% +% Can't really do superscripts, so do footnotes with [] +% +\def\@makefnmark{\hbox{(\@thefnmark)}} +\long\def\@makefntext#1{\parindent 1em\noindent + \hbox to 3em{\hss\@thefnmark.}\ #1} +\skip\footins 24pt plus 4pt minus 2pt +\def\footnoterule{\kern-12\p@ +\hbox to .4\columnwidth{\leaders\hbox{-}\hfill}} +% +% \arrayrulewidth 1em \doublerulesep 1em +% +% Some fairly obvious hacks. No odd/even pages in doc files. Can't do the +% fancy TeX symbols. +% +\oddsidemargin 0pt \evensidemargin 0pt +\def\TeX{TeX} +\def\LaTeX{LaTeX} +\def\SliTeX{SliTeX} +\def\BibTeX{BibTeX} +% +% special versions of stuff from xxx10.sty, since only one font size +% +\def\@normalsize{\@setsize\normalsize{12pt}\xpt\@xpt +\abovedisplayskip 12pt +\belowdisplayskip 12pt +\abovedisplayshortskip 12pt +\belowdisplayshortskip 12pt +\let\@listi\@listI} % Setting of \@listi added 9 Jun 87 +\let\small\@normalsize +\let\footnotesize\@normalsize +\normalsize +\footnotesep 12pt +\labelsep 10pt +\def\@listI{\leftmargin\leftmargini \parsep 12pt% +\topsep 12pt% +\partopsep 0pt% +\itemsep 0pt} +\let\@listi\@listI +\let\@listii\@listI +\let\@listiii\@listI +\let\@listiv\@listI +\let\@listv\@listI +\let\@listvi\@listI +\@listI + +% We had sort of random numbers of blank lines around section numbers. +% Turns out they used various fractional spacing. Rather than depend +% upon the definition of startsection, just wrap something around it +% that normalizes the arguments to 12pt. Negative args have special +% meanings. +\let\@oldstartsec\@startsection +\def\@startsection#1#2#3#4#5#6{ + \@tempskipa #4\relax + \@tempskipb #5\relax + \ifdim \@tempskipa <\z@ \@tempskipa -12pt \else \@tempskipa 12pt \fi + \ifdim \@tempskipb >\z@ \@tempskipb 12pt \fi +\@oldstartsec{#1}{#2}{#3}{\@tempskipa}{\@tempskipb}{#6} +} + +% To get even spacing in the table of contents + +\def\@pnumwidth{3em} + +\def\l@part#1#2{\addpenalty{-\@highpenalty}% + \addvspace{12pt}% space above part line + \begingroup + \@tempdima 3em + \parindent \z@ \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + {\large \bf + \leavevmode + #1\hfil \hbox to\@pnumwidth{\hss #2}}\par + \nobreak + \global\@nobreaktrue + \everypar{\global\@nobreakfalse\everypar{}}%% suggested by + + \endgroup} + +\def\l@chapter#1#2{\addpenalty{-\@highpenalty}% + \vskip 12pt + \@tempdima 2em + \begingroup + \parindent \z@ \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + \bf + \leavevmode + \advance\leftskip\@tempdima + \hskip -\leftskip + #1\nobreak\hfil \nobreak\hbox to\@pnumwidth{\hss #2}\par + \penalty\@highpenalty + \endgroup} + +\def\l@section{\@dottedtocline{1}{2em}{3em}} +\def\l@subsection{\@dottedtocline{2}{4em}{3em}} +\def\l@subsubsection{\@dottedtocline{3}{7em}{4em}} +\def\l@paragraph{\@dottedtocline{4}{10em}{5em}} +\def\l@subparagraph{\@dottedtocline{5}{12em}{6em}} + diff --git a/manual/styles/scroll.sty b/manual/styles/scroll.sty new file mode 100644 index 00000000..a344b03d --- /dev/null +++ b/manual/styles/scroll.sty @@ -0,0 +1,5 @@ +% Modification to plaintext.sty to suppress page headings +% and make pages contiguous when processed with dvi2txt + +\pagestyle{empty} +\advance\voffset by -2\baselineskip diff --git a/manual/styles/syntaxdef.hva b/manual/styles/syntaxdef.hva new file mode 100644 index 00000000..7266d7ef --- /dev/null +++ b/manual/styles/syntaxdef.hva @@ -0,0 +1,157 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Hevea code for syntax definitions of the ocaml manual % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Important commands +% \token, for typesetting grammar terminals +% \nonterm, for typesetting grammar non-terminals +% +% Beware: \nonterm introduces either a local anchor or a local reference +% -Anchors are introduced when \nonterm occurs in the first column of +% syntax definitions (environment 'syntax') +% - References are introduced everywhere else +% +% For pure typesetting effect without links (eg. to typeset 'e' as 'expr') +% use the \nt command (eg. \nt{e}). +% In syntax definitions, the tool 'transf' translates @word@ into \nt{word}. +% +% Warnings are produced +% - For references to non-defined non terminals +% - For multiple definitions of the same non-terminal +% Warnings can be avoided for a given non-terminal 'expr' by issuing +% the command \stx@silent{'expr'} +% +%It is also possible to alias a nonterminal: +%\stx@alias{name}{othername} +%will make reference to 'name' point to the definition of non-terminal +%'othername' +\newif\ifspace +\def\addspace{\ifspace\;\spacefalse\fi} +\ifhtml +\newcommand{\token}[1]{\texttt{\blue#1}} +\else +\newcommand{\token}[1]{\texttt{#1}} +\fi +%%% warnings +\def\stx@warning#1#2{\@ifundefined{stx@#1@silent}{\hva@warn{#2}}{}} +\def\stx@silent#1{\def\csname stx@#1@silent\endcsname{}} +%%% Do not warn about those +%initial example +\stx@silent{like}\stx@silent{that}% +%Not defined +\stx@silent{regular-char}% +\stx@silent{regular-string-char}% +%\stx@silent{regular-char-str}% +\stx@silent{lowercase-ident}% +\stx@silent{capitalized-ident}% +\stx@silent{space}% +\stx@silent{tab}% +\stx@silent{newline}% +%Used in many places +\stx@silent{prefix}% +\stx@silent{name}% +\stx@silent{xname}% +%Not defined +\stx@silent{external-declaration}% +\stx@silent{unit-name}% +%%Redefined in exten.etex +\stx@silent{parameter}% +\stx@silent{pattern}% +\stx@silent{constr-decl}% +\stx@silent{type-param}% +\stx@silent{let-binding}% +\stx@silent{expr}% +\stx@silent{typexpr}% +\stx@silent{module-expr}% +\stx@silent{type-representation}% +\stx@silent{definition}% +\stx@silent{specification}% +\stx@silent{type-equation}% +\stx@silent{class-field}% +\stx@silent{mod-constraint}% +\stx@silent{module-type}% +\stx@silent{constant}% +%%Redefined in names.etex +\stx@silent{label-name}% +%%Not really defined in lexyacc.etex +\stx@silent{character-set}% +\stx@silent{symbol}% +%%Not defined in debugger.etex +\stx@silent{integer} +%%Not defined in ocamldoc.etex +\stx@silent{string} +\stx@silent{id} +\stx@silent{Exc} +\stx@silent{URL} +%%%%%%%%%%%%% +%% Aliases %% +%%%%%%%%%%%%% +\newcommand{\stx@alias}[2]{\def\csname stx@#1@alias\endcsname{#2}} +\stx@alias{typ}{typexpr}% +\stx@alias{met}{method-name}% +\stx@alias{tag}{tag-name}% +\stx@alias{lab}{label-name}% +\stx@alias{C}{constr-name} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%special anchor +\newstyle{a.syntax:link}{color:maroon;text-decoration:underline} +\newstyle{a.syntax:visited}{color:maroon;text-decoration:underline} +\newstyle{a.syntax:hover}{color:black;text-decoration:none;background-color:\#FF6060} +%compatibility for hevea-1.1?/heeva-2.?? +\ifu\@tr@url +\providecommand{\@tr@url}[1]{#1}\def\stx@id{NAME}\else +\def\stx@id{id}\fi +\newcommand{\@syntaxlocref}[2] +{\@aelement{href="\@print{#}\@tr@url{#1}" class="syntax"}{#2}} +\newcommand{\@syntaxaname}[2] +{\@aelement{\stx@id="#1" class="syntax"}{#2}} +%%Refer to anchor, internal : +%#1 -> anchor #2 -> visible tag +\def\@ref@anchor#1#2{% +\@ifundefined{stx@#1@exists} +{\stx@warning{#1}{Undefined non-terminal: '#1'}#2} +{\@syntaxlocref{#1}{#2}}} +%%Refer to anchor +\def\ref@anchor#1{% +\ifu\csname stx@#1@alias\endcsname +\@ref@anchor{#1}{#1}\else +\@ref@anchor{\csname stx@#1@alias\endcsname}{#1}\fi} +\def\stx@exists#1{\def\csname stx@#1@exists\endcsname{}} +%%Define anachor +\def\def@anchor#1{% +\@ifundefined{stx@#1} +{{\@nostyle\@auxdowrite{\string\stx@exists\{#1\}}}% +\gdef\csname stx@#1\endcsname{}\@syntaxaname{#1}{#1}} +{\@ifundefined{stx@#1@silent} +{\hva@warn{Redefinition of non-terminal '#1'}#1} +{\ref@anchor{#1}}}} +%%%Change \@anchor and initial definition, for html only, of course! +\ifhtml +\def\set@name{\let\@anchor\def@anchor} +\let\@anchor\ref@anchor +\else +\def\set@name{} +\def\@anchor{} +\fi +%%%Format non-terminal +\def\nt#1{\textit{\maroon#1}} +%%%Link for non-terminal and format +\def\nonterm#1{\addspace\nt{\@anchor{#1}}\spacetrue} +\def\brepet{\addspace\{} +\def\erepet{\}} +\def\boption{\addspace[} +\def\eoption{]} +\def\brepets{\addspace\{} +\def\erepets{\}^+} +\def\bparen{\addspace(} +\def\eparen{)} +\def\orelse{\mid \spacefalse} +\def\is{ & ::= & \spacefalse } +\def\alt{ \\ & \mid & \spacefalse } +\def\sep{ \\ \\ \spacefalse } +\def\cutline{} +\def\emptystring{\epsilon} +\def\syntax{\@open{div}{class="syntax"}$$\begin{array}{>{\set@name}rcl}\spacefalse} +\def\endsyntax{\end{array}$$\@close{div}} +\def\syntaxleft{\@open{div}{class="syntaxleft"}$\begin{array}{>{\set@name}rcl}\spacefalse} +\def\endsyntaxleft{\end{array}$\@close{div}} +\def\synt#1{$\spacefalse#1$} diff --git a/manual/styles/syntaxdef.sty b/manual/styles/syntaxdef.sty new file mode 100644 index 00000000..1db6f5bf --- /dev/null +++ b/manual/styles/syntaxdef.sty @@ -0,0 +1,26 @@ +\newif\ifspace +\def\addspace{\ifspace \; \spacefalse \fi} +\def\token#1{\addspace\hbox{\tt #1} \spacetrue} +\def\nonterm#1{\addspace\nt{#1} \spacetrue} +\def\nt#1{\hbox{\sl #1\/}} +\def\brepet{\addspace\{} +\def\erepet{\}} +\def\boption{\addspace[} +\def\eoption{]} +\def\brepets{\addspace\{} +\def\erepets{\}^+} +\def\bparen{\addspace(} +\def\eparen{)} +\def\orelse{\mid \spacefalse} +\def\is{ & ::= & \spacefalse } +\def\alt{ \\ & \mid & \spacefalse } +\def\cutline{ \\ & & \spacefalse } +\def\sep{ \\[2mm] \spacefalse } +\def\emptystring{\epsilon} +\def\syntax{$$\begin{array}{rrl}\spacefalse} +\def\endsyntax{\end{array}$$} +\def\syntaxleft{$\begin{array}{rrl}\spacefalse} +\def\endsyntaxleft{\end{array}$} +\let\oldldots=\ldots +\def\ldots{\spacefalse\oldldots} +\def\synt#1{$\spacefalse#1$} diff --git a/manual/styles/syntaxdeftxt.sty b/manual/styles/syntaxdeftxt.sty new file mode 100644 index 00000000..370b6580 --- /dev/null +++ b/manual/styles/syntaxdeftxt.sty @@ -0,0 +1,22 @@ +\newif\ifspace +\def\addspace{\ifspace\ \spacefalse\fi} +\def\token#1{\addspace\hbox{\tt #1}\spacetrue\ignorespaces} +%%% \def\nonterm#1{\addspace\hbox{\tt <#1>}\spacetrue\ignorespaces} +\def\nonterm#1{\addspace\hbox{\it #1}\spacetrue\ignorespaces} +\def\brepet{\addspace\hbox to1em{$\{$\hfil}\ignorespaces} +\def\erepet{\hbox to1em{$\}$\hfil}\ignorespaces} +\def\boption{\addspace[\ignorespaces} +\def\eoption{]\ignorespaces} +\def\brepets{\brepet\ignorespaces} +\def\erepets{\erepet+\ignorespaces} +\def\bparen{\addspace(\ignorespaces} +\def\eparen{)\ignorespaces} +\def\orelse{~\hbox to1em{$|$\hfil}~\spacefalse\ignorespaces} +\def\is{& ::= & \spacefalse\ignorespaces} +\def\alt{\\ & \hbox to1em{$|$\hfil} & \spacefalse } +\def\sep{\\[\baselineskip] \spacefalse} +\def\emptystring{nothing} +\def\syntax{\begin{center}\begin{tabular}{rrl}\spacefalse\ignorespaces} +\def\endsyntax{\end{tabular}\end{center}} +\def\ldots{\spacefalse...\ignorespaces} +\def\synt#1{$\spacefalse#1$} diff --git a/manual/tests/Makefile b/manual/tests/Makefile new file mode 100644 index 00000000..3947b175 --- /dev/null +++ b/manual/tests/Makefile @@ -0,0 +1,20 @@ +TOPDIR=$(abspath ../..) +include $(TOPDIR)/Makefile.tools +MANUAL=$(TOPDIR)/manual/manual + +.PHONY: all +all: check-cross-references check-stdlib + +cross-reference-checker: cross_reference_checker.ml + $(OCAMLC) $(TOPDIR)/compilerlibs/ocamlcommon.cma -I $(TOPDIR)/parsing \ + -I $(TOPDIR)/driver \ + cross_reference_checker.ml -o cross-reference-checker + +check-cross-references: cross-reference-checker + $(OCAMLRUN) ./cross-reference-checker \ + -auxfile $(MANUAL)/texstuff/manual.aux \ + $(TOPDIR)/utils/warnings.ml \ + $(TOPDIR)/bytecomp/translmod.ml + +check-stdlib: + ./check-stdlib-modules $(TOPDIR) diff --git a/manual/tests/README.md b/manual/tests/README.md new file mode 100644 index 00000000..31d2ab40 --- /dev/null +++ b/manual/tests/README.md @@ -0,0 +1,8 @@ +These tests have for objective to test the consistency between the manual and +the rest of the compiler sources: + +- `cross_reference_checker.ml` checks that reference to the manual from the + compiler sources are still accurate. + +- `check-stdlib-modules` checks that all stdlib modules are linked from the + main entry of the stdlib in the manual: `manual/manual/library/stdlib.etex` diff --git a/manual/tests/check-stdlib-modules b/manual/tests/check-stdlib-modules new file mode 100755 index 00000000..6e983523 --- /dev/null +++ b/manual/tests/check-stdlib-modules @@ -0,0 +1,23 @@ +#!/bin/sh + +TMPDIR="${TMPDIR:-/tmp}" + +(cd $1/stdlib; ls -1 *.mli) | sed -e 's/\.mli//' >$TMPDIR/stdlib-$$-files +cut -c 1 $TMPDIR/stdlib-$$-files | tr a-z A-Z >$TMPDIR/stdlib-$$-initials +cut -c 2- $TMPDIR/stdlib-$$-files \ +| paste -d '\0' $TMPDIR/stdlib-$$-initials - >$TMPDIR/stdlib-$$-modules + +exitcode=0 +for i in `cat $TMPDIR/stdlib-$$-modules`; do + case $i in + Stdlib | Camlinternal* | *Labels | Obj | Pervasives) continue;; + esac + grep -q -e '"'$i'" & p\.~\\pageref{'$i'} &' $1/manual/manual/library/stdlib.etex || { + echo "Module $i is missing from stdlib.etex." >&2 + exitcode=2 + } +done + +rm -f $TMPDIR/stdlib-$$-* + +exit $exitcode diff --git a/manual/tests/cross_reference_checker.ml b/manual/tests/cross_reference_checker.ml new file mode 100644 index 00000000..98eb598d --- /dev/null +++ b/manual/tests/cross_reference_checker.ml @@ -0,0 +1,243 @@ +(** Check reference to manual section in ml files + + [cross-reference-cheker -auxfile tex.aux src.ml ] + checks that all expression and let bindings in [src.ml] annotated + with [[@manual.ref "tex_label"]] are integer tuple literals, e.g + {[ + let[@manual.ref "sec:major"] ref = 1, 1 + (* or *) + let ref = (3 [@manual.ref "ch:pentatonic"]) + ]} + and that their values are consistent with the computed references for the + payload labels (e.g "sec:major", "ch:pentatonic") present in the TeX + auxiliary file [tex.aux] + +*) + + +(** {1 Error printing } *) +type error = + | Reference_mismatch of + {loc:Location.t; label:string; ocaml:int list; tex:int list} + | Unknown_label of Location.t * string + | Tuple_expected of Location.t + | No_aux_file + | Wrong_attribute_payload of Location.t + +let pp_ref ppf = Format.pp_print_list ~pp_sep:( fun ppf () -> + Format.pp_print_string ppf ".") Format.pp_print_int ppf + +let print_error error = + Location.report_error Format.std_formatter @@ match error with + | Tuple_expected loc -> + Location.errorf ~loc + "Integer tuple expected after manual reference annotation@." + | Unknown_label (loc,label) -> + Location.errorf ~loc + "@[Unknown manual label:@ %s@]@." label + | Reference_mismatch r -> + Location.errorf ~loc:r.loc + "@[References for label %S do not match:@,\ + OCaml side %a,@,\ + manual %a@]@." + r.label + pp_ref r.ocaml + pp_ref r.tex + | No_aux_file -> + Location.errorf "No aux file provided@." + | Wrong_attribute_payload loc -> + Location.errorf ~loc "Wrong payload for \"@manual.ref\"@." + + +(** {1 Main types} *) + +(** Maps of ocaml reference to manual labels *) +module Refs = Map.Make(String) + +(** Reference extracted from TeX aux files *) +type tex_reference = + { label: string; + pos: int list; + level: string + } + +type status = Ok | Bad | Unknown + +(** Reference extracted from OCaml source files *) +type ml_reference = { loc: Location.t; pos: int list; status:status } + +(** {1 Consistency check } *) + +let check_consistency (ref:tex_reference) {loc; pos; _ } = + if ref.pos = pos then + { loc; pos; status = Ok } + else begin + print_error @@ Reference_mismatch {loc;label=ref.label;tex=ref.pos;ocaml=pos}; + {loc; pos; status = Bad } + end + +let rec check_final_status label error = function + | { status = Ok; _ } -> error + | { status = Bad; _ } -> true + | { status = Unknown; loc; _} -> + print_error (Unknown_label (loc,label)); + true + +(** {1 Data extraction from TeX side} *) + +module TeX = struct + + (** Read reference information from a line of the aux file *) + let scan s = + try + Scanf.sscanf s + "\\newlabel{%s@}{{%s@}{%_d}{%_s@}{%s@.%_s@}{%_s@}}" + (fun label position_string level -> + let pos = + List.map int_of_string (String.split_on_char '.' position_string) in + Some {label;level;pos} ) + with + | Scanf.Scan_failure _ -> None + | Failure _ -> None + + let check_line refs line = + match scan line with + | None -> refs + | Some ref -> + match Refs.find_opt ref.label refs with + | None -> refs + | Some l -> + Refs.add ref.label + (List.map (check_consistency ref) l) + refs + + let check_all aux refs = + let chan = open_in aux in + let rec lines refs = + let s = try Some (input_line chan) with End_of_file -> None in + match s with + | None -> refs + | Some line -> + lines @@ check_line refs line in + let refs = lines refs in + close_in chan; + let error = Refs.fold (fun label ocaml_refs error -> + List.fold_left (check_final_status label) error ocaml_refs) + refs false in + if error then exit 2 else exit 0 +end + +(** {1 Extract references from Ocaml source files} *) +module OCaml_refs = struct + + let parse ppf sourcefile = + Pparse.parse_implementation ppf ~tool_name:"manual_cross_reference_check" + sourcefile + + (** search for an attribute [[@manual.ref "tex_label_name"]] *) + let manual_reference_attribute (s, payload) = + if s.Location.txt = "manual.ref" then + match payload with + | Parsetree.( + PStr [{pstr_desc= Pstr_eval + ({ pexp_desc = Pexp_constant Pconst_string (s,_) },_) } ] ) -> + Some s + | _ -> print_error (Wrong_attribute_payload s.Location.loc); + Some "" (* triggers an error *) + else + None + + let rec label_from_attributes = function + | [] -> None + | a :: q -> match manual_reference_attribute a with + | Some _ as x -> x + | None -> label_from_attributes q + + let int e = + let open Parsetree in + match e.pexp_desc with + | Pexp_constant Pconst_integer (s, _ ) -> int_of_string s + | _ -> raise Exit + + let int_list l = + try Some (List.map int l) with + | Exit -> None + + (** We keep a list of OCaml-side references to the same label *) + let add_ref label ref refs = + let l = match Refs.find_opt label refs with + | None -> [ref] + | Some l -> ref :: l in + Refs.add label l refs + + let inner_expr loc e = + let tuple_expected () = print_error (Tuple_expected loc) in + match e.Parsetree.pexp_desc with + | Parsetree.Pexp_tuple l -> + begin match int_list l with + | None -> tuple_expected (); [] + | Some pos -> pos + end + | Parsetree.Pexp_constant Pconst_integer (n,_) -> + [int_of_string n] + | _ -> tuple_expected (); [] + + (** extract from [let[@manual.ref "label"] x= 1, 2] *) + let value_binding m iterator vb = + let open Parsetree in + begin match label_from_attributes vb.pvb_attributes with + | None -> () + | Some label -> + let pos = inner_expr vb.pvb_loc vb.pvb_expr in + m := add_ref label {loc = vb.pvb_loc; pos; status = Unknown } !m + end; + iterator.Ast_iterator.expr iterator vb.pvb_expr + + + (** extract from [ (1,2)[@manual.ref "label"]] *) + let expr m iterator e = + let open Parsetree in + begin match label_from_attributes e.pexp_attributes with + | None -> () + | Some label -> + let pos = inner_expr e.pexp_loc e in + m := add_ref label {loc = e.pexp_loc; pos; status = Unknown } !m + end; + Ast_iterator.default_iterator.expr iterator e + + let from_ast m ast = + let iterator = + let value_binding = value_binding m in + let expr = expr m in + Ast_iterator.{ default_iterator with value_binding; expr } in + iterator.structure iterator ast + + let from_file m f = + from_ast m @@ parse Format.std_formatter f +end + + +(** {1 Argument handling and main function } *) + +let usage = + "cross-reference-check -auxfile [file.aux] file_1 ... file_n checks that \ + the cross reference annotated with [@manual_cross_reference] are consistent \ + with the provided auxiliary TeX file" + +(** the auxiliary file containing reference to be checked *) +let aux_file = ref None + +let args = + [ + "-auxfile",Arg.String (fun s -> aux_file := Some s), + "set the reference file" + ] + +let () = + let m = ref Refs.empty in + Arg.parse args (OCaml_refs.from_file m) usage; + match !aux_file with + | None -> print_error No_aux_file; exit 2 + | Some aux -> + let error = TeX.check_all aux !m in + if error then exit 2 else exit 0 diff --git a/manual/tools/.gitignore b/manual/tools/.gitignore new file mode 100644 index 00000000..db7f8368 --- /dev/null +++ b/manual/tools/.gitignore @@ -0,0 +1,12 @@ +transf.ml +texquote2 +htmltransf.ml +transf +htmlgen +htmlquote +latexscan.ml +dvi2txt +caml-tex2 +*.dSYM +*.cm[io] +*.o diff --git a/manual/tools/.ignore b/manual/tools/.ignore new file mode 100644 index 00000000..12c72e4a --- /dev/null +++ b/manual/tools/.ignore @@ -0,0 +1,11 @@ +transf.ml +texquote2 +htmltransf.ml +transf +htmlgen +htmlquote +latexscan.ml +dvi2txt +caml-tex2 +*.dSYM +*.cm[io] diff --git a/manual/tools/Makefile b/manual/tools/Makefile new file mode 100644 index 00000000..b3500acb --- /dev/null +++ b/manual/tools/Makefile @@ -0,0 +1,54 @@ +TOPDIR=../.. +COMPFLAGS=-I $(OTOPDIR)/otherlibs/str -I $(OTOPDIR)/otherlibs/unix +include $(TOPDIR)/Makefile.tools + +CFLAGS=-g -O + +all: texquote2 transf htmlquote htmlgen dvi2txt caml-tex2 + +dvi2txt: + cd dvi_to_txt; ${MAKE} + +transf: transf.cmo htmltransf.cmo transfmain.cmo + $(OCAMLC) -o transf -g transf.cmo htmltransf.cmo transfmain.cmo + +transf.ml: transf.mll + $(OCAMLLEX) transf.mll + +htmltransf.ml: htmltransf.mll + $(OCAMLLEX) htmltransf.mll + +htmlgen: latexmacros.cmo latexscan.cmo latexmain.cmo + $(OCAMLC) -o htmlgen -g latexmacros.cmo latexscan.cmo latexmain.cmo + +latexscan.ml: latexscan.mll + ocamllex latexscan.mll + +caml-tex2: caml_tex2.ml + $(OCAMLC) $(TOPDIR)/compilerlibs/ocamlcommon.cma -I $(TOPDIR)/parsing \ + -o caml-tex2 str.cma unix.cma caml_tex2.ml + +.SUFFIXES: +.SUFFIXES: .ml .cmo .mli .cmi .c + +.ml.cmo: + $(OCAMLC) -c $< + +.mli.cmi: + $(OCAMLC) -c $< + +.c: + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f transf.ml latexscan.ml htmltransf.ml + rm -f texquote2 transf htmlquote htmlgen dvi2txt + rm -f transf.ml latex.ml + rm -f *.o *.cm? *.cmxa + rm -f *~ #*# + cd dvi_to_txt; ${MAKE} clean + +latexmacros.cmo: latexmacros.cmi +latexmain.cmo: latexscan.cmo +latexscan.cmo: latexmacros.cmi +transfmain.cmo: transf.cmo htmltransf.cmo diff --git a/manual/tools/caml-tex b/manual/tools/caml-tex new file mode 100755 index 00000000..7eea11b5 --- /dev/null +++ b/manual/tools/caml-tex @@ -0,0 +1,131 @@ +#!/usr/bin/perl + +$camllight = "TERM=dumb ocaml"; +$camlbegin = "\\caml\n"; +$camlend = "\\endcaml\n"; +$camlin = "\\?"; +$camlout = "\\:"; +$camlblank = "\\;\n"; + +$linelen = 72; +$output = ""; +$cut_at_blanks = 0; + +while ($#ARGV >= 0) { + $_ = $ARGV[0]; + last unless (/^-/); + $linelen = $ARGV[1], shift, shift, next if (/^-n$/); + $output = $ARGV[1], shift, shift, next if (/^-o$/); + $camllight = $ARGV[1], shift, shift, next if (/^-caml$/); + $cut_at_blanks = 1, shift, next if (/^-w$/); + printf STDERR ("Unknown option '%s', ignored\n", $_); + shift; +} + +# First pass: extract the Caml phrases to evaluate + +open(ML, "> .input.ml") || die("Cannot create .input.ml : $!"); + +foreach $infile (@ARGV) { + open(IN, $infile) || die("Cannot open $infile : $!"); + while() { + if (m/^\\begin{caml_(example|example\*|eval)}\s*$/) { + while() { + last if m/^\\end{caml_(example|example\*|eval)}\s*$/; + print ML $_; + } + } + } + close(IN); +} + +close(ML); + +# Feed the phrases to a Caml toplevel + +open(TOPLEVEL, "$camllight 2>&1 < .input.ml |") || + die("Cannot start camllight : $!"); + +; ; # skip the banner +$lastread = ; +$lastread =~ s/^# //; + +# Second pass: shuffle the TeX source and the output of the toplevel + +if ($output) { + if ($output eq "-") { + open(OUT, ">&STDOUT"); + } else { + open(OUT, ">$output") || die("Cannot create $output: $!"); + } +} + +foreach $infile (@ARGV) { + open(IN, $infile) || die("Cannot open $infile: $!"); + if (! $output) { + $outfile = $infile; + $outfile =~ s/\.tex$//; + open(OUT, "> $outfile.ml.tex") || die("Cannot create $outfile.ml.tex: $!"); + } + while() { + if (m/^\\begin{caml_example(\*?)}\s*$/) { + $omit_answer = $1; # true if caml_example*, false if caml_example + print OUT $camlbegin; + $severalphrases = 0; + while() { + last if m/\\end{caml_example\*?}\s*$/; + print OUT $camlblank if ($severalphrases); + while(1) { + s/\\/\\\\/g; + print OUT $camlin, $_; + last if m/;; *$/; + $_ = ; + } + while ($lastread =~ s/^ //) { } + while($lastread) { + last if $lastread =~ s/^# //; + print STDERR $lastread; + if (! $omit_answer) { + while (length($lastread) > $linelen) { + if ($cut_at_blanks) { + $cutpos = rindex($lastread, ' ', $linelen); + if ($cutpos == -1) { $cutpos = $linelen; } else { $cutpos++; } + } else { + $cutpos = $linelen; + } + $line = substr($lastread, 0, $cutpos); + $line =~ s/\\/\\\\/g; + print OUT $camlout, $line, "\n"; + $lastread = substr($lastread, $cutpos, + length($lastread) - $cutpos); + } + $lastread =~ s/\\/\\\\/g; + print OUT $camlout, $lastread; + } + $lastread = ; + } + $severalphrases = 1; + } + print OUT $camlend; + } + elsif (m/^\\begin{caml_eval}\s*$/) { + while() { + last if m/^\\end{caml_eval}\s*$/; + if (m/;; *$/) { + while ($lastread =~ s/^ //) { } + while($lastread) { + last if $lastread =~ s/^#//; + print STDERR $lastread; + $lastread = ; + } + } + } + } + else { + print OUT $_; + } + } + close(IN); +} + +close(TOPLEVEL); diff --git a/manual/tools/caml_tex2.ml b/manual/tools/caml_tex2.ml new file mode 100644 index 00000000..d115b274 --- /dev/null +++ b/manual/tools/caml_tex2.ml @@ -0,0 +1,605 @@ +(* $Id$ *) + +open StdLabels +open Printf +open Str + +let camlbegin = "\\caml" +let camlend = "\\endcaml" +let camlin = {|\\?\1|} +let camlout = {|\\:\1|} +let camlbunderline = "\\<" +let camleunderline = "\\>" + +let start newline out s args = + Printf.fprintf out "%s%s" camlbegin s; + List.iter (Printf.fprintf out "{%s}") args; + if newline then Printf.fprintf out "\n" + +let stop newline out s = + Printf.fprintf out "%s%s" camlend s; + if newline then Printf.fprintf out "\n" + +let code_env ?(newline=true) env out s = + Printf.fprintf out "%a%s\n%a" + (fun ppf env -> start false ppf env []) env s (stop newline) env + +let main = "example" +type example_mode = Toplevel | Verbatim | Signature +let string_of_mode = function + | Toplevel -> "toplevel" + | Verbatim -> "verbatim" + | Signature -> "signature" + +let input_env = "input" +let ok_output ="output" +let error ="error" +let warning ="warn" +let phrase_env = "" + + +let camllight = ref "TERM=norepeat ocaml" +let verbose = ref true +let linelen = ref 72 +let outfile = ref "" +let cut_at_blanks = ref false +let files = ref [] + +let _ = + Arg.parse ["-n", Arg.Int (fun n -> linelen := n), "line length"; + "-o", Arg.String (fun s -> outfile := s), "output"; + "-caml", Arg.String (fun s -> camllight := s), "toplevel"; + "-w", Arg.Set cut_at_blanks, "cut at blanks"; + "-v", Arg.Bool (fun b -> verbose := b ), "output result on stderr" + ] + (fun s -> files := s :: !files) + "caml-tex2: " + +let (~!) = + let memo = ref [] in + fun key -> + try List.assq key !memo + with Not_found -> + let data = Str.regexp key in + memo := (key, data) :: !memo; + data + +(** The Output module deals with the analysis and classification + of the interpreter output and the parsing of status-related options + or annotations for the caml_example environment *) +module Output = struct + + (** Interpreter output status *) + type status = + | Ok + | Warning of int + | Error + + type kind = + | Annotation (** Local annotation: [ [@@expect (*annotation*) ] ]*) + | Option (** Global environment option: + [\begin{caml_example}[option[=value]] + ... + \end{caml_example}] *) + + (** Pretty printer for status *) + let pp_status ppf = function + | Error -> Printf.fprintf ppf "error" + | Ok -> Printf.fprintf ppf "ok" + | Warning n -> Printf.fprintf ppf "warning %d" n + + (** Pretty printer for status preceded with an undefined determinant *) + let pp_a_status ppf = function + | Error -> Printf.fprintf ppf "an error" + | Ok -> Printf.fprintf ppf "an ok" + | Warning n -> Printf.fprintf ppf "a warning %d" n + + (** {1 Related latex environment } *) + let env = function + | Error -> error + | Warning _ -> warning + | Ok -> ok_output + + (** {1 Exceptions } *) + exception Parsing_error of kind * string + + type source = { file:string; lines:int * int; phrase:string; output:string } + type unexpected_report = {source:source; expected:status; got:status} + exception Unexpected_status of unexpected_report + + let print_source ppf {file; lines = (start, stop); phrase; output} = + Printf.fprintf ppf "%s, lines %d to %d:\n\"\n%s\n\"\n\"\n%s\n\"." + file start stop phrase output + + let print_unexpected {source; expected; got} = + if expected = Ok then + Printf.eprintf + "Error when evaluating a caml_example environment in %a\n\ + Unexpected %a status.\n\ + If %a status was expected, add an [@@expect %a] annotation.\n" + print_source source + pp_status got + pp_a_status got + pp_status got + else + Printf.eprintf + "Error when evaluating a guarded caml_example environment in %a\n\ + Unexpected %a status, %a status was expected.\n\ + If %a status was in fact expected, change the status annotation to \ + [@@expect %a].\n" + print_source source + pp_status got + pp_a_status expected + pp_a_status got + pp_status got; + flush stderr + + let print_parsing_error k s = + match k with + | Option -> + Printf.eprintf + "Unknown caml_example option: [%s].\n\ + Supported options are \"ok\",\"error\", or \"warning=n\" (with n \ + a warning number).\n" s + | Annotation -> + Printf.eprintf + "Unknown caml_example phrase annotation: [@@expect %s].\n\ + Supported annotations are [@@expect ok], [@@expect error],\n\ + and [@@expect warning n] (with n a warning number).\n" s + + (** {1 Output analysis} *) + let catch_error s = + if string_match ~!{|Error:|} s 0 then Some Error else None + + let catch_warning s = + if string_match ~!{|Warning \([0-9]+\):|} s 0 then + Some (Warning (int_of_string @@ matched_group 1 s)) + else + None + + let status s = match catch_warning s, catch_error s with + | Some w, _ -> w + | None, Some e -> e + | None, None -> Ok + + (** {1 Parsing caml_example options } *) + + (** Parse [warning=n] options for caml_example options *) + let parse_warning s = + if string_match ~!{|warning=\([0-9]+\)|} s 0 then + Some (Warning (int_of_string @@ matched_group 1 s)) + else + None + + (** Parse [warning n] annotations *) + let parse_local_warning s = + if string_match ~!{|warning \([0-9]+\)|} s 0 then + Some (Warning (int_of_string @@ matched_group 1 s)) + else + None + + let parse_error s = + if s="error" then Some Error else None + + let parse_ok s = + if s = "ok" then Some Ok else None + + (** Parse the environment-wide expected status output *) + let expected s = + match parse_warning s, parse_error s with + | Some w, _ -> w + | None, Some e -> e + | None, None -> raise (Parsing_error (Option,s)) + + (** Parse the local (i.e. phrase-wide) expected status output *) + let local_expected s = + match parse_local_warning s, parse_error s, parse_ok s with + | Some w, _, _ -> w + | None, Some e, _ -> e + | None, None, Some ok -> ok + | None, None, None -> raise (Parsing_error (Annotation,s)) + +end + +module Text_transform = struct + + type kind = + | Underline + | Ellipsis + + exception Intersection of + {line:int; file:string; left:kind; stop:int; start:int; right:kind} + + let pp ppf = function + | Underline -> Format.fprintf ppf "underline" + | Ellipsis -> Format.fprintf ppf "ellipsis" + + type t = { kind:kind; start:int; stop:int} + let escape_specials s = + let s1 = global_replace ~!"\\\\" "\\\\\\\\" s in + let s2 = global_replace ~!"'" "\\\\textquotesingle\\\\-" s1 in + let s3 = global_replace ~!"`" "\\\\textasciigrave\\\\-" s2 in + s3 + + let rec apply_transform input (pos,underline_stop,out) t = + if pos >= String.length input then pos, underline_stop, out + else match underline_stop with + | Some stop when stop <= t.start -> + let f = escape_specials (String.sub input ~pos ~len:(stop - pos)) in + let out = {|\>|} :: f :: out in + apply_transform input (stop,None,out) t + | _ -> + let out = + escape_specials (String.sub input ~pos ~len:(t.start - pos))::out in + match t.kind with + | Ellipsis -> t.stop, underline_stop, {|\ldots|} :: out + | Underline -> + t.start, Some t.stop, {|\<|} :: out + + (** Check that all ellipsis are strictly nested inside underline transform + and that otherwise no transform starts before the end of the previous + transform in a list of transforms *) + type partition = U of t * t list | E of t + let check_partition line file l = + let init = Ellipsis, 0 in + let rec partition = function + | [] -> [] + | {kind=Underline; _ } as t :: q -> underline t [] q + | {kind=Ellipsis; _ } as t :: q -> E t :: partition q + and underline u n = function + | [] -> end_underline u n [] + | {kind=Underline; _ } :: _ as q -> end_underline u n q + | {kind=Ellipsis; _ } as t :: q -> + if t.stop < u.stop then underline u (t::n) q + else end_underline u n (t::q) + and end_underline u n l = U(u,List.rev n) :: partition l in + let check_elt (left,stop) t = + if t.start < stop then + raise (Intersection{line;file;left;stop;start=t.start;right=t.kind}) + else + (t.kind,t.stop) in + let check acc = function + | E t -> check_elt acc t + | U(u,n) -> + let _ = check_elt acc u in + let _ = List.fold_left ~f:check_elt ~init n in + u.kind, u.stop in + List.fold_left ~f:check ~init (partition l) + |> ignore + + let apply ts file line s = + let ts = List.sort (fun x y -> compare x.start y.start) ts in + check_partition line file ts; + let last, underline, ls = + List.fold_left ~f:(apply_transform s) ~init:(0,None,[]) ts in + let last, ls = match underline with + | None -> last, ls + | Some stop -> + let f = escape_specials (String.sub s ~pos:last ~len:(stop - last)) in + stop, {|\>|} :: f :: ls in + let ls = + let n = String.length s in + if last = n then ls else + escape_specials (String.sub s last (n-last)) :: ls in + String.concat "" (List.rev ls) +end + + +let caml_input, caml_output = + let cmd = !camllight ^ " 2>&1" in + try Unix.open_process cmd with _ -> failwith "Cannot start toplevel" +let () = + at_exit (fun () -> ignore (Unix.close_process (caml_input, caml_output))); + ignore (input_line caml_input); + ignore (input_line caml_input) + +let read_output () = + let input = ref (input_line caml_input) in + input := replace_first ~!{|^#\( *\*\)* *|} "" !input; + (* the inner ( *\* )* group is here to clean the starting "*" + introduced for multiline comments *) + let underline = + if string_match ~!"Characters *\\([0-9]+\\)-\\([0-9]+\\):$" !input 0 + then + let start = int_of_string (matched_group 1 !input) + and stop = int_of_string (matched_group 2 !input) in + input := input_line caml_input; + Text_transform.[{kind=Underline; start; stop}] + else [] + in + let output = Buffer.create 256 in + let first_line = ref true in + while not (string_match ~!".*\"end_of_input\"$" !input 0) do + if !verbose then prerr_endline !input; + if not !first_line then Buffer.add_char output '\n' else first_line:=false; + Buffer.add_string output !input; + input := input_line caml_input; + done; + Buffer.contents output, underline + +exception Missing_double_semicolon of string * int + +exception Missing_mode of string * int + +type incompatibility = + | Signature_with_visible_answer of string * int +exception Incompatible_options of incompatibility + +exception Phrase_parsing of string + +module Ellipsis = struct + (** This module implements the extraction of ellipsis locations + from phrases. + + An ellipsis is either an [[@ellipsis]] attribute, or a pair + of [[@@@ellipsis.start]...[@@@ellipsis.stop]] attributes. *) + + exception Unmatched_ellipsis of {kind:string; start:int; stop:int} + (** raised when an [[@@@ellipsis.start]] or [[@@@ellipsis.stop]] is + not paired with another ellipsis attribute *) + + exception Nested_ellipses of {first:int ; second:int } + (** raised by [[@@@ellipsis.start][@@@ellipsis.start]] *) + + let extract f x = + let transforms = ref [] in + let last_loc = ref Location.none in + let left_mark = ref None (* stored position of [@@@ellipsis.start]*) in + let location _this loc = + (* we rely on the fact that the default iterator call first + the location subiterator, then the attribute subiterator *) + last_loc := loc in + let attribute _this (attr,_) = + let name = attr.Location.txt in + let loc = !last_loc in + let start = loc.Location.loc_start.Lexing.pos_cnum in + let attr_start = attr.Location.loc.loc_start.Lexing.pos_cnum in + let attr_stop = 1 + attr.Location.loc.loc_end.Lexing.pos_cnum in + let stop = loc.Location.loc_end.Lexing.pos_cnum in + let check_nested () = match !left_mark with + | Some (first,_) -> raise (Nested_ellipses {first; second=attr_start}) + | None -> () in + match name with + | "ellipsis" -> + check_nested (); + transforms := + {Text_transform.kind=Ellipsis; start; stop=max attr_stop stop } + :: !transforms + | "ellipsis.start" -> + check_nested (); + left_mark := Some (start, stop) + | "ellipsis.stop" -> + begin match !left_mark with + | None -> raise (Unmatched_ellipsis {kind="right"; start; stop}) + | Some (start, _ ) -> + transforms := {kind=Ellipsis; start ; stop } :: !transforms; + left_mark := None + end + | _ -> () + in + f {Ast_iterator.default_iterator with location; attribute} x; + (match !left_mark with + | None -> () + | Some (start,stop) -> + raise (Unmatched_ellipsis {kind="left"; start; stop }) + ); + !transforms + + let find fname mode s = + let lex = Lexing.from_string s in + Location.init lex fname; + Location.input_name := fname; + Location.input_lexbuf := Some lex; + try + match mode with + | Toplevel -> begin + match Parse.toplevel_phrase lex with + | Ptop_dir _ -> [] + | Ptop_def str -> extract (fun it -> it.structure it) str + end + | Verbatim -> + extract (fun it -> it.structure it) (Parse.implementation lex) + | Signature -> + extract (fun it -> it.signature it) (Parse.interface lex) + with Syntaxerr.Error _ -> raise (Phrase_parsing s) + +end + +let process_file file = + prerr_endline ("Processing " ^ file); + let ic = try open_in file with _ -> failwith "Cannot read input file" in + let phrase_start = ref 1 and phrase_stop = ref 1 in + let incr_phrase_start () = + incr phrase_start; + phrase_stop := !phrase_start in + let oc = + try if !outfile = "-" then + stdout + else if !outfile = "" then + open_out (replace_first ~!"\\.tex$" "" file ^ ".ml.tex") + else + open_out_gen [Open_wronly; Open_creat; Open_append; Open_text] + 0x666 !outfile + with _ -> failwith "Cannot open output file" in + let fatal fmt = + Format.kfprintf + (fun ppf -> Format.fprintf ppf "@]@."; close_in ic; close_out oc; exit 1) + Format.err_formatter ("@[ Error " ^^ fmt) in + let re_spaces = "[ \t]*" in + let re_start = ~!( + {|\\begin{caml_example\(\*?\)}|} ^ re_spaces + ^ {|\({toplevel}\|{verbatim}\|{signature}\)?|} ^ re_spaces + ^ {|\(\[\(.*\)\]\)?|} ^ re_spaces + ^ "$" + ) in + try while true do + let input = ref (input_line ic) in + incr_phrase_start(); + if string_match re_start !input 0 + then begin + let omit_answer = matched_group 1 !input = "*" in + let mode = + match matched_group 2 !input with + | exception Not_found -> raise (Missing_mode(file, !phrase_stop)) + | "{toplevel}" -> Toplevel + | "{verbatim}" -> Verbatim + | "{signature}" -> Signature + | _ -> assert false in + if mode = Signature && not omit_answer then raise + (Incompatible_options( + Signature_with_visible_answer(file,!phrase_stop)) + ); + let explicit_stop = match mode with + | Verbatim | Signature -> false + | Toplevel -> true in + let global_expected = try Output.expected @@ matched_group 4 !input + with Not_found -> Output.Ok in + start true oc main [string_of_mode mode]; + let first = ref true in + let read_phrase () = + let phrase = Buffer.create 256 in + let rec read () = + let input = incr phrase_stop; input_line ic in + let implicit_stop = + if string_match ~!"\\\\end{caml_example\\*?}[ \t]*$" + input 0 + then + begin + if !phrase_stop = 1 + !phrase_start then + raise End_of_file + else if explicit_stop then + raise @@ Missing_double_semicolon (file,!phrase_stop) + else + true + end + else false in + if Buffer.length phrase > 0 then Buffer.add_char phrase '\n'; + let stop = + implicit_stop || + ( not (mode = Signature) + && string_match ~!"\\(.*\\)[ \t]*;;[ \t]*$" input 0 ) + in + if not stop then ( + Buffer.add_string phrase input; read () + ) + else begin + decr phrase_stop; + let last_input = if implicit_stop then "" else matched_group 1 input in + let expected = + if string_match ~!{|\(.*\)\[@@expect \(.*\)\]|} last_input 0 then + ( Buffer.add_string phrase (matched_group 1 last_input); + Output.local_expected @@ matched_group 2 last_input ) + else + (Buffer.add_string phrase last_input; global_expected) + in + if not implicit_stop then Buffer.add_string phrase ";;"; + implicit_stop, Buffer.contents phrase, expected + end in + read () + in + try while true do + let implicit_stop, phrase, expected = read_phrase () in + let ellipses = Ellipsis.find file mode phrase in + if mode = Signature then fprintf caml_output "module type Wrap = sig\n"; + fprintf caml_output "%s%s%s" phrase + (if mode = Signature then "\nend" else "") + (if implicit_stop then ";;\n" else "\n"); + flush caml_output; + output_string caml_output "\"end_of_input\";;\n"; + flush caml_output; + let output, underline = read_output () in + let status = Output.status output in + if status <> expected then ( + let source = Output.{ + file; + lines = (!phrase_start, !phrase_stop); + phrase; + output + } in + raise (Output.Unexpected_status + {Output.got=status; expected; source} ) ) + else ( incr phrase_stop; phrase_start := !phrase_stop ); + let phrase = + Text_transform.apply (underline @ ellipses) + file !phrase_stop phrase in + (* Special characters may also appear in output strings -Didier *) + let output = Text_transform.escape_specials output in + let phrase = global_replace ~!{|^\(.\)|} camlin phrase + and output = global_replace ~!{|^\(.\)|} camlout output in + start false oc phrase_env []; + code_env ~newline:omit_answer input_env oc phrase; + if not omit_answer then + code_env ~newline:false (Output.env status) oc output; + stop true oc phrase_env; + flush oc; + first := false; + if implicit_stop then raise End_of_file + done + with End_of_file -> phrase_start:= !phrase_stop; stop true oc main + end + else if string_match ~!"\\\\begin{caml_eval}[ \t]*$" !input 0 + then begin + while input := input_line ic; + not (string_match ~!"\\\\end{caml_eval}[ \t]*$" !input 0) + do + fprintf caml_output "%s\n" !input; + if string_match ~!".*;;[ \t]*$" !input 0 then begin + flush caml_output; + output_string caml_output "\"end_of_input\";;\n"; + flush caml_output; + ignore (read_output ()) + end + done + end else begin + fprintf oc "%s\n" !input; + flush oc + end + done with + | End_of_file -> close_in ic; close_out oc + | Output.Unexpected_status r -> + ( Output.print_unexpected r; close_in ic; close_out oc; exit 1 ) + | Output.Parsing_error (k,s) -> + ( Output.print_parsing_error k s; + close_in ic; close_out oc; exit 1 ) + | Phrase_parsing s -> fatal "when parsing the following phrase:@ %s" s + | Missing_double_semicolon (file, line_number) -> + fatal + "when evaluating a caml_example environment in %s:@;\ + missing \";;\" at line %d@]@." file (line_number-2) + | Missing_mode (file, line_number) -> + fatal "when parsing a caml_example environment in %s:@;\ + missing mode argument at line %d,@ \ + available modes {toplevel,verbatim}@]@." + file (line_number-2) + | Incompatible_options Signature_with_visible_answer (file, line_number) -> + fatal + "when parsing a caml_example environment in@ \ + %s, line %d:@,\ + the signature mode is only compatible with \"caml_example*\"@ \ + Hint: did you forget to add \"*\"?@]@." + file (line_number-2); + | Text_transform.Intersection {line;file;left;stop;start;right} -> + fatal + "when evaluating a caml_example environment in %s, line %d:@ \ + Textual transforms must be well-separated.@ The \"%a\" transform \ + ended at %d,@ after the start at %d of another \"%a\" transform.@ \ + Hind: did you try to elide a code fragment which raised a warning?\ + @]@." + file (line-2) + Text_transform.pp left stop start Text_transform.pp right + | Ellipsis.Unmatched_ellipsis {kind;start;stop} -> + fatal "when evaluating a caml_example environment,@ \ + the %s mark at position %d-%d was unmatched" + kind start stop + | Ellipsis.Nested_ellipses {first;second} -> + fatal "when evaluating a caml_example environment,@ \ + there were two nested ellipsis attribute.@ The first one \ + started at position %d,@ the second one at %d" + first second + +let _ = + if !outfile <> "-" && !outfile <> "" then begin + try close_out (open_out !outfile) + with _ -> failwith "Cannot open output file" + end; + List.iter process_file (List.rev !files) diff --git a/manual/tools/dvi_to_txt/Makefile b/manual/tools/dvi_to_txt/Makefile new file mode 100644 index 00000000..852996a9 --- /dev/null +++ b/manual/tools/dvi_to_txt/Makefile @@ -0,0 +1,8 @@ +OBJS=io.o interp.o output.o main.o print.o print_rtf.o print_styl.o +CFLAGS=-g + +../dvi2txt: $(OBJS) + $(CC) $(CFLAGS) -o ../dvi2txt $(OBJS) + +clean: + rm -f ../dvi2txt *.o *~ #*# diff --git a/manual/tools/dvi_to_txt/dvi.h b/manual/tools/dvi_to_txt/dvi.h new file mode 100644 index 00000000..8dfb25dc --- /dev/null +++ b/manual/tools/dvi_to_txt/dvi.h @@ -0,0 +1,8 @@ +enum { + SET_CHAR_0=0, SET_CHAR_127=127, SET1=128, SET2, SET3, SET4, SET_RULE, + PUT1, PUT2, PUT3, PUT4, PUT_RULE, NOP, BOP, EOP, PUSH, POP, RIGHT1, + RIGHT2, RIGHT3, RIGHT4, W0, W1, W2, W3, W4, X0, X1, X2, X3, X4, DOWN1, + DOWN2, DOWN3, DOWN4, Y0, Y1, Y2, Y3, Y4, Z0, Z1, Z2, Z3, Z4, + FNT_NUM_0=171, FNT_NUM_63=234, FNT1=235, FNT2, FNT3, FNT4, XXX1, XXX2, + XXX3, XXX4, FNT_DEF1, FNT_DEF2, FNT_DEF3, FNT_DEF4, PRE, POST, POST_POST +}; diff --git a/manual/tools/dvi_to_txt/interp.c b/manual/tools/dvi_to_txt/interp.c new file mode 100644 index 00000000..e50aed36 --- /dev/null +++ b/manual/tools/dvi_to_txt/interp.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include "io.h" +#include "dvi.h" +#include "output.h" + +#define SEEK_CUR 1 + +int h, v, w, x, y, z, sp; +int currfont; +int encoding; +int style; + +#define FONT_NAME_SIZE 31 +#define NUM_FONTS 256 + +struct { + char name[FONT_NAME_SIZE+1]; + int encoding; + int style; +} font[NUM_FONTS]; + +#define TYPEWRITER 0 +#define ROMAN 1 +#define MATH_ITALIC 2 +#define MATH_SYMBOL 3 +#define MATH_EXTENSION 4 +#define LINE_SEGMENTS 5 +#define CIRCLE_SEGMENTS 6 +#define LATEX_SYMBOLS 7 + +char * transcode[] = { +/* 0.......+.......1.......+.......2.......+.......3.......+.......4.......+.......5.......+.......6.......+.......7.......+....... */ +/* TYPEWRITER */ + "GDTLXPSUPYO##################### !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~#", +/* ROMAN */ + "GDTLXPSUPYO***** 0'!\"#$%&'()*+,-./0123456789:;!=??@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\"]^.`abcdefghijklmnopqrstuvwxyz--\"~#", +/* MATH_ITALIC */ + "GDTLXPSUPYOabgdezhtiklmnxpystupxyoeuorsp----`'><0123456789.,*dABCDEFGHIJKLMNOPQRSTUVWXYZ#####labcdefghijklmnopqrstuvwxyzij###", +/* MATH_SYMBOL */ + "-.x*/###+-x/.ooo==##<><>==##<><><>||####<>||####'#####/|###0RIT##ABCDEFGHIJKLMNOPQRSTUVWXYZ###########{}<>||||\\|################", +/* MATH_EXTENSION */ + "()[]||||{}<>||##()[]||||{}<>||##()[]||||{}<>||##########################################################[]||||{}################", +/* LINE_SEGMENTS */ + "/||||| _ / / _/ // _ / / __// / _ / \\||||| \\ \\ \\ _\\ \\\\ _ \\ \\ __\\\\ \\ _ \\ ", +/* CIRCLE_SEGMENTS */ + " ", +/* LATEX_SYMBOLS */ + " <<>> U#O0 ~~[] " +}; + +#define STACK_SIZE 100 + +struct { int sh, sv, sw, sx, sy, sz; } stack[STACK_SIZE]; + +struct known_font_struct { + char * prefix; + int encoding, style; +} known_fonts[] = { + "docrm", ROMAN, PLAIN, + "doctt", TYPEWRITER, MONOSPACED, + "docit", ROMAN, ITALICS, + "docbf", ROMAN, BOLD, + "docmi", MATH_ITALIC, PLAIN, + "cmsy", MATH_SYMBOL, PLAIN, + "cmex", MATH_EXTENSION, PLAIN, + "line", LINE_SEGMENTS, PLAIN, + "lcircle", CIRCLE_SEGMENTS, PLAIN, + "lasy", LATEX_SYMBOLS, PLAIN +}; + +void fontdef(input, fontnum) + FILE * input; + int fontnum; +{ + int a, l, i; + + assert(fontnum >= 0 && fontnum < NUM_FONTS); + fseek(input, 12, SEEK_CUR); /* skip c, s and d parameters */ + a = get8u(input); + l = get8u(input); + assert(l < FONT_NAME_SIZE); + fseek(input, a, SEEK_CUR); /* skip the "area" part */ + fread(font[fontnum].name, 1, l, input); /* read the font name */ + font[fontnum].name[l] = 0; + for (i = 0; + i < sizeof(known_fonts) / sizeof(struct known_font_struct); + i++) { + if (strncmp(font[fontnum].name, known_fonts[i].prefix, + strlen(known_fonts[i].prefix)) == 0) { + font[fontnum].encoding = known_fonts[i].encoding; + font[fontnum].style = known_fonts[i].style; + return; + } + } + fprintf(stderr, "Warning: unknown font `%s'\n", font[fontnum].name); + font[fontnum].encoding = ROMAN; + font[fontnum].style = PLAIN; +} + +void setfont(fontnum) + int fontnum; +{ + currfont = fontnum; + encoding = font[fontnum].encoding; + style = font[fontnum].style; +} + +int outchar(c) + int c; +{ + if (c < 0 || c > 127) + out(h, v, '#', PLAIN); + else + out(h, v, transcode[encoding][c], style); + return scalex; +} + +void outrule(height, width) + int height, width; +{ + char c; + int dx, dy; + + if (height <= 0 || width <= 0) return; + c = height >= width ? '|' : '-'; + dy = 0; + do { + dx = 0; + do { + out(h + dx, v - dy, c, PLAIN); + dx += scalex; + } while (dx <= width); + dy += scaley; + } while (dy < height); +} + +void interprete(input) + FILE * input; +{ + int c, n, height, width, mag; + + sp = 0; + c = get8u(input); + n = get8u(input); + if (c != PRE || n != 2) { + fprintf(stderr, "File does not start with DVI preamble.\n"); + exit(2); + } + (void) get32s(input); + (void) get32s(input); + mag = get32s(input); + scalex = SCALEX * mag / 1000; + scaley = SCALEY * mag / 1000; + n = get8u(input); + fseek(input, n, SEEK_CUR); /* skip comment */ + + begin_document(); + + while (1) { + c = get8u(input); + if (c >= SET_CHAR_0 && c <= SET_CHAR_127) + h += outchar(c); + else if (c >= FNT_NUM_0 && c <= FNT_NUM_63) + setfont(c - FNT_NUM_0); + else switch(c) { + case SET1: + h += outchar(get8u(input)); break; + case SET2: + h += outchar(get16u(input)); break; + case SET3: + h += outchar(get24u(input)); break; + case SET4: + h += outchar(get32s(input)); break; + case SET_RULE: + height = get32s(input); + width = get32s(input); + outrule(height, width); + h += width; + break; + case PUT1: + (void) outchar(get8u(input)); break; + case PUT2: + (void) outchar(get16u(input)); break; + case PUT3: + (void) outchar(get24u(input)); break; + case PUT4: + (void) outchar(get32s(input)); break; + case PUT_RULE: + height = get32s(input); + width = get32s(input); + outrule(height, width); + break; + case NOP: + break; + case BOP: + clear_page(); + h = v = w = x = y = z = 0; + sp = 0; + fseek(input, 44, SEEK_CUR); /* skip c0...c9 and ptr to previous page */ + break; + case EOP: + output_page(); + break; + case PUSH: + assert(sp < STACK_SIZE); + stack[sp].sh = h; stack[sp].sv = v; stack[sp].sw = w; + stack[sp].sx = x; stack[sp].sy = y; stack[sp].sz = z; + sp++; + break; + case POP: + assert(sp > 0); + sp--; + h = stack[sp].sh; v = stack[sp].sv; w = stack[sp].sw; + x = stack[sp].sx; y = stack[sp].sy; z = stack[sp].sz; + break; + case RIGHT1: + h += get8s(input); break; + case RIGHT2: + h += get16s(input); break; + case RIGHT3: + h += get24s(input); break; + case RIGHT4: + h += get32s(input); break; + case W0: + h += w; break; + case W1: + w = get8s(input); h += w; break; + case W2: + w = get16s(input); h += w; break; + case W3: + w = get24s(input); h += w; break; + case W4: + w = get32s(input); h += w; break; + case X0: + h += x; break; + case X1: + x = get8s(input); h += x; break; + case X2: + x = get16s(input); h += x; break; + case X3: + x = get24s(input); h += x; break; + case X4: + x = get32s(input); h += x; break; + case DOWN1: + v += get8s(input); break; + case DOWN2: + v += get16s(input); break; + case DOWN3: + v += get24s(input); break; + case DOWN4: + v += get32s(input); break; + case Y0: + v += y; break; + case Y1: + y = get8s(input); v += y; break; + case Y2: + y = get16s(input); v += y; break; + case Y3: + y = get24s(input); v += y; break; + case Y4: + y = get32s(input); v += y; break; + case Z0: + v += z; break; + case Z1: + z = get8s(input); v += z; break; + case Z2: + z = get16s(input); v += z; break; + case Z3: + z = get24s(input); v += z; break; + case Z4: + z = get32s(input); v += z; break; + case FNT1: + setfont(get8u(input)); break; + case FNT2: + setfont(get16u(input)); break; + case FNT3: + setfont(get24u(input)); break; + case FNT4: + setfont(get32s(input)); break; + case XXX1: + n = get8u(input); fseek(input, n, SEEK_CUR); break; + case XXX2: + n = get16u(input); fseek(input, n, SEEK_CUR); break; + case XXX3: + n = get24u(input); fseek(input, n, SEEK_CUR); break; + case XXX4: + n = get32s(input); fseek(input, n, SEEK_CUR); break; + case FNT_DEF1: + fontdef(input, get8u(input)); break; + case FNT_DEF2: + fontdef(input, get16u(input)); break; + case FNT_DEF3: + fontdef(input, get24u(input)); break; + case FNT_DEF4: + fontdef(input, get32s(input)); break; + case POST: + end_document(); return; + default: + assert(0); + } + } +} diff --git a/manual/tools/dvi_to_txt/io.c b/manual/tools/dvi_to_txt/io.c new file mode 100644 index 00000000..5dfe1ccc --- /dev/null +++ b/manual/tools/dvi_to_txt/io.c @@ -0,0 +1,43 @@ +#include +#include "io.h" + +int get16u(input) + FILE * input; +{ + int b1 = getc(input); + int b2 = getc(input); + return (b1 << 8) + b2; +} +int get16s(input) + FILE * input; +{ + int b1 = (schar) getc(input); + int b2 = getc(input); + return (b1 << 8) + b2; +} +int get24u(input) + FILE * input; +{ + int b1 = getc(input); + int b2 = getc(input); + int b3 = getc(input); + return (b1 << 16) + (b2 << 8) + b3; +} +int get24s(input) + FILE * input; +{ + int b1 = (schar) getc(input); + int b2 = getc(input); + int b3 = getc(input); + return (b1 << 16) + (b2 << 8) + b3; +} +int get32s(input) + FILE * input; +{ + int b1 = (schar) getc(input); + int b2 = getc(input); + int b3 = getc(input); + int b4 = getc(input); + return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; +} + diff --git a/manual/tools/dvi_to_txt/io.h b/manual/tools/dvi_to_txt/io.h new file mode 100644 index 00000000..f9a800d4 --- /dev/null +++ b/manual/tools/dvi_to_txt/io.h @@ -0,0 +1,10 @@ +#ifdef __STDC__ +typedef signed char schar; +#else +typedef char schar; +#endif + +#define get8u(input) getc(input) +#define get8s(input) (schar) getc(input) + +int get16u(), get16s(), get24u(), get24s(), get32u(), get32s(); diff --git a/manual/tools/dvi_to_txt/main.c b/manual/tools/dvi_to_txt/main.c new file mode 100644 index 00000000..0fb03c43 --- /dev/null +++ b/manual/tools/dvi_to_txt/main.c @@ -0,0 +1,47 @@ +#include +#include "output.h" + +void interprete(FILE *input); + +char * input_name; + +int main(argc, argv) + int argc; + char ** argv; +{ + FILE * f; + int i; + + output_device = OUTPUT_PLAIN; + standout_tt = 0; + for (i = 1; i < argc && argv[i][0] == '-'; i++) { + switch(argv[i][1]) { + case 'p': + output_device = OUTPUT_PRINTER; break; + case 'r': + output_device = OUTPUT_RTF; break; + case 's': + output_device = OUTPUT_STYL; break; + case 't': + standout_tt = 1; break; + default: + fprintf(stderr, "Unknown option `%s', ignored\n", argv[i]); + } + } + if (i >= argc) { + input_name = "unknown.dvi"; + interprete(stdin); + } else { + for (/*nothing*/; i < argc; i++) { + f = fopen(argv[i], "r"); + if (f == NULL) { + perror(argv[i]); + continue; + } + input_name = argv[i]; + interprete(f); + fclose(f); + } + } + return 0; +} diff --git a/manual/tools/dvi_to_txt/output.c b/manual/tools/dvi_to_txt/output.c new file mode 100644 index 00000000..fc79ed80 --- /dev/null +++ b/manual/tools/dvi_to_txt/output.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include "output.h" + +void null(), print_FF(), plain_line(), printer_line(); +void begin_rtf_document(), end_rtf_document(), end_rtf_page(), rtf_line(); +void begin_styl_page(), end_styl_page(), styl_line(); + +struct output_device { + void (*begin_document)(); + void (*end_document)(); + void (*begin_page)(); + void (*end_page)(); + void (*line)(); +} device[] = { + null, null, null, print_FF, plain_line, + null, null, null, print_FF, printer_line, + begin_rtf_document, end_rtf_document, null, end_rtf_page, rtf_line, + null, null, begin_styl_page, end_styl_page, styl_line +}; + +#define SIZEX 160 + +struct line { + int ypos; + int len; + char * contents; + char * styles; + struct line * next_in_bucket; +}; + +#define NBUCKETS 101 + +struct line * screenlines[NBUCKETS]; + +int numlines; + +char * xmalloc(size) + int size; +{ + char * res = (char *) malloc(size); + if (res == NULL) { + fprintf(stderr, "Out of memory\n"); + exit(2); + } + return res; +} + +char * xrealloc(ptr, size) + char * ptr; + int size; +{ + char * res = (char *) realloc(ptr, size); + if (res == NULL) { + fprintf(stderr, "Out of memory\n"); + exit(2); + } + return res; +} + +void begin_document() +{ + device[output_device].begin_document(); +} + +void end_document() +{ + device[output_device].end_document(); +} + +void clear_page() +{ + int i; + + for (i = 0; i < NBUCKETS; i++) screenlines[i] = NULL; + numlines = 0; +} + +void out(x, y, c, style) + int x, y; + char c; + char style; +{ + unsigned int h; + struct line * line; + + h = ((unsigned int) y) % NBUCKETS; + line = screenlines[h]; + while (line != NULL && line->ypos != y) line = line->next_in_bucket; + if (line == NULL) { + line = (struct line *) xmalloc(sizeof(struct line)); + line->ypos = y; + line->len = 80; + line->contents = (char *) xmalloc(line->len); + memset(line->contents, ' ', line->len); + line->styles = (char *) xmalloc(line->len); + memset(line->styles, PLAIN, line->len); + line->next_in_bucket = screenlines[h]; + screenlines[h] = line; + numlines++; + } + x = x / scalex; + if (x < 0) return; + while (x >= line->len) { + int newlen = 2 * line->len; + line->contents = (char *) xrealloc(line->contents, newlen); + memset(line->contents + line->len, ' ', newlen - line->len); + line->styles = (char *) xrealloc(line->styles, newlen); + memset(line->styles + line->len, PLAIN, newlen - line->len); + line->len = newlen; + } + line->contents[x] = c; + line->styles[x] = style; +} + +static void free_bucket(l) + struct line * l; +{ + if (l != NULL) { + free(l->contents); + free(l->styles); + free_bucket(l->next_in_bucket); + free(l); + } +} + +static void free_buckets() +{ + int i; + for (i = 0; i < NBUCKETS; i++) free_bucket(screenlines[i]); +} + +static int compare_lines(l1, l2) + struct line ** l1, ** l2; +{ + return (**l1).ypos - (**l2).ypos; +} + +void output_page() +{ + struct line ** lines; + struct line * l; + int i, j, k, y; + char * p, * q, * style_p, * style_q, * s; + + device[output_device].begin_page(); + + /* First, sort the lines by y coordinate */ + lines = (struct line **) malloc(numlines * sizeof(struct line *)); + if (lines == NULL) { + printf("*** Out of memory ***\n\014"); + free_buckets(); + return; + } + j = 0; + for (i = 0; i < NBUCKETS; i++) + for (l = screenlines[i]; l != NULL; l = l->next_in_bucket) + lines[j++] = l; + qsort(lines, numlines, sizeof(struct line *), compare_lines); + + /* Output the lines */ + + y = 0; + for (i = 0; i < numlines; i++) { + /* Emit blank lines to reach the current line ypos */ + while (lines[i]->ypos - y >= 3 * scaley / 2) { + device[output_device].line(NULL, NULL, 0); + y += scaley; + } + /* If next line is close to current line, attempt to merge them */ + while (i + 1 < numlines && + lines[i+1]->ypos - lines[i]->ypos < scaley) { + p = lines[i]->contents; + q = lines[i+1]->contents; + style_p = lines[i]->styles; + style_q = lines[i+1]->styles; + for (j = lines[i]->len; j < lines[i+1]->len; j++) + if (q[j] != ' ') goto cannot_merge; + for (j = lines[i+1]->len; j < lines[i]->len; j++) + if (p[j] != ' ') goto cannot_merge; + k = lines[i]->len; + if (k > lines[i+1]->len) k = lines[i+1]->len; + for (j = 0; j < k; j++) + if (p[j] != ' ' && q[j] != ' ') goto cannot_merge; + /* Seems OK, do the merging */ + for (j = 0; j < k; j++) + if (p[j] != ' ') { + q[j] = p[j]; + style_q[j] = style_p[j]; + } + /* Now consider next line */ + i++; + } + cannot_merge: + /* Now print the current line */ + p = lines[i]->contents; + q = p + lines[i]->len; + while (q >= p && *--q == ' ') /*nothing*/; + device[output_device].line(p, lines[i]->styles, q-p+1); + /* Go on with next line */ + y = lines[i]->ypos; + } + + device[output_device].end_page(); + free(lines); + free_buckets(); +} + diff --git a/manual/tools/dvi_to_txt/output.h b/manual/tools/dvi_to_txt/output.h new file mode 100644 index 00000000..43ce317b --- /dev/null +++ b/manual/tools/dvi_to_txt/output.h @@ -0,0 +1,24 @@ +#define SCALEX 404685 +#define SCALEY 786432 + +int scalex; +int scaley; + +#define PLAIN 0 +#define ITALICS 1 +#define BOLD 2 +#define MONOSPACED 3 + +void begin_document(); +void end_document(); +void clear_page(); +void output_page(); +void out(); + +int output_device; +int standout_tt; + +#define OUTPUT_PLAIN 0 +#define OUTPUT_PRINTER 1 +#define OUTPUT_RTF 2 +#define OUTPUT_STYL 3 diff --git a/manual/tools/dvi_to_txt/print.c b/manual/tools/dvi_to_txt/print.c new file mode 100644 index 00000000..d0f02cc3 --- /dev/null +++ b/manual/tools/dvi_to_txt/print.c @@ -0,0 +1,41 @@ +#include +#include "output.h" + +/* Low-level output functions */ + +void null() +{ +} + +void print_FF() +{ + putchar('\014'); +} + +void plain_line(txt, style, len) + char * txt, * style; + int len; +{ + fwrite(txt, 1, len, stdout); + putchar('\n'); +} + +void printer_line(txt, style, len) + char * txt, * style; + int len; +{ + for (/*nothing*/; len > 0; len--, txt++, style++) { + putchar(*txt); + switch(*style) { + case ITALICS: + putchar('\b'); putchar('_'); break; + case BOLD: + putchar('\b'); putchar(*txt); break; + case MONOSPACED: + if (standout_tt) { putchar('\b'); putchar(*txt); } + break; + } + } + putchar('\n'); +} + diff --git a/manual/tools/dvi_to_txt/print_rtf.c b/manual/tools/dvi_to_txt/print_rtf.c new file mode 100644 index 00000000..c12c67a3 --- /dev/null +++ b/manual/tools/dvi_to_txt/print_rtf.c @@ -0,0 +1,80 @@ +#include +#include "output.h" + +/* Rich Text Format */ + +void begin_rtf_document() +{ + printf("{\\rtf1\\ansi\\deff0\n"); + printf("{\\fonttbl{\\f0\\fmodern Courier;}}\n"); + printf("\\f0\\fs20\n"); +} + +void end_rtf_document() +{ + printf("}\n"); +} + +void end_rtf_page() +{ + printf("\\page\n"); +} + +void rtf_line(txt, style, len) + char * txt, * style; + int len; +{ + int currstyle; + + for (currstyle = PLAIN; len > 0; len--, txt++, style++) { + if (*txt != ' ') { + switch(*style) { + case PLAIN: + if (currstyle != PLAIN) { + putchar('}'); + currstyle = PLAIN; + } + break; + case ITALICS: + if (currstyle != ITALICS) { + if (currstyle != PLAIN) putchar('}'); + printf("{\\i "); + currstyle = ITALICS; + } + break; + case BOLD: + if (currstyle != BOLD) { + if (currstyle != PLAIN) putchar('}'); + printf("{\\b "); + currstyle = BOLD; + } + break; + case MONOSPACED: + if (standout_tt) { + if (currstyle != BOLD) { + if (currstyle != PLAIN) putchar('}'); + printf("{\\b "); + currstyle = BOLD; + } + } else { + if (currstyle != PLAIN) { + putchar('}'); + currstyle = PLAIN; + } + } + break; + } + } + switch(*txt) { + case '\\': + case '{': + case '}': + putchar('\\'); putchar(*txt); break; + default: + putchar(*txt); break; + } + } + if (currstyle != PLAIN) putchar('}'); + printf("\\par\n"); +} + diff --git a/manual/tools/dvi_to_txt/print_styl.c b/manual/tools/dvi_to_txt/print_styl.c new file mode 100644 index 00000000..39135f23 --- /dev/null +++ b/manual/tools/dvi_to_txt/print_styl.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include "output.h" + +/* Macintosh STYL tables */ + +extern char * input_name; + +static FILE * text; +static FILE * styl; +static int partnum = 0; +static int currstyle; +static int currstart; +static int currpos; + +static void output_current_style() +{ + int style_code; + + switch(currstyle) { + case PLAIN: + style_code = 0; break; + case ITALICS: + style_code = 2; break; + case BOLD: + style_code = 1 + 32; break; /* bold condensed */ + case MONOSPACED: + style_code = standout_tt ? 1 + 32 : 0; break; + } + fprintf(styl, "%d %d Monaco %d 9 0 0 0\n", currstart, currpos, style_code); +} + + +static void output_style_change(newstyle) + int newstyle; +{ + if (!standout_tt && (newstyle == PLAIN && currstyle == MONOSPACED || + newstyle == MONOSPACED && currstyle == PLAIN)) { + currstyle = newstyle; + return; + } + output_current_style(); + currstyle = newstyle; + currstart = currpos; +} + +void begin_styl_page() +{ + char name[1024], buffer[1024]; + int n; + + strcpy(name, input_name); + n = strlen(name); + if (n >= 4 && strcmp(name + n - 4, ".dvi") == 0) name[n - 4] = 0; + partnum++; + sprintf(buffer, "%s.%03d.txt", name, partnum); + text = fopen(buffer, "w"); + if (text == NULL) { perror(buffer); exit(2); } + sprintf(buffer, "%s.%03d.stl", name, partnum); + styl = fopen(buffer, "w"); + if (styl == NULL) { perror(buffer); exit(2); } + currstyle = PLAIN; + currstart = 0; + currpos = 0; +} + +void end_styl_page() +{ + output_current_style(); + fclose(text); + fclose(styl); +} + +void styl_line(txt, style, len) + char * txt, * style; + int len; +{ + for (/*nothing*/; len > 0; len--, txt++, style++, currpos++) { + putc(*txt, text); + if (*txt != ' ' && *style != currstyle) { + output_style_change(*style); + } + } + putc('\n', text); + currpos++; +} + + + diff --git a/manual/tools/fix_index.sh b/manual/tools/fix_index.sh new file mode 100755 index 00000000..d2402b40 --- /dev/null +++ b/manual/tools/fix_index.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# usage: fix_index.sh .idx + +# This script works around a hyperref bug: hyperref does not handle +# quotes in \index arguments properly. +# +# Symptom: +# When \index{-pipe-pipe@\verb`("|"|)`} appears in your .tex, the hyperref +# package mangles it and produces this line in your .idx: +# \indexentry{(-pipe-pipe)@\verb`("|hyperindexformat{\"}}{292} +# instead of the expected: +# \indexentry{(-pipe-pipe)@\verb`("|"|)`|hyperpage}{292} +# +# This is because it fails to handle quoted characters correctly. +# +# The workaround: +# Look for the buggy line in the given .idx file and change it. + +# Note: this bug will happen every time you have a | (pipe) character +# in an index entry (properly quoted with a " (double-quote) before it). +# We fix only the one case that appears in the OCaml documentation. +# We do not attempt a general solution because hyperref erases part +# of the argument, so we cannot recover the correct string from its +# output. + +# Note 2013-06-19: +# The above was for the || operator in the stdlib's Pervasives module. +# Now we have the same problem with the |> operator that was added +# to the same module in commit 13739, hence the second special case. + +usage(){ + echo "usage: fix_index.sh .idx" >&2 + exit 2 +} + +case $# in + 1) ;; + *) usage;; +esac + +ed "$1" <<'EOF' +/-pipe-pipe/s/verb`("|hyperindexformat{\\"}/verb`("|"|)`|hyperpage/ +/-pipe-gt/s/verb`("|hyperindexformat{\\>)`}/verb`("|>)`|hyperpage/ +w +q +EOF + +case $? in + 0) echo "fix_index.sh: fixed $1 successfully.";; + *) echo "fix_index.sh: some error occurred."; exit 0;; +esac diff --git a/manual/tools/format-intf b/manual/tools/format-intf new file mode 100755 index 00000000..0228ecc1 --- /dev/null +++ b/manual/tools/format-intf @@ -0,0 +1,153 @@ +#!/usr/bin/perl + +$sep = "\246"; + +$html = 0; +if ($ARGV[0] eq "-html") { + $html = 1; + shift; +} + +# Skip initial junk + +while(($_ = <>) && ! m/^\(\* Module \[(.*)\]:/) { } +m/^\(\* Module \[(.*)\]:/; +$modname = $1; +chop; +s/^\(\* *//; +s/ *\*\) *$//; +s/\[/{\\tt /g; +s/\]/}/g; +print "\\section{$_}\n\n"; +$label = $modname; $label =~ s/[^A-Za-z0-9]//g; +print "\\label{s:$label}\n"; +print "\\index{$modname (module)@\\verb~$modname~ (module)}%\n\n"; +s/{\\tt //g; +s/}//g; +s/_//g; +print "\\pdfsection{$_}\n\n"; + +$incomment = 0; +$inverbatim = 0; + +line: +while(<>) { + chop; + last line if /^\s*\(\*--/; + if (s/^\(\*- //) { + s/ *\*\)$//; + } + if (m/^\s*\(\*\*\*\s*(.*)\*\)\s*$/) { + if ($inverbatim) { + do end_verbatim(); + } + print "\\subsection*{", $1, "}\n"; + next line; + } + if (m/^\s*\(\*\*\s*(.*)\*\)\s*$/) { + if ($inverbatim) { + do end_verbatim(); + } + print "\\subsubsection*{", $1, "}\n"; + next line; + } + if (s/^\s*\(\*//) { + if ($inverbatim) { + do end_verbatim(); + } + print "\\begin{comment}\n"; + $incomment = 1; + } + if ($incomment) { + $endcomment = s/\*\)\s*$//; + if (m/^\s*\[\s*$/) { + print "\\begin{restoreindent}\n" unless $html; + print "\\begin{verbatim}\n"; + while (($_ = <>) && ! m/^\s*\]\s*$/) { + print $_; + } + print "\\end{verbatim}\n"; + print "\\end{restoreindent}\n" unless $html; + } else { + if (s/^-//) { + print "\\\\"; + print "[\\smallskipamount]" unless $html; + } + s/^\s*//; + $count = 0; + foreach $part (split(/(\\?[\[\]])/, $_)) { + if ($part eq "[") { + print ($count == 0 ? "\\verb$sep" : "["); + $count++; + } elsif ($part eq "]") { + $count--; + print ($count == 0 ? "$sep" : "]"); + } elsif ($part =~ m/^\\([\[\]])$/) { + print $1; + } else { + print $part; + } + } + } + if ($endcomment) { + print "\n\\end{comment}"; + $incomment = 0; + $inverbatim = 0; + } + } else { + next line if /^$/; + if (! $inverbatim) { + print "\\begin{verbatim}\n"; + $inverbatim = 1; + } + s/^external /val /; + s/ = ("[^"]*"\s*)+$//; + next line if /^\s*$/; + s/^val \( ([^ )]+) \)/val (\1)/; + { + do indexentry($1, " (operator)"), last + if (m/^val \(([^)]*)\)/); + do indexentry($1, ""), last + if (m/^val ([a-zA-Z0-9_']*)/); + do indexentry($1, " (type)"), last + if (m/^type\s.*([a-zA-Z0-9_']*)\s*=/); + do indexentry($1, " (exception)"), last + if (m/^exception ([a-zA-Z0-9_']*)/); + do indexentry($1, " (module type)"), last + if (m/^module type ([a-zA-Z0-9_']*)/); + do indexentry($1, " (functor)"), last + if (m/^module ([a-zA-Z0-9_']*)\s*\(/); + do indexentry($1, " (module)"), last + if (m/^module ([a-zA-Z0-9_']*)/); + } + print $_; + } + print "\n"; +} +do end_verbatim() if $inverbatim; +print "\\end{comment}\n" if $incomment; + +sub indexentry { + local ($_, $comment) = @_; + return if m/^$/ || m/^[a-zA-Z]$/; + s/([@|!])/"$1/g; + if (! m|`|) { + $s = "`"; + } elsif (! m|~|) { + $s = "~"; + } elsif (! m/\|/) { + $s = "|"; + } else { + die("Can't find quote character for $_"); + } + push (@index, "\\index{$_$comment@\\verb$s$_$s$comment}"); +} + +sub end_verbatim { + print "\\end{verbatim}\n"; + foreach $idx (@index) { + print $idx, "%\n"; + } + undef(@index); + $inverbatim = 0; +} diff --git a/manual/tools/htmlcut b/manual/tools/htmlcut new file mode 100755 index 00000000..be079abb --- /dev/null +++ b/manual/tools/htmlcut @@ -0,0 +1,111 @@ +#!/usr/local/bin/perl +# Split an HTML file into smaller nodes. +# Split at

    headers and also at some

    headers. + +$h0 = "H0"; +$h1 = "H1"; +$h2 = "H2"; + +# Parse options + +option: +while(1) { + $_ = $ARGV[0]; + if (/^-([0-9]+)$/) { + $split2[$1] = 1; + } + elsif (/^-article/) { + $h0 = "H1"; + $h1 = "H2"; + $h2 = "H3"; + } + else { + last option; + } + shift(@ARGV); +} + +$infile = $ARGV[0]; + +# Find URL's for the links + +$level0 = 0; +$level1 = 0; +$uselabel = 1; +open(INPUT, $infile); +while() { + if (m|^<$h0>(.*)|o) { + $level0++; + $currfile = "node" . ($level1 + 1) . ".html"; + $lblnum = $level0; + $uselabel = 0; + } + if (m|^<$h1>(.*)|o) { + $level1++; + $level2 = 0; + $currfile = "node$level1.html"; + $lblnum = $level1; + $uselabel = 1; + } + if (m|^<$h2>(.*)|o) { + $level2++; + if ($split2[$level1]) { $currfile = "node$level1.$level2.html"; } + $lblnum = "$level1.$level2"; + } + s||do set_url($1)|ige; +} + +sub set_url { + local ($lbl) = @_; + if ($uselabel) { + $url{$lbl} = "$currfile#$lbl"; + } else { + $url{$lbl} = $currfile; + } + $label{$lbl} = $lblnum; +} + +# Cut the file + +$level1 = 0; +open(INPUT, $infile); +while() { + if (m|^<$h0>(.*)|o) { + if ($level2 > 0) { print FILE1 "\n"; } + select(STDOUT); + if ($level1 >= 1) { print ""; } + print "<$h2>$1\n"; + if ($level1 >= 1) { print "
      "; } + next; + } + if (m|^<$h1>(.*)|o) { + if ($level2 > 0) { print FILE1 "
    \n"; } + $level1++; + $level2 = 0; + select(STDOUT); + if ($level1 == 1) { print "

      \n"; } + print "
    • $1\n"; + open(FILE1, "> node$level1.html"); + select(FILE1); + &print_title($1); + } + if ($split2[$level1] && m|^<$h2>(.*)|o) { + $level2++; + select(FILE1); + if ($level2 == 1) { print "

        \n"; } + print "
      • $1\n"; + open(FILE2, "> node$level1.$level2.html"); + select(FILE2); + &print_title($1); + } + s|X|'' . $label{$1} . ''|ige; + print $_; +} +select(STDOUT); +if ($level1 >= 1) { print "
      \n"; } + +sub print_title { + local ($title) = @_; + $title =~ s|<[a-zA-Z/]+>||g; + print "$title\n"; +} diff --git a/manual/tools/htmlquote.c b/manual/tools/htmlquote.c new file mode 100644 index 00000000..1d11eca5 --- /dev/null +++ b/manual/tools/htmlquote.c @@ -0,0 +1,87 @@ +#include +#include + +#define LINE_LENGTH 1024 + +char line[LINE_LENGTH]; + +int isprefix(s, pref) + char * s; + char * pref; +{ + while (1) { + if (*pref == 0) return 1; + if (*s == 0) return 0; + if (*s != *pref) return 0; + s++; + pref++; + } +} + +int main(argc, argv) + int argc; + char * argv []; +{ + unsigned char * p; + int c; + int inquote; + int inverb; + int inverbatim; + + inverbatim = 0; + inquote = 0; + + while(fgets(line, LINE_LENGTH, stdin) != NULL) { + if (inverbatim) { + fputs(line, stdout); + if (isprefix(line, "\\end{verbatim") + || isprefix(line, "\\end{alltt}")) inverbatim = 0; + continue; + } + if (isprefix(line, "\\begin{verbatim") + || isprefix(line, "\\begin{alltt}")) { + fputs(line, stdout); + inverbatim = 1; + continue; + } + inverb = 0; + for (p = (unsigned char *) line; *p != 0; p++) { + c = *p; + if (inverb) { + if (c == inverb) inverb = 0; + putchar(c); + continue; + } + switch(c) { + case '"': + if (inquote) { + fputs("\001", stdout); + inquote = 0; + } else { + fputs("\\verb\001", stdout); + inquote = 1; + } + break; + case '\\': + if (isprefix(p, "\\verb") && p[5] != 0 && !isalpha(p[5])) { + inverb = p[5]; + p = p + 5; + fputs("\\verb", stdout); + putchar(inverb); + } else if (inquote) { + if (p[1] == '"' || p[1] == '\\') { + c = p[1]; + p++; + } + putchar(c); + } else { + putchar('\\'); + } + break; + default: + putchar(c); + } + } + } + return 0; +} diff --git a/manual/tools/htmltbl b/manual/tools/htmltbl new file mode 100755 index 00000000..4b7b41a7 --- /dev/null +++ b/manual/tools/htmltbl @@ -0,0 +1,134 @@ +#!/usr/local/bin/perl + +while (<>) { + if (m|^ ]|) { + while (! m|$|) { $_ .= <>; } + s/\n//g; + print "
      \n";
      +    do format_table($_);
      +    print "
      \n"; + } else { + print $_; + } +} + +sub format_table { +# On input, $_ contains: +# Header 1Header2...Header M +# Data11Data12...Data1M +# ... +# DataN1DataN2...DataNM +# + +# Extract the entries and compute the number of lines and columns + + $numlines = 0; + $numcols = 0; + $border = 0; + $header = 0; + $x = 0; + $y = 0; + foreach $_ (split(/(||||<\/tbl>)/, $_)) { + if (/^$/) { next; } + elsif (//) { $border = 1; } + elsif (//i) { + if ($x > $numcols) { $numcols = $x; } + $x = 0; + $y++; + } + elsif (//) { $header = 1; } + elsif (!/(||||<\/tbl>)/) { + s|||g; # Remove embedded tags + s/^\s*//; # and initial blanks + s/\s*$//; # and final blanks + s/\s\s\s*/ /g; # and extra blanks + s/<//g; + s/&/&/g; + $entry{$x, $y} = $_; + $x++; + } + } + $numlines = $y; + +# Compute the max width of each column + + $totalwidth = 0; + + for ($x = 0; $x < $numcols; $x++) { + $max = 0; + for ($y = 0; $y < $numlines; $y++) { + $len = length($entry{$x, $y}); + if ($len > $max) { $max = $len; } + } + $width[$x] = $max; + $totalwidth += $max; + } + +# If it does not fit in one line, turn wide fields into multi-line fields + + if ($totalwidth >= 65) { + $totalwidth = 0; + $maxwidth = 65 / $numcols; + for ($x = 0; $x < $numcols; $x++) { + if ($width[$x] > $maxwidth) { + if ($x < $numcols - 1) { + $width[$x] = $maxwidth; + } else { + $width[$x] = 70 - $totalwidth; + } + } + $totalwidth += $width[$x]; + } + } + +# Compute the separators + + if ($border) { + $horsep = '+-'; + for ($x = 0; $x < $numcols; $x++) { + if ($x > 0) { $horsep .= '-+-'; } + $horsep .= '-' x $width[$x]; + } + $horsep .= '-+'; + $verleft = '| '; + $versep = ' | '; + $verright = ' |'; + } else { + $horsep = ''; + $verleft = ' '; + $versep = ' '; + $verright = ' '; + } + +# Print the table + print $horsep, "\n"; + for ($y = 0; $y < $numlines; $y++) { + do { + $overflow = 0; + print $verleft; + for ($x = 0; $x < $numcols; $x++) { + if ($x > 0) { print $versep; } + $_ = $entry{$x, $y}; + if (length($_) > $width[$x]) { + $pos = rindex($_, ' ', $width[$x]); + if ($pos < 0) { $pos = $width[$x]; } else { $pos++; } + $entry{$x, $y} = substr($_, $pos); + $_ = substr($_, 0, $pos - 1); + $overflow = 1; + } else { + $entry{$x, $y} = ''; + } + $len = length($_); + s/&/&/g; + s//>/g; + print $_, ' ' x ($width[$x] - $len); + } + print $verright, "\n"; + } while($overflow); + if ($header && $y == 0) { print $horsep, "\n"; } + } + print $horsep, "\n"; +} + diff --git a/manual/tools/htmlthread b/manual/tools/htmlthread new file mode 100755 index 00000000..fa66cdb2 --- /dev/null +++ b/manual/tools/htmlthread @@ -0,0 +1,58 @@ +#!/usr/local/bin/perl +# Insert Next/Previous/Contents buttons in a set of pages. + +@pages = sort fragmentorder @ARGV; + +sub fragmentorder { + $a =~ /^node([0-9]+)/; $na = $1; + if ($a =~ /^node[0-9]+\.([0-9]+)\.html/) { $fa = $1; } else { $fa = 0; } + $b =~ /^node([0-9]+)/; $nb = $1; + if ($b =~ /^node[0-9]+\.([0-9]+)\.html/) { $fb = $1; } else { $fb = 0; } + return (($na <=> $nb) || ($fa <=> $fb)); +} + +for ($i = 0; $i <= $#pages; $i++) { + open(SRC, $pages[$i]); + open(DST, "> newpage.html"); + select(DST); + $_ = ; # Title line + print "\n"; + print $_; + do links(); + print "\n"; + print "\n"; + do buttons(); + print "
      \n"; + $numlines = 0; + while () { + $numlines++; + print $_; + } + if ($numlines >= 40) { + print "
      \n"; + do buttons(); + } + close(SRC); + close(DST); + rename("newpage.html", $pages[$i]); +} + +sub links { + if ($i > 0) { + print '\n"; + } + if ($i < $#pages) { + print '\n"; + } + print "\n"; +} + +sub buttons { + if ($i > 0) { + print 'Previous', "\n"; + } + if ($i < $#pages) { + print 'Next', "\n"; + } + print 'Contents', "\n"; +} diff --git a/manual/tools/htmltransf.mll b/manual/tools/htmltransf.mll new file mode 100644 index 00000000..3db5e31f --- /dev/null +++ b/manual/tools/htmltransf.mll @@ -0,0 +1,117 @@ +{ +open Lexing;; + +let need_space = + ref false;; + +let addspace () = + if !need_space then begin print_char ' '; need_space := false end;; +} + +rule main = parse + "\\begin{syntax}" { + print_string "\\begin{rawhtml}\n
      \n";
      +      need_space := false;
      +      syntax lexbuf;
      +      print_string "
      \n\\end{rawhtml}\n"; + main lexbuf } + | "\\@" { + print_string "@"; + main lexbuf } + | "@" { + print_string "%\n\\begin{rawhtml}"; + need_space := false; + syntax lexbuf; + print_string "\\end{rawhtml}%\n"; + main lexbuf } + | _ { + print_char (lexeme_char lexbuf 0); main lexbuf } + | eof { + () } + +and syntax = parse + "\\end{syntax}" { () } + | "@" { () } + | '\'' { + addspace(); + print_string ""; + inquote lexbuf; + print_string ""; + need_space := true; + syntax lexbuf } + | '\"' { + addspace(); + print_string ""; + indoublequote lexbuf; + print_string ""; + need_space := true; + syntax lexbuf } + | ['a'-'z'] ['a'-'z' '0'-'9' '-'] * { + addspace(); + print_string ""; + print_string (lexeme lexbuf); + print_string ""; + need_space := true; + syntax lexbuf } + | '\\' ['a'-'z''A'-'Z'] + { + begin match lexeme lexbuf with + "\\ldots" -> print_string "..."; need_space := false + | s -> Printf.eprintf "Warning: %s ignored.\n" s + end; + syntax lexbuf } + | '_' _ { + print_string ""; + print_char(lexeme_char lexbuf 1); + print_string ""; + syntax lexbuf } + | '^' _ { + print_string ""; + print_char(lexeme_char lexbuf 1); + print_string ""; + syntax lexbuf } + | ":" { + print_string ":\n "; + need_space := false; + syntax lexbuf } + | "|" { + print_string "\n | "; + need_space := false; + syntax lexbuf } + | ";" { + print_string "\n\n"; + need_space := false; + syntax lexbuf } + | [ '{' '[' '('] { + addspace(); print_string (lexeme lexbuf); syntax lexbuf } + | [ '}' ']' ')'] { + print_string (lexeme lexbuf); syntax lexbuf } + | "{{" { + addspace(); print_string "{"; syntax lexbuf } + | "}}" { + print_string "}+"; syntax lexbuf } + | "||" { + print_string " | "; need_space := false; syntax lexbuf } + | [ ' ' '\n' '\t' '~'] { + syntax lexbuf } + | [ ',' ] { + print_char(lexeme_char lexbuf 0); syntax lexbuf } + | _ { + Printf.eprintf "Warning: %s ignored at char %d.\n" + (lexeme lexbuf) (lexeme_start lexbuf); + syntax lexbuf } + +and inquote = parse + '\'' { () } + | '&' { print_string "&"; inquote lexbuf } + | '<' { print_string "<"; inquote lexbuf } + | '>' { print_string ">"; inquote lexbuf } + | _ { print_char (lexeme_char lexbuf 0); inquote lexbuf } + +and indoublequote = parse + '"' { () } + | '&' { print_string "&"; indoublequote lexbuf } + | '<' { print_string "<"; indoublequote lexbuf } + | '>' { print_string ">"; indoublequote lexbuf } + | _ { print_char (lexeme_char lexbuf 0); indoublequote lexbuf } + + diff --git a/manual/tools/latexmacros.ml b/manual/tools/latexmacros.ml new file mode 100644 index 00000000..7353b494 --- /dev/null +++ b/manual/tools/latexmacros.ml @@ -0,0 +1,149 @@ +type action = + Print of string + | Print_arg + | Skip_arg;; + +let cmdtable = (Hashtbl.create 19 : (string, action list) Hashtbl.t);; + +let def_macro name action = + Hashtbl.add cmdtable name action;; + +let find_macro name = + try + Hashtbl.find cmdtable name + with Not_found -> + prerr_string "Unknown macro: "; prerr_endline name; [];; + +(* General LaTeX macros *) + +def_macro "\\part" + [Print ""; Print_arg; Print "\n"]; +def_macro "\\chapter" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\chapter*" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\section" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\section*" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\subsection" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\subsection*" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\subsubsection" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\subsubsection*" + [Print "

      "; Print_arg; Print "

      \n"]; +def_macro "\\paragraph" + [Print ""; Print_arg; Print "  \n"]; +def_macro "\\begin{alltt}" [Print "
      "];
      +def_macro "\\end{alltt}" [Print "
      "]; +def_macro "\\begin{itemize}" [Print "

        "]; +def_macro "\\end{itemize}" [Print "
      "]; +def_macro "\\begin{enumerate}" [Print "

        "]; +def_macro "\\end{enumerate}" [Print "
      "]; +def_macro "\\begin{description}" [Print "

      "]; +def_macro "\\end{description}" [Print "
      "]; +def_macro "\\begin{center}" [Print "
      "]; +def_macro "\\end{center}" [Print "
      "]; +def_macro "\\begin{quote}" [Print "
      "]; +def_macro "\\end{quote}" [Print "
      "]; +def_macro "\\begin{quotation}" [Print "
      "]; +def_macro "\\end{quotation}" [Print "
      "]; +def_macro "\\smallskip" []; +def_macro "\\medskip" []; +def_macro "\\bigskip" []; +def_macro "\\markboth" [Skip_arg; Skip_arg]; +def_macro "\\ldots" [Print "..."]; +def_macro "\\ " [Print " "]; +def_macro "\\{" [Print "{"]; +def_macro "\\}" [Print "}"]; +def_macro "\\%" [Print "%"]; +def_macro "\\$" [Print "$"]; +def_macro "\\#" [Print "#"]; +def_macro "\\/" []; +def_macro "\\newpage" []; +def_macro "\\label" [Print ""]; +def_macro "\\ref" [Print "X"]; +def_macro "\\pageref" [Print "X"]; +def_macro "\\index" [Skip_arg]; +def_macro "\\oe" [Print "oe"]; +def_macro "\\&" [Print "&"]; +def_macro "\\_" [Print "_"]; +def_macro "\\leq" [Print "<="]; +def_macro "\\geq" [Print ">="]; +def_macro "\\hbox" [Print_arg]; +def_macro "\\copyright" [Print "\169"]; +def_macro "\\noindent" []; +def_macro "\\begin{flushleft}" [Print "
      "]; +def_macro "\\end{flushleft}" [Print "
      "]; +def_macro "\\\\" [Print "
      "]; +def_macro "\\begin{htmlonly}" []; +def_macro "\\end{htmlonly}" []; +();; + +(* Macros specific to the Caml manual *) + +def_macro "\\begin{options}" [Print "

      "]; +def_macro "\\end{options}" [Print "
      "]; +def_macro "\\var" [Print ""; Print_arg; Print ""]; +def_macro "\\optvar" [Print "["; Print_arg; Print "]"]; +def_macro "\\nth" [Print ""; Print_arg; + Print ""; Print_arg; Print ""]; +def_macro "\\nmth" [Print ""; Print_arg; + Print ""; Print_arg; + Print ""; Print_arg; + Print ""]; +def_macro "\\begin{unix}" [Print "
      Unix:
      "]; +def_macro "\\end{unix}" [Print "
      "]; +def_macro "\\begin{macos}" [Print "
      MacOS:
      "]; +def_macro "\\end{macos}" [Print "
      "]; +def_macro "\\begin{windows}" [Print "
      Windows:
      "]; +def_macro "\\end{windows}" [Print "
      "]; +def_macro "\\begin{requirements}" [Print "
      Requirements:
      "]; +def_macro "\\end{requirements}" [Print "
      "]; +def_macro "\\begin{troubleshooting}" [Print "
      Troubleshooting:
      "]; +def_macro "\\end{troubleshooting}" [Print "
      "]; +def_macro "\\begin{installation}" [Print "
      Installation:
      "]; +def_macro "\\end{installation}" [Print "
      "]; +def_macro "\\index" [Skip_arg]; +def_macro "\\ikwd" [Skip_arg]; +def_macro "\\th" [Print "-th"]; +def_macro "\\begin{library}" []; +def_macro "\\end{library}" []; +def_macro "\\begin{comment}" [Print "
      "]; +def_macro "\\end{comment}" [Print "
      "]; +def_macro "\\begin{tableau}" + [Skip_arg; + Print "\n"]; +def_macro "\\entree" + [Print ""]; +def_macro "\\end{tableau}" [Print "
      "; + Print_arg; + Print ""; + Print_arg; + Print "
      "; Print_arg; + Print ""; Print_arg; Print "
      "]; +def_macro "\\begin{gcrule}" [Print "
      Rule:
      "]; +def_macro "\\end{gcrule}" [Print "
      "]; +def_macro "\\begin{tableauoperateurs}" + [Print "\n"]; +def_macro "\\end{tableauoperateurs}" [Print "
      OperatorAssociated identBehavior in the default environment
      \n"]; +def_macro "\\entreeoperateur" + [Print ""; Print_arg; Print ""; Print_arg; + Print ""; Print_arg; Print ""]; +def_macro "\\fromoneto" + [Print ""; Print_arg; Print " = 1, ..., "; + Print_arg; Print ""]; +def_macro "\\caml" [Print "
      "];
      +def_macro "\\endcaml" [Print "
      "]; +def_macro "\\<" [Print ""]; +def_macro "\\>" [Print ""]; +def_macro "\\rminalltt" [Print_arg]; +def_macro "\\event" [Print "*"]; +def_macro "\\pdfchapter" [Skip_arg]; +def_macro "\\pdfchapterfold" [Skip_arg; Skip_arg]; +def_macro "\\pdfsection" [Skip_arg]; +def_macro "\\transl" [Print "<"; Print_arg; Print ">"]; +();; + diff --git a/manual/tools/latexmacros.mli b/manual/tools/latexmacros.mli new file mode 100644 index 00000000..e7e4066f --- /dev/null +++ b/manual/tools/latexmacros.mli @@ -0,0 +1,8 @@ +type action = + Print of string + | Print_arg + | Skip_arg;; + +val find_macro: string -> action list;; + +val def_macro: string -> action list -> unit;; diff --git a/manual/tools/latexmain.ml b/manual/tools/latexmain.ml new file mode 100644 index 00000000..02d936f5 --- /dev/null +++ b/manual/tools/latexmain.ml @@ -0,0 +1,4 @@ +let main () = + Latexscan.main (Lexing.from_channel stdin);; + +Printexc.print main (); exit 0;; diff --git a/manual/tools/latexscan.mll b/manual/tools/latexscan.mll new file mode 100644 index 00000000..1acc5231 --- /dev/null +++ b/manual/tools/latexscan.mll @@ -0,0 +1,166 @@ +{ +open Lexing;; +open Latexmacros;; + +let delimiter = ref (char_of_int 0);; + +let upto delim lexfun lexbuf = + let old_delim = !delimiter in + delimiter := delim; + lexfun lexbuf; + delimiter := old_delim;; + +let verb_delim = ref (char_of_int 0);; + +let brace_nesting = ref 0;; + +let rindex c s = + let rec find i = + if i < 0 then raise Not_found else + if s.[i] = c then i else find (i-1) in + find (String.length s - 1);; + +let first_caml_line = ref true;; +let in_caml = ref false;; +} + +rule main = parse +(* Comments *) + '%' [^ '\n'] * '\n' { main lexbuf } +(* Paragraphs *) + | "\n\n" '\n' * + { print_string "

      \n"; main lexbuf } +(* Font changes *) + | "{\\it" " "* | "{\\em" " "* + { print_string ""; upto '}' main lexbuf; + print_string ""; main lexbuf } + | "{\\bf" " "* { print_string ""; upto '}' main lexbuf; + print_string ""; main lexbuf } + | "{\\rm" " "* { print_string ""; upto '}' main lexbuf; + print_string ""; main lexbuf } + | "{\\tt" " "* { print_string ""; upto '}' main lexbuf; + print_string ""; main lexbuf } + | '"' { print_string ""; indoublequote lexbuf; + print_string ""; main lexbuf } +(* Verb, verbatim *) + | "\\verb" _ { verb_delim := lexeme_char lexbuf 5; + print_string ""; inverb lexbuf; print_string ""; + main lexbuf } + | "\\begin{verbatim}" + { print_string "

      "; inverbatim lexbuf;
      +                  print_string "
      "; main lexbuf } +(* Caml programs *) + | "\\caml" + { print_string "
      ";
      +                  first_caml_line := true; in_caml := false;
      +                  camlprog lexbuf; print_string "
      "; main lexbuf } +(* Raw html, latex only *) + | "\\begin{rawhtml}" + { rawhtml lexbuf; main lexbuf } + | "\\begin{latexonly}" + { latexonly lexbuf; main lexbuf } +(* Itemize and similar environments *) + | "\\item[" { print_string "
      "; upto ']' main lexbuf; + print_string "
      "; main lexbuf } + | "\\item" { print_string "
    • "; main lexbuf } +(* Math mode (hmph) *) + | "$" { main lexbuf } +(* Special characters *) + | "\\char" ['0'-'9']+ + { let lxm = lexeme lexbuf in + let code = String.sub lxm 5 (String.length lxm - 5) in + print_char(char_of_int(int_of_string code)); + main lexbuf } + | "<" { print_string "<"; main lexbuf } + | ">" { print_string ">"; main lexbuf } + | "~" { print_string " "; main lexbuf } +(* Definitions of very simple macros *) + | "\\def\\" (['A'-'Z' 'a'-'z']+ | [^ 'A'-'Z' 'a'-'z']) "{" [^ '{' '}']* "}" + { let s = lexeme lexbuf in + let l = String.length s in + let p = rindex '{' s in + let name = String.sub s 4 (p - 4) in + let expansion = String.sub s (p + 1) (l - p - 2) in + def_macro name [Print expansion]; + main lexbuf } +(* General case for environments and commands *) + | ("\\begin{" | "\\end{") ['A'-'Z' 'a'-'z']+ "}" | + "\\" (['A'-'Z' 'a'-'z']+ '*'? | [^ 'A'-'Z' 'a'-'z']) + { let exec_action = function + Print str -> print_string str + | Print_arg -> print_arg lexbuf + | Skip_arg -> skip_arg lexbuf in + List.iter exec_action (find_macro(lexeme lexbuf)); + main lexbuf } +(* Default rule for other characters *) + | eof { () } + | _ { let c = lexeme_char lexbuf 0 in + if c == !delimiter then () else (print_char c; main lexbuf) } + +and indoublequote = parse + '"' { () } + | "<" { print_string "<"; indoublequote lexbuf } + | ">" { print_string ">"; indoublequote lexbuf } + | "&" { print_string "&"; indoublequote lexbuf } + | "\\\"" { print_string "\""; indoublequote lexbuf } + | "\\\\" { print_string "\\"; indoublequote lexbuf } + | _ { print_char(lexeme_char lexbuf 0); indoublequote lexbuf } + +and inverb = parse + "<" { print_string "<"; inverb lexbuf } + | ">" { print_string ">"; inverb lexbuf } + | "&" { print_string "&"; inverb lexbuf } + | _ { let c = lexeme_char lexbuf 0 in + if c == !verb_delim then () + else (print_char c; inverb lexbuf) } +and inverbatim = parse + "<" { print_string "<"; inverbatim lexbuf } + | ">" { print_string ">"; inverbatim lexbuf } + | "&" { print_string "&"; inverbatim lexbuf } + | "\\end{verbatim}" { () } + | _ { print_char(lexeme_char lexbuf 0); inverbatim lexbuf } + +and camlprog = parse + "<" { print_string "<"; camlprog lexbuf } + | ">" { print_string ">"; camlprog lexbuf } + | "&" { print_string "&"; camlprog lexbuf } + | "\\?" { if !first_caml_line then begin + print_string "# "; + first_caml_line := false + end else + print_string " "; + in_caml := true; + camlprog lexbuf } + | "\\:" { print_string ""; + in_caml := true; + camlprog lexbuf } + | "\\;" { first_caml_line := true; camlprog lexbuf } + | "\\\\" { print_string "\\"; camlprog lexbuf } + | "\\endcaml" { () } + | "\n" { if !in_caml then begin + print_string ""; + in_caml := false + end; + print_char '\n'; + camlprog lexbuf } + | _ { print_char(lexeme_char lexbuf 0); camlprog lexbuf } + +and rawhtml = parse + "\\end{rawhtml}" { () } + | _ { print_char(lexeme_char lexbuf 0); rawhtml lexbuf } + +and latexonly = parse + "\\end{latexonly}" { () } + | _ { latexonly lexbuf } + +and print_arg = parse + [' ' '\n'] * "{" { upto '}' main lexbuf } + | _ { print_char(lexeme_char lexbuf 0); rawhtml lexbuf } + +and skip_arg = parse + "{" { incr brace_nesting; skip_arg lexbuf } + | "}" { decr brace_nesting; + if !brace_nesting > 0 then skip_arg lexbuf } + | _ { skip_arg lexbuf } + + diff --git a/manual/tools/texexpand b/manual/tools/texexpand new file mode 100755 index 00000000..b2d8032f --- /dev/null +++ b/manual/tools/texexpand @@ -0,0 +1,40 @@ +#!/usr/local/bin/perl +# Expand \input commands + +@path = split(/:/, $ENV{'TEXINPUTS'}); + +while(<>) { + if (/^\\input\s*([^\s]*)/) { + do expand($1); + } else { + print $_; + } +} + +sub expand { + local ($filename) = @_; + local (*INPUT); + $filename =~ s/\.tex$//; + $filename = do find_in_path($filename); + open(INPUT, $filename) || (warn("cannot find $filename"), return); + print "%%% $filename\n"; + while() { + if (/^\\input\s*([^\s]*)/) { + do expand($1); + } else { + print $_; + } + } + close(INPUT); +} + +sub find_in_path { + local ($name) = @_; + local ($dir); + foreach $dir (@path) { + return "$dir/$name.htex" if (-f "$dir/$name.htex"); + return "$dir/$name.tex" if (-f "$dir/$name.tex"); + } + return $name; +} + diff --git a/manual/tools/texquote2.c b/manual/tools/texquote2.c new file mode 100644 index 00000000..23ef01e5 --- /dev/null +++ b/manual/tools/texquote2.c @@ -0,0 +1,167 @@ +#include +#include + +char * transl[256]; + +#define LINE_LENGTH 1024 + +char line[LINE_LENGTH]; + +int isprefix(s, pref) + char * s; + char * pref; +{ + while (1) { + if (*pref == 0) return 1; + if (*s == 0) return 0; + if (*s != *pref) return 0; + s++; + pref++; + } +} + +int main(argc, argv) + int argc; + char * argv []; +{ + unsigned char * p; + int c; + int inquote; + int inverb; + int inverbatim_like; + int incaml; + int inverbatim = 0; + char *verbatim_end_in = ""; + char *verbatim_end_out = ""; + + for (c = 0; c < 256; c++) transl[c] = NULL; +#ifdef TIE_BLANKS + transl[' '] = "~"; + transl['\n'] = "~"; +#else + transl[' '] = "\\ "; + transl['\n'] = "\\ "; +#endif + transl['{'] = "{\\char123}"; + transl['}'] = "{\\char125}"; + transl['^'] = "{\\char94}"; + transl['_'] = "{\\char95}"; + transl['\\'] = "{\\char92}"; + transl['~'] = "{\\char126}"; + transl['$'] = "\\$"; + transl['&'] = "{\\char38}"; + transl['#'] = "\\#"; + transl['%'] = "\\%"; + transl['\''] = "{\\textquotesingle}"; + transl['`'] = "{\\textasciigrave}"; + inverbatim_like = 0; + incaml = 0; + inquote = 0; + inverbatim = 0; + + puts ("% THIS FILE IS GENERATED.\n"); + + while(fgets(line, LINE_LENGTH, stdin) != NULL) { + if (inverbatim_like) { + fputs(line, stdout); + if (isprefix(line, "\\end{caml_") + || isprefix(line, "\\end{rawhtml}")) inverbatim_like = 0; + continue; + } + if (incaml) { + fputs(line, stdout); + if (isprefix(line, "\\endcamlexample")) incaml = 0; + continue; + } + if (inverbatim){ + if (isprefix (line, verbatim_end_in)){ + fputs (verbatim_end_out, stdout); + inverbatim = 0; + }else{ + for (p = (unsigned char *) line; *p != 0; p++){ + c = *p; + if (c == ' ' || c == '\n' || transl[c] == NULL){ + putchar (c); + }else{ + fputs (transl[c], stdout); + } + } + } + continue; + } + if (isprefix(line, "\\begin{caml_") + || isprefix(line, "\\begin{rawhtml}")) { + fputs(line, stdout); + inverbatim_like = 1; + continue; + } + if (isprefix(line, "\\camlexample")) { + fputs(line, stdout); + incaml = 1; + continue; + } + if (isprefix (line, "\\begin{verbatim}")){ + fputs ("\\begin{machineenv}", stdout); + inverbatim = 1; + verbatim_end_in = "\\end{verbatim}"; + verbatim_end_out = "\\end{machineenv}"; + continue; + } + if (isprefix (line, "\\begin{ocamldoccode}")){ + fputs ("\\begin{ocamldoccode}", stdout); + inverbatim = 1; + verbatim_end_in = "\\end{ocamldoccode}"; + verbatim_end_out = "\\end{ocamldoccode}"; + continue; + } + inverb = 0; + for (p = (unsigned char *) line; *p != 0; p++) { + c = *p; + if (inverb) { + if (c == inverb){ + inverb = 0; + }else if (c == '\'' || c == '`'){ + fprintf (stderr, "Warning: %c found in \\verb\n", c); + } + putchar(c); + continue; + } + switch(c) { + case '"': + if (inquote) { + fputs("}}", stdout); + inquote = 0; + } else { + fputs("{\\machine{", stdout); + inquote = 1; + } + break; + case '\\': + if (inquote) { + if (p[1] == '"' || p[1] == '\\') { + c = p[1]; + p++; + } + if (transl[c] != NULL) + fputs(transl[c], stdout); + else + putchar(c); + } else if (isprefix(p, "\\verb") && p[5] != 0 && !isalpha(p[5])) { + inverb = p[5]; + p = p + 5; + fputs("\\verb", stdout); + putchar(inverb); + } else { + putchar('\\'); + } + break; + default: + if (inquote && transl[c] != NULL) + fputs(transl[c], stdout); + else + putchar(c); + } + } + } + return 0; +} diff --git a/manual/tools/transf.mll b/manual/tools/transf.mll new file mode 100644 index 00000000..dcb5f3e2 --- /dev/null +++ b/manual/tools/transf.mll @@ -0,0 +1,107 @@ +{ + open Lexing;; + open Printf;; + + let print_char_repr c = + match c with + | '\'' -> printf "{\\textquotesingle}" + | '`' -> printf "{\\textasciigrave}" + | _ -> printf "\\char%d" (int_of_char c); + ;; +} + +rule main = parse + "\\begin{syntax}" { + print_string "\\begin{syntax}"; + syntax lexbuf } + | "\\begin{verbatim}" | "\\camlexample" as s { + print_string s; + verbatim lexbuf } + | "\\@" { + print_string "@"; + main lexbuf } + | "@" { + print_string "\\synt{"; + syntax lexbuf } + | _ { + print_char (lexeme_char lexbuf 0); main lexbuf } + | eof { + () } + +and syntax = parse + "\\end{syntax}" { + print_string "\\end{syntax}"; + main lexbuf } + | "@" { + print_string "}"; + main lexbuf } + | '\'' { + print_string "\\token{"; + inquote lexbuf } + | '\"' { + print_string "\\token{"; + indoublequote lexbuf } + | "epsilon" { print_string "\\emptystring"; syntax lexbuf } + | ['a'-'z' 'A'-'Z'] ['a'-'z' 'A'-'Z' '0'-'9' '-'] * as lxm { + print_string "\\nonterm{"; + print_string lxm ; + print_string"}"; + syntax lexbuf } + | '@' (['a'-'z' 'A'-'Z'] ['a'-'z' 'A'-'Z' '0'-'9' '-'] * as lxm) '@' { + print_string "\\nt{"; + print_string lxm ; + print_string"}"; + syntax lexbuf } + + | '\\' ['a'-'z''A'-'Z'] + { + print_string (lexeme lexbuf); + syntax lexbuf } + | ['_' '^'] _ { + print_string (lexeme lexbuf); + syntax lexbuf } + | "{" { print_string "\\brepet{}"; syntax lexbuf } + | "}" { print_string "\\erepet{}"; syntax lexbuf } + | "{{" { print_string "\\brepets{}"; syntax lexbuf } + | "}}" { print_string "\\erepets{}"; syntax lexbuf } + | "[" { print_string "\\boption{}"; syntax lexbuf } + | "]" { print_string "\\eoption{}"; syntax lexbuf } + | "(" { print_string "\\bparen{}"; syntax lexbuf } + | ")" { print_string "\\eparen{}"; syntax lexbuf } + | "||" { print_string "\\orelse{}"; syntax lexbuf } + | ":" { print_string "\\is{}"; syntax lexbuf } + | "|" { print_string "\\alt{}"; syntax lexbuf } + | ";" { print_string "\\sep{}"; syntax lexbuf } + | "\\\\" { print_string "\\cutline{}"; syntax lexbuf } + | _ { + print_char (lexeme_char lexbuf 0); + syntax lexbuf } + +and inquote = parse + ['A'-'Z' 'a'-'z' '0'-'9'] { + print_char (lexeme_char lexbuf 0); + inquote lexbuf } + | '\'' { + print_string "}"; + syntax lexbuf } + | _ { + print_char_repr (lexeme_char lexbuf 0); + inquote lexbuf } + +and indoublequote = parse + ['A'-'Z' 'a'-'z' '0'-'9'] { + print_char (lexeme_char lexbuf 0); + indoublequote lexbuf } + | '"' { + print_string "}"; + syntax lexbuf } + | _ { + print_char_repr (lexeme_char lexbuf 0); + indoublequote lexbuf } + +and verbatim = parse + "\n\\end{verbatim}"|"\\endcamlexample" as s { + print_string s; + main lexbuf } + | _ { + print_char (lexeme_char lexbuf 0); + verbatim lexbuf } diff --git a/manual/tools/transfmain.ml b/manual/tools/transfmain.ml new file mode 100644 index 00000000..49d9840d --- /dev/null +++ b/manual/tools/transfmain.ml @@ -0,0 +1,8 @@ +let main() = + let lexbuf = Lexing.from_channel stdin in + if Array.length Sys.argv >= 2 && Sys.argv.(1) = "-html" + then Htmltransf.main lexbuf + else Transf.main lexbuf; + exit 0;; + +Printexc.print main ();; diff --git a/middle_end/allocated_const.ml b/middle_end/allocated_const.ml index 10632a5f..f6e9d8e5 100644 --- a/middle_end/allocated_const.ml +++ b/middle_end/allocated_const.ml @@ -26,12 +26,12 @@ type t = | String of string | Immutable_string of string +let compare_floats x1 x2 = + (* It is important to compare the bit patterns here, so as not to + be subject to bugs such as GPR#295. *) + Int64.compare (Int64.bits_of_float x1) (Int64.bits_of_float x2) + let compare (x : t) (y : t) = - let compare_floats x1 x2 = - (* It is important to compare the bit patterns here, so as not to - be subject to bugs such as GPR#295. *) - Int64.compare (Int64.bits_of_float x1) (Int64.bits_of_float x2) - in let rec compare_float_lists l1 l2 = match l1, l2 with | [], [] -> 0 diff --git a/middle_end/allocated_const.mli b/middle_end/allocated_const.mli index 3182ab09..0bdbe49e 100644 --- a/middle_end/allocated_const.mli +++ b/middle_end/allocated_const.mli @@ -31,6 +31,8 @@ type t = | String of string | Immutable_string of string +val compare_floats : float -> float -> int + val compare : t -> t -> int val print : Format.formatter -> t -> unit diff --git a/middle_end/augment_specialised_args.ml b/middle_end/augment_specialised_args.ml index a38be378..83b45377 100755 --- a/middle_end/augment_specialised_args.ml +++ b/middle_end/augment_specialised_args.ml @@ -99,7 +99,6 @@ module W = What_to_specialise module type S = sig val pass_name : string - val variable_suffix : string val what_to_specialise : env:Inline_and_simplify_aux.Env.t @@ -120,7 +119,6 @@ module Processed_what_to_specialise = struct } type t = { - variable_suffix : string; set_of_closures : Flambda.set_of_closures; existing_definitions_via_spec_args_indexed_by_fun_var : Definition.Set.t Variable.Map.t; @@ -192,9 +190,7 @@ module Processed_what_to_specialise = struct | existing_outer_var -> existing_outer_var.var, t end | Projection_from_existing_specialised_arg projection -> - let new_outer_var = - Variable.rename group ~append:t.variable_suffix - in + let new_outer_var = Variable.rename group in let projection = lift_projection t ~projection in let new_outer_vars_indexed_by_new_lifted_defns = Projection.Map.add @@ -214,9 +210,7 @@ module Processed_what_to_specialise = struct in new_outer_var, t in - let new_inner_var = - Variable.rename group ~append:t.variable_suffix - in + let new_inner_var = Variable.rename group in let new_inner_to_new_outer_vars = Variable.Map.add new_inner_var new_outer_var for_one_function.new_inner_to_new_outer_vars @@ -285,7 +279,7 @@ module Processed_what_to_specialise = struct if exists_already then t else really_add_new_specialised_arg t ~group ~definition ~for_one_function - let create ~env ~(what_to_specialise : W.t) ~variable_suffix = + let create ~env ~(what_to_specialise : W.t) = let existing_definitions_via_spec_args_indexed_by_fun_var = Variable.Map.map (fun (function_decl : Flambda.function_declaration) -> if function_decl.stub then @@ -309,8 +303,7 @@ module Processed_what_to_specialise = struct what_to_specialise.set_of_closures.function_decls.funs in let t : t = - { variable_suffix; - set_of_closures = what_to_specialise.set_of_closures; + { set_of_closures = what_to_specialise.set_of_closures; existing_definitions_via_spec_args_indexed_by_fun_var; new_lifted_defns_indexed_by_new_outer_vars = Variable.Map.empty; new_outer_vars_indexed_by_new_lifted_defns = Projection.Map.empty; @@ -407,10 +400,10 @@ module Make (T : S) = struct let rename_function_and_parameters ~fun_var ~(function_decl : Flambda.function_declaration) = - let new_fun_var = Variable.rename fun_var ~append:T.variable_suffix in + let new_fun_var = Variable.rename fun_var in let params_renaming_list = List.map (fun param -> - let new_param = Parameter.rename param ~append:T.variable_suffix in + let new_param = Parameter.rename param in param, new_param) function_decl.params in @@ -542,6 +535,7 @@ module Make (T : S) = struct ~inline:Default_inline ~specialise:Default_specialise ~is_a_functor:false + ~closure_origin:function_decl.closure_origin in new_fun_var, new_function_decl, rewritten_existing_specialised_args, benefit @@ -600,7 +594,7 @@ module Make (T : S) = struct specialised_args, None else let function_decl, new_specialised_args = - duplicate_function ~env ~set_of_closures ~fun_var + duplicate_function ~env ~set_of_closures ~fun_var ~new_fun_var in let specialised_args = Variable.Map.disjoint_union specialised_args new_specialised_args @@ -617,6 +611,9 @@ module Make (T : S) = struct in function_decl.params @ new_params in + let closure_origin = + Closure_origin.create (Closure_id.wrap new_fun_var) + in let rewritten_function_decl = Flambda.create_function_declaration ~params:all_params @@ -626,10 +623,11 @@ module Make (T : S) = struct ~inline:function_decl.inline ~specialise:function_decl.specialise ~is_a_functor:function_decl.is_a_functor + ~closure_origin in let funs, direct_call_surrogates = if for_one_function.make_direct_call_surrogates then - let surrogate = Variable.rename fun_var ~append:"_surrogate" in + let surrogate = Variable.rename fun_var in let funs = (* In this case, the original function declaration remains untouched up to alpha-equivalence. Direct calls to it @@ -664,8 +662,9 @@ module Make (T : S) = struct ~(set_of_closures : Flambda.set_of_closures) ~benefit ~new_lifted_defns_indexed_by_new_outer_vars = let body = - Flambda_utils.name_expr (Set_of_closures set_of_closures) - ~name:("set_of_closures" ^ T.variable_suffix) + Flambda_utils.name_expr + ~name:Internal_variable_names.set_of_closures + (Set_of_closures set_of_closures) in Variable.Map.fold (fun new_outer_var (projection : Projection.t) (expr, benefit) -> @@ -679,7 +678,7 @@ module Make (T : S) = struct let rewrite_set_of_closures_core ~env ~duplicate_function ~benefit ~(set_of_closures : Flambda.set_of_closures) = let what_to_specialise = - P.create ~env ~variable_suffix:T.variable_suffix + P.create ~env ~what_to_specialise:(T.what_to_specialise ~env ~set_of_closures) in let original_set_of_closures = set_of_closures in diff --git a/middle_end/augment_specialised_args.mli b/middle_end/augment_specialised_args.mli index 94ccfc09..5c48a126 100644 --- a/middle_end/augment_specialised_args.mli +++ b/middle_end/augment_specialised_args.mli @@ -41,7 +41,6 @@ end module type S = sig val pass_name : string - val variable_suffix : string val what_to_specialise : env:Inline_and_simplify_aux.Env.t @@ -58,6 +57,7 @@ module Make (T : S) : sig env:Inline_and_simplify_aux.Env.t -> set_of_closures:Flambda.set_of_closures -> fun_var:Variable.t + -> new_fun_var:Variable.t -> Flambda.function_declaration * Flambda.specialised_to Variable.Map.t) -> set_of_closures:Flambda.set_of_closures diff --git a/middle_end/base_types/closure_origin.ml b/middle_end/base_types/closure_origin.ml new file mode 100644 index 00000000..324e7189 --- /dev/null +++ b/middle_end/base_types/closure_origin.ml @@ -0,0 +1,21 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Pierre Chambart, OCamlPro *) +(* Mark Shinwell, Leo White and Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2013--2017 OCamlPro SAS *) +(* Copyright 2014--2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-9-30-40-41-42"] + +include Closure_id + +let create t = t diff --git a/middle_end/base_types/closure_origin.mli b/middle_end/base_types/closure_origin.mli new file mode 100644 index 00000000..86fcd56c --- /dev/null +++ b/middle_end/base_types/closure_origin.mli @@ -0,0 +1,21 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Pierre Chambart, OCamlPro *) +(* Mark Shinwell, Leo White and Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2013--2017 OCamlPro SAS *) +(* Copyright 2014--2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +include Identifiable.S + +val create : Closure_id.t -> t + +val get_compilation_unit : t -> Compilation_unit.t diff --git a/middle_end/base_types/compilation_unit.ml b/middle_end/base_types/compilation_unit.ml index a21d9f1e..18031724 100644 --- a/middle_end/base_types/compilation_unit.ml +++ b/middle_end/base_types/compilation_unit.ml @@ -58,12 +58,16 @@ let create (id : Ident.t) linkage_name = if not (Ident.persistent id) then begin Misc.fatal_error "Compilation_unit.create with non-persistent Ident.t" end; - { id; linkage_name; hash = Hashtbl.hash id.name } + { id; linkage_name; hash = Hashtbl.hash (Ident.name id); } let get_persistent_ident cu = cu.id let get_linkage_name cu = cu.linkage_name let current = ref None +let is_current arg = + match !current with + | None -> Misc.fatal_error "Current compilation unit is not set!" + | Some cur -> equal cur arg let set_current t = current := Some t let get_current () = !current let get_current_exn () = diff --git a/middle_end/base_types/compilation_unit.mli b/middle_end/base_types/compilation_unit.mli index e9375685..fc7d3bfd 100644 --- a/middle_end/base_types/compilation_unit.mli +++ b/middle_end/base_types/compilation_unit.mli @@ -25,6 +25,7 @@ val create : Ident.t -> Linkage_name.t -> t val get_persistent_ident : t -> Ident.t val get_linkage_name : t -> Linkage_name.t +val is_current : t -> bool val set_current : t -> unit val get_current : unit -> t option val get_current_exn : unit -> t diff --git a/middle_end/base_types/mutable_variable.ml b/middle_end/base_types/mutable_variable.ml index a320806e..04e952d0 100644 --- a/middle_end/base_types/mutable_variable.ml +++ b/middle_end/base_types/mutable_variable.ml @@ -16,76 +16,6 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -type t = { - compilation_unit : Compilation_unit.t; - ident : Ident.t; -} +include Variable -include Identifiable.Make (struct - type nonrec t = t - - let compare v1 v2 = - let c = Ident.compare v1.ident v2.ident in - if c = 0 - then Compilation_unit.compare v1.compilation_unit v2.compilation_unit - else c - - let output c v = Ident.output c v.ident - - let hash v = Ident.hash v.ident - - let equal v1 v2 = - Ident.same v1.ident v2.ident && - Compilation_unit.equal v1.compilation_unit v2.compilation_unit - - let print ppf v = - Format.fprintf ppf "%a.%a" - Compilation_unit.print v.compilation_unit - Ident.print v.ident -end) - -let create ?current_compilation_unit name = - let compilation_unit = - match current_compilation_unit with - | Some compilation_unit -> compilation_unit - | None -> Compilation_unit.get_current_exn () - in - { compilation_unit; - ident = Ident.create name; - } - -let of_ident ident = create (Ident.name ident) - -let unique_ident t = - { t.ident with - name = - Format.asprintf "%a_%s" - Compilation_unit.print t.compilation_unit - t.ident.name; - } - -let rename ?current_compilation_unit ?append t = - let compilation_unit = - match current_compilation_unit with - | Some compilation_unit -> compilation_unit - | None -> Compilation_unit.get_current_exn () - in - let ident = - match append with - | None -> Ident.rename t.ident - | Some s -> Ident.create (t.ident.Ident.name ^ s) - in - { compilation_unit = compilation_unit; - ident; - } - -let freshen t = - rename t ~current_compilation_unit:(Compilation_unit.get_current_exn ()) - -let in_compilation_unit t cu = - Compilation_unit.equal t.compilation_unit cu - -let output_full c t = - Compilation_unit.output c t.compilation_unit; - Printf.fprintf c "."; - Ident.output c t.ident +let create_from_variable = rename diff --git a/middle_end/base_types/mutable_variable.mli b/middle_end/base_types/mutable_variable.mli index b33beee2..17fe208f 100644 --- a/middle_end/base_types/mutable_variable.mli +++ b/middle_end/base_types/mutable_variable.mli @@ -18,20 +18,30 @@ include Identifiable.S -val create : ?current_compilation_unit:Compilation_unit.t -> string -> t -val of_ident : Ident.t -> t +val create + : ?current_compilation_unit:Compilation_unit.t + -> Internal_variable_names.t + -> t -(** For [Flambda_to_clambda] only. *) -val unique_ident : t -> Ident.t +val create_with_same_name_as_ident : Ident.t -> t -val freshen : t -> t +val create_from_variable + : ?current_compilation_unit:Compilation_unit.t + -> Variable.t + -> t val rename : ?current_compilation_unit:Compilation_unit.t - -> ?append:string -> t -> t val in_compilation_unit : t -> Compilation_unit.t -> bool +val name : t -> string + +val unique_name : t -> string + +val print_list : Format.formatter -> t list -> unit +val print_opt : Format.formatter -> t option -> unit + val output_full : out_channel -> t -> unit diff --git a/middle_end/base_types/symbol.ml b/middle_end/base_types/symbol.ml index 3dee3cb1..940fc10d 100644 --- a/middle_end/base_types/symbol.ml +++ b/middle_end/base_types/symbol.ml @@ -16,60 +16,85 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -type t = { - compilation_unit : Compilation_unit.t; - label : Linkage_name.t; - hash : int; -} + +type t = + | Linkage of + { compilation_unit : Compilation_unit.t; + label : Linkage_name.t; + hash : int; } + | Variable of + { compilation_unit : Compilation_unit.t; + variable : Variable.t; } + +let label t = + match t with + | Linkage { label; _ } -> label + | Variable { variable; _ } -> + (* Use the variable's compilation unit for the label, since the + symbol's compilation unit might be a pack *) + let compilation_unit = Variable.get_compilation_unit variable in + let unit_linkage_name = + Linkage_name.to_string + (Compilation_unit.get_linkage_name compilation_unit) + in + let label = unit_linkage_name ^ "__" ^ Variable.unique_name variable in + Linkage_name.create label include Identifiable.Make (struct + type nonrec t = t let compare t1 t2 = - (* Linkage names are unique across a whole project, so just comparing - those is sufficient. *) if t1 == t2 then 0 - else - let c = compare t1.hash t2.hash in - if c <> 0 then c - else Linkage_name.compare t1.label t2.label + else begin + match t1, t2 with + | Linkage _, Variable _ -> 1 + | Variable _, Linkage _ -> -1 + | Linkage l1, Linkage l2 -> + let c = compare l1.hash l2.hash in + if c <> 0 then c else begin + (* Linkage names are unique across a whole project, so just comparing + those is sufficient. *) + Linkage_name.compare l1.label l2.label + end + | Variable v1, Variable v2 -> + Variable.compare v1.variable v2.variable + end let equal x y = if x == y then true else compare x y = 0 - let output chan t = Linkage_name.output chan t.label + let output chan t = + Linkage_name.output chan (label t) - let hash t = t.hash + let hash t = + match t with + | Linkage { hash; _ } -> hash + | Variable { variable } -> Variable.hash variable let print ppf t = - Compilation_unit.print ppf t.compilation_unit; - Format.pp_print_string ppf "."; - Linkage_name.print ppf t.label + Linkage_name.print ppf (label t) + end) -let create compilation_unit label = - let unit_linkage_name = - Linkage_name.to_string - (Compilation_unit.get_linkage_name compilation_unit) - in - let label = - Linkage_name.create - (unit_linkage_name ^ "__" ^ (Linkage_name.to_string label)) - in +let of_global_linkage compilation_unit label = let hash = Linkage_name.hash label in - { compilation_unit; label; hash; } + Linkage { compilation_unit; hash; label } -let unsafe_create compilation_unit label = - let hash = Linkage_name.hash label in - { compilation_unit; label; hash; } +let of_variable variable = + let compilation_unit = Variable.get_compilation_unit variable in + Variable { variable; compilation_unit } let import_for_pack ~pack:compilation_unit symbol = - let hash = Linkage_name.hash symbol.label in - { compilation_unit; label = symbol.label; hash; } + match symbol with + | Linkage l -> Linkage { l with compilation_unit } + | Variable v -> Variable { v with compilation_unit } -let compilation_unit t = t.compilation_unit -let label t = t.label +let compilation_unit t = + match t with + | Linkage { compilation_unit; _ } -> compilation_unit + | Variable { compilation_unit; _ } -> compilation_unit let print_opt ppf = function | None -> Format.fprintf ppf "" diff --git a/middle_end/base_types/symbol.mli b/middle_end/base_types/symbol.mli index fdf6aae2..d2771af2 100644 --- a/middle_end/base_types/symbol.mli +++ b/middle_end/base_types/symbol.mli @@ -28,10 +28,11 @@ include Identifiable.S -val create : Compilation_unit.t -> Linkage_name.t -> t +val of_variable : Variable.t -> t + (* Create the symbol without prefixing with the compilation unit. - Used for predefined exceptions *) -val unsafe_create : Compilation_unit.t -> Linkage_name.t -> t + Used for global symbols like predefined exceptions *) +val of_global_linkage : Compilation_unit.t -> Linkage_name.t -> t val import_for_pack : pack:Compilation_unit.t -> t -> t diff --git a/middle_end/base_types/variable.ml b/middle_end/base_types/variable.ml index b2ad07a0..edfdf1f8 100644 --- a/middle_end/base_types/variable.ml +++ b/middle_end/base_types/variable.ml @@ -61,7 +61,7 @@ end) let previous_name_stamp = ref (-1) -let create ?current_compilation_unit name = +let create_with_name_string ?current_compilation_unit name = let compilation_unit = match current_compilation_unit with | Some compilation_unit -> compilation_unit @@ -76,29 +76,23 @@ let create ?current_compilation_unit name = name_stamp; } -let create_with_same_name_as_ident ident = create (Ident.name ident) +let create ?current_compilation_unit name = + let name = (name : Internal_variable_names.t :> string) in + create_with_name_string ?current_compilation_unit name -let clambda_name t = - (Compilation_unit.string_for_printing t.compilation_unit) ^ "_" ^ t.name +let create_with_same_name_as_ident ident = + create_with_name_string (Ident.name ident) -let rename ?current_compilation_unit ?append t = - let current_compilation_unit = - match current_compilation_unit with - | Some compilation_unit -> compilation_unit - | None -> Compilation_unit.get_current_exn () - in - let name = - match append with - | None -> t.name - | Some s -> t.name ^ s - in - create ~current_compilation_unit name +let rename ?current_compilation_unit t = + create_with_name_string ?current_compilation_unit t.name let in_compilation_unit t cu = Compilation_unit.equal cu t.compilation_unit let get_compilation_unit t = t.compilation_unit +let name t = t.name + let unique_name t = t.name ^ "_" ^ (string_of_int t.name_stamp) diff --git a/middle_end/base_types/variable.mli b/middle_end/base_types/variable.mli index 9cd469b0..b5d3f136 100644 --- a/middle_end/base_types/variable.mli +++ b/middle_end/base_types/variable.mli @@ -28,20 +28,21 @@ include Identifiable.S -val create : ?current_compilation_unit:Compilation_unit.t -> string -> t +val create + : ?current_compilation_unit:Compilation_unit.t + -> Internal_variable_names.t + -> t val create_with_same_name_as_ident : Ident.t -> t -val clambda_name : t -> string -(* CR-someday pchambart: Should we propagate Variable.t into clambda ??? *) - val rename : ?current_compilation_unit:Compilation_unit.t - -> ?append:string -> t -> t val in_compilation_unit : t -> Compilation_unit.t -> bool +val name : t -> string + val unique_name : t -> string val get_compilation_unit : t -> Compilation_unit.t diff --git a/middle_end/closure_conversion.ml b/middle_end/closure_conversion.ml index 807889fc..7831b0b1 100755 --- a/middle_end/closure_conversion.ml +++ b/middle_end/closure_conversion.ml @@ -19,9 +19,10 @@ module Env = Closure_conversion_aux.Env module Function_decls = Closure_conversion_aux.Function_decls module Function_decl = Function_decls.Function_decl -module IdentSet = Lambda.IdentSet +module Names = Internal_variable_names let name_expr = Flambda_utils.name_expr +let name_expr_from_var = Flambda_utils.name_expr_from_var type t = { current_unit_id : Ident.t; @@ -70,11 +71,9 @@ let add_default_argument_wrappers lam = (** Generate a wrapper ("stub") function that accepts a tuple argument and calls another function with arguments extracted in the obvious manner from the tuple. *) -let tupled_function_call_stub original_params unboxed_version +let tupled_function_call_stub original_params unboxed_version ~closure_bound_var : Flambda.function_declaration = - let tuple_param_var = - Variable.rename ~append:"tupled_stub_param" unboxed_version - in + let tuple_param_var = Variable.rename unboxed_version in let params = List.map (fun p -> Variable.rename p) original_params in let call : Flambda.t = Apply ({ @@ -100,57 +99,59 @@ let tupled_function_call_stub original_params unboxed_version Flambda.create_function_declaration ~params:[tuple_param] ~body ~stub:true ~dbg:Debuginfo.none ~inline:Default_inline ~specialise:Default_specialise ~is_a_functor:false + ~closure_origin:(Closure_origin.create (Closure_id.wrap closure_bound_var)) let register_const t (constant:Flambda.constant_defining_value) name - : Flambda.constant_defining_value_block_field * string = - let current_compilation_unit = Compilation_unit.get_current_exn () in - (* Create a variable to ensure uniqueness of the symbol *) - let var = Variable.create ~current_compilation_unit name in - let symbol = - Symbol.create current_compilation_unit - (Linkage_name.create (Variable.unique_name var)) - in + : Flambda.constant_defining_value_block_field * Internal_variable_names.t = + let var = Variable.create name in + let symbol = Symbol.of_variable var in t.declared_symbols <- (symbol, constant) :: t.declared_symbols; Symbol symbol, name let rec declare_const t (const : Lambda.structured_constant) - : Flambda.constant_defining_value_block_field * string = + : Flambda.constant_defining_value_block_field * Internal_variable_names.t = match const with - | Const_base (Const_int c) -> Const (Int c), "int" - | Const_base (Const_char c) -> Const (Char c), "char" + | Const_base (Const_int c) -> (Const (Int c), Names.const_int) + | Const_base (Const_char c) -> (Const (Char c), Names.const_char) | Const_base (Const_string (s, _)) -> let const, name = if Config.safe_string then - Flambda.Allocated_const (Immutable_string s), "immstring" - else Flambda.Allocated_const (String s), "string" + (Flambda.Allocated_const (Immutable_string s), + Names.const_immstring) + else + (Flambda.Allocated_const (String s), + Names.const_string) in register_const t const name | Const_base (Const_float c) -> register_const t (Allocated_const (Float (float_of_string c))) - "float" + Names.const_float | Const_base (Const_int32 c) -> - register_const t (Allocated_const (Int32 c)) "int32" + register_const t (Allocated_const (Int32 c)) + Names.const_int32 | Const_base (Const_int64 c) -> - register_const t (Allocated_const (Int64 c)) "int64" + register_const t (Allocated_const (Int64 c)) + Names.const_int64 | Const_base (Const_nativeint c) -> - register_const t (Allocated_const (Nativeint c)) "nativeint" - | Const_pointer c -> Const (Const_pointer c), "pointer" + register_const t (Allocated_const (Nativeint c)) Names.const_nativeint + | Const_pointer c -> Const (Const_pointer c), Names.const_ptr | Const_immstring c -> - register_const t (Allocated_const (Immutable_string c)) "immstring" + register_const t (Allocated_const (Immutable_string c)) + Names.const_immstring | Const_float_array c -> register_const t (Allocated_const (Immutable_float_array (List.map float_of_string c))) - "float_array" + Names.const_float_array | Const_block (tag, consts) -> let const : Flambda.constant_defining_value = Block (Tag.create_exn tag, List.map (fun c -> fst (declare_const t c)) consts) in - register_const t const "const_block" + register_const t const Names.const_block let close_const t (const : Lambda.structured_constant) - : Flambda.named * string = + : Flambda.named * Internal_variable_names.t = match declare_const t const with | Const c, name -> Const c, name @@ -164,14 +165,15 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = | var -> Var var | exception Not_found -> match Env.find_mutable_var_exn env id with - | mut_var -> name_expr (Read_mutable mut_var) ~name:"read_mutable" + | mut_var -> + name_expr (Read_mutable mut_var) ~name:Names.read_mutable | exception Not_found -> Misc.fatal_errorf "Closure_conversion.close: unbound identifier %a" Ident.print id end | Lconst cst -> let cst, name = close_const t cst in - name_expr cst ~name:("const_" ^ name) + name_expr cst ~name | Llet ((Strict | Alias | StrictOpt), _value_kind, id, defining_expr, body) -> (* TODO: keep value_kind in flambda *) let var = Variable.create_with_same_name_as_ident id in @@ -181,7 +183,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = let body = close t (Env.add_var env id var) body in Flambda.create_let var defining_expr body | Llet (Variable, block_kind, id, defining_expr, body) -> - let mut_var = Mutable_variable.of_ident id in + let mut_var = Mutable_variable.create_with_same_name_as_ident id in let var = Variable.create_with_same_name_as_ident id in let defining_expr = close_let_bound_expression t var env defining_expr @@ -194,15 +196,11 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = body; contents_kind = block_kind }) | Lfunction { kind; params; body; attr; loc; } -> - let name = - (* Name anonymous functions by their source location, if known. *) - if loc = Location.none then "anon-fn" - else Format.asprintf "anon-fn[%a]" Location.print_compact loc - in + let name = Names.anon_fn_with_loc loc in let closure_bound_var = Variable.create name in (* CR-soon mshinwell: some of this is now very similar to the let rec case below *) - let set_of_closures_var = Variable.create ("set_of_closures_" ^ name) in + let set_of_closures_var = Variable.create Names.set_of_closures in let set_of_closures = let decl = Function_decl.create ~let_rec_ident:None ~closure_bound_var ~kind @@ -216,16 +214,15 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = } in Flambda.create_let set_of_closures_var set_of_closures - (name_expr (Project_closure (project_closure)) - ~name:("project_closure_" ^ name)) + (name_expr (Project_closure (project_closure)) ~name) | Lapply { ap_func; ap_args; ap_loc; ap_should_be_tailcall = _; ap_inlined; ap_specialised; } -> Lift_code.lifting_helper (close_list t env ap_args) ~evaluation_order:`Right_to_left - ~name:"apply_arg" + ~name:Names.apply_arg ~create_body:(fun args -> let func = close t env ap_func in - let func_var = Variable.create "apply_funct" in + let func_var = Variable.create Names.apply_funct in Flambda.create_let func_var (Expr func) (Apply ({ func = func_var; @@ -270,19 +267,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = (* CR-someday lwhite: This is a very syntactic criteria. Adding an unused value to a set of recursive bindings changes how functions are represented at runtime. *) - let name = - (* The Microsoft assembler has a 247-character limit on symbol - names, so we keep them shorter to try not to hit this. *) - if Sys.win32 then begin - match defs with - | (id, _)::_ -> (Ident.unique_name id) ^ "_let_rec" - | _ -> "let_rec" - end else begin - String.concat "_and_" - (List.map (fun (id, _) -> Ident.unique_name id) defs) - end - in - let set_of_closures_var = Variable.create name in + let set_of_closures_var = Variable.create (Names.set_of_closures) in let set_of_closures = close_functions t env (Function_decls.create function_declarations) in @@ -316,14 +301,14 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = Let_rec (defs, close t env body) end | Lsend (kind, meth, obj, args, loc) -> - let meth_var = Variable.create "meth" in - let obj_var = Variable.create "obj" in + let meth_var = Variable.create Names.meth in + let obj_var = Variable.create Names.obj in let dbg = Debuginfo.from_location loc in Flambda.create_let meth_var (Expr (close t env meth)) (Flambda.create_let obj_var (Expr (close t env obj)) (Lift_code.lifting_helper (close_list t env args) ~evaluation_order:`Right_to_left - ~name:"send_arg" + ~name:Names.send_arg ~create_body:(fun args -> Send { kind; meth = meth_var; obj = obj_var; args; dbg; }))) | Lprim ((Pdivint Safe | Pmodint Safe @@ -332,11 +317,11 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = when not !Clflags.fast -> (* not -unsafe *) let arg2 = close t env arg2 in let arg1 = close t env arg1 in - let numerator = Variable.create "numerator" in - let denominator = Variable.create "denominator" in - let zero = Variable.create "zero" in - let is_zero = Variable.create "is_zero" in - let exn = Variable.create "division_by_zero" in + let numerator = Variable.create Names.numerator in + let denominator = Variable.create Names.denominator in + let zero = Variable.create Names.zero in + let is_zero = Variable.create Names.is_zero in + let exn = Variable.create Names.division_by_zero in let exn_symbol = t.symbol_for_global' Predef.ident_division_by_zero in @@ -376,7 +361,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = (Prim (comparison, [zero; denominator], dbg)) (If_then_else (is_zero, name_expr (Prim (Praise Raise_regular, [exn], dbg)) - ~name:"dummy", + ~name:Names.dummy, (* CR-someday pchambart: find the right event. mshinwell: I briefly looked at this, and couldn't figure it out. @@ -384,7 +369,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = are suitable. I had to add a new one for a similar case in the array data types work. mshinwell: deferred CR *) - name_expr ~name:"result" + name_expr ~name:Names.result (Prim (prim, [numerator; denominator], dbg)))))))) | Lprim ((Pdivint Safe | Pmodint Safe | Pdivbint { is_safe = Safe } | Pmodbint { is_safe = Safe }), _, _) @@ -393,16 +378,16 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = | Lprim (Psequor, [arg1; arg2], _) -> let arg1 = close t env arg1 in let arg2 = close t env arg2 in - let const_true = Variable.create "const_true" in - let cond = Variable.create "cond_sequor" in + let const_true = Variable.create Names.const_true in + let cond = Variable.create Names.cond_sequor in Flambda.create_let const_true (Const (Const_pointer 1)) (Flambda.create_let cond (Expr arg1) (If_then_else (cond, Var const_true, arg2))) | Lprim (Psequand, [arg1; arg2], _) -> let arg1 = close t env arg1 in let arg2 = close t env arg2 in - let const_false = Variable.create "const_false" in - let cond = Variable.create "cond_sequand" in + let const_false = Variable.create Names.const_false in + let cond = Variable.create Names.const_sequand in Flambda.create_let const_false (Const (Const_pointer 0)) (Flambda.create_let cond (Expr arg1) (If_then_else (cond, arg2, Var const_false))) @@ -425,12 +410,12 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = in close t env (Lambda.Lapply apply) | Lprim (Praise kind, [arg], loc) -> - let arg_var = Variable.create "raise_arg" in + let arg_var = Variable.create Names.raise_arg in let dbg = Debuginfo.from_location loc in Flambda.create_let arg_var (Expr (close t env arg)) (name_expr (Prim (Praise kind, [arg_var], dbg)) - ~name:"raise") + ~name:Names.raise) | Lprim (Pfield _, [Lprim (Pgetglobal id, [],_)], _) when Ident.same id t.current_unit_id -> Misc.fatal_errorf "[Pfield (Pgetglobal ...)] for the current compilation \ @@ -441,12 +426,12 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = | Lprim (Pgetglobal id, [], _) when Ident.is_predef_exn id -> let symbol = t.symbol_for_global' id in t.imported_symbols <- Symbol.Set.add symbol t.imported_symbols; - name_expr (Symbol symbol) ~name:"predef_exn" + name_expr (Symbol symbol) ~name:Names.predef_exn | Lprim (Pgetglobal id, [], _) -> assert (not (Ident.same id t.current_unit_id)); let symbol = t.symbol_for_global' id in t.imported_symbols <- Symbol.Set.add symbol t.imported_symbols; - name_expr (Symbol symbol) ~name:"Pgetglobal" + name_expr (Symbol symbol) ~name:Names.pgetglobal | Lprim (p, args, loc) -> (* One of the important consequences of the ANF-like representation here is that we obtain names corresponding to the components of @@ -454,28 +439,34 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = by the simplification pass to increase the likelihood of eliminating the allocation, since some field accesses can be tracked back to known field values. *) - let name = Printlambda.name_of_primitive p in let dbg = Debuginfo.from_location loc in Lift_code.lifting_helper (close_list t env args) ~evaluation_order:`Right_to_left - ~name:(name ^ "_arg") + ~name:(Names.of_primitive_arg p) ~create_body:(fun args -> name_expr (Prim (p, args, dbg)) - ~name) + ~name:(Names.of_primitive p)) | Lswitch (arg, sw, _loc) -> - let scrutinee = Variable.create "switch" in + let scrutinee = Variable.create Names.switch in let aux (i, lam) = i, close t env lam in - let zero_to_n = Numbers.Int.zero_to_n in + let nums sw_num cases default = + let module I = Numbers.Int in + match default with + | Some _ -> + I.zero_to_n (sw_num - 1) + | None -> + List.fold_left (fun set (i, _) -> I.Set.add i set) I.Set.empty cases + in Flambda.create_let scrutinee (Expr (close t env arg)) (Switch (scrutinee, - { numconsts = zero_to_n (sw.sw_numconsts - 1); + { numconsts = nums sw.sw_numconsts sw.sw_consts sw.sw_failaction; consts = List.map aux sw.sw_consts; - numblocks = zero_to_n (sw.sw_numblocks - 1); + numblocks = nums sw.sw_numblocks sw.sw_blocks sw.sw_failaction; blocks = List.map aux sw.sw_blocks; failaction = Misc.may_map (close t env) sw.sw_failaction; })) | Lstringswitch (arg, sw, def, _) -> - let scrutinee = Variable.create "string_switch" in + let scrutinee = Variable.create Names.string_switch in Flambda.create_let scrutinee (Expr (close t env arg)) (String_switch (scrutinee, List.map (fun (s, e) -> s, close t env e) sw, @@ -483,7 +474,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = | Lstaticraise (i, args) -> Lift_code.lifting_helper (close_list t env args) ~evaluation_order:`Right_to_left - ~name:"staticraise_arg" + ~name:Names.staticraise_arg ~create_body:(fun args -> let static_exn = Env.find_static_exception env i in Static_raise (static_exn, args)) @@ -498,19 +489,19 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = Try_with (close t env body, var, close t (Env.add_var env id var) handler) | Lifthenelse (cond, ifso, ifnot) -> let cond = close t env cond in - let cond_var = Variable.create "cond" in + let cond_var = Variable.create Names.cond in Flambda.create_let cond_var (Expr cond) (If_then_else (cond_var, close t env ifso, close t env ifnot)) | Lsequence (lam1, lam2) -> - let var = Variable.create "sequence" in + let var = Variable.create Names.sequence in let lam1 = Flambda.Expr (close t env lam1) in let lam2 = close t env lam2 in Flambda.create_let var lam1 lam2 | Lwhile (cond, body) -> While (close t env cond, close t env body) | Lfor (id, lo, hi, direction, body) -> let bound_var = Variable.create_with_same_name_as_ident id in - let from_value = Variable.create "for_from" in - let to_value = Variable.create "for_to" in + let from_value = Variable.create Names.for_from in + let to_value = Variable.create Names.for_to in let body = close t (Env.add_var env id bound_var) body in Flambda.create_let from_value (Expr (close t env lo)) (Flambda.create_let to_value (Expr (close t env hi)) @@ -524,7 +515,7 @@ let rec close t env (lam : Lambda.lambda) : Flambda.t = variable %s in assignment" (Ident.unique_name id) in - let new_value_var = Variable.create "new_value" in + let new_value_var = Variable.create Names.new_value in Flambda.create_let new_value_var (Expr (close t env new_value)) (Assign { being_assigned; new_value = new_value_var; }) | Levent (lam, _) -> close t env lam @@ -567,35 +558,42 @@ and close_functions t external_env function_declarations : Flambda.named = let param_vars = List.map (Env.find_var closure_env) params in let params = List.map Parameter.wrap param_vars in let closure_bound_var = Function_decl.closure_bound_var decl in + let unboxed_version = Variable.rename closure_bound_var in let body = close t closure_env body in + let closure_origin = + Closure_origin.create (Closure_id.wrap unboxed_version) + in let fun_decl = Flambda.create_function_declaration ~params ~body ~stub ~dbg ~inline:(Function_decl.inline decl) ~specialise:(Function_decl.specialise decl) ~is_a_functor:(Function_decl.is_a_functor decl) + ~closure_origin in match Function_decl.kind decl with | Curried -> Variable.Map.add closure_bound_var fun_decl map | Tupled -> let unboxed_version = Variable.rename closure_bound_var in let generic_function_stub = - tupled_function_call_stub param_vars unboxed_version + tupled_function_call_stub param_vars unboxed_version ~closure_bound_var in Variable.Map.add unboxed_version fun_decl (Variable.Map.add closure_bound_var generic_function_stub map) in let function_decls = - Flambda.create_function_declarations - ~funs: - (List.fold_left close_one_function Variable.Map.empty - (Function_decls.to_list function_declarations)) + let is_classic_mode = !Clflags.classic_inlining in + let funs = + List.fold_left close_one_function Variable.Map.empty + (Function_decls.to_list function_declarations) + in + Flambda.create_function_declarations ~is_classic_mode ~funs in (* The closed representation of a set of functions is a "set of closures". (For avoidance of doubt, the runtime representation of the *whole set* is a single block with tag [Closure_tag].) *) let set_of_closures = let free_vars = - IdentSet.fold (fun var map -> + Ident.Set.fold (fun var map -> let internal_var = Env.find_var closure_env_without_parameters var in @@ -626,9 +624,7 @@ and close_let_bound_expression t ?let_rec_ident let_bound_var env Function_decl.create ~let_rec_ident ~closure_bound_var ~kind ~params ~body ~attr ~loc in - let set_of_closures_var = - Variable.rename let_bound_var ~append:"_set_of_closures" - in + let set_of_closures_var = Variable.rename let_bound_var in let set_of_closures = close_functions t env (Function_decls.create [decl]) in @@ -638,8 +634,8 @@ and close_let_bound_expression t ?let_rec_ident let_bound_var env } in Expr (Flambda.create_let set_of_closures_var set_of_closures - (name_expr (Project_closure (project_closure)) - ~name:(Variable.unique_name let_bound_var))) + (name_expr_from_var (Project_closure (project_closure)) + ~var:let_bound_var)) | lam -> Expr (close t env lam) let lambda_to_flambda ~backend ~module_ident ~size ~filename lam @@ -657,8 +653,8 @@ let lambda_to_flambda ~backend ~module_ident ~size ~filename lam in let module_symbol = Backend.symbol_for_global' module_ident in let block_symbol = - let linkage_name = Linkage_name.create "module_as_block" in - Symbol.create compilation_unit linkage_name + let var = Variable.create Internal_variable_names.module_as_block in + Symbol.of_variable var in (* The global module block is built by accessing the fields of all the introduced symbols. *) @@ -666,10 +662,9 @@ let lambda_to_flambda ~backend ~module_ident ~size ~filename lam compiled. *) let fields = Array.init size (fun pos -> - let pos_str = string_of_int pos in - let sym_v = Variable.create ("block_symbol_" ^ pos_str) in - let result_v = Variable.create ("block_symbol_get_" ^ pos_str) in - let value_v = Variable.create ("block_symbol_get_field_" ^ pos_str) in + let sym_v = Variable.create Names.block_symbol in + let result_v = Variable.create Names.block_symbol_get in + let value_v = Variable.create Names.block_symbol_get_field in Flambda.create_let sym_v (Symbol block_symbol) (Flambda.create_let result_v diff --git a/middle_end/closure_conversion_aux.ml b/middle_end/closure_conversion_aux.ml index 2dbc38e3..b3e67a6f 100644 --- a/middle_end/closure_conversion_aux.ml +++ b/middle_end/closure_conversion_aux.ml @@ -16,8 +16,6 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -module IdentSet = Lambda.IdentSet - module Env = struct type t = { variables : Variable.t Ident.tbl; @@ -90,7 +88,7 @@ module Function_decls = struct kind : Lambda.function_kind; params : Ident.t list; body : Lambda.lambda; - free_idents_of_body : IdentSet.t; + free_idents_of_body : Ident.Set.t; attr : Lambda.function_attribute; loc : Location.t; } @@ -128,7 +126,7 @@ module Function_decls = struct type t = { function_decls : Function_decl.t list; - all_free_idents : IdentSet.t; + all_free_idents : Ident.Set.t; } (* All identifiers free in the bodies of the given function declarations, @@ -140,8 +138,8 @@ module Function_decls = struct function_decls Variable.Map.empty let all_free_idents function_decls = - Variable.Map.fold (fun _ -> IdentSet.union) - (free_idents_by_function function_decls) IdentSet.empty + Variable.Map.fold (fun _ -> Ident.Set.union) + (free_idents_by_function function_decls) Ident.Set.empty (* All identifiers of simultaneously-defined functions in [ts]. *) let let_rec_idents function_decls = @@ -151,8 +149,8 @@ module Function_decls = struct let all_params function_decls = List.concat (List.map Function_decl.params function_decls) - let set_diff (from : IdentSet.t) (idents : Ident.t list) = - List.fold_right IdentSet.remove idents from + let set_diff (from : Ident.Set.t) (idents : Ident.t list) = + List.fold_right Ident.Set.remove idents from (* CR-someday lwhite: use a different name from above or explain the difference *) @@ -179,7 +177,7 @@ module Function_decls = struct t.function_decls (Env.clear_local_bindings external_env) in (* For free variables. *) - IdentSet.fold (fun id env -> - Env.add_var env id (Variable.create (Ident.name id))) + Ident.Set.fold (fun id env -> + Env.add_var env id (Variable.create_with_same_name_as_ident id)) t.all_free_idents closure_env end diff --git a/middle_end/closure_conversion_aux.mli b/middle_end/closure_conversion_aux.mli index 67ba1e11..f16f05f0 100755 --- a/middle_end/closure_conversion_aux.mli +++ b/middle_end/closure_conversion_aux.mli @@ -74,7 +74,7 @@ module Function_decls : sig val loc : t -> Location.t (* Like [all_free_idents], but for just one function. *) - val free_idents : t -> Lambda.IdentSet.t + val free_idents : t -> Ident.Set.t end type t @@ -84,7 +84,7 @@ module Function_decls : sig (* All identifiers free in the given function declarations after the binding of parameters and function identifiers has been performed. *) - val all_free_idents : t -> Lambda.IdentSet.t + val all_free_idents : t -> Ident.Set.t (* A map from identifiers to their corresponding [Variable.t]s whose domain is the set of all identifiers free in the bodies of the declarations that diff --git a/middle_end/flambda.ml b/middle_end/flambda.ml index a00091a2..e781af20 100644 --- a/middle_end/flambda.ml +++ b/middle_end/flambda.ml @@ -110,12 +110,14 @@ and set_of_closures = { } and function_declarations = { + is_classic_mode : bool; set_of_closures_id : Set_of_closures_id.t; set_of_closures_origin : Set_of_closures_origin.t; funs : function_declaration Variable.Map.t; } and function_declaration = { + closure_origin: Closure_origin.t; params : Parameter.t list; body : t; free_variables : Variable.Set.t; @@ -410,13 +412,15 @@ and print_set_of_closures ppf (set_of_closures : set_of_closures) = in fprintf ppf "@[<2>(set_of_closures id=%a@ %a@ @[<2>free_vars={%a@ }@]@ \ @[<2>specialised_args={%a})@]@ \ - @[<2>direct_call_surrogates=%a@]@]" + @[<2>direct_call_surrogates=%a@]@ \ + @[<2>set_of_closures_origin=%a@]@]]" Set_of_closures_id.print function_decls.set_of_closures_id funs function_decls.funs vars free_vars spec specialised_args (Variable.Map.print Variable.print) set_of_closures.direct_call_surrogates + Set_of_closures_origin.print function_decls.set_of_closures_origin and print_const ppf (c : const) = match c with @@ -428,7 +432,8 @@ let print_function_declarations ppf (fd : function_declarations) = let funs ppf = Variable.Map.iter (print_function_declaration ppf) in - fprintf ppf "@[<2>(%a)@]" funs fd.funs + fprintf ppf "@[<2>(%a)(origin = %a)@]" funs fd.funs + Set_of_closures_origin.print fd.set_of_closures_origin let print ppf flam = fprintf ppf "%a@." lam flam @@ -982,9 +987,39 @@ let free_symbols_program (program : program) = loop program.program_body; !symbols +let update_body_of_function_declaration (func_decl: function_declaration) + ~body : function_declaration = + { closure_origin = func_decl.closure_origin; + params = func_decl.params; + body; + free_variables = free_variables body; + free_symbols = free_symbols body; + stub = func_decl.stub; + dbg = func_decl.dbg; + inline = func_decl.inline; + specialise = func_decl.specialise; + is_a_functor = func_decl.is_a_functor; + } + +let update_function_decl's_params_and_body + (func_decl : function_declaration) ~params ~body = + { closure_origin = func_decl.closure_origin; + params; + body; + free_variables = free_variables body; + free_symbols = free_symbols body; + stub = func_decl.stub; + dbg = func_decl.dbg; + inline = func_decl.inline; + specialise = func_decl.specialise; + is_a_functor = func_decl.is_a_functor; + } + + let create_function_declaration ~params ~body ~stub ~dbg ~(inline : Lambda.inline_attribute) ~(specialise : Lambda.specialise_attribute) ~is_a_functor + ~closure_origin : function_declaration = begin match stub, inline with | true, (Never_inline | Default_inline) @@ -1002,7 +1037,8 @@ let create_function_declaration ~params ~body ~stub ~dbg "Stubs may not be annotated as [Always_specialise]: %a" print body end; - { params; + { closure_origin; + params; body; free_variables = free_variables body; free_symbols = free_symbols body; @@ -1013,33 +1049,68 @@ let create_function_declaration ~params ~body ~stub ~dbg is_a_functor; } -let create_function_declarations ~funs = +let update_function_declaration fun_decl ~params ~body = + let free_variables = free_variables body in + let free_symbols = free_symbols body in + { fun_decl with params; body; free_variables; free_symbols } + +let create_function_declarations ~is_classic_mode ~funs = let compilation_unit = Compilation_unit.get_current_exn () in let set_of_closures_id = Set_of_closures_id.create compilation_unit in let set_of_closures_origin = Set_of_closures_origin.create set_of_closures_id in - { set_of_closures_id; + { is_classic_mode; + set_of_closures_id; + set_of_closures_origin; + funs; + } + +let create_function_declarations_with_origin + ~is_classic_mode ~funs ~set_of_closures_origin = + let compilation_unit = Compilation_unit.get_current_exn () in + let set_of_closures_id = Set_of_closures_id.create compilation_unit in + { is_classic_mode; + set_of_closures_id; set_of_closures_origin; funs; } let update_function_declarations function_decls ~funs = + let is_classic_mode = function_decls.is_classic_mode in let compilation_unit = Compilation_unit.get_current_exn () in let set_of_closures_id = Set_of_closures_id.create compilation_unit in let set_of_closures_origin = function_decls.set_of_closures_origin in - { set_of_closures_id; + { is_classic_mode; + set_of_closures_id; set_of_closures_origin; funs; } +let create_function_declarations_with_closures_origin + ~is_classic_mode ~funs ~set_of_closures_origin = + let compilation_unit = Compilation_unit.get_current_exn () in + let set_of_closures_id = Set_of_closures_id.create compilation_unit in + { is_classic_mode; + set_of_closures_id; + set_of_closures_origin; + funs + } + let import_function_declarations_for_pack function_decls - import_set_of_closures_id import_set_of_closures_origin = - { set_of_closures_id = - import_set_of_closures_id function_decls.set_of_closures_id; - set_of_closures_origin = - import_set_of_closures_origin function_decls.set_of_closures_origin; - funs = function_decls.funs; + import_set_of_closures_id import_set_of_closures_origin = + let is_classic_mode = function_decls.is_classic_mode in + let set_of_closures_id = + import_set_of_closures_id function_decls.set_of_closures_id + in + let set_of_closures_origin = + import_set_of_closures_origin function_decls.set_of_closures_origin + in + let funs = function_decls.funs in + { is_classic_mode; + set_of_closures_id; + set_of_closures_origin; + funs; } let create_set_of_closures ~function_decls ~free_vars ~specialised_args diff --git a/middle_end/flambda.mli b/middle_end/flambda.mli index 695616f3..00e9dd16 100755 --- a/middle_end/flambda.mli +++ b/middle_end/flambda.mli @@ -285,6 +285,9 @@ and set_of_closures = private { } and function_declarations = private { + is_classic_mode: bool; + (** Indicates whether this [function_declarations] was compiled + with -Oclassic. *) set_of_closures_id : Set_of_closures_id.t; (** An identifier (unique across all Flambda trees currently in memory) of the set of closures associated with this set of function @@ -300,6 +303,7 @@ and function_declarations = private { } and function_declaration = private { + closure_origin: Closure_origin.t; params : Parameter.t list; body : t; (* CR-soon mshinwell: inconsistent naming free_variables/free_vars here and @@ -553,13 +557,44 @@ val create_function_declaration -> inline:Lambda.inline_attribute -> specialise:Lambda.specialise_attribute -> is_a_functor:bool + -> closure_origin:Closure_origin.t + -> function_declaration + +(** Create a function declaration based on another function declaration *) +val update_function_declaration + : function_declaration + -> params:Parameter.t list + -> body:t -> function_declaration (** Create a set of function declarations given the individual declarations. *) val create_function_declarations - : funs:function_declaration Variable.Map.t + : is_classic_mode:bool + -> funs:function_declaration Variable.Map.t + -> function_declarations + +(** Create a set of function declarations with a given set of closures + origin. *) +val create_function_declarations_with_origin + : is_classic_mode:bool + -> funs:function_declaration Variable.Map.t + -> set_of_closures_origin:Set_of_closures_origin.t -> function_declarations +(** Change only the code of a function declaration. *) +val update_body_of_function_declaration + : function_declaration + -> body:expr + -> function_declaration + +(** Change only the code and parameters of a function declaration. *) +(* CR-soon mshinwell: rename this to match new update function above *) +val update_function_decl's_params_and_body + : function_declaration + -> params:Parameter.t list + -> body:expr + -> function_declaration + (** Create a set of function declarations based on another set of function declarations. *) val update_function_declarations @@ -567,6 +602,12 @@ val update_function_declarations -> funs:function_declaration Variable.Map.t -> function_declarations +val create_function_declarations_with_closures_origin + : is_classic_mode: bool + -> funs:function_declaration Variable.Map.t + -> set_of_closures_origin:Set_of_closures_origin.t + -> function_declarations + val import_function_declarations_for_pack : function_declarations -> (Set_of_closures_id.t -> Set_of_closures_id.t) diff --git a/middle_end/flambda_invariants.ml b/middle_end/flambda_invariants.ml index 7236c17f..5c49a4b7 100755 --- a/middle_end/flambda_invariants.ml +++ b/middle_end/flambda_invariants.ml @@ -77,7 +77,6 @@ exception Access_to_global_module_identifier of Lambda.primitive exception Pidentity_should_not_occur exception Pdirapply_should_be_expanded exception Prevapply_should_be_expanded -exception Ploc_should_be_expanded exception Sequential_logical_operator_primitives_must_be_expanded of Lambda.primitive exception Var_within_closure_bound_multiple_times of Var_within_closure.t @@ -265,9 +264,11 @@ let variable_and_symbol_invariants (program : Flambda.program) = ({ Flambda.function_decls; free_vars; specialised_args; direct_call_surrogates = _; } as set_of_closures) = (* CR-soon mshinwell: check [direct_call_surrogates] *) - let { Flambda.set_of_closures_id; set_of_closures_origin; funs; } = + let { Flambda. is_classic_mode; + set_of_closures_id; set_of_closures_origin; funs; } = function_decls in + ignore (is_classic_mode : bool); ignore_set_of_closures_id set_of_closures_id; ignore_set_of_closures_origin set_of_closures_origin; let functions_in_closure = Variable.Map.keys funs in @@ -469,7 +470,6 @@ let primitive_invariants flam ~no_access_to_global_module_identifiers = | Pidentity -> raise Pidentity_should_not_occur | Pdirapply -> raise Pdirapply_should_be_expanded | Prevapply -> raise Prevapply_should_be_expanded - | Ploc _ -> raise Ploc_should_be_expanded | _ -> () end | _ -> ()) @@ -815,9 +815,6 @@ let check_exn ?(kind=Normal) ?(cmxfile=false) (flam:Flambda.program) = | Prevapply_should_be_expanded -> Format.eprintf ">> The Prevapply primitive should never occur in an \ Flambda expression (see simplif.ml); use Apply instead" - | Ploc_should_be_expanded -> - Format.eprintf ">> The Ploc primitive should never occur in an \ - Flambda expression (see translcore.ml); use Apply instead" | Move_to_a_closure_not_in_the_free_variables (start_from, move_to) -> Format.eprintf ">> A Move_within_set_of_closures from the closure %a \ to closures that are not parts of its free variables: %a" diff --git a/middle_end/flambda_iterators.ml b/middle_end/flambda_iterators.ml index 709ccc67..19f7d067 100644 --- a/middle_end/flambda_iterators.ml +++ b/middle_end/flambda_iterators.ml @@ -409,14 +409,8 @@ let map_general ~toplevel f f_named tree = func_decl end else begin done_something := true; - Flambda.create_function_declaration - ~params:func_decl.params - ~body:new_body - ~stub:func_decl.stub - ~dbg:func_decl.dbg - ~inline:func_decl.inline - ~specialise:func_decl.specialise - ~is_a_functor:func_decl.is_a_functor + Flambda.update_function_declaration func_decl + ~params:func_decl.params ~body:new_body end) function_decls.funs in @@ -499,14 +493,8 @@ let map_symbols_on_set_of_closures if not (body == func_decl.body) then begin done_something := true; end; - Flambda.create_function_declaration - ~params:func_decl.params - ~body - ~stub:func_decl.stub - ~dbg:func_decl.dbg - ~inline:func_decl.inline - ~specialise:func_decl.specialise - ~is_a_functor:func_decl.is_a_functor) + Flambda.update_function_declaration func_decl + ~params:func_decl.params ~body) function_decls.funs in if not !done_something then @@ -593,13 +581,8 @@ let map_function_bodies (set_of_closures : Flambda.set_of_closures) ~f = function_decl else begin done_something := true; - Flambda.create_function_declaration ~body:new_body - ~params:function_decl.params - ~stub:function_decl.stub - ~dbg:function_decl.dbg - ~inline:function_decl.inline - ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor + Flambda.update_function_declaration function_decl + ~body:new_body ~params:function_decl.params end) set_of_closures.function_decls.funs in @@ -629,13 +612,8 @@ let map_sets_of_closures_of_program (program : Flambda.program) function_decl else begin done_something := true; - Flambda.create_function_declaration ~body - ~params:function_decl.params - ~stub:function_decl.stub - ~dbg:function_decl.dbg - ~inline:function_decl.inline - ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor + Flambda.update_function_declaration function_decl + ~body ~params:function_decl.params end) set_of_closures.function_decls.funs in @@ -730,13 +708,8 @@ let map_exprs_at_toplevel_of_program (program : Flambda.program) function_decl else begin done_something := true; - Flambda.create_function_declaration ~body - ~params:function_decl.params - ~stub:function_decl.stub - ~dbg:function_decl.dbg - ~inline:function_decl.inline - ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor + Flambda.update_function_declaration function_decl + ~body ~params:function_decl.params end) set_of_closures.function_decls.funs in diff --git a/middle_end/flambda_utils.ml b/middle_end/flambda_utils.ml index f5f44b36..e5d2b715 100644 --- a/middle_end/flambda_utils.ml +++ b/middle_end/flambda_utils.ml @@ -16,7 +16,7 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -let name_expr (named : Flambda.named) ~name : Flambda.t = +let name_expr ~name (named : Flambda.named) : Flambda.t = let var = Variable.create ~current_compilation_unit:(Compilation_unit.get_current_exn ()) @@ -24,6 +24,14 @@ let name_expr (named : Flambda.named) ~name : Flambda.t = in Flambda.create_let var named (Var var) +let name_expr_from_var ~var (named : Flambda.named) : Flambda.t = + let var = + Variable.rename + ~current_compilation_unit:(Compilation_unit.get_current_exn ()) + var + in + Flambda.create_let var named (Var var) + let find_declaration cf ({ funs } : Flambda.function_declarations) = Variable.Map.find (Closure_id.unwrap cf) funs @@ -313,12 +321,14 @@ let toplevel_substitution sb tree = (* CR-someday mshinwell: Fix [Flambda_iterators] so this can be implemented properly. *) let toplevel_substitution_named sb named = - let expr = name_expr named ~name:"toplevel_substitution_named" in + let name = Internal_variable_names.toplevel_substitution_named in + let expr = name_expr named ~name in match toplevel_substitution sb expr with | Let let_expr -> let_expr.defining_expr | _ -> assert false -let make_closure_declaration ~id ~body ~params ~stub : Flambda.t = +let make_closure_declaration + ~is_classic_mode ~id ~body ~params ~stub : Flambda.t = let free_variables = Flambda.free_variables body in let param_set = Parameter.Set.vars params in if not (Variable.Set.subset param_set free_variables) then begin @@ -339,6 +349,7 @@ let make_closure_declaration ~id ~body ~params ~stub : Flambda.t = Flambda.create_function_declaration ~params:(List.map subst_param params) ~body ~stub ~dbg:Debuginfo.none ~inline:Default_inline ~specialise:Default_specialise ~is_a_functor:false + ~closure_origin:(Closure_origin.create (Closure_id.wrap id)) in assert (Variable.Set.equal (Variable.Set.map subst free_variables) function_declaration.free_variables); @@ -357,12 +368,13 @@ let make_closure_declaration ~id ~body ~params ~stub : Flambda.t = in let compilation_unit = Compilation_unit.get_current_exn () in let set_of_closures_var = - Variable.create "set_of_closures" + Variable.create Internal_variable_names.set_of_closures ~current_compilation_unit:compilation_unit in let set_of_closures = let function_decls = Flambda.create_function_declarations + ~is_classic_mode ~funs:(Variable.Map.singleton id function_declaration) in Flambda.create_set_of_closures ~function_decls ~free_vars @@ -376,7 +388,7 @@ let make_closure_declaration ~id ~body ~params ~stub : Flambda.t = } in let project_closure_var = - Variable.create "project_closure" + Variable.create Internal_variable_names.project_closure ~current_compilation_unit:compilation_unit in Flambda.create_let set_of_closures_var (Set_of_closures set_of_closures) @@ -466,7 +478,8 @@ let make_closure_map program = { function_decls } -> Variable.Map.iter (fun var _ -> let closure_id = Closure_id.wrap var in - map := Closure_id.Map.add closure_id function_decls !map) + let set_of_closures_id = function_decls.set_of_closures_id in + map := Closure_id.Map.add closure_id set_of_closures_id !map) function_decls.funs in Flambda_iterators.iter_on_set_of_closures_of_program @@ -474,16 +487,18 @@ let make_closure_map program = ~f:add_set_of_closures; !map -let make_closure_map' input = - let map = ref Closure_id.Map.empty in - let add_set_of_closures _ (function_decls : Flambda.function_declarations) = - Variable.Map.iter (fun var _ -> - let closure_id = Closure_id.wrap var in - map := Closure_id.Map.add closure_id function_decls !map) - function_decls.funs - in - Set_of_closures_id.Map.iter add_set_of_closures input; - !map +let all_lifted_constant_closures program = + List.fold_left (fun unchanged flambda -> + match flambda with + | (_, Flambda.Set_of_closures { function_decls = { funs } }) -> + Variable.Map.fold + (fun key (_ : Flambda.function_declaration) acc -> + Closure_id.Set.add (Closure_id.wrap key) acc) + funs + unchanged + | _ -> unchanged) + Closure_id.Set.empty + (all_lifted_constants program) let all_lifted_constant_sets_of_closures program = let set = ref Set_of_closures_id.Set.empty in @@ -511,34 +526,6 @@ let all_sets_of_closures_map program = set_of_closures !r); !r -let all_function_decls_indexed_by_set_of_closures_id program = - Set_of_closures_id.Map.map - (fun { Flambda. function_decls; _ } -> function_decls) - (all_sets_of_closures_map program) - -let all_function_decls_indexed_by_closure_id program = - let aux_fun function_decls fun_var _ map = - let closure_id = Closure_id.wrap fun_var in - Closure_id.Map.add closure_id function_decls map - in - let aux _ ({ function_decls; _ } : Flambda.set_of_closures) map = - Variable.Map.fold (aux_fun function_decls) function_decls.funs map - in - Set_of_closures_id.Map.fold aux (all_sets_of_closures_map program) - Closure_id.Map.empty - -let make_variable_symbol var = - Symbol.create (Compilation_unit.get_current_exn ()) - (Linkage_name.create - (Variable.unique_name (Variable.rename var))) - -let make_variables_symbol vars = - let name = - String.concat "_and_" - (List.map (fun var -> Variable.unique_name (Variable.rename var)) vars) - in - Symbol.create (Compilation_unit.get_current_exn ()) (Linkage_name.create name) - let substitute_read_symbol_field_for_variables (substitution : (Symbol.t * int list) Variable.Map.t) (expr : Flambda.t) = @@ -549,8 +536,10 @@ let substitute_read_symbol_field_for_variables | [] -> Symbol symbol | [i] -> Read_symbol_field (symbol, i) | h :: t -> - let block = Variable.create "symbol_field_block" in - let field = Variable.create "get_symbol_field" in + let block_name = Internal_variable_names.symbol_field_block in + let block = Variable.create block_name in + let field_name = Internal_variable_names.get_symbol_field in + let field = Variable.create field_name in Expr ( Flambda.create_let block (make_named t) (Flambda.create_let field diff --git a/middle_end/flambda_utils.mli b/middle_end/flambda_utils.mli index 37196c06..34a33db0 100644 --- a/middle_end/flambda_utils.mli +++ b/middle_end/flambda_utils.mli @@ -63,7 +63,8 @@ val description_of_toplevel_node : Flambda.t -> string lwhite: the params restriction seems odd, perhaps give a reason in the comment. *) val make_closure_declaration - : id:Variable.t + : is_classic_mode:bool + -> id:Variable.t -> body:Flambda.t -> params:Parameter.t list -> stub:bool @@ -87,7 +88,15 @@ val bind -> body:Flambda.t -> Flambda.t -val name_expr : Flambda.named -> name:string -> Flambda.t +val name_expr + : name:Internal_variable_names.t + -> Flambda.named + -> Flambda.t + +val name_expr_from_var + : var:Variable.t + -> Flambda.named + -> Flambda.t val compare_const : Flambda.const -> Flambda.const -> int @@ -107,17 +116,11 @@ val root_symbol : Flambda.program -> Symbol.t exception. *) val might_raise_static_exn : Flambda.named -> Static_exception.t -> bool -(** Creates a map from closure IDs to function declarations by iterating over +(** Creates a map from closure IDs to set_of_closure IDs by iterating over all sets of closures in the given program. *) val make_closure_map : Flambda.program - -> Flambda.function_declarations Closure_id.Map.t - -(** Like [make_closure_map], but takes a mapping from set of closures IDs to - function declarations, instead of a [program]. *) -val make_closure_map' - : Flambda.function_declarations Set_of_closures_id.Map.t - -> Flambda.function_declarations Closure_id.Map.t + -> Set_of_closures_id.t Closure_id.Map.t (** The definitions of all constants that have been lifted out to [Let_symbol] or [Let_rec_symbol] constructions. *) @@ -136,6 +139,8 @@ val all_lifted_constant_sets_of_closures : Flambda.program -> Set_of_closures_id.Set.t +val all_lifted_constant_closures : Flambda.program -> Closure_id.Set.t + (** All sets of closures in the given program (whether or not bound to a symbol.) *) val all_sets_of_closures : Flambda.program -> Flambda.set_of_closures list @@ -144,16 +149,6 @@ val all_sets_of_closures_map : Flambda.program -> Flambda.set_of_closures Set_of_closures_id.Map.t -val all_function_decls_indexed_by_set_of_closures_id - : Flambda.program - -> Flambda.function_declarations Set_of_closures_id.Map.t - -val all_function_decls_indexed_by_closure_id - : Flambda.program - -> Flambda.function_declarations Closure_id.Map.t - -val make_variable_symbol : Variable.t -> Symbol.t -val make_variables_symbol : Variable.t list -> Symbol.t (* CR-someday pchambart: A more general version of this function might take a [named] instead of a symbol and be called with @@ -165,7 +160,7 @@ val substitute_read_symbol_field_for_variables (** For the compilation of switch statements. *) module Switch_storer : sig - val mk_store : unit -> Flambda.t Switch.t_store + val mk_store : unit -> (Flambda.t, unit) Switch.t_store end (** Within a set of function declarations there is a set of function bodies, diff --git a/middle_end/freshening.ml b/middle_end/freshening.ml index 3d891cbd..839d5414 100644 --- a/middle_end/freshening.ml +++ b/middle_end/freshening.ml @@ -159,7 +159,7 @@ let add_variables' t ids = id' :: ids, t) ids ([], t) let active_add_mutable_variable t id = - let id' = Mutable_variable.freshen id in + let id' = Mutable_variable.rename id in let t = add_sb_mutable_var t id id' in id', t @@ -197,7 +197,11 @@ let rewrite_recursive_calls_with_symbols t | Inactive -> function_declarations | Active _ -> let all_free_symbols = - Flambda_utils.all_free_symbols function_declarations + Variable.Map.fold + (fun _ (function_decl : Flambda.function_declaration) + syms -> + Symbol.Set.union syms function_decl.free_symbols) + function_declarations.funs Symbol.Set.empty in let closure_symbols_used = ref false in let closure_symbols = @@ -230,9 +234,7 @@ let rewrite_recursive_calls_with_symbols t | e -> e) ffun.body in - Flambda.create_function_declaration ~params:ffun.params - ~body ~stub:ffun.stub ~dbg:ffun.dbg ~inline:ffun.inline - ~specialise:ffun.specialise ~is_a_functor:ffun.is_a_functor) + Flambda.update_body_of_function_declaration ffun ~body) function_declarations.funs in Flambda.update_function_declarations function_declarations ~funs @@ -314,10 +316,11 @@ module Project_var = struct Flambda_utils.toplevel_substitution subst.sb_var func_decl.body in let function_decl = - Flambda.create_function_declaration ~params - ~body ~stub:func_decl.stub ~dbg:func_decl.dbg + Flambda.create_function_declaration ~params ~body + ~stub:func_decl.stub ~dbg:func_decl.dbg ~inline:func_decl.inline ~specialise:func_decl.specialise ~is_a_functor:func_decl.is_a_functor + ~closure_origin:func_decl.closure_origin in function_decl, subst in diff --git a/middle_end/initialize_symbol_to_let_symbol.mli b/middle_end/initialize_symbol_to_let_symbol.mli index c431156b..fc54f760 100644 --- a/middle_end/initialize_symbol_to_let_symbol.mli +++ b/middle_end/initialize_symbol_to_let_symbol.mli @@ -16,6 +16,10 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] +val constant_field + : Flambda.t + -> Flambda.constant_defining_value_block_field option + (** Transform Initialize_symbol with only constant fields to let_symbol construction. *) val run : Flambda.program -> Flambda.program diff --git a/middle_end/inline_and_simplify.ml b/middle_end/inline_and_simplify.ml index 3c3ea48f..c25d3f5f 100755 --- a/middle_end/inline_and_simplify.ml +++ b/middle_end/inline_and_simplify.ml @@ -119,7 +119,9 @@ let simplify_free_variables_named env vars ~f : Flambda.named * R.t = in let body = match body with - | Is_named body -> Flambda_utils.name_expr body ~name:"simplify_fv" + | Is_named body -> + let name = Internal_variable_names.simplify_fv in + Flambda_utils.name_expr body ~name | Is_expr body -> body in Is_expr (W.create_let_reusing_defining_expr var named body), r @@ -357,13 +359,17 @@ let simplify_move_within_set_of_closures env r | Some _ | None -> match set_of_closures_symbol with | Some set_of_closures_symbol -> - let set_of_closures_var = Variable.create "symbol" in + let set_of_closures_var = + Variable.create Internal_variable_names.symbol + in let project_closure : Flambda.project_closure = { set_of_closures = set_of_closures_var; closure_id = move_to; } in - let project_closure_var = Variable.create "project_closure" in + let project_closure_var = + Variable.create Internal_variable_names.project_closure + in let let1 = Flambda.create_let project_closure_var (Project_closure project_closure) @@ -598,34 +604,17 @@ and simplify_set_of_closures original_env r ~inline_inside: (Inlining_decision.should_inline_inside_declaration function_decl) ~dbg:function_decl.dbg - ~f:(fun body_env -> simplify body_env r function_decl.body) - in - let inline : Lambda.inline_attribute = - match function_decl.inline with - | Default_inline -> - if !Clflags.classic_inlining && not function_decl.stub then - (* In classic-inlining mode, the inlining decision is taken at - definition site (here). If the function is small enough - (below the -inline threshold) it will always be inlined. *) - let inlining_threshold = - Inline_and_simplify_aux.initial_inlining_threshold - ~round:(E.round env) - in - if Inlining_cost.can_inline body inlining_threshold ~bonus:0 - then - Always_inline - else - Default_inline - else - Default_inline - | inline -> - inline + ~f:(fun body_env -> + assert (E.inside_set_of_closures_declaration + function_decls.set_of_closures_origin body_env); + simplify body_env r function_decl.body) in let function_decl = Flambda.create_function_declaration ~params:function_decl.params ~body ~stub:function_decl.stub ~dbg:function_decl.dbg - ~inline ~specialise:function_decl.specialise + ~inline:function_decl.inline ~specialise:function_decl.specialise ~is_a_functor:function_decl.is_a_functor + ~closure_origin:function_decl.closure_origin in let used_params' = Flambda.used_params function_decl in Variable.Map.add fun_var function_decl funs, @@ -642,11 +631,25 @@ and simplify_set_of_closures original_env r lazy (Invariant_params.invariant_params_in_recursion function_decls ~backend:(E.backend env)) in + let recursive = + lazy (Find_recursive_functions.in_function_declarations function_decls + ~backend:(E.backend env)) + in + let keep_body = + Inline_and_simplify_aux.keep_body_check + ~is_classic_mode:function_decls.is_classic_mode ~recursive + in + let function_decls_approx = + A.function_declarations_approx ~keep_body function_decls + in let value_set_of_closures = - A.create_value_set_of_closures ~function_decls + A.create_value_set_of_closures + ~function_decls:function_decls_approx ~bound_vars:internal_value_set_of_closures.bound_vars ~invariant_params + ~recursive ~specialised_args:internal_value_set_of_closures.specialised_args + ~free_vars:internal_value_set_of_closures.free_vars ~freshening:internal_value_set_of_closures.freshening ~direct_call_surrogates: internal_value_set_of_closures.direct_call_surrogates @@ -702,9 +705,7 @@ and simplify_apply env r ~(apply : Flambda.apply) : Flambda.t * R.t = | surrogate -> find_transitively surrogate in let surrogate = find_transitively surrogate in - let surrogate_var = - Variable.rename lhs_of_application ~append:"_surrogate" - in + let surrogate_var = Variable.rename lhs_of_application in let move_to_surrogate : Projection.move_within_set_of_closures = { closure = lhs_of_application; start_from = closure_id_being_applied; @@ -727,8 +728,9 @@ and simplify_apply env r ~(apply : Flambda.apply) : Flambda.t * R.t = let function_decls = value_set_of_closures.function_decls in let function_decl = try - Flambda_utils.find_declaration closure_id_being_applied - function_decls + Variable.Map.find + (Closure_id.unwrap closure_id_being_applied) + function_decls.funs with | Not_found -> Misc.fatal_errorf "When handling application expression, \ @@ -742,7 +744,7 @@ and simplify_apply env r ~(apply : Flambda.apply) : Flambda.t * R.t = | Direct _ -> r in let nargs = List.length args in - let arity = Flambda_utils.function_arity function_decl in + let arity = A.function_arity function_decl in let result, r = if nargs = arity then simplify_full_application env r ~function_decls @@ -780,7 +782,7 @@ and simplify_full_application env r ~function_decls ~lhs_of_application and simplify_partial_application env r ~lhs_of_application ~closure_id_being_applied ~function_decl ~args ~dbg ~inline_requested ~specialise_requested = - let arity = Flambda_utils.function_arity function_decl in + let arity = A.function_arity function_decl in assert (arity > List.length args); (* For simplicity, we disallow [@inline] attributes on partial applications. The user may always write an explicit wrapper instead @@ -807,7 +809,7 @@ and simplify_partial_application env r ~lhs_of_application | Default_specialise -> () end; let freshened_params = - List.map (fun p -> Parameter.rename p) function_decl.Flambda.params + List.map (fun p -> Parameter.rename p) function_decl.A.params in let applied_args, remaining_args = Misc.Stdlib.List.map2_prefix (fun arg id' -> id', arg) @@ -826,10 +828,10 @@ and simplify_partial_application env r ~lhs_of_application in let closure_variable = Variable.rename - ~append:"_partial_fun" (Closure_id.unwrap closure_id_being_applied) in Flambda_utils.make_closure_declaration ~id:closure_variable + ~is_classic_mode:false ~body ~params:remaining_args ~stub:true @@ -845,7 +847,7 @@ and simplify_partial_application env r ~lhs_of_application and simplify_over_application env r ~args ~args_approxs ~function_decls ~lhs_of_application ~closure_id_being_applied ~function_decl ~value_set_of_closures ~dbg ~inline_requested ~specialise_requested = - let arity = Flambda_utils.function_arity function_decl in + let arity = A.function_arity function_decl in assert (arity < List.length args); assert (List.length args = List.length args_approxs); let full_app_args, remaining_args = @@ -860,7 +862,7 @@ and simplify_over_application env r ~args ~args_approxs ~function_decls ~args:full_app_args ~args_approxs:full_app_approxs ~dbg ~inline_requested ~specialise_requested in - let func_var = Variable.create "full_apply" in + let func_var = Variable.create Internal_variable_names.full_apply in let expr : Flambda.t = Flambda.create_let func_var (Expr expr) (Apply { func = func_var; args = remaining_args; kind = Indirect; dbg; @@ -971,7 +973,7 @@ and simplify_named env r (tree : Flambda.named) : Flambda.named * R.t = | Some set_of_closures -> let expr = Flambda_utils.name_expr (Set_of_closures set_of_closures) - ~name:"remove_unused_arguments" + ~name:Internal_variable_names.remove_unused_arguments in simplify env r expr ~pass_name:"Remove_unused_arguments" | None -> @@ -1384,7 +1386,7 @@ and simplify_list env r l = else h' :: t', approxs, r and duplicate_function ~env ~(set_of_closures : Flambda.set_of_closures) - ~fun_var = + ~fun_var ~new_fun_var = let function_decl = match Variable.Map.find fun_var set_of_closures.function_decls.funs with | exception Not_found -> @@ -1417,6 +1419,8 @@ and duplicate_function ~env ~(set_of_closures : Flambda.set_of_closures) ~inline_inside:false ~dbg:function_decl.dbg ~f:(fun body_env -> + assert (E.inside_set_of_closures_declaration + function_decls.set_of_closures_origin body_env); simplify body_env (R.create ()) function_decl.body) in let function_decl = @@ -1424,6 +1428,7 @@ and duplicate_function ~env ~(set_of_closures : Flambda.set_of_closures) ~body ~stub:function_decl.stub ~dbg:function_decl.dbg ~inline:function_decl.inline ~specialise:function_decl.specialise ~is_a_functor:function_decl.is_a_functor + ~closure_origin:(Closure_origin.create (Closure_id.wrap new_fun_var)) in function_decl, specialised_args @@ -1457,11 +1462,24 @@ let constant_defining_value_approx lazy (Invariant_params.invariant_params_in_recursion function_decls ~backend:(E.backend env)) in + let recursive = + lazy (Find_recursive_functions.in_function_declarations function_decls + ~backend:(E.backend env)) + in let value_set_of_closures = + let keep_body = + Inline_and_simplify_aux.keep_body_check + ~is_classic_mode:function_decls.is_classic_mode ~recursive + in + let function_decls = + A.function_declarations_approx ~keep_body function_decls + in A.create_value_set_of_closures ~function_decls ~bound_vars:Var_within_closure.Map.empty ~invariant_params + ~recursive ~specialised_args:Variable.Map.empty + ~free_vars:Variable.Map.empty ~freshening:Freshening.Project_var.empty ~direct_call_surrogates:Closure_id.Map.empty in @@ -1491,29 +1509,29 @@ let constant_defining_value_approx end (* See documentation on [Let_rec_symbol] in flambda.mli. *) -let define_let_rec_symbol_approx env defs = +let define_let_rec_symbol_approx orig_env defs = (* First declare an empty version of the symbols *) - let env = - List.fold_left (fun env (symbol, _) -> - E.add_symbol env symbol (A.value_unresolved (Symbol symbol))) - env defs + let init_env = + List.fold_left (fun building_env (symbol, _) -> + E.add_symbol building_env symbol (A.value_unresolved (Symbol symbol))) + orig_env defs in - let rec loop times env = + let rec loop times lookup_env = if times <= 0 then - env + lookup_env else let env = - List.fold_left (fun newenv (symbol, constant_defining_value) -> + List.fold_left (fun building_env (symbol, constant_defining_value) -> let approx = - constant_defining_value_approx env constant_defining_value + constant_defining_value_approx lookup_env constant_defining_value in let approx = A.augment_with_symbol approx symbol in - E.redefine_symbol newenv symbol approx) - env defs + E.add_symbol building_env symbol approx) + orig_env defs in loop (times-1) env in - loop 2 env + loop 2 init_env let simplify_constant_defining_value env r symbol @@ -1573,19 +1591,32 @@ let rec simplify_program_body env r (program : Flambda.program_body) : Flambda.program_body * R.t = match program with | Let_rec_symbol (defs, program) -> - let env = define_let_rec_symbol_approx env defs in - let env, r, defs = - List.fold_left (fun (newenv, r, defs) (symbol, def) -> - let r, def, approx = - simplify_constant_defining_value env r symbol def - in - let approx = A.augment_with_symbol approx symbol in - let newenv = E.redefine_symbol newenv symbol approx in - (newenv, r, (symbol, def) :: defs)) + let set_of_closures_defs, other_defs = + List.partition + (function + | (_, Flambda.Set_of_closures _) -> true + | _ -> false) + defs in + let process_defs ~lookup_env ~env r defs = + List.fold_left (fun (building_env, r, defs) (symbol, def) -> + let r, def, approx = + simplify_constant_defining_value lookup_env r symbol def + in + let approx = A.augment_with_symbol approx symbol in + let building_env = E.add_symbol building_env symbol approx in + (building_env, r, (symbol, def) :: defs)) (env, r, []) defs in + let env, r, set_of_closures_defs = + let lookup_env = define_let_rec_symbol_approx env defs in + process_defs ~lookup_env ~env r set_of_closures_defs + in + let env, r, other_defs = + let lookup_env = define_let_rec_symbol_approx env other_defs in + process_defs ~lookup_env ~env r other_defs + in let program, r = simplify_program_body env r program in - Let_rec_symbol (defs, program), r + Let_rec_symbol (set_of_closures_defs @ other_defs, program), r | Let_symbol (symbol, constant_defining_value, program) -> let r, constant_defining_value, approx = simplify_constant_defining_value env r symbol constant_defining_value diff --git a/middle_end/inline_and_simplify.mli b/middle_end/inline_and_simplify.mli index a4ddf475..ad0845e2 100644 --- a/middle_end/inline_and_simplify.mli +++ b/middle_end/inline_and_simplify.mli @@ -34,5 +34,6 @@ val duplicate_function : env:Inline_and_simplify_aux.Env.t -> set_of_closures:Flambda.set_of_closures -> fun_var:Variable.t + -> new_fun_var:Variable.t -> Flambda.function_declaration * Flambda.specialised_to Variable.Map.t (* new specialised arguments *) diff --git a/middle_end/inline_and_simplify_aux.ml b/middle_end/inline_and_simplify_aux.ml index 56d556fc..39cb54f0 100644 --- a/middle_end/inline_and_simplify_aux.ml +++ b/middle_end/inline_and_simplify_aux.ml @@ -37,7 +37,7 @@ module Env = struct never_inline_inside_closures : bool; never_inline_outside_closures : bool; unroll_counts : int Set_of_closures_origin.Map.t; - inlining_counts : int Closure_id.Map.t; + inlining_counts : int Closure_origin.Map.t; actively_unrolling : int Set_of_closures_origin.Map.t; closure_depth : int; inlining_stats_closure_stack : Inlining_stats.Closure_stack.t; @@ -59,7 +59,7 @@ module Env = struct never_inline_inside_closures = false; never_inline_outside_closures = false; unroll_counts = Set_of_closures_origin.Map.empty; - inlining_counts = Closure_id.Map.empty; + inlining_counts = Closure_origin.Map.empty; actively_unrolling = Set_of_closures_origin.Map.empty; closure_depth = 0; inlining_stats_closure_stack = @@ -225,7 +225,7 @@ module Env = struct let activate_freshening t = { t with freshening = Freshening.activate t.freshening } - let enter_set_of_closures_declaration origin t = + let enter_set_of_closures_declaration t origin = { t with current_functions = Set_of_closures_origin.Set.add origin t.current_functions; } @@ -327,7 +327,7 @@ module Env = struct let inlining_allowed t id = let inlining_count = try - Closure_id.Map.find id t.inlining_counts + Closure_origin.Map.find id t.inlining_counts with Not_found -> max 1 (Clflags.Int_arg_helper.get ~key:t.round !Clflags.inline_max_unroll) @@ -337,13 +337,13 @@ module Env = struct let inside_inlined_function t id = let inlining_count = try - Closure_id.Map.find id t.inlining_counts + Closure_origin.Map.find id t.inlining_counts with Not_found -> max 1 (Clflags.Int_arg_helper.get ~key:t.round !Clflags.inline_max_unroll) in let inlining_counts = - Closure_id.Map.add id (inlining_count - 1) t.inlining_counts + Closure_origin.Map.add id (inlining_count - 1) t.inlining_counts in { t with inlining_counts } @@ -512,6 +512,38 @@ end module A = Simple_value_approx module E = Env +let keep_body_check ~is_classic_mode ~recursive = + if not is_classic_mode then begin + fun _ _ -> true + end else begin + let can_inline_non_rec_function (fun_decl : Flambda.function_declaration) = + (* In classic-inlining mode, the inlining decision is taken at + definition site (here). If the function is small enough + (below the -inline threshold) it will always be inlined. + + Closure gives a bonus of [8] to optional arguments. In classic + mode, however, we would inline functions with the "*opt*" argument + in all cases, as it is a stub. (This is ensured by + [middle_end/closure_conversion.ml]). + *) + let inlining_threshold = initial_inlining_threshold ~round:0 in + let bonus = Flambda_utils.function_arity fun_decl in + Inlining_cost.can_inline fun_decl.body inlining_threshold ~bonus + in + fun (var : Variable.t) (fun_decl : Flambda.function_declaration) -> + if fun_decl.stub then begin + true + end else if Variable.Set.mem var (Lazy.force recursive) then begin + false + end else begin + match fun_decl.inline with + | Default_inline -> can_inline_non_rec_function fun_decl + | Unroll factor -> factor > 0 + | Always_inline -> true + | Never_inline -> false + end + end + let prepare_to_simplify_set_of_closures ~env ~(set_of_closures : Flambda.set_of_closures) ~function_decls ~freshen @@ -608,8 +640,8 @@ let prepare_to_simplify_set_of_closures ~env Closure_id.Map.empty in let env = - E.enter_set_of_closures_declaration - function_decls.set_of_closures_origin env + E.enter_set_of_closures_declaration env + function_decls.set_of_closures_origin in (* we use the previous closure for evaluating the functions *) let internal_value_set_of_closures = @@ -618,8 +650,16 @@ let prepare_to_simplify_set_of_closures ~env Var_within_closure.Map.add (Var_within_closure.wrap id) desc map) free_vars Var_within_closure.Map.empty in + let free_vars = Variable.Map.map fst free_vars in + let invariant_params = lazy Variable.Map.empty in + let recursive = lazy (Variable.Map.keys function_decls.funs) in + let is_classic_mode = function_decls.is_classic_mode in + let keep_body = keep_body_check ~is_classic_mode ~recursive in + let function_decls = + A.function_declarations_approx ~keep_body function_decls + in A.create_value_set_of_closures ~function_decls ~bound_vars - ~invariant_params:(lazy Variable.Map.empty) ~specialised_args + ~free_vars ~invariant_params ~recursive ~specialised_args ~freshening ~direct_call_surrogates in (* Populate the environment with the approximation of each closure. diff --git a/middle_end/inline_and_simplify_aux.mli b/middle_end/inline_and_simplify_aux.mli index b9ea66f3..43619b2f 100755 --- a/middle_end/inline_and_simplify_aux.mli +++ b/middle_end/inline_and_simplify_aux.mli @@ -128,12 +128,6 @@ module Env : sig variables from outer scopes that are not accessible. *) val local : t -> t - (** Note that the inliner is descending into a function body from the given - set of closures. A set of such descents is maintained. *) - (* CR-someday mshinwell: consider changing name to remove "declaration". - Also, isn't this the inlining stack? Maybe we can use that instead. *) - val enter_set_of_closures_declaration : Set_of_closures_origin.t -> t -> t - (** Determine whether the inliner is currently inside a function body from the given set of closures. This is used to detect whether a given function call refers to a function which exists somewhere on the current @@ -200,11 +194,11 @@ module Env : sig (** Whether it is permissible to inline a call to a function in the given environment. *) - val inlining_allowed : t -> Closure_id.t -> bool + val inlining_allowed : t -> Closure_origin.t -> bool (** Whether the given environment is currently being used to rewrite the body of an inlined function. *) - val inside_inlined_function : t -> Closure_id.t -> t + val inside_inlined_function : t -> Closure_origin.t -> t (** If collecting inlining statistics, record that the inliner is about to descend into [closure_id]. This information enables us to produce a @@ -361,3 +355,10 @@ val prepare_to_simplify_closure -> parameter_approximations:Simple_value_approx.t Variable.Map.t -> set_of_closures_env:Env.t -> Env.t + +val keep_body_check + : is_classic_mode:bool + -> recursive:Variable.Set.t Lazy.t + -> Variable.t + -> Flambda.function_declaration + -> bool diff --git a/middle_end/inlining_cost.ml b/middle_end/inlining_cost.ml index 7b8f04f3..d288316a 100644 --- a/middle_end/inlining_cost.ml +++ b/middle_end/inlining_cost.ml @@ -53,7 +53,6 @@ let prim_size (prim : Lambda.primitive) args = | Parrayrefs _ -> 8 | Parraysets Pgenarray -> 22 | Parraysets _ -> 10 - | Pbittest -> 3 | Pbigarrayref (_, ndims, _, _) -> 4 + ndims * 6 | Pbigarrayset (_, ndims, _, _) -> 4 + ndims * 6 | Psequand | Psequor -> diff --git a/middle_end/inlining_decision.ml b/middle_end/inlining_decision.ml index ee7abf2d..b8ac437a 100755 --- a/middle_end/inlining_decision.ml +++ b/middle_end/inlining_decision.ml @@ -19,12 +19,16 @@ module A = Simple_value_approx module E = Inline_and_simplify_aux.Env module R = Inline_and_simplify_aux.Result -module U = Flambda_utils module W = Inlining_cost.Whether_sufficient_benefit module T = Inlining_cost.Threshold module S = Inlining_stats_types module D = S.Decision +let get_function_body (function_decl : A.function_declaration) = + match function_decl.function_body with + | None -> assert false + | Some function_body -> function_body + type ('a, 'b) inlining_result = | Changed of (Flambda.t * R.t) * 'a | Original of 'b @@ -34,26 +38,23 @@ type 'b good_idea = | Don't_try_it of 'b let inline env r ~lhs_of_application - ~(function_decls : Flambda.function_declarations) - ~closure_id_being_applied ~(function_decl : Flambda.function_declaration) + ~closure_id_being_applied + ~(function_decl : A.function_declaration) + ~(function_body : A.function_body) ~value_set_of_closures ~only_use_of_function ~original ~recursive ~(args : Variable.t list) ~size_from_approximation ~dbg ~simplify ~(inline_requested : Lambda.inline_attribute) ~(specialise_requested : Lambda.specialise_attribute) + ~fun_vars ~set_of_closures_origin ~self_call ~fun_cost ~inlining_threshold = let toplevel = E.at_toplevel env in let branch_depth = E.branch_depth env in let unrolling, always_inline, never_inline, env = - let unrolling = - E.actively_unrolling env function_decls.set_of_closures_origin - in + let unrolling = E.actively_unrolling env set_of_closures_origin in match unrolling with | Some count -> if count > 0 then - let env = - E.continue_actively_unrolling - env function_decls.set_of_closures_origin - in + let env = E.continue_actively_unrolling env set_of_closures_origin in true, true, false, env else false, false, true, env | None -> begin @@ -62,7 +63,7 @@ let inline env r ~lhs_of_application The call site annotation takes precedence *) match (inline_requested : Lambda.inline_attribute) with | Always_inline | Never_inline | Unroll _ -> inline_requested - | Default_inline -> function_decl.inline + | Default_inline -> function_body.inline in match inline_annotation with | Always_inline -> false, true, false, env @@ -72,7 +73,7 @@ let inline env r ~lhs_of_application if count > 0 then let env = E.start_actively_unrolling - env function_decls.set_of_closures_origin (count - 1) + env set_of_closures_origin (count - 1) in true, true, false, env else false, false, true, env @@ -87,15 +88,13 @@ let inline env r ~lhs_of_application Try_it else if self_call then Don't_try_it S.Not_inlined.Self_call - else if not (E.inlining_allowed env closure_id_being_applied) then + else if not (E.inlining_allowed env function_decl.closure_origin) then Don't_try_it S.Not_inlined.Unrolling_depth_exceeded else if only_use_of_function || always_inline then Try_it else if never_inline then Don't_try_it S.Not_inlined.Annotation - else if !Clflags.classic_inlining then - Don't_try_it S.Not_inlined.Classic_mode - else if not (E.unrolling_allowed env function_decls.set_of_closures_origin) + else if not (E.unrolling_allowed env set_of_closures_origin) && (Lazy.force recursive) then Don't_try_it S.Not_inlined.Unrolling_depth_exceeded else if remaining_inlining_threshold = T.Never_inline then @@ -152,14 +151,14 @@ let inline env r ~lhs_of_application else acc | None -> acc with Not_found -> acc) - function_decl.free_variables benefit + function_body.free_variables benefit in W.create_estimate ~original_size:Inlining_cost.direct_call_size ~new_size:body_size ~toplevel:(E.at_toplevel env) ~branch_depth:(E.branch_depth env) - ~lifting:function_decl.Flambda.is_a_functor + ~lifting:function_body.A.is_a_functor ~round:(E.round env) ~benefit in @@ -190,9 +189,9 @@ let inline env r ~lhs_of_application the function, without doing any further inlining upon it, to the call site. *) Inlining_transforms.inline_by_copying_function_body ~env - ~r:(R.reset_benefit r) ~function_decls ~lhs_of_application + ~r:(R.reset_benefit r) ~lhs_of_application ~closure_id_being_applied ~specialise_requested ~inline_requested - ~function_decl ~args ~dbg ~simplify + ~function_decl ~function_body ~fun_vars ~args ~dbg ~simplify in let num_direct_applications_seen = (R.num_direct_applications r_inlined) - (R.num_direct_applications r) @@ -220,9 +219,9 @@ let inline env r ~lhs_of_application let env = (* We decrement the unrolling count even if the function is not recursive to avoid having to check whether or not it is recursive *) - E.inside_unrolled_function env function_decls.set_of_closures_origin + E.inside_unrolled_function env set_of_closures_origin in - let env = E.inside_inlined_function env closure_id_being_applied in + let env = E.inside_inlined_function env function_decl.closure_origin in let env = if E.inlining_level env = 0 (* If the function was considered for inlining without considering @@ -242,7 +241,7 @@ let inline env r ~lhs_of_application W.create ~original body ~toplevel:(E.at_toplevel env) ~branch_depth:(E.branch_depth env) - ~lifting:function_decl.Flambda.is_a_functor + ~lifting:function_body.is_a_functor ~round:(E.round env) ~benefit:(R.benefit r_inlined) in @@ -261,14 +260,14 @@ let inline env r ~lhs_of_application let env = (* We decrement the unrolling count even if the function is recursive to avoid having to check whether or not it is recursive *) - E.inside_unrolled_function env function_decls.set_of_closures_origin + E.inside_unrolled_function env set_of_closures_origin in let body, r_inlined = simplify env r_inlined body in let wsb_with_subfunctions = W.create ~original body ~toplevel:(E.at_toplevel env) ~branch_depth:(E.branch_depth env) - ~lifting:function_decl.Flambda.is_a_functor + ~lifting:function_body.is_a_functor ~round:(E.round env) ~benefit:(R.benefit r_inlined) in @@ -298,37 +297,15 @@ let inline env r ~lhs_of_application end let specialise env r ~lhs_of_application - ~(function_decls : Flambda.function_declarations) - ~(function_decl : Flambda.function_declaration) + ~(function_decls : A.function_declarations) + ~(function_decl : A.function_declaration) ~closure_id_being_applied - ~(value_set_of_closures : Simple_value_approx.value_set_of_closures) + ~(value_set_of_closures : A.value_set_of_closures) ~args ~args_approxs ~dbg ~simplify ~original ~recursive ~self_call ~inlining_threshold ~fun_cost ~inline_requested ~specialise_requested = - let bound_vars = - lazy - (let closures_required = - Flambda_utils.closures_required_by_entry_point - ~entry_point:closure_id_being_applied - ~backend:(E.backend env) - function_decls - in - let bound_vars_required = - Variable.Set.fold (fun fun_var bound_vars_required -> - let bound_vars = - Flambda_utils.variables_bound_by_the_closure - (Closure_id.wrap fun_var) - function_decls - in - Variable.Set.union bound_vars bound_vars_required) - closures_required - Variable.Set.empty - in - Var_within_closure.Map.filter (fun var _approx -> - Variable.Set.mem (Var_within_closure.unwrap var) bound_vars_required) - value_set_of_closures.bound_vars) - in let invariant_params = value_set_of_closures.invariant_params in + let free_vars = value_set_of_closures.free_vars in let has_no_useful_approxes = lazy (List.for_all2 @@ -344,10 +321,13 @@ let specialise env r ~lhs_of_application | Always_specialise -> true, false | Never_specialise -> false, true | Default_specialise -> begin - match (function_decl.specialise : Lambda.specialise_attribute) with - | Always_specialise -> true, false - | Never_specialise -> false, true - | Default_specialise -> false, false + match function_decl.function_body with + | None -> false, true + | Some { specialise } -> + match (specialise : Lambda.specialise_attribute) with + | Always_specialise -> true, false + | Never_specialise -> false, true + | Default_specialise -> false, false end in let remaining_inlining_threshold : Inlining_cost.Threshold.t = @@ -360,7 +340,7 @@ let specialise env r ~lhs_of_application - is closed (it and all other members of the set of closures on which it depends); and - has useful approximations for some invariant parameters. *) - if !Clflags.classic_inlining then + if function_decls.is_classic_mode then Don't_try_it S.Not_specialised.Classic_mode else if self_call then Don't_try_it S.Not_specialised.Self_call @@ -375,7 +355,7 @@ let specialise env r ~lhs_of_application | T.Can_inline_if_no_larger_than threshold -> threshold in Don't_try_it (S.Not_specialised.Above_threshold threshold) - else if not (Var_within_closure.Map.is_empty (Lazy.force bound_vars)) then + else if not (Variable.Map.is_empty free_vars) then Don't_try_it S.Not_specialised.Not_closed else if not (Lazy.force recursive) then Don't_try_it S.Not_specialised.Not_recursive @@ -396,8 +376,9 @@ let specialise env r ~lhs_of_application ~r:(R.reset_benefit r) ~lhs_of_application ~function_decls ~closure_id_being_applied ~function_decl ~args ~args_approxs - ~invariant_params:value_set_of_closures.invariant_params + ~invariant_params:invariant_params ~specialised_args:value_set_of_closures.specialised_args + ~free_vars:value_set_of_closures.free_vars ~direct_call_surrogates:value_set_of_closures.direct_call_surrogates ~dbg ~simplify ~inline_requested in @@ -489,10 +470,10 @@ let specialise env r ~lhs_of_application Original decision end -let for_call_site ~env ~r ~(function_decls : Flambda.function_declarations) +let for_call_site ~env ~r ~(function_decls : A.function_declarations) ~lhs_of_application ~closure_id_being_applied - ~(function_decl : Flambda.function_declaration) - ~(value_set_of_closures : Simple_value_approx.value_set_of_closures) + ~(function_decl : A.function_declaration) + ~(value_set_of_closures : A.value_set_of_closures) ~args ~args_approxs ~dbg ~simplify ~inline_requested ~specialise_requested = if List.length args <> List.length args_approxs then begin @@ -526,134 +507,222 @@ let for_call_site ~env ~r ~(function_decls : Flambda.function_declarations) let original_r = R.set_approx (R.seen_direct_application r) (A.value_unknown Other) in - if function_decl.stub then - let body, r = - Inlining_transforms.inline_by_copying_function_body ~env - ~r ~function_decls ~lhs_of_application - ~closure_id_being_applied ~specialise_requested ~inline_requested - ~function_decl ~args ~dbg ~simplify - in - simplify env r body - else if E.never_inline env then - (* This case only occurs when examining the body of a stub function - but not in the context of inlining said function. As such, there - is nothing to do here (and no decision to report). *) - original, original_r - else begin - let env = E.unset_never_inline_inside_closures env in - let env = - E.note_entering_call env - ~closure_id:closure_id_being_applied ~dbg:dbg - in - let max_level = - Clflags.Int_arg_helper.get ~key:(E.round env) !Clflags.inline_max_depth - in - let raw_inlining_threshold = R.inlining_threshold r in - let max_inlining_threshold = - if E.at_toplevel env then - Inline_and_simplify_aux.initial_inlining_toplevel_threshold - ~round:(E.round env) - else - Inline_and_simplify_aux.initial_inlining_threshold ~round:(E.round env) - in - let unthrottled_inlining_threshold = - match raw_inlining_threshold with - | None -> max_inlining_threshold - | Some inlining_threshold -> inlining_threshold - in - let inlining_threshold = - T.min unthrottled_inlining_threshold max_inlining_threshold - in - let inlining_threshold_diff = - T.sub unthrottled_inlining_threshold inlining_threshold - in - let inlining_prevented = - match inlining_threshold with - | Never_inline -> true - | Can_inline_if_no_larger_than _ -> false - in - let simpl = - if inlining_prevented then - Original (D.Prevented Function_prevented_from_inlining) - else if E.inlining_level env >= max_level then - Original (D.Prevented Level_exceeded) - else begin - let self_call = - E.inside_set_of_closures_declaration - function_decls.set_of_closures_origin env - in - let fun_cost = - lazy - (Inlining_cost.can_try_inlining function_decl.body - inlining_threshold - ~number_of_arguments:(List.length function_decl.params) - (* CR-someday mshinwell: for the moment, this is None, since - the Inlining_cost code isn't checking sizes up to the max - inlining threshold---this seems to take too long. *) - ~size_from_approximation:None) - in - let fun_var = - U.find_declaration_variable closure_id_being_applied function_decls - in - let recursive = - lazy - (Variable.Set.mem fun_var - ((Find_recursive_functions.in_function_declarations - function_decls - ~backend:(E.backend env)))) - in - let specialise_result = - specialise env r ~lhs_of_application ~function_decls ~recursive - ~closure_id_being_applied ~function_decl ~value_set_of_closures - ~args ~args_approxs ~dbg ~simplify ~original ~inline_requested - ~specialise_requested ~fun_cost ~self_call ~inlining_threshold - in - match specialise_result with - | Changed (res, spec_reason) -> - Changed (res, D.Specialised spec_reason) - | Original spec_reason -> - let only_use_of_function = false in - (* If we didn't specialise then try inlining *) - let size_from_approximation = - match - Variable.Map.find fun_var (Lazy.force value_set_of_closures.size) - with - | size -> size - | exception Not_found -> + match function_decl.function_body with + | None -> original, original_r + | Some { stub; _ } -> + if stub then begin + let fun_vars = Variable.Map.keys function_decls.funs in + let function_body = get_function_body function_decl in + let body, r = + Inlining_transforms.inline_by_copying_function_body ~env + ~r ~fun_vars ~lhs_of_application + ~closure_id_being_applied ~specialise_requested ~inline_requested + ~function_decl ~function_body ~args ~dbg ~simplify + in + simplify env r body + end else if E.never_inline env then + (* This case only occurs when examining the body of a stub function + but not in the context of inlining said function. As such, there + is nothing to do here (and no decision to report). *) + original, original_r + else if function_decls.is_classic_mode then begin + let env = + E.note_entering_call env + ~closure_id:closure_id_being_applied ~dbg:dbg + in + let simpl = + match function_decl.function_body with + | None -> Original S.Not_inlined.Classic_mode + | Some function_body -> + let self_call = + E.inside_set_of_closures_declaration + function_decls.set_of_closures_origin env + in + let try_inlining = + if self_call then + Don't_try_it S.Not_inlined.Self_call + else if not (E.inlining_allowed env function_decl.closure_origin) then + Don't_try_it S.Not_inlined.Unrolling_depth_exceeded + else + Try_it + in + match try_inlining with + | Don't_try_it decision -> Original decision + | Try_it -> + let fun_vars = Variable.Map.keys function_decls.funs in + let body, r = + Inlining_transforms.inline_by_copying_function_body ~env + ~r ~function_body ~lhs_of_application + ~closure_id_being_applied ~specialise_requested ~inline_requested + ~function_decl ~fun_vars ~args ~dbg ~simplify + in + let env = E.note_entering_inlined env in + let env = + (* We decrement the unrolling count even if the function is not + recursive to avoid having to check whether or not it is + recursive *) + E.inside_unrolled_function env function_decls.set_of_closures_origin + in + let env = E.inside_inlined_function env function_decl.closure_origin in + Changed ((simplify env r body), S.Inlined.Classic_mode) + in + let res, decision = + match simpl with + | Original decision -> + let decision = + S.Decision.Unchanged (S.Not_specialised.Classic_mode, decision) + in + (original, original_r), decision + | Changed ((expr, r), decision) -> + let max_inlining_threshold = + if E.at_toplevel env then + Inline_and_simplify_aux.initial_inlining_toplevel_threshold + ~round:(E.round env) + else + Inline_and_simplify_aux.initial_inlining_threshold + ~round:(E.round env) + in + let raw_inlining_threshold = R.inlining_threshold r in + let unthrottled_inlining_threshold = + match raw_inlining_threshold with + | None -> max_inlining_threshold + | Some inlining_threshold -> inlining_threshold + in + let inlining_threshold = + T.min unthrottled_inlining_threshold max_inlining_threshold + in + let inlining_threshold_diff = + T.sub unthrottled_inlining_threshold inlining_threshold + in + let res = + if E.inlining_level env = 0 + then expr, R.set_inlining_threshold r raw_inlining_threshold + else expr, R.add_inlining_threshold r inlining_threshold_diff + in + res, S.Decision.Inlined (S.Not_specialised.Classic_mode, decision) + in + E.record_decision env decision; + res + end else begin + let function_body = get_function_body function_decl in + let env = E.unset_never_inline_inside_closures env in + let env = + E.note_entering_call env + ~closure_id:closure_id_being_applied ~dbg:dbg + in + let max_level = + Clflags.Int_arg_helper.get ~key:(E.round env) !Clflags.inline_max_depth + in + let raw_inlining_threshold = R.inlining_threshold r in + let max_inlining_threshold = + if E.at_toplevel env then + Inline_and_simplify_aux.initial_inlining_toplevel_threshold + ~round:(E.round env) + else + Inline_and_simplify_aux.initial_inlining_threshold ~round:(E.round env) + in + let unthrottled_inlining_threshold = + match raw_inlining_threshold with + | None -> max_inlining_threshold + | Some inlining_threshold -> inlining_threshold + in + let inlining_threshold = + T.min unthrottled_inlining_threshold max_inlining_threshold + in + let inlining_threshold_diff = + T.sub unthrottled_inlining_threshold inlining_threshold + in + let inlining_prevented = + match inlining_threshold with + | Never_inline -> true + | Can_inline_if_no_larger_than _ -> false + in + let simpl = + if inlining_prevented then + Original (D.Prevented Function_prevented_from_inlining) + else if E.inlining_level env >= max_level then + Original (D.Prevented Level_exceeded) + else begin + let self_call = + E.inside_set_of_closures_declaration + function_decls.set_of_closures_origin env + in + let fun_cost = + lazy + (Inlining_cost.can_try_inlining function_body.body + inlining_threshold + ~number_of_arguments:(List.length function_decl.params) + (* CR-someday mshinwell: for the moment, this is None, since + the Inlining_cost code isn't checking sizes up to the max + inlining threshold---this seems to take too long. *) + ~size_from_approximation:None) + in + let recursive = + lazy + (let fun_var = Closure_id.unwrap closure_id_being_applied in + Variable.Set.mem fun_var + (Lazy.force value_set_of_closures.recursive)) + in + let specialise_result = + specialise env r + ~function_decls ~function_decl + ~lhs_of_application ~recursive ~closure_id_being_applied + ~value_set_of_closures ~args ~args_approxs ~dbg ~simplify + ~original ~inline_requested ~specialise_requested ~fun_cost + ~self_call ~inlining_threshold + in + match specialise_result with + | Changed (res, spec_reason) -> + Changed (res, D.Specialised spec_reason) + | Original spec_reason -> + let only_use_of_function = false in + (* If we didn't specialise then try inlining *) + let size_from_approximation = + let fun_var = Closure_id.unwrap closure_id_being_applied in + match + Variable.Map.find fun_var (Lazy.force value_set_of_closures.size) + with + | size -> size + | exception Not_found -> Misc.fatal_errorf "Approximation does not give a size for the \ - function having fun_var %a. value_set_of_closures: %a" + function having fun_var %a. value_set_of_closures: %a" Variable.print fun_var A.print_value_set_of_closures value_set_of_closures + in + let fun_vars = Variable.Map.keys function_decls.funs in + let set_of_closures_origin = + function_decls.set_of_closures_origin + in + let inline_result = + inline env r ~lhs_of_application + ~closure_id_being_applied ~function_decl ~value_set_of_closures + ~only_use_of_function ~original ~recursive + ~inline_requested ~specialise_requested + ~fun_vars ~set_of_closures_origin ~args + ~size_from_approximation ~dbg ~simplify ~fun_cost ~self_call + ~inlining_threshold ~function_body + in + match inline_result with + | Changed (res, inl_reason) -> + Changed (res, D.Inlined (spec_reason, inl_reason)) + | Original inl_reason -> + Original (D.Unchanged (spec_reason, inl_reason)) + end + in + let res, decision = + match simpl with + | Original decision -> (original, original_r), decision + | Changed ((expr, r), decision) -> + let res = + if E.inlining_level env = 0 + then expr, R.set_inlining_threshold r raw_inlining_threshold + else expr, R.add_inlining_threshold r inlining_threshold_diff in - let inline_result = - inline env r ~function_decls ~lhs_of_application - ~closure_id_being_applied ~function_decl ~value_set_of_closures - ~only_use_of_function ~original ~recursive - ~inline_requested ~specialise_requested ~args - ~size_from_approximation ~dbg ~simplify ~fun_cost ~self_call - ~inlining_threshold - in - match inline_result with - | Changed (res, inl_reason) -> - Changed (res, D.Inlined (spec_reason, inl_reason)) - | Original inl_reason -> - Original (D.Unchanged (spec_reason, inl_reason)) - end - in - let res, decision = - match simpl with - | Original decision -> (original, original_r), decision - | Changed ((expr, r), decision) -> - let res = - if E.inlining_level env = 0 - then expr, R.set_inlining_threshold r raw_inlining_threshold - else expr, R.add_inlining_threshold r inlining_threshold_diff - in - res, decision - in - E.record_decision env decision; - res - end + res, decision + in + E.record_decision env decision; + res + end (* We do not inline inside stubs, which are always inlined at their call site. Inlining inside the declaration of a stub could result in more code than diff --git a/middle_end/inlining_decision.mli b/middle_end/inlining_decision.mli index 40cb4f66..3694e303 100644 --- a/middle_end/inlining_decision.mli +++ b/middle_end/inlining_decision.mli @@ -24,10 +24,10 @@ val for_call_site : env:Inline_and_simplify_aux.Env.t -> r:Inline_and_simplify_aux.Result.t - -> function_decls:Flambda.function_declarations + -> function_decls:Simple_value_approx.function_declarations -> lhs_of_application:Variable.t -> closure_id_being_applied:Closure_id.t - -> function_decl:Flambda.function_declaration + -> function_decl:Simple_value_approx.function_declaration -> value_set_of_closures:Simple_value_approx.value_set_of_closures -> args:Variable.t list -> args_approxs:Simple_value_approx.t list diff --git a/middle_end/inlining_stats_types.ml b/middle_end/inlining_stats_types.ml index ce434f1d..801ed84b 100644 --- a/middle_end/inlining_stats_types.ml +++ b/middle_end/inlining_stats_types.ml @@ -35,12 +35,17 @@ let print_calculation ~depth ~title ~subfunctions ppf wsb = module Inlined = struct type t = + | Classic_mode | Annotation | Decl_local_to_application | Without_subfunctions of Wsb.t | With_subfunctions of Wsb.t * Wsb.t let summary ppf = function + | Classic_mode -> + Format.pp_print_text ppf + "This function was inlined because it was small enough \ + to be inlined in `-Oclassic'" | Annotation -> Format.pp_print_text ppf "This function was inlined because of an annotation." @@ -57,6 +62,7 @@ module Inlined = struct the expected benefit outweighed the change in code size." let calculation ~depth ppf = function + | Classic_mode -> () | Annotation -> () | Decl_local_to_application -> () | Without_subfunctions wsb -> @@ -85,7 +91,8 @@ module Not_inlined = struct let summary ppf = function | Classic_mode -> Format.pp_print_text ppf - "This function was prevented from inlining by `-Oclassic'." + "This function was not inlined because it was too \ + large to be inlined in `-Oclassic'." | Above_threshold size -> Format.pp_print_text ppf "This function was not inlined because \ @@ -182,8 +189,8 @@ module Not_specialised = struct let summary ppf = function | Classic_mode -> Format.pp_print_text ppf - "This function was prevented from specialising by \ - `-Oclassic'." + "This function was not specialised because it was \ + compiled with `-Oclassic'." | Above_threshold size -> Format.pp_print_text ppf "This function was not specialised because \ diff --git a/middle_end/inlining_stats_types.mli b/middle_end/inlining_stats_types.mli index 1c0a20e1..9d476c89 100644 --- a/middle_end/inlining_stats_types.mli +++ b/middle_end/inlining_stats_types.mli @@ -20,6 +20,7 @@ module Inlined : sig type t = + | Classic_mode | Annotation | Decl_local_to_application | Without_subfunctions of diff --git a/middle_end/inlining_transforms.ml b/middle_end/inlining_transforms.ml index 68c8d3bc..b905c50b 100755 --- a/middle_end/inlining_transforms.ml +++ b/middle_end/inlining_transforms.ml @@ -19,45 +19,19 @@ module B = Inlining_cost.Benefit module E = Inline_and_simplify_aux.Env module R = Inline_and_simplify_aux.Result +module A = Simple_value_approx let new_var name = Variable.create name ~current_compilation_unit:(Compilation_unit.get_current_exn ()) -let which_function_parameters_can_we_specialise ~params ~args - ~args_approxs ~(invariant_params:Variable.Set.t Variable.Map.t lazy_t) - ~specialised_args = - assert (List.length params = List.length args); - assert (List.length args = List.length args_approxs); - List.fold_right2 (fun (var, arg) approx - (worth_specialising_args, spec_args, args, args_decl) -> - let spec_args = - if Variable.Map.mem var (Lazy.force invariant_params) || - Variable.Set.mem var specialised_args - then - Variable.Map.add var arg spec_args - else - spec_args - in - let worth_specialising_args = - if Simple_value_approx.useful approx - && Variable.Map.mem var (Lazy.force invariant_params) - then - Variable.Set.add var worth_specialising_args - else - worth_specialising_args - in - worth_specialising_args, spec_args, arg :: args, args_decl) - (List.combine params args) args_approxs - (Variable.Set.empty, Variable.Map.empty, [], []) - (** Fold over all variables bound by the given closure, which is bound to the variable [lhs_of_application], and corresponds to the given [function_decls]. Each variable bound by the closure is passed to the user-specified function as an [Flambda.named] value that projects the variable from its closure. *) let fold_over_projections_of_vars_bound_by_closure ~closure_id_being_applied - ~lhs_of_application ~function_decls ~init ~f = + ~lhs_of_application ~bound_variables ~init ~f = Variable.Set.fold (fun var acc -> let expr : Flambda.named = Project_var { @@ -67,8 +41,7 @@ let fold_over_projections_of_vars_bound_by_closure ~closure_id_being_applied } in f ~acc ~var ~expr) - (Flambda_utils.variables_bound_by_the_closure closure_id_being_applied - function_decls) + bound_variables init let set_inline_attribute_on_all_apply body inline specialise = @@ -80,7 +53,8 @@ let set_inline_attribute_on_all_apply body inline specialise = (** Assign fresh names for a function's parameters and rewrite the body to use these new names. *) let copy_of_function's_body_with_freshened_params env - ~(function_decl : Flambda.function_declaration) = + ~(function_decl : A.function_declaration) + ~(function_body : A.function_body) = let params = function_decl.params in let param_vars = Parameter.List.vars params in (* We cannot avoid the substitution in the case where we are inlining @@ -94,14 +68,14 @@ let copy_of_function's_body_with_freshened_params env if E.does_not_bind env param_vars && E.does_not_freshen env param_vars then - params, function_decl.body + params, function_body.body else let freshened_params = List.map (fun p -> Parameter.rename p) params in let subst = Variable.Map.of_list (List.combine param_vars (Parameter.List.vars freshened_params)) in - let body = Flambda_utils.toplevel_substitution subst function_decl.body in + let body = Flambda_utils.toplevel_substitution subst function_body.body in freshened_params, body (* CR-soon mshinwell: Add a note somewhere to explain why "bound by the closure" @@ -114,23 +88,26 @@ let copy_of_function's_body_with_freshened_params env (= "variables bound by the closure"), and any function identifiers introduced by the corresponding set of closures. *) let inline_by_copying_function_body ~env ~r - ~(function_decls : Flambda.function_declarations) ~lhs_of_application ~(inline_requested : Lambda.inline_attribute) ~(specialise_requested : Lambda.specialise_attribute) ~closure_id_being_applied - ~(function_decl : Flambda.function_declaration) ~args ~dbg ~simplify = + ~(function_decl : A.function_declaration) + ~(function_body : A.function_body) + ~fun_vars + ~args ~dbg ~simplify = assert (E.mem env lhs_of_application); assert (List.for_all (E.mem env) args); let r = - if function_decl.stub then r + if function_body.stub then r else R.map_benefit r B.remove_call in let freshened_params, body = - copy_of_function's_body_with_freshened_params env ~function_decl + copy_of_function's_body_with_freshened_params env + ~function_decl ~function_body in let body = - if function_decl.stub && + if function_body.stub && ((inline_requested <> Lambda.Default_inline) || (specialise_requested <> Lambda.Default_specialise)) then (* When the function inlined function is a stub, the annotation @@ -151,8 +128,14 @@ let inline_by_copying_function_body ~env ~r in (* Add bindings for the variables bound by the closure. *) let bindings_for_vars_bound_by_closure_and_params_to_args = + let bound_variables = + let params = Parameter.Set.vars function_decl.params in + Variable.Set.diff + (Variable.Set.diff function_body.free_variables params) + fun_vars + in fold_over_projections_of_vars_bound_by_closure ~closure_id_being_applied - ~lhs_of_application ~function_decls ~init:bindings_for_params_to_args + ~lhs_of_application ~bound_variables ~init:bindings_for_params_to_args ~f:(fun ~acc:body ~var ~expr -> Flambda.create_let var expr body) in (* Add bindings for variables corresponding to the functions introduced by @@ -161,10 +144,10 @@ let inline_by_copying_function_body ~env ~r applied to another closure in the same set. *) let expr = - Variable.Map.fold (fun another_closure_in_the_same_set _ expr -> + Variable.Set.fold (fun another_closure_in_the_same_set expr -> let used = Variable.Set.mem another_closure_in_the_same_set - function_decl.free_variables + function_body.free_variables in if used then Flambda.create_let another_closure_in_the_same_set @@ -175,363 +158,505 @@ let inline_by_copying_function_body ~env ~r }) expr else expr) - function_decls.funs + fun_vars bindings_for_vars_bound_by_closure_and_params_to_args in - let env = E.activate_freshening (E.set_never_inline env) in + let env = E.set_never_inline env in + let env = E.activate_freshening env in let env = E.set_inline_debuginfo ~dbg env in simplify env r expr -let inline_by_copying_function_declaration ~env ~r - ~(function_decls : Flambda.function_declarations) - ~lhs_of_application - ~(inline_requested : Lambda.inline_attribute) - ~closure_id_being_applied - ~(function_decl : Flambda.function_declaration) - ~args ~args_approxs - ~(invariant_params:Variable.Set.t Variable.Map.t lazy_t) - ~(specialised_args : Flambda.specialised_to Variable.Map.t) - ~direct_call_surrogates ~dbg ~simplify = - let function_decls = - (* To simplify a substitution (see comment below), rewrite any references - to closures in the set being defined that go via symbols, so they go - via closure variables instead. *) - let make_closure_symbol = - let module Backend = (val (E.backend env) : Backend_intf.S) in - Backend.closure_symbol - in - Freshening.rewrite_recursive_calls_with_symbols - (Freshening.activate Freshening.empty) - ~make_closure_symbol - function_decls +type state = { + old_inside_to_new_inside : Variable.t Variable.Map.t; + (* Map from old inner vars to new inner vars *) + old_outside_to_new_outside : Variable.t Variable.Map.t; + (* Map from old outer vars to new outer vars *) + old_params_to_new_outside : Variable.t Variable.Map.t; + (* Map from old parameters to new outer vars. These are params + that should be specialised if they are copied to the new set of + closures. *) + old_fun_var_to_new_fun_var : Variable.t Variable.Map.t; + (* Map from old fun vars to new fun vars. These are the functions + that will be copied into the new set of closures *) + let_bindings : (Variable.t * Flambda.named) list; + (* Let bindings that will surround the definition of the new set + of closures *) + to_copy : Variable.t list; + (* List of functions that still need to be copied to the new set + of closures *) + new_funs : Flambda.function_declaration Variable.Map.t; + (* The function declerations for the new set of closures *) + new_free_vars_with_old_projections : Flambda.specialised_to Variable.Map.t; + (* The free variables for the new set of closures, but the projection + fields still point to old free variables. *) + new_specialised_args_with_old_projections : + Flambda.specialised_to Variable.Map.t; + (* The specialised parameters for the new set of closures, but the + projection fields still point to old specialised parameters. *) +} + +let empty_state = + { to_copy = []; + old_inside_to_new_inside = Variable.Map.empty; + old_outside_to_new_outside = Variable.Map.empty; + old_params_to_new_outside = Variable.Map.empty; + old_fun_var_to_new_fun_var = Variable.Map.empty; + let_bindings = []; + new_funs = Variable.Map.empty; + new_free_vars_with_old_projections = Variable.Map.empty; + new_specialised_args_with_old_projections = Variable.Map.empty; } + +(* Add let bindings for the free vars in the set_of_closures and + add them to [old_outside_to_new_outside] *) +let bind_free_vars ~lhs_of_application ~closure_id_being_applied + ~state ~free_vars = + Variable.Map.fold + (fun free_var (spec : Flambda.specialised_to) state -> + let var_clos = new_var Internal_variable_names.from_closure in + let expr : Flambda.named = + Project_var { + closure = lhs_of_application; + closure_id = closure_id_being_applied; + var = Var_within_closure.wrap free_var; + } + in + let let_bindings = (var_clos, expr) :: state.let_bindings in + let old_outside_to_new_outside = + Variable.Map.add spec.var var_clos state.old_outside_to_new_outside + in + { state with let_bindings; old_outside_to_new_outside }) + free_vars state + +(* For arguments of specialised parameters: + - Add them to [old_outside_to_new_outside] + - Add them and their invariant aliases to [old_params_to_new_outside] + For other arguments that are also worth specialising: + - Add them and their invariant aliases to [old_params_to_new_outside] *) +let register_arguments ~specialised_args ~invariant_params + ~state ~params ~args ~args_approxs = + let rec loop ~state ~params ~args ~args_approxs = + match params, args, args_approxs with + | [], [], [] -> state + | param :: params, arg :: args, arg_approx :: args_approxs -> begin + let param = Parameter.var param in + let worth_specialising, old_outside_to_new_outside = + match Variable.Map.find_opt param specialised_args with + | Some (spec : Flambda.specialised_to) -> + let old_outside_to_new_outside = + Variable.Map.add spec.var arg state.old_outside_to_new_outside + in + true, old_outside_to_new_outside + | None -> + let worth_specialising = + A.useful arg_approx + && Variable.Map.mem param (Lazy.force invariant_params) + in + worth_specialising, state.old_outside_to_new_outside + in + let old_params_to_new_outside = + if worth_specialising then begin + let old_params_to_new_outside = + Variable.Map.add param arg state.old_params_to_new_outside + in + match Variable.Map.find_opt param (Lazy.force invariant_params) with + | Some set -> + Variable.Set.fold + (fun elem acc -> Variable.Map.add elem arg acc) + set old_params_to_new_outside + | None -> + old_params_to_new_outside + end else begin + state.old_params_to_new_outside + end + in + let state = + { state with old_outside_to_new_outside; old_params_to_new_outside } + in + loop ~state ~params ~args ~args_approxs + end + | _, _, _ -> assert false in - let original_function_decls = function_decls in - let specialised_args_set = Variable.Map.keys specialised_args in - let worth_specialising_args, specialisable_args, args, args_decl = - which_function_parameters_can_we_specialise - ~params:(Parameter.List.vars function_decl.params) ~args ~args_approxs - ~invariant_params - ~specialised_args:specialised_args_set + loop ~state ~params ~args ~args_approxs + +(* Add an old parameter to [old_inside_to_new_inside]. If it appears in + [old_params_to_new_outside] then also add it to the new specialised args. *) +let add_param ~specialised_args ~state ~param = + let param = Parameter.var param in + let new_param = Variable.rename param in + let old_inside_to_new_inside = + Variable.Map.add param new_param state.old_inside_to_new_inside in - (* Arguments of functions that are not directly called but are - aliased to arguments of a directly called one may need to be - marked as specialised. *) - let specialisable_args_with_aliases = - Variable.Map.fold (fun arg outside_var map -> - match Variable.Map.find arg (Lazy.force invariant_params) with - | exception Not_found -> map - | set -> - Variable.Set.fold (fun alias map -> - Variable.Map.add alias outside_var map) - set map) - specialisable_args specialisable_args + let new_specialised_args_with_old_projections = + match Variable.Map.find_opt param specialised_args with + | Some (spec : Flambda.specialised_to) -> + let new_outside_var = + Variable.Map.find spec.var state.old_outside_to_new_outside + in + let new_spec : Flambda.specialised_to = + { spec with var = new_outside_var } + in + Variable.Map.add new_param new_spec + state.new_specialised_args_with_old_projections + | None -> begin + match Variable.Map.find_opt param state.old_params_to_new_outside with + | None -> state.new_specialised_args_with_old_projections + | Some new_outside_var -> + let new_spec : Flambda.specialised_to = + { var = new_outside_var; projection = None } + in + Variable.Map.add new_param new_spec + state.new_specialised_args_with_old_projections + end in - (* The other closures from the same set of closures may have - specialised arguments. Those refer to variables that may not be - bound anymore in the current environment. The only allowed - remaining specialised arguments after duplicating a function are - those that either comes from the free variables of set of - closures or the arguments of the closure being applied (and - propagated transitively to other functions). This is ensured by - the fact that no closure not directly required by the closure - being applied are kept in the set. If an argument of an other - function of the set does not come from the closure being applied - then, that function cannot be applied (unreachable from the one - being aplied). - - For specialised arguments of other function to reference a valid - value, they need to be rewritten accordingly to the ones of the - closure being applied. *) - let specialisable_renaming = - Variable.Map.fold (fun param outside_var map -> - match Variable.Map.find param specialised_args with - | exception Not_found -> - (* Newly specialised argument: no other function argument - may need renaming for that one *) - map - | original_spec_to -> - let original_outside_var = original_spec_to.var in - let spec_to = - { original_spec_to with var = outside_var; } - in - Variable.Map.add original_outside_var spec_to map) - specialisable_args_with_aliases Variable.Map.empty + let state = + { state with old_inside_to_new_inside; + new_specialised_args_with_old_projections } in - if Variable.Set.subset worth_specialising_args specialised_args_set - then - (* Don't duplicate the function definition if we would make its - specialisation information worse. (Note that this judgement is made - based only on those arguments found to be invariant with known-useful - approximations, rather than on all invariant arguments.) *) - None - else - let set_of_closures_var = new_var "dup_set_of_closures" in - (* The free variable map for the duplicated declaration(s) maps the - "internal" names used within the function bodies to fresh names, - which in turn are bound to projections from the set of closures being - copied. We add these bindings using [Let] around the new - set-of-closures declaration. *) - let free_vars, free_vars_for_lets = - fold_over_projections_of_vars_bound_by_closure ~closure_id_being_applied - ~lhs_of_application ~function_decls ~init:(Variable.Map.empty, []) - ~f:(fun ~acc:(map, for_lets) ~var:internal_var ~expr -> - let from_closure : Flambda.specialised_to = - { var = new_var "from_closure"; - projection = None; - } - in - Variable.Map.add internal_var from_closure map, - (from_closure.var, expr)::for_lets) + state, Parameter.wrap new_param + +(* Add a let binding for an old fun_var, add it to the new free variables, and + add it to [old_inside_to_new_inside] *) +let add_fun_var ~lhs_of_application ~closure_id_being_applied ~state ~fun_var = + if Variable.Map.mem fun_var state.old_inside_to_new_inside then state + else begin + let inside_var = Variable.rename fun_var in + let outside_var = Variable.create Internal_variable_names.closure in + let expr = + Flambda.Move_within_set_of_closures + { closure = lhs_of_application; + start_from = closure_id_being_applied; + move_to = Closure_id.wrap fun_var; } in - let required_functions = - Flambda_utils.closures_required_by_entry_point ~backend:(E.backend env) - ~entry_point:closure_id_being_applied - function_decls + let let_bindings = (outside_var, expr) :: state.let_bindings in + let spec : Flambda.specialised_to = + { var = outside_var; projection = None; } in - let funs = - Variable.Map.filter (fun func _ -> - Variable.Set.mem func required_functions) - function_decls.funs + let new_free_vars_with_old_projections = + Variable.Map.add inside_var spec state.new_free_vars_with_old_projections in - let free_vars, free_vars_for_lets, original_vars = - (* Bind all the closures from the original (non-specialised) set as - free variables in the set. This means that we can reference them - when some particular recursive call cannot be specialised. See - detailed comment below. *) - Variable.Map.fold (fun fun_var _fun_decl - (free_vars, free_vars_for_lets, original_vars) -> - let var = Variable.create "closure" in - let original_closure : Flambda.named = - Move_within_set_of_closures - { closure = lhs_of_application; - start_from = closure_id_being_applied; - move_to = Closure_id.wrap fun_var; - } - in - let internal_var = Variable.rename ~append:"_original" fun_var in - let free_vars = - Variable.Map.add internal_var { Flambda. var; projection = None } - free_vars - in - free_vars, - (var, original_closure) :: free_vars_for_lets, - Variable.Map.add fun_var internal_var original_vars) - funs - (free_vars, free_vars_for_lets, Variable.Map.empty) + let old_inside_to_new_inside = + Variable.Map.add fun_var inside_var state.old_inside_to_new_inside in - let direct_call_surrogates = - Closure_id.Map.fold (fun existing surrogate surrogates -> - let existing = Closure_id.unwrap existing in - let surrogate = Closure_id.unwrap surrogate in - if Variable.Map.mem existing funs - && Variable.Map.mem surrogate funs - then - Variable.Map.add existing surrogate surrogates - else - surrogates) - direct_call_surrogates - Variable.Map.empty + { state with + old_inside_to_new_inside; let_bindings; + new_free_vars_with_old_projections } + end + +(* Add an old free_var to the new free variables and add it to + [old_inside_to_new_inside]. *) +let add_free_var ~free_vars ~state ~free_var = + if Variable.Map.mem free_var state.old_inside_to_new_inside then state + else begin + let spec : Flambda.specialised_to = Variable.Map.find free_var free_vars in + let outside_var = spec.var in + let new_outside_var = + Variable.Map.find outside_var state.old_outside_to_new_outside in - let function_decls = - Flambda.update_function_declarations ~funs function_decls + let new_spec : Flambda.specialised_to = + { spec with var = new_outside_var } in - let all_functions_parameters = - Flambda_utils.all_functions_parameters function_decls + let new_inside_var = Variable.rename free_var in + let new_free_vars_with_old_projections = + Variable.Map.add new_inside_var new_spec + state.new_free_vars_with_old_projections in - let specialisable_args = - Variable.Map.merge (fun param v1 v2 -> - match v1, v2 with - | None, None -> None - | Some var, _ -> - (* New specialised argument being introduced. *) - let spec_to : Flambda.specialised_to = - { var; - projection = None; - } - in - Some spec_to - | None, Some (spec_to : Flambda.specialised_to) -> - (* Renaming an existing specialised argument. *) - if Variable.Set.mem param all_functions_parameters then - match Variable.Map.find spec_to.var specialisable_renaming with - | exception Not_found -> - Misc.fatal_errorf - "Missing renaming for specialised argument of a function \ - being duplicated but not directly applied: %a -> %a.@ \ - Closure ID being applied = %a.@ \ - required_functions = %a.@ \ - specialisable_renaming = %a@ \ - specialisable_args_with_aliases = %a@ \ - Original function declarations = %a@ \ - Filtered function declarations = %a@ \ - Original specialised args = %a" - Variable.print param - Flambda.print_specialised_to spec_to - Closure_id.print closure_id_being_applied - Variable.Set.print required_functions - (Variable.Map.print Flambda.print_specialised_to) - specialisable_renaming - (Variable.Map.print Variable.print) - specialisable_args_with_aliases - Flambda.print_function_declarations original_function_decls - Flambda.print_function_declarations function_decls - (Variable.Map.print Flambda.print_specialised_to) - specialised_args - | argument_from_the_current_application -> - Some argument_from_the_current_application - else - None) - specialisable_args_with_aliases specialised_args + let old_inside_to_new_inside = + Variable.Map.add free_var new_inside_var state.old_inside_to_new_inside in - let functions'_specialised_params = - Flambda_utils.parameters_specialised_to_the_same_variable - ~function_decls - ~specialised_args:specialisable_args + { state with old_inside_to_new_inside; new_free_vars_with_old_projections } + end + +(* Add a function to the new set of closures iff: + 1) All it's specialised parameters are available in + [old_outside_to_new_outside] + 2) At least one more parameter will become specialised *) +let add_function ~specialised_args ~state ~fun_var ~function_decl = + match function_decl.A.function_body with + | None -> None + | Some _ -> begin + let rec loop worth_specialising = function + | [] -> worth_specialising + | param :: params -> begin + let param = Parameter.var param in + match Variable.Map.find_opt param specialised_args with + | Some (spec : Flambda.specialised_to) -> + Variable.Map.mem spec.var state.old_outside_to_new_outside + && loop worth_specialising params + | None -> + let worth_specialising = + worth_specialising + || Variable.Map.mem param state.old_params_to_new_outside + in + loop worth_specialising params + end in - let rewrite_function (fun_decl:Flambda.function_declaration) = - (* First rewrite every use of the closure(s) defined by the current set - of closures to free variable(s) corresponding to the original - (non-specialised) closure(s). + let worth_specialising = loop false function_decl.A.params in + if not worth_specialising then None + else begin + let new_fun_var = Variable.rename fun_var in + let old_fun_var_to_new_fun_var = + Variable.Map.add fun_var new_fun_var state.old_fun_var_to_new_fun_var + in + let to_copy = fun_var :: state.to_copy in + let state = { state with old_fun_var_to_new_fun_var; to_copy } in + Some (state, new_fun_var) + end + end + +(* Lookup a function in the new set of closures, trying to add it if + necessary. *) +let lookup_function ~specialised_args ~state ~fun_var ~function_decl = + match Variable.Map.find_opt fun_var state.old_fun_var_to_new_fun_var with + | Some new_fun_var -> Some (state, new_fun_var) + | None -> add_function ~specialised_args ~state ~fun_var ~function_decl - Then for each call to such closures, if the arguments to the call are - obviously the same as the arguments to which we are specialising the - function, redirect the call to the specialised function. +(* A direct call to a function in the new set of closures can be specialised + if all the function's newly specialised parameters are passed arguments + that are specialised to the same outside variable *) +let specialisable_call ~specialised_args ~state ~args ~params = + List.for_all2 + (fun arg param -> + let param = Parameter.var param in + if Variable.Map.mem param specialised_args then true + else begin + let old_params_to_new_outside = state.old_params_to_new_outside in + match Variable.Map.find_opt param old_params_to_new_outside with + | None -> true + | Some outside_var -> begin + match Variable.Map.find_opt arg old_params_to_new_outside with + | Some outside_var' -> + Variable.equal outside_var outside_var' + | None -> false + end + end) + args params + +(* Rewrite a call iff: + 1) It is to a function in the old set of closures that can be specialised + 2) All the newly specialised parameters of that function are passed values + known to be equal to their new specialisation. *) +let rec rewrite_direct_call ~specialised_args ~funs ~direct_call_surrogates + ~state ~closure_id ~(apply : Flambda.apply) = + match Closure_id.Map.find_opt closure_id direct_call_surrogates with + | Some closure_id -> + rewrite_direct_call ~specialised_args ~funs ~direct_call_surrogates + ~state ~closure_id ~apply + | None -> begin + let fun_var = Closure_id.unwrap closure_id in + match Variable.Map.find_opt fun_var funs with + | None -> None + | Some function_decl -> begin + match + lookup_function ~specialised_args ~state ~fun_var ~function_decl + with + | None -> None + | Some (state, new_fun_var) -> begin + let args = apply.args in + let params = function_decl.A.params in + let specialisable = + specialisable_call ~specialised_args ~state ~args ~params + in + if not specialisable then None + else begin + let kind = Flambda.Direct (Closure_id.wrap new_fun_var) in + let apply = { apply with func = new_fun_var; kind } in + Some (state, Flambda.Apply apply) + end + end + end + end - In a function like [List.map]: - {[ - let rec specialised_map f l = - match l with - | [] -> [] - | h :: t -> f h :: specialised_map f t - ]} ( with [f] a specialised argument ) +(* Rewrite the body a function declaration for use in the new set of + closures. *) +let rewrite_function ~lhs_of_application ~closure_id_being_applied + ~direct_call_surrogates ~specialised_args ~free_vars ~funs + ~state fun_var = + let function_decl : A.function_declaration = + Variable.Map.find fun_var funs + in + let function_body = + match function_decl.function_body with + | None -> assert false + | Some function_body -> function_body + in + let new_fun_var = + Variable.Map.find fun_var state.old_fun_var_to_new_fun_var + in + let state, params = + List.fold_right + (fun param (state, params) -> + let state, param = add_param ~specialised_args ~state ~param in + (state, param :: params)) + function_decl.params (state, []) + in + let state = + Variable.Set.fold + (fun var state -> + if Variable.Map.mem var funs then + add_fun_var ~lhs_of_application ~closure_id_being_applied + ~state ~fun_var:var + else if Variable.Map.mem var free_vars then + add_free_var ~free_vars ~state ~free_var:var + else + state) + function_body.free_variables state + in + let state_ref = ref state in + let body = + Flambda_iterators.map_toplevel_expr + (fun (expr : Flambda.t) -> + match expr with + | Apply ({ kind = Direct closure_id } as apply) -> begin + match + rewrite_direct_call ~specialised_args ~funs ~direct_call_surrogates + ~state:!state_ref ~closure_id ~apply + with + | None -> expr + | Some (state, expr) -> + state_ref := state; + expr + end + | _ -> expr) + function_body.body + in + let body = + Flambda_utils.toplevel_substitution state.old_inside_to_new_inside body + in + let new_function_decl = + Flambda.create_function_declaration + ~params ~body + ~stub:function_body.stub + ~dbg:function_body.dbg + ~inline:function_body.inline + ~specialise:function_body.specialise + ~is_a_functor:function_body.is_a_functor + ~closure_origin:(Closure_origin.create (Closure_id.wrap new_fun_var)) + in + let new_funs = + Variable.Map.add new_fun_var new_function_decl state.new_funs + in + let state = { !state_ref with new_funs } in + state - The first step turns it into: - {[ - let map_original = map in - let rec specialised_map f l = - match l with - | [] -> [] - | h :: t -> f h :: map_original f t - ]} - and the second recognizes the call to [map_original] as a call - preserving the specialised arguments (here [f]). So it is - replaced by [specialised_map f t]. +let update_projections ~state projections = + let old_to_new = state.old_inside_to_new_inside in + Variable.Map.map + (fun (spec_to : Flambda.specialised_to) -> + let projection : Projection.t option = + match spec_to.projection with + | None -> None + | Some (Project_var proj) -> begin + match Variable.Map.find_opt proj.closure old_to_new with + | None -> None + | Some closure -> + let proj = { proj with closure } in + Some (Projection.Project_var proj) + end + | Some (Project_closure proj) -> begin + match Variable.Map.find_opt proj.set_of_closures old_to_new with + | None -> None + | Some set_of_closures -> + let proj = { proj with set_of_closures } in + Some (Projection.Project_closure proj) + end + | Some (Move_within_set_of_closures proj) -> begin + match Variable.Map.find_opt proj.closure old_to_new with + | None -> None + | Some closure -> + let proj = { proj with closure } in + Some (Projection.Move_within_set_of_closures proj) + end + | Some (Field (index, var)) -> begin + match Variable.Map.find_opt var old_to_new with + | None -> None + | Some var -> Some (Projection.Field(index, var)) + end + in + { spec_to with projection }) + projections - In the case of [map] this is a circuituous means of achieving the - desired result, but in general, this provides a way of handling - situations where some recursive calls (for example in subfunctions) - are made with arguments different from the specialised arguments. - The two-pass approach is convenient since the first pass performs - a correct code transformation without optimisation; and then the - second just performs the optimisation on a best-effort basis. - *) - let body_substituted = - (* The use of [Freshening.rewrite_recursive_calls_with_symbols] above - ensures that we catch all calls to the functions being defined - in the current set of closures. *) - Flambda_utils.toplevel_substitution original_vars fun_decl.body +let inline_by_copying_function_declaration + ~(env : Inline_and_simplify_aux.Env.t) + ~(r : Inline_and_simplify_aux.Result.t) + ~(function_decls : A.function_declarations) + ~(lhs_of_application : Variable.t) + ~(inline_requested : Lambda.inline_attribute) + ~(closure_id_being_applied : Closure_id.t) + ~(function_decl : A.function_declaration) + ~(args : Variable.t list) + ~(args_approxs : A.t list) + ~(invariant_params : Variable.Set.t Variable.Map.t lazy_t) + ~(specialised_args : Flambda.specialised_to Variable.Map.t) + ~(free_vars : Flambda.specialised_to Variable.Map.t) + ~(direct_call_surrogates : Closure_id.t Closure_id.Map.t) + ~(dbg : Debuginfo.t) + ~(simplify : Inlining_decision_intf.simplify) = + let state = empty_state in + let state = + bind_free_vars ~lhs_of_application ~closure_id_being_applied + ~state ~free_vars + in + let params = function_decl.params in + let state = + register_arguments ~specialised_args ~invariant_params + ~state ~params ~args ~args_approxs + in + let fun_var = Closure_id.unwrap closure_id_being_applied in + match add_function ~specialised_args ~state ~fun_var ~function_decl with + | None -> None + | Some (state, new_fun_var) -> begin + let funs = function_decls.funs in + let rec loop state = + match state.to_copy with + | [] -> state + | next :: rest -> + let state = { state with to_copy = rest } in + let state = + rewrite_function ~lhs_of_application ~closure_id_being_applied + ~direct_call_surrogates ~specialised_args ~free_vars ~funs + ~state next + in + loop state in - let body = - Flambda_iterators.map_toplevel_expr (fun (expr : Flambda.t) -> - match expr with - | Apply apply -> - begin match apply.kind with - | Indirect -> expr - | Direct closure_id -> - (* We recognize the potential recursive calls using the - closure ID rather than [apply.func] because the latter can be - aliases to the function (through a symbol for instance; the - fact that we've now rewritten such symbols to variables - doesn't squash any aliases) rather than being the closure var - directly. *) - let closure_var = Closure_id.unwrap closure_id in - begin match - Variable.Map.find closure_var functions'_specialised_params - with - | exception Not_found -> expr - | specialised_params -> - (* This is a call to one of the functions from the set being - specialised. *) - let apply_is_preserving_specialised_args = - List.length apply.args = List.length specialised_params - && List.for_all2 (fun arg param -> - match - (arg : Flambda_utils.specialised_to_same_as) - with - | Not_specialised -> true - | Specialised_and_aliased_to args -> - (* This is using one of the aliases of [param]. This - is not necessarily the exact same variable as - the original parameter---in particular when the - set contains multiply-recursive functions. *) - Variable.Set.mem param args) - specialised_params - apply.args - in - if apply_is_preserving_specialised_args then - Flambda.Apply - { apply with - func = closure_var; - kind = Direct closure_id; - } - else - expr - end - end - | _ -> expr) - body_substituted + let state = loop state in + let closure_id = Closure_id.wrap new_fun_var in + let function_decls = + Flambda.create_function_declarations_with_origin + ~funs:state.new_funs + ~set_of_closures_origin:function_decls.set_of_closures_origin + ~is_classic_mode:function_decls.is_classic_mode in - Flambda.create_function_declaration - ~params:fun_decl.params - ~stub:fun_decl.stub - ~dbg:fun_decl.dbg - ~inline:fun_decl.inline - ~specialise:fun_decl.specialise - ~is_a_functor:fun_decl.is_a_functor - ~body - in - let funs = - Variable.Map.map rewrite_function function_decls.funs - in - let function_decls = - Flambda.update_function_declarations ~funs function_decls - in - let set_of_closures = - (* This is the new set of closures, with more precise specialisation - information than the one being copied. *) - Flambda.create_set_of_closures ~function_decls ~free_vars - ~specialised_args:specialisable_args - ~direct_call_surrogates - in - (* Generate a copy of the function application, including the function - declaration(s), but with variables (not yet bound) in place of the - arguments. *) - let duplicated_application : Flambda.t = - let project_closure : Flambda.project_closure = - { set_of_closures = set_of_closures_var; - closure_id = closure_id_being_applied; - } + let free_vars = + update_projections ~state + state.new_free_vars_with_old_projections in - let func = new_var "dup_func" in - let body : Flambda.t = - Flambda.create_let set_of_closures_var - (Set_of_closures set_of_closures) - (Flambda.create_let func (Project_closure project_closure) - (Apply { - func; - args; - kind = Direct closure_id_being_applied; - dbg; - inline = inline_requested; - specialise = Default_specialise; - })) + let specialised_args = + update_projections ~state + state.new_specialised_args_with_old_projections in - Flambda_utils.bind ~bindings:free_vars_for_lets ~body - in - (* Now bind the variables that will hold the arguments from the original - application. *) - let expr : Flambda.t = - Flambda_utils.bind ~body:duplicated_application ~bindings:args_decl - in - let env = E.activate_freshening (E.set_never_inline env) in - Some (simplify env r expr) + let direct_call_surrogates = Variable.Map.empty in + let set_of_closures = + Flambda.create_set_of_closures ~function_decls + ~free_vars ~specialised_args ~direct_call_surrogates + in + let closure_var = new_var Internal_variable_names.dup_func in + let set_of_closures_var = + new_var Internal_variable_names.dup_set_of_closures + in + let project : Flambda.project_closure = + {set_of_closures = set_of_closures_var; closure_id} + in + let apply : Flambda.apply = + { func = closure_var; args; kind = Direct closure_id; dbg; + inline = inline_requested; specialise = Default_specialise; } + in + let body = + Flambda.create_let + set_of_closures_var (Set_of_closures set_of_closures) + (Flambda.create_let closure_var (Project_closure project) + (Apply apply)) + in + let expr = Flambda_utils.bind ~body ~bindings:state.let_bindings in + let env = E.activate_freshening (E.set_never_inline env) in + Some (simplify env r expr) + end diff --git a/middle_end/inlining_transforms.mli b/middle_end/inlining_transforms.mli index b86716ac..e31d1b08 100644 --- a/middle_end/inlining_transforms.mli +++ b/middle_end/inlining_transforms.mli @@ -67,12 +67,13 @@ val inline_by_copying_function_body : env:Inline_and_simplify_aux.Env.t -> r:Inline_and_simplify_aux.Result.t - -> function_decls:Flambda.function_declarations -> lhs_of_application:Variable.t -> inline_requested:Lambda.inline_attribute -> specialise_requested:Lambda.specialise_attribute -> closure_id_being_applied:Closure_id.t - -> function_decl:Flambda.function_declaration + -> function_decl:Simple_value_approx.function_declaration + -> function_body:Simple_value_approx.function_body + -> fun_vars:Variable.Set.t -> args:Variable.t list -> dbg:Debuginfo.t -> simplify:Inlining_decision_intf.simplify @@ -88,15 +89,16 @@ val inline_by_copying_function_body val inline_by_copying_function_declaration : env:Inline_and_simplify_aux.Env.t -> r:Inline_and_simplify_aux.Result.t - -> function_decls:Flambda.function_declarations + -> function_decls:Simple_value_approx.function_declarations -> lhs_of_application:Variable.t -> inline_requested:Lambda.inline_attribute -> closure_id_being_applied:Closure_id.t - -> function_decl:Flambda.function_declaration + -> function_decl:Simple_value_approx.function_declaration -> args:Variable.t list -> args_approxs:Simple_value_approx.t list -> invariant_params:Variable.Set.t Variable.Map.t lazy_t -> specialised_args:Flambda.specialised_to Variable.Map.t + -> free_vars:Flambda.specialised_to Variable.Map.t -> direct_call_surrogates:Closure_id.t Closure_id.Map.t -> dbg:Debuginfo.t -> simplify:Inlining_decision_intf.simplify diff --git a/middle_end/internal_variable_names.ml b/middle_end/internal_variable_names.ml new file mode 100644 index 00000000..93ce10f7 --- /dev/null +++ b/middle_end/internal_variable_names.ml @@ -0,0 +1,504 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-9-30-40-41-42"] + +type t = string + +let anon_fn = "anon_fn" +let apply_arg = "apply_arg" +let apply_funct = "apply_funct" +let block_symbol = "block_symbol" +let block_symbol_get = "block_symbol_get" +let block_symbol_get_field = "block_symbol_get_field" +let closure = "closure" +let cond = "cond" +let cond_sequor = "cond_sequor" +let const_block = "const_block" +let const_bool = "const_bool" +let const_boxed_int = "const_boxed_int" +let const_char = "const_char" +let const_false = "const_false" +let const_float = "const_float" +let const_int = "const_int" +let const_one = "const_one" +let const_ptr = "const_ptr" +let const_ptr_one = "const_ptr_one" +let const_ptr_zero = "const_ptr_zero" +let const_sequand = "const_sequand" +let const_string = "const_string" +let const_true = "const_true" +let const_zero = "const_zero" +let denominator = "denominator" +let division_by_zero = "division_by_zero" +let dummy = "dummy" +let dup_func = "dup_func" +let dup_set_of_closures = "dup_set_of_closures" +let const_float_array = "const_float_array" +let fake_effect_symbol = "fake_effect_symbol" +let for_from = "for_from" +let for_to = "for_to" +let from_closure = "from_closure" +let full_apply = "full_apply" +let get_symbol_field = "get_symbol_field" +let const_immstring = "const_immstring" +let const_int32 = "const_int32" +let const_int64 = "const_int64" +let is_zero = "is_zero" +let lifted_let_rec_block = "lifted_let_rec_block" +let meth = "meth" +let module_as_block = "module_as_block" +let const_nativeint = "const_nativeint" +let new_value = "new_value" +let numerator = "numerator" +let obj = "obj" +let offsetted = "offsetted" +let pabsfloat = "Pabsfloat" +let paddbint = "Paddbint" +let paddfloat = "Paddfloat" +let paddint = "Paddint" +let pandbint = "Pandbint" +let pandint = "Pandint" +let parraylength = "Parraylength" +let parrayrefs = "Parrayrefs" +let parrayrefu = "Parrayrefu" +let parraysets = "Parraysets" +let parraysetu = "Parraysetu" +let pasrbint = "Pasrbint" +let pasrint = "Pasrint" +let pbbswap = "Pbbswap" +let pbigarraydim = "Pbigarraydim" +let pbigarrayref = "Pbigarrayref" +let pbigarrayset = "Pbigarrayset" +let pbigstring_load_16 = "Pbigstring_load_16" +let pbigstring_load_32 = "Pbigstring_load_32" +let pbigstring_load_64 = "Pbigstring_load_64" +let pbigstring_set_16 = "Pbigstring_set_16" +let pbigstring_set_32 = "Pbigstring_set_32" +let pbigstring_set_64 = "Pbigstring_set_64" +let pbintcomp = "Pbintcomp" +let pbintofint = "Pbintofint" +let pbswap16 = "Pbswap16" +let pbytes_of_string = "Pbytes_of_string" +let pbytes_load_16 = "Pbytes_load_16" +let pbytes_load_32 = "Pbytes_load_32" +let pbytes_load_64 = "Pbytes_load_64" +let pbytes_set_16 = "Pbytes_set_16" +let pbytes_set_32 = "Pbytes_set_32" +let pbytes_set_64 = "Pbytes_set_64" +let pbytes_to_string = "Pbytes_to_string" +let pbyteslength = "Pbyteslength" +let pbytesrefs = "Pbytesrefs" +let pbytesrefu = "Pbytesrefu" +let pbytessets = "Pbytessets" +let pbytessetu = "Pbytessetu" +let pccall = "Pccall" +let pctconst = "Pctconst" +let pcvtbint = "Pcvtbint" +let pdirapply = "Pdirapply" +let pdivbint = "Pdivbint" +let pdivfloat = "Pdivfloat" +let pdivint = "Pdivint" +let pduparray = "Pduparray" +let pduprecord = "Pduprecord" +let pfield = "Pfield" +let pfield_computed = "Pfield_computed" +let pfloatcomp = "Pfloatcomp" +let pfloatfield = "Pfloatfield" +let pfloatofint = "Pfloatofint" +let pgetglobal = "Pgetglobal" +let pidentity = "Pidentity" +let pignore = "Pignore" +let pint_as_pointer = "Pint_as_pointer" +let pintcomp = "Pintcomp" +let pintofbint = "Pintofbint" +let pintoffloat = "Pintoffloat" +let pisint = "Pisint" +let pisout = "Pisout" +let plslbint = "Plslbint" +let plslint = "Plslint" +let plsrbint = "Plsrbint" +let plsrint = "Plsrint" +let pmakearray = "Pmakearray" +let pmakeblock = "Pmakeblock" +let pmodbint = "Pmodbint" +let pmodint = "Pmodint" +let pmulbint = "Pmulbint" +let pmulfloat = "Pmulfloat" +let pmulint = "Pmulint" +let pnegbint = "Pnegbint" +let pnegfloat = "Pnegfloat" +let pnegint = "Pnegint" +let pnot = "Pnot" +let poffsetint = "Poffsetint" +let poffsetref = "Poffsetref" +let pointer = "pointer" +let popaque = "Popaque" +let porbint = "Porbint" +let porint = "Porint" +let praise = "Praise" +let predef_exn = "predef_exn" +let prevapply = "Prevapply" +let project_closure = "project_closure" +let psequand = "Psequand" +let psequor = "Psequor" +let psetfield = "Psetfield" +let psetfield_computed = "Psetfield_computed" +let psetfloatfield = "Psetfloatfield" +let psetglobal = "Psetglobal" +let pstring_load_16 = "Pstring_load_16" +let pstring_load_32 = "Pstring_load_32" +let pstring_load_64 = "Pstring_load_64" +let pstringlength = "Pstringlength" +let pstringrefs = "Pstringrefs" +let pstringrefu = "Pstringrefu" +let psubbint = "Psubbint" +let psubfloat = "Psubfloat" +let psubint = "Psubint" +let pxorbint = "Pxorbint" +let pxorint = "Pxorint" +let pabsfloat_arg = "Pabsfloat_arg" +let paddbint_arg = "Paddbint_arg" +let paddfloat_arg = "Paddfloat_arg" +let paddint_arg = "Paddint_arg" +let pandbint_arg = "Pandbint_arg" +let pandint_arg = "Pandint_arg" +let parraylength_arg = "Parraylength_arg" +let parrayrefs_arg = "Parrayrefs_arg" +let parrayrefu_arg = "Parrayrefu_arg" +let parraysets_arg = "Parraysets_arg" +let parraysetu_arg = "Parraysetu_arg" +let partial_fun = "partial_fun" +let pasrbint_arg = "Pasrbint_arg" +let pasrint_arg = "Pasrint_arg" +let pbbswap_arg = "Pbbswap_arg" +let pbigarraydim_arg = "Pbigarraydim_arg" +let pbigarrayref_arg = "Pbigarrayref_arg" +let pbigarrayset_arg = "Pbigarrayset_arg" +let pbigstring_load_16_arg = "Pbigstring_load_16_arg" +let pbigstring_load_32_arg = "Pbigstring_load_32_arg" +let pbigstring_load_64_arg = "Pbigstring_load_64_arg" +let pbigstring_set_16_arg = "Pbigstring_set_16_arg" +let pbigstring_set_32_arg = "Pbigstring_set_32_arg" +let pbigstring_set_64_arg = "Pbigstring_set_64_arg" +let pbintcomp_arg = "Pbintcomp_arg" +let pbintofint_arg = "Pbintofint_arg" +let pbswap16_arg = "Pbswap16_arg" +let pbytes_of_string_arg = "Pbytes_of_string_arg" +let pbytes_to_string_arg = "Pbytes_to_string_arg" +let pbyteslength_arg = "Pbyteslength_arg" +let pbytesrefs_arg = "Pbytesrefs_arg" +let pbytesrefu_arg = "Pbytesrefu_arg" +let pbytessets_arg = "Pbytessets_arg" +let pbytessetu_arg = "Pbytessetu_arg" +let pccall_arg = "Pccall_arg" +let pctconst_arg = "Pctconst_arg" +let pcvtbint_arg = "Pcvtbint_arg" +let pdirapply_arg = "Pdirapply_arg" +let pdivbint_arg = "Pdivbint_arg" +let pdivfloat_arg = "Pdivfloat_arg" +let pdivint_arg = "Pdivint_arg" +let pduparray_arg = "Pduparray_arg" +let pduprecord_arg = "Pduprecord_arg" +let pfield_arg = "Pfield_arg" +let pfield_computed_arg = "Pfield_computed_arg" +let pfloatcomp_arg = "Pfloatcomp_arg" +let pfloatfield_arg = "Pfloatfield_arg" +let pfloatofint_arg = "Pfloatofint_arg" +let pgetglobal_arg = "Pgetglobal_arg" +let pidentity_arg = "Pidentity_arg" +let pignore_arg = "Pignore_arg" +let pint_as_pointer_arg = "Pint_as_pointer_arg" +let pintcomp_arg = "Pintcomp_arg" +let pintofbint_arg = "Pintofbint_arg" +let pintoffloat_arg = "Pintoffloat_arg" +let pisint_arg = "Pisint_arg" +let pisout_arg = "Pisout_arg" +let plslbint_arg = "Plslbint_arg" +let plslint_arg = "Plslint_arg" +let plsrbint_arg = "Plsrbint_arg" +let plsrint_arg = "Plsrint_arg" +let pmakearray_arg = "Pmakearray_arg" +let pmakeblock_arg = "Pmakeblock_arg" +let pmodbint_arg = "Pmodbint_arg" +let pmodint_arg = "Pmodint_arg" +let pmulbint_arg = "Pmulbint_arg" +let pmulfloat_arg = "Pmulfloat_arg" +let pmulint_arg = "Pmulint_arg" +let pnegbint_arg = "Pnegbint_arg" +let pnegfloat_arg = "Pnegfloat_arg" +let pnegint_arg = "Pnegint_arg" +let pnot_arg = "Pnot_arg" +let poffsetint_arg = "Poffsetint_arg" +let poffsetref_arg = "Poffsetref_arg" +let popaque_arg = "Popaque_arg" +let porbint_arg = "Porbint_arg" +let porint_arg = "Porint_arg" +let praise_arg = "Praise_arg" +let prevapply_arg = "Prevapply_arg" +let psequand_arg = "Psequand_arg" +let psequor_arg = "Psequor_arg" +let psetfield_arg = "Psetfield_arg" +let psetfield_computed_arg = "Psetfield_computed_arg" +let psetfloatfield_arg = "Psetfloatfield_arg" +let psetglobal_arg = "Psetglobal_arg" +let pstring_load_16_arg = "Pstring_load_16_arg" +let pstring_load_32_arg = "Pstring_load_32_arg" +let pstring_load_64_arg = "Pstring_load_64_arg" +let pbytes_load_16_arg = "Pbytes_load_16_arg" +let pbytes_load_32_arg = "Pbytes_load_32_arg" +let pbytes_load_64_arg = "Pbytes_load_64_arg" +let pbytes_set_16_arg = "Pbytes_set_16_arg" +let pbytes_set_32_arg = "Pbytes_set_32_arg" +let pbytes_set_64_arg = "Pbytes_set_64_arg" +let pstringlength_arg = "Pstringlength_arg" +let pstringrefs_arg = "Pstringrefs_arg" +let pstringrefu_arg = "Pstringrefu_arg" +let psubbint_arg = "Psubbint_arg" +let psubfloat_arg = "Psubfloat_arg" +let psubint_arg = "Psubint_arg" +let pxorbint_arg = "Pxorbint_arg" +let pxorint_arg = "Pxorint_arg" +let raise = "raise" +let raise_arg = "raise_arg" +let read_mutable = "read_mutable" +let remove_unused_arguments = "remove_unused_arguments" +let result = "result" +let send_arg = "send_arg" +let sequence = "sequence" +let set_of_closures = "set_of_closures" +let simplify_fv = "simplify_fv" +let staticraise_arg = "staticraise_arg" +let string_switch = "string_switch" +let switch = "switch" +let symbol = "symbol" +let symbol_field = "symbol_field" +let symbol_field_block = "symbol_field_block" +let the_dead_constant = "the_dead_constant" +let toplevel_substitution_named = "toplevel_substitution_named" +let unbox_free_vars_of_closures = "unbox_free_vars_of_closures" +let zero = "zero" + +let anon_fn_with_loc_fmt = format_of_string "anon_fn[%a]" +let anon_fn_with_loc loc = + if loc = Location.none then anon_fn + else begin + Format.asprintf anon_fn_with_loc_fmt Location.print_compact loc + end + +let of_primitive : Lambda.primitive -> string = function + | Pidentity -> pidentity + | Pbytes_of_string -> pbytes_of_string + | Pbytes_to_string -> pbytes_to_string + | Pignore -> pignore + | Prevapply -> prevapply + | Pdirapply -> pdirapply + | Pgetglobal _ -> pgetglobal + | Psetglobal _ -> psetglobal + | Pmakeblock _ -> pmakeblock + | Pfield _ -> pfield + | Pfield_computed -> pfield_computed + | Psetfield _ -> psetfield + | Psetfield_computed _ -> psetfield_computed + | Pfloatfield _ -> pfloatfield + | Psetfloatfield _ -> psetfloatfield + | Pduprecord _ -> pduprecord + | Pccall _ -> pccall + | Praise _ -> praise + | Psequand -> psequand + | Psequor -> psequor + | Pnot -> pnot + | Pnegint -> pnegint + | Paddint -> paddint + | Psubint -> psubint + | Pmulint -> pmulint + | Pdivint _ -> pdivint + | Pmodint _ -> pmodint + | Pandint -> pandint + | Porint -> porint + | Pxorint -> pxorint + | Plslint -> plslint + | Plsrint -> plsrint + | Pasrint -> pasrint + | Pintcomp _ -> pintcomp + | Poffsetint _ -> poffsetint + | Poffsetref _ -> poffsetref + | Pintoffloat -> pintoffloat + | Pfloatofint -> pfloatofint + | Pnegfloat -> pnegfloat + | Pabsfloat -> pabsfloat + | Paddfloat -> paddfloat + | Psubfloat -> psubfloat + | Pmulfloat -> pmulfloat + | Pdivfloat -> pdivfloat + | Pfloatcomp _ -> pfloatcomp + | Pstringlength -> pstringlength + | Pstringrefu -> pstringrefu + | Pstringrefs -> pstringrefs + | Pbyteslength -> pbyteslength + | Pbytesrefu -> pbytesrefu + | Pbytessetu -> pbytessetu + | Pbytesrefs -> pbytesrefs + | Pbytessets -> pbytessets + | Parraylength _ -> parraylength + | Pmakearray _ -> pmakearray + | Pduparray _ -> pduparray + | Parrayrefu _ -> parrayrefu + | Parraysetu _ -> parraysetu + | Parrayrefs _ -> parrayrefs + | Parraysets _ -> parraysets + | Pctconst _ -> pctconst + | Pisint -> pisint + | Pisout -> pisout + | Pbintofint _ -> pbintofint + | Pintofbint _ -> pintofbint + | Pcvtbint _ -> pcvtbint + | Pnegbint _ -> pnegbint + | Paddbint _ -> paddbint + | Psubbint _ -> psubbint + | Pmulbint _ -> pmulbint + | Pdivbint _ -> pdivbint + | Pmodbint _ -> pmodbint + | Pandbint _ -> pandbint + | Porbint _ -> porbint + | Pxorbint _ -> pxorbint + | Plslbint _ -> plslbint + | Plsrbint _ -> plsrbint + | Pasrbint _ -> pasrbint + | Pbintcomp _ -> pbintcomp + | Pbigarrayref _ -> pbigarrayref + | Pbigarrayset _ -> pbigarrayset + | Pbigarraydim _ -> pbigarraydim + | Pstring_load_16 _ -> pstring_load_16 + | Pstring_load_32 _ -> pstring_load_32 + | Pstring_load_64 _ -> pstring_load_64 + | Pbytes_load_16 _ -> pbytes_load_16 + | Pbytes_load_32 _ -> pbytes_load_32 + | Pbytes_load_64 _ -> pbytes_load_64 + | Pbytes_set_16 _ -> pbytes_set_16 + | Pbytes_set_32 _ -> pbytes_set_32 + | Pbytes_set_64 _ -> pbytes_set_64 + | Pbigstring_load_16 _ -> pbigstring_load_16 + | Pbigstring_load_32 _ -> pbigstring_load_32 + | Pbigstring_load_64 _ -> pbigstring_load_64 + | Pbigstring_set_16 _ -> pbigstring_set_16 + | Pbigstring_set_32 _ -> pbigstring_set_32 + | Pbigstring_set_64 _ -> pbigstring_set_64 + | Pbswap16 -> pbswap16 + | Pbbswap _ -> pbbswap + | Pint_as_pointer -> pint_as_pointer + | Popaque -> popaque + +let of_primitive_arg : Lambda.primitive -> string = function + | Pidentity -> pidentity_arg + | Pbytes_of_string -> pbytes_of_string_arg + | Pbytes_to_string -> pbytes_to_string_arg + | Pignore -> pignore_arg + | Prevapply -> prevapply_arg + | Pdirapply -> pdirapply_arg + | Pgetglobal _ -> pgetglobal_arg + | Psetglobal _ -> psetglobal_arg + | Pmakeblock _ -> pmakeblock_arg + | Pfield _ -> pfield_arg + | Pfield_computed -> pfield_computed_arg + | Psetfield _ -> psetfield_arg + | Psetfield_computed _ -> psetfield_computed_arg + | Pfloatfield _ -> pfloatfield_arg + | Psetfloatfield _ -> psetfloatfield_arg + | Pduprecord _ -> pduprecord_arg + | Pccall _ -> pccall_arg + | Praise _ -> praise_arg + | Psequand -> psequand_arg + | Psequor -> psequor_arg + | Pnot -> pnot_arg + | Pnegint -> pnegint_arg + | Paddint -> paddint_arg + | Psubint -> psubint_arg + | Pmulint -> pmulint_arg + | Pdivint _ -> pdivint_arg + | Pmodint _ -> pmodint_arg + | Pandint -> pandint_arg + | Porint -> porint_arg + | Pxorint -> pxorint_arg + | Plslint -> plslint_arg + | Plsrint -> plsrint_arg + | Pasrint -> pasrint_arg + | Pintcomp _ -> pintcomp_arg + | Poffsetint _ -> poffsetint_arg + | Poffsetref _ -> poffsetref_arg + | Pintoffloat -> pintoffloat_arg + | Pfloatofint -> pfloatofint_arg + | Pnegfloat -> pnegfloat_arg + | Pabsfloat -> pabsfloat_arg + | Paddfloat -> paddfloat_arg + | Psubfloat -> psubfloat_arg + | Pmulfloat -> pmulfloat_arg + | Pdivfloat -> pdivfloat_arg + | Pfloatcomp _ -> pfloatcomp_arg + | Pstringlength -> pstringlength_arg + | Pstringrefu -> pstringrefu_arg + | Pstringrefs -> pstringrefs_arg + | Pbyteslength -> pbyteslength_arg + | Pbytesrefu -> pbytesrefu_arg + | Pbytessetu -> pbytessetu_arg + | Pbytesrefs -> pbytesrefs_arg + | Pbytessets -> pbytessets_arg + | Parraylength _ -> parraylength_arg + | Pmakearray _ -> pmakearray_arg + | Pduparray _ -> pduparray_arg + | Parrayrefu _ -> parrayrefu_arg + | Parraysetu _ -> parraysetu_arg + | Parrayrefs _ -> parrayrefs_arg + | Parraysets _ -> parraysets_arg + | Pctconst _ -> pctconst_arg + | Pisint -> pisint_arg + | Pisout -> pisout_arg + | Pbintofint _ -> pbintofint_arg + | Pintofbint _ -> pintofbint_arg + | Pcvtbint _ -> pcvtbint_arg + | Pnegbint _ -> pnegbint_arg + | Paddbint _ -> paddbint_arg + | Psubbint _ -> psubbint_arg + | Pmulbint _ -> pmulbint_arg + | Pdivbint _ -> pdivbint_arg + | Pmodbint _ -> pmodbint_arg + | Pandbint _ -> pandbint_arg + | Porbint _ -> porbint_arg + | Pxorbint _ -> pxorbint_arg + | Plslbint _ -> plslbint_arg + | Plsrbint _ -> plsrbint_arg + | Pasrbint _ -> pasrbint_arg + | Pbintcomp _ -> pbintcomp_arg + | Pbigarrayref _ -> pbigarrayref_arg + | Pbigarrayset _ -> pbigarrayset_arg + | Pbigarraydim _ -> pbigarraydim_arg + | Pstring_load_16 _ -> pstring_load_16_arg + | Pstring_load_32 _ -> pstring_load_32_arg + | Pstring_load_64 _ -> pstring_load_64_arg + | Pbytes_load_16 _ -> pbytes_load_16_arg + | Pbytes_load_32 _ -> pbytes_load_32_arg + | Pbytes_load_64 _ -> pbytes_load_64_arg + | Pbytes_set_16 _ -> pbytes_set_16_arg + | Pbytes_set_32 _ -> pbytes_set_32_arg + | Pbytes_set_64 _ -> pbytes_set_64_arg + | Pbigstring_load_16 _ -> pbigstring_load_16_arg + | Pbigstring_load_32 _ -> pbigstring_load_32_arg + | Pbigstring_load_64 _ -> pbigstring_load_64_arg + | Pbigstring_set_16 _ -> pbigstring_set_16_arg + | Pbigstring_set_32 _ -> pbigstring_set_32_arg + | Pbigstring_set_64 _ -> pbigstring_set_64_arg + | Pbswap16 -> pbswap16_arg + | Pbbswap _ -> pbbswap_arg + | Pint_as_pointer -> pint_as_pointer_arg + | Popaque -> popaque_arg diff --git a/middle_end/internal_variable_names.mli b/middle_end/internal_variable_names.mli new file mode 100644 index 00000000..24712e89 --- /dev/null +++ b/middle_end/internal_variable_names.mli @@ -0,0 +1,95 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Fu Yong Quah, Jane Street Europe *) +(* *) +(* Copyright 2017 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-9-30-40-41-42"] + +type t = private string + +val apply_arg : t +val apply_funct : t +val block_symbol : t +val block_symbol_get : t +val block_symbol_get_field : t +val closure : t +val cond : t +val cond_sequor : t +val const_block : t +val const_bool : t +val const_boxed_int : t +val const_char : t +val const_false : t +val const_float : t +val const_int : t +val const_one : t +val const_ptr : t +val const_ptr_one : t +val const_ptr_zero : t +val const_sequand : t +val const_string : t +val const_true : t +val const_zero : t +val denominator : t +val division_by_zero : t +val dummy : t +val dup_func : t +val dup_set_of_closures : t +val const_float_array : t +val fake_effect_symbol : t +val for_from : t +val for_to : t +val from_closure : t +val full_apply : t +val get_symbol_field : t +val const_immstring : t +val const_int32 : t +val const_int64 : t +val is_zero : t +val lifted_let_rec_block : t +val meth : t +val module_as_block : t +val const_nativeint : t +val new_value : t +val numerator : t +val obj : t +val offsetted : t +val partial_fun : t +val pgetglobal : t +val pointer : t +val predef_exn : t +val project_closure : t +val raise : t +val raise_arg : t +val read_mutable : t +val remove_unused_arguments : t +val result : t +val send_arg : t +val sequence : t +val set_of_closures : t +val staticraise_arg : t +val simplify_fv : t +val string_switch : t +val switch : t +val symbol : t +val symbol_field : t +val symbol_field_block : t +val the_dead_constant : t +val toplevel_substitution_named : t +val unbox_free_vars_of_closures : t +val zero : t + +val of_primitive : Lambda.primitive -> t + +val of_primitive_arg : Lambda.primitive -> t + +val anon_fn_with_loc : Location.t -> t diff --git a/middle_end/lift_code.mli b/middle_end/lift_code.mli index 9cbfa878..92ecda01 100644 --- a/middle_end/lift_code.mli +++ b/middle_end/lift_code.mli @@ -39,5 +39,5 @@ val lifting_helper : Flambda.t list -> evaluation_order:[ `Left_to_right | `Right_to_left ] -> create_body:(Variable.t list -> Flambda.t) - -> name:string + -> name:Internal_variable_names.t -> Flambda.t diff --git a/middle_end/lift_constants.ml b/middle_end/lift_constants.ml index 4059e3cd..c5f78235 100644 --- a/middle_end/lift_constants.ml +++ b/middle_end/lift_constants.ml @@ -28,11 +28,6 @@ let closure_symbol ~(backend : (module Backend_intf.S)) closure_id = let module Backend = (val backend) in Backend.closure_symbol closure_id -let make_variable_symbol prefix var = - Symbol.create (Compilation_unit.get_current_exn ()) - (Linkage_name.create - (prefix ^ Variable.unique_name (Variable.rename var))) - (** Traverse the given expression assigning symbols to [let]- and [let rec]- bound constant variables. At the same time collect the definitions of such variables. *) @@ -46,7 +41,7 @@ let assign_symbols_and_collect_constant_definitions let assign_symbol var (named : Flambda.named) = if not (Inconstant_idents.variable var inconstants) then begin let assign_symbol () = - let symbol = make_variable_symbol "" var in + let symbol = Symbol.of_variable (Variable.rename var) in Variable.Tbl.add var_to_symbol_tbl var symbol in let assign_existing_symbol = Variable.Tbl.add var_to_symbol_tbl var in @@ -543,6 +538,8 @@ let constant_dependencies ~backend:_ | Project_closure (s, _) -> Symbol.Set.singleton s +module Symbol_SCC = Strongly_connected_components.Make (Symbol) + let program_graph ~backend imported_symbols symbol_to_constant (initialize_symbol_tbl : (Tag.t * Flambda.t list * Symbol.t option) Symbol.Tbl.t) @@ -584,7 +581,6 @@ let program_graph ~backend imported_symbols symbol_to_constant ) effect_tbl graph_with_initialisation in - let module Symbol_SCC = Strongly_connected_components.Make (Symbol) in let components = Symbol_SCC.connected_components_sorted_from_roots_to_leaf graph @@ -605,7 +601,6 @@ let add_definition_of_symbol constant_definitions assert(not (Symbol.Tbl.mem initialize_symbol_tbl sym)); (sym, Symbol.Map.find sym constant_definitions) in - let module Symbol_SCC = Strongly_connected_components.Make (Symbol) in match component with | Symbol_SCC.Has_loop l -> let l = List.map symbol_declaration l in @@ -676,14 +671,7 @@ let introduce_free_variables_in_set_of_closures end else begin done_something := true; let body = Flambda_utils.toplevel_substitution subst body in - Flambda.create_function_declaration - ~params:func_decl.params - ~body - ~stub:func_decl.stub - ~dbg:func_decl.dbg - ~inline:func_decl.inline - ~specialise:func_decl.specialise - ~is_a_functor:func_decl.is_a_functor + Flambda.update_body_of_function_declaration func_decl ~body end) function_decls.funs) in @@ -760,12 +748,9 @@ let var_to_block_field var_to_block_field_tbl let program_symbols ~backend (program : Flambda.program) = - let new_fake_symbol = - let r = ref 0 in - fun () -> - incr r; - Symbol.create (Compilation_unit.get_current_exn ()) - (Linkage_name.create ("fake_effect_symbol_" ^ string_of_int !r)) + let new_fake_symbol () = + let var = Variable.create Internal_variable_names.fake_effect_symbol in + Symbol.of_variable var in let initialize_symbol_tbl = Symbol.Tbl.create 42 in let effect_tbl = Symbol.Tbl.create 42 in @@ -876,15 +861,10 @@ let project_closure_map symbol_definition_map = symbol_definition_map Symbol.Map.empty -let the_dead_constant_index = ref 0 - let lift_constants (program : Flambda.program) ~backend = let the_dead_constant = - let index = !the_dead_constant_index in - incr the_dead_constant_index; - let name = Printf.sprintf "the_dead_constant_%d" index in - Symbol.create (Compilation_unit.get_current_exn ()) - (Linkage_name.create name) + let var = Variable.create Internal_variable_names.the_dead_constant in + Symbol.of_variable var in let program_body : Flambda.program_body = Let_symbol (the_dead_constant, Allocated_const (Nativeint 0n), diff --git a/middle_end/lift_let_to_initialize_symbol.ml b/middle_end/lift_let_to_initialize_symbol.ml index d573f546..169d5e0d 100644 --- a/middle_end/lift_let_to_initialize_symbol.ml +++ b/middle_end/lift_let_to_initialize_symbol.ml @@ -122,9 +122,10 @@ let rec accumulate ~substitution ~copied_lets ~extracted_lets in let extracted = let expr = + let name = Internal_variable_names.lifted_let_rec_block in Flambda_utils.toplevel_substitution def_substitution (Let_rec (renamed_defs, - Flambda_utils.name_expr ~name:"lifted_let_rec_block" + Flambda_utils.name_expr ~name (Prim (Pmakeblock (0, Immutable, None), List.map fst renamed_defs, Debuginfo.none)))) @@ -172,9 +173,11 @@ let rebuild (used_variables:Variable.Set.t) (accumulated:accumulated) = List.map (fun decl -> match decl with | Block (var, _, _) | Expr (var, _) -> - Flambda_utils.make_variable_symbol var, decl - | Exprs (vars, _) -> - Flambda_utils.make_variables_symbol vars, decl) + Symbol.of_variable (Variable.rename var), decl + | Exprs _ -> + let name = Internal_variable_names.lifted_let_rec_block in + let var = Variable.create name in + Symbol.of_variable var, decl) accumulated.extracted_lets in let extracted_definitions = diff --git a/middle_end/parameter.ml b/middle_end/parameter.ml index 213611b0..020fb5b1 100644 --- a/middle_end/parameter.ml +++ b/middle_end/parameter.ml @@ -58,8 +58,8 @@ module Set = struct let vars l = Variable.Set.of_list (List.map var l) end -let rename ?current_compilation_unit ?append p = - { var = Variable.rename ?current_compilation_unit ?append p.var } +let rename ?current_compilation_unit p = + { var = Variable.rename ?current_compilation_unit p.var } let map_var f { var } = { var = f var } diff --git a/middle_end/parameter.mli b/middle_end/parameter.mli index 45657205..ceed1678 100644 --- a/middle_end/parameter.mli +++ b/middle_end/parameter.mli @@ -30,7 +30,6 @@ val var : t -> Variable.t (** Rename the inner variable of the parameter *) val rename : ?current_compilation_unit:Compilation_unit.t - -> ?append:string -> t -> t diff --git a/middle_end/ref_to_variables.ml b/middle_end/ref_to_variables.ml index a59563e2..f21ffb1a 100644 --- a/middle_end/ref_to_variables.ml +++ b/middle_end/ref_to_variables.ml @@ -16,9 +16,6 @@ [@@@ocaml.warning "+a-4-9-30-40-41-42"] -let rename_var var = - Mutable_variable.create - (Variable.unique_name var) (* Variable.rename var *) (* ~current_compilation_unit:(Compilation_unit.get_current_exn ()) *) @@ -118,7 +115,7 @@ let eliminate_ref_of_expr flam = else let convertible_variables = Variable.Map.mapi (fun v size -> - Array.init size (fun _ -> rename_var v)) + Array.init size (fun _ -> Mutable_variable.create_from_variable v)) convertible_variables in let convertible_variable v = Variable.Map.mem v convertible_variables in @@ -172,8 +169,10 @@ let eliminate_ref_of_expr flam = | Some (var,size) -> if size = 1 then begin - let mut = Variable.create "read_mutable" in - let new_value = Variable.create "offseted" in + let mut_name = Internal_variable_names.read_mutable in + let mut = Variable.create mut_name in + let new_value_name = Internal_variable_names.offsetted in + let new_value = Variable.create new_value_name in let expr = Flambda.create_let mut (Read_mutable var) (Flambda.create_let new_value diff --git a/middle_end/remove_free_vars_equal_to_args.ml b/middle_end/remove_free_vars_equal_to_args.ml index c149b4ff..fdb38ff4 100755 --- a/middle_end/remove_free_vars_equal_to_args.ml +++ b/middle_end/remove_free_vars_equal_to_args.ml @@ -48,14 +48,8 @@ let rewrite_one_function_decl ~(function_decl : Flambda.function_declaration) params_for_equal_free_vars function_decl.body in - Flambda.create_function_declaration - ~params:function_decl.params - ~body:body - ~stub:function_decl.stub - ~dbg:function_decl.dbg - ~inline:function_decl.inline - ~specialise:function_decl.specialise - ~is_a_functor:function_decl.is_a_functor + Flambda.update_function_declaration function_decl + ~params:function_decl.params ~body:body let rewrite_one_set_of_closures (set_of_closures : Flambda.set_of_closures) = let back_free_vars = diff --git a/middle_end/remove_unused_arguments.ml b/middle_end/remove_unused_arguments.ml index a810ce98..ea276b68 100644 --- a/middle_end/remove_unused_arguments.ml +++ b/middle_end/remove_unused_arguments.ml @@ -23,7 +23,8 @@ let rename_var var = Variable.rename var ~current_compilation_unit:(Compilation_unit.get_current_exn ()) -let remove_params unused (fun_decl: Flambda.function_declaration) = +let remove_params unused (fun_decl: Flambda.function_declaration) + ~new_fun_var = let unused_params, used_params = List.partition (fun v -> Variable.Set.mem (Parameter.var v) unused) fun_decl.params @@ -40,6 +41,7 @@ let remove_params unused (fun_decl: Flambda.function_declaration) = Flambda.create_function_declaration ~params:used_params ~body ~stub:fun_decl.stub ~dbg:fun_decl.dbg ~inline:fun_decl.inline ~specialise:fun_decl.specialise ~is_a_functor:fun_decl.is_a_functor + ~closure_origin:(Closure_origin.create (Closure_id.wrap new_fun_var)) let make_stub unused var (fun_decl : Flambda.function_declaration) ~specialised_args ~additional_specialised_args = @@ -97,6 +99,7 @@ let make_stub unused var (fun_decl : Flambda.function_declaration) Flambda.create_function_declaration ~params:(List.map snd args') ~body ~stub:true ~dbg:fun_decl.dbg ~inline:Default_inline ~specialise:Default_specialise ~is_a_functor:fun_decl.is_a_functor + ~closure_origin:fun_decl.closure_origin in function_decl, renamed, additional_specialised_args @@ -132,7 +135,9 @@ let separate_unused_arguments ~only_specialised ~specialised_args:set_of_closures.specialised_args ~additional_specialised_args in - let cleaned = remove_params unused fun_decl in + let cleaned = + remove_params unused fun_decl ~new_fun_var:renamed_fun_id + in Variable.Map.add fun_id stub (Variable.Map.add renamed_fun_id cleaned funs), additional_specialised_args diff --git a/middle_end/simple_value_approx.ml b/middle_end/simple_value_approx.ml index 506c755c..29c320be 100644 --- a/middle_end/simple_value_approx.ml +++ b/middle_end/simple_value_approx.ml @@ -66,11 +66,37 @@ and value_closure = { closure_id : Closure_id.t; } +and function_declarations = { + is_classic_mode : bool; + set_of_closures_id : Set_of_closures_id.t; + set_of_closures_origin : Set_of_closures_origin.t; + funs : function_declaration Variable.Map.t; +} + +and function_body = { + free_variables : Variable.Set.t; + free_symbols : Symbol.Set.t; + stub : bool; + dbg : Debuginfo.t; + inline : Lambda.inline_attribute; + specialise : Lambda.specialise_attribute; + is_a_functor : bool; + body : Flambda.t; +} + +and function_declaration = { + closure_origin : Closure_origin.t; + params : Parameter.t list; + function_body : function_body option; +} + and value_set_of_closures = { - function_decls : Flambda.function_declarations; + function_decls : function_declarations; bound_vars : t Var_within_closure.Map.t; - invariant_params : Variable.Set.t Variable.Map.t lazy_t; - size : int option Variable.Map.t lazy_t; + free_vars : Flambda.specialised_to Variable.Map.t; + invariant_params : Variable.Set.t Variable.Map.t Lazy.t; + recursive : Variable.Set.t Lazy.t; + size : int option Variable.Map.t Lazy.t; specialised_args : Flambda.specialised_to Variable.Map.t; freshening : Freshening.Project_var.t; direct_call_surrogates : Closure_id.t Closure_id.Map.t; @@ -88,11 +114,16 @@ and value_float_array = { let descr t = t.descr let print_value_set_of_closures ppf - { function_decls = { funs }; invariant_params; freshening; _ } = - Format.fprintf ppf "(set_of_closures:@ %a invariant_params=%a freshening=%a)" + { function_decls = { funs }; invariant_params; freshening; size; _ } = + Format.fprintf ppf "(set_of_closures:@ %a invariant_params=%a freshening=%a size=%a)" (fun ppf -> Variable.Map.iter (fun id _ -> Variable.print ppf id)) funs (Variable.Map.print Variable.Set.print) (Lazy.force invariant_params) Freshening.Project_var.print freshening + (Variable.Map.print (fun ppf some_size -> + match some_size with + | None -> Format.fprintf ppf "None" + | Some size -> Format.fprintf ppf "Some %d" size)) + (Lazy.force size) let print_unresolved_value ppf = function | Set_of_closures_id set -> @@ -100,6 +131,41 @@ let print_unresolved_value ppf = function | Symbol symbol -> Format.fprintf ppf "Symbol %a" Symbol.print symbol +let print_function_declaration ppf var (f : function_declaration) = + let param ppf p = Variable.print ppf (Parameter.var p) in + let params ppf = List.iter (Format.fprintf ppf "@ %a" param) in + match f.function_body with + | None -> + Format.fprintf ppf "@[<2>(%a@ =@ fun@[<2>%a@])@]@ " + Variable.print var params f.params + | Some (b : function_body) -> + let stub = if b.stub then " *stub*" else "" in + let is_a_functor = if b.is_a_functor then " *functor*" else "" in + let inline = + match b.inline with + | Always_inline -> " *inline*" + | Never_inline -> " *never_inline*" + | Unroll _ -> " *unroll*" + | Default_inline -> "" + in + let specialise = + match b.specialise with + | Always_specialise -> " *specialise*" + | Never_specialise -> " *never_specialise*" + | Default_specialise -> "" + in + let print_body ppf _ = + Format.fprintf ppf "" + in + Format.fprintf ppf "@[<2>(%a%s%s%s%s@ =@ fun@[<2>%a@] ->@ @[<2><%a>@])@]@ " + Variable.print var stub is_a_functor inline specialise + params f.params + print_body b + +let print_function_declarations ppf (fd : function_declarations) = + let funs ppf = Variable.Map.iter (print_function_declaration ppf) in + Format.fprintf ppf "@[<2>(%a)@]" funs fd.funs + let rec print_descr ppf = function | Value_int i -> Format.pp_print_int ppf i | Value_char c -> Format.fprintf ppf "%c" c @@ -236,30 +302,39 @@ let value_closure ?closure_var ?set_of_closures_var ?set_of_closures_symbol } let create_value_set_of_closures - ~(function_decls : Flambda.function_declarations) ~bound_vars - ~invariant_params ~specialised_args ~freshening + ~(function_decls : function_declarations) ~bound_vars ~free_vars + ~invariant_params ~recursive ~specialised_args ~freshening ~direct_call_surrogates = let size = lazy ( let functions = Variable.Map.keys function_decls.funs in - Variable.Map.map (fun (function_decl : Flambda.function_declaration) -> - let params = Parameter.Set.vars function_decl.params in - let free_vars = - Variable.Set.diff - (Variable.Set.diff function_decl.free_variables params) - functions - in - let num_free_vars = Variable.Set.cardinal free_vars in - let max_size = - Inlining_cost.maximum_interesting_size_of_function_body - num_free_vars - in - Inlining_cost.lambda_smaller' function_decl.body ~than:max_size) - function_decls.funs) + Variable.Map.fold + (fun fun_var function_decl sizes -> + match function_decl.function_body with + | None -> sizes + | Some function_body -> + let params = Parameter.Set.vars function_decl.params in + let free_vars = + Variable.Set.diff + (Variable.Set.diff function_body.free_variables params) + functions + in + let num_free_vars = Variable.Set.cardinal free_vars in + let max_size = + Inlining_cost.maximum_interesting_size_of_function_body + num_free_vars + in + let size = + Inlining_cost.lambda_smaller' function_body.body ~than:max_size + in + Variable.Map.add fun_var size sizes) + function_decls.funs Variable.Map.empty) in { function_decls; bound_vars; + free_vars; invariant_params; + recursive; size; specialised_args; freshening; @@ -303,37 +378,40 @@ let make_const_int_named n : Flambda.named * t = let make_const_int (n : int) = let name = match n with - | 0 -> "const_zero" - | 1 -> "const_one" - | _ -> "const_int" + | 0 -> Internal_variable_names.const_zero + | 1 -> Internal_variable_names.const_one + | _ -> Internal_variable_names.const_int in name_expr_fst (make_const_int_named n) ~name let make_const_char_named n : Flambda.named * t = Const (Char n), value_char n let make_const_char n = - name_expr_fst (make_const_char_named n) ~name:"const_char" + let name = Internal_variable_names.const_char in + name_expr_fst (make_const_char_named n) ~name let make_const_ptr_named n : Flambda.named * t = Const (Const_pointer n), value_constptr n let make_const_ptr (n : int) = let name = match n with - | 0 -> "const_ptr_zero" - | 1 -> "const_ptr_one" - | _ -> "const_ptr" + | 0 -> Internal_variable_names.const_ptr_zero + | 1 -> Internal_variable_names.const_ptr_one + | _ -> Internal_variable_names.const_ptr in name_expr_fst (make_const_ptr_named n) ~name let make_const_bool_named b : Flambda.named * t = make_const_ptr_named (if b then 1 else 0) let make_const_bool b = - name_expr_fst (make_const_bool_named b) ~name:"const_bool" + name_expr_fst (make_const_bool_named b) + ~name:Internal_variable_names.const_bool let make_const_float_named f : Flambda.named * t = Allocated_const (Float f), value_float f let make_const_float f = - name_expr_fst (make_const_float_named f) ~name:"const_float" + name_expr_fst (make_const_float_named f) + ~name:Internal_variable_names.const_float let make_const_boxed_int_named (type bi) (t:bi boxed_int) (i:bi) : Flambda.named * t = @@ -345,7 +423,8 @@ let make_const_boxed_int_named (type bi) (t:bi boxed_int) (i:bi) in Allocated_const c, value_boxed_int t i let make_const_boxed_int t i = - name_expr_fst (make_const_boxed_int_named t i) ~name:"const_boxed_int" + name_expr_fst (make_const_boxed_int_named t i) + ~name:Internal_variable_names.const_boxed_int type simplification_summary = | Nothing_done @@ -373,7 +452,8 @@ let simplify t (lam : Flambda.t) : simplification_result = let const, approx = make_const_boxed_int t i in const, Replaced_term, approx | Value_symbol sym -> - U.name_expr (Symbol sym) ~name:"symbol", Replaced_term, t + let name = Internal_variable_names.symbol in + U.name_expr (Symbol sym) ~name, Replaced_term, t | Value_string _ | Value_float_array _ | Value_float None | Value_block _ | Value_set_of_closures _ | Value_closure _ | Value_unknown _ | Value_bottom | Value_extern _ | Value_unresolved _ -> @@ -440,10 +520,12 @@ let simplify_using_env t ~is_present_in_env flam = | Some var when is_present_in_env var -> true, Flambda.Var var | _ -> match t.symbol with - | Some (sym, None) -> true, - U.name_expr (Symbol sym) ~name:"symbol" + | Some (sym, None) -> + let name = Internal_variable_names.symbol in + (true, U.name_expr (Symbol sym) ~name) | Some (sym, Some field) -> - true, U.name_expr (Read_symbol_field (sym, field)) ~name:"symbol_field" + let name = Internal_variable_names.symbol_field in + (true, U.name_expr (Read_symbol_field (sym, field)) ~name) | None -> false, flam in let const, summary, approx = simplify t flam in @@ -573,6 +655,12 @@ let equal_boxed_int (type t1) (type t2) | Nativeint, Nativeint -> Nativeint.equal i1 i2 | _ -> false +let equal_floats f1 f2 = + match f1, f2 with + | None, None -> true + | None, Some _ | Some _, None -> false + | Some f1, Some f2 -> Allocated_const.compare_floats f1 f2 = 0 + (* Closures and set of closures descriptions cannot be merged. let f x = @@ -603,7 +691,7 @@ let rec meet_descr ~really_import_approx d1 d2 = match d1, d2 with d1 | Value_extern e1, Value_extern e2 when Export_id.equal e1 e2 -> d1 - | Value_float i, Value_float j when i = j -> + | Value_float i, Value_float j when equal_floats i j -> d1 | Value_boxed_int (bi1, i1), Value_boxed_int (bi2, i2) when equal_boxed_int bi1 i1 bi2 i2 -> @@ -660,15 +748,17 @@ let freshen_and_check_closure_id value_set_of_closures.freshening closure_id in try - ignore (Flambda_utils.find_declaration closure_id - value_set_of_closures.function_decls); + ignore ( + Variable.Map.find (Closure_id.unwrap closure_id) + value_set_of_closures.function_decls.funs + ); closure_id with Not_found -> Misc.fatal_error (Format.asprintf "Function %a not found in the set of closures@ %a@.%a@." Closure_id.print closure_id print_value_set_of_closures value_set_of_closures - Flambda.print_function_declarations value_set_of_closures.function_decls) + print_function_declarations value_set_of_closures.function_decls) type checked_approx_for_set_of_closures = | Wrong @@ -859,3 +949,93 @@ let potentially_taken_block_switch_branch t tag = Cannot_be_taken | Value_bottom -> Cannot_be_taken + +let function_arity (fun_decl : function_declaration) = + List.length fun_decl.params + +let function_declaration_approx ~keep_body fun_var + (fun_decl : Flambda.function_declaration) = + let function_body = + if not (keep_body fun_var fun_decl) then None + else begin + Some { body = fun_decl.body; + stub = fun_decl.stub; + inline = fun_decl.inline; + dbg = fun_decl.dbg; + specialise = fun_decl.specialise; + is_a_functor = fun_decl.is_a_functor; + free_variables = fun_decl.free_variables; + free_symbols = fun_decl.free_symbols; } + end + in + { function_body; + params = fun_decl.params; + closure_origin = fun_decl.closure_origin; } + +let function_declarations_approx ~keep_body + (fun_decls : Flambda.function_declarations) = + let funs = + Variable.Map.mapi (function_declaration_approx ~keep_body) fun_decls.funs + in + { funs; + is_classic_mode = fun_decls.is_classic_mode; + set_of_closures_id = fun_decls.set_of_closures_id; + set_of_closures_origin = fun_decls.set_of_closures_origin; } + +let import_function_declarations_for_pack function_decls + import_set_of_closures_id import_set_of_closures_origin = + { set_of_closures_id = + import_set_of_closures_id function_decls.set_of_closures_id; + set_of_closures_origin = + import_set_of_closures_origin function_decls.set_of_closures_origin; + funs = function_decls.funs; + is_classic_mode = function_decls.is_classic_mode; + } + +let update_function_declarations function_decls ~funs = + let compilation_unit = Compilation_unit.get_current_exn () in + let is_classic_mode = function_decls.is_classic_mode in + let set_of_closures_id = Set_of_closures_id.create compilation_unit in + let set_of_closures_origin = function_decls.set_of_closures_origin in + { is_classic_mode; + set_of_closures_id; + set_of_closures_origin; + funs; + } + +let clear_function_bodies (function_decls : function_declarations) = + let funs = + Variable.Map.map (fun (fun_decl : function_declaration) -> + match fun_decl.function_body with + | None | Some { stub = true; _ } -> + fun_decl + | Some _ -> + { fun_decl with function_body = None }) + function_decls.funs + in + { function_decls with funs } + +let update_function_declaration_body + (function_decl : function_declaration) + (f : Flambda.t -> Flambda.t) = + match function_decl.function_body with + | None -> function_decl + | Some function_body -> + let new_function_body = + let body = f function_body.body in + let free_variables = Flambda.free_variables body in + let free_symbols = Flambda.free_symbols body in + { function_body with free_variables; free_symbols; body; } + in + { function_decl with function_body = Some new_function_body } + +let make_closure_map input = + let map = ref Closure_id.Map.empty in + let add_set_of_closures _ (function_decls : function_declarations) = + Variable.Map.iter (fun var _ -> + let closure_id = Closure_id.wrap var in + map := Closure_id.Map.add closure_id function_decls !map) + function_decls.funs + in + Set_of_closures_id.Map.iter add_set_of_closures input; + !map diff --git a/middle_end/simple_value_approx.mli b/middle_end/simple_value_approx.mli index 6e082e32..a193e77e 100644 --- a/middle_end/simple_value_approx.mli +++ b/middle_end/simple_value_approx.mli @@ -143,13 +143,47 @@ and value_closure = { closure_id : Closure_id.t; } +and function_declarations = private { + is_classic_mode: bool; + set_of_closures_id : Set_of_closures_id.t; + set_of_closures_origin : Set_of_closures_origin.t; + funs : function_declaration Variable.Map.t; +} + +and function_body = private { + free_variables : Variable.Set.t; + free_symbols : Symbol.Set.t; + stub : bool; + dbg : Debuginfo.t; + inline : Lambda.inline_attribute; + specialise : Lambda.specialise_attribute; + is_a_functor : bool; + body : Flambda.t; +} + +and function_declaration = private { + closure_origin : Closure_origin.t; + params : Parameter.t list; + function_body : function_body option; +} + + (* CR-soon mshinwell: add support for the approximations of the results, so we can do all of the tricky higher-order cases. *) +(* when [is_classic_mode] is [false], functions in [function_declarations] + are guranteed to have function bodies (ie: + [function_declaration.function_body] will be of the [Some] variant). + + When it [is_classic_mode] is [true], however, no gurantees about the + function_bodies are given. +*) and value_set_of_closures = private { - function_decls : Flambda.function_declarations; + function_decls : function_declarations; bound_vars : t Var_within_closure.Map.t; - invariant_params : Variable.Set.t Variable.Map.t lazy_t; - size : int option Variable.Map.t lazy_t; + free_vars : Flambda.specialised_to Variable.Map.t; + invariant_params : Variable.Set.t Variable.Map.t Lazy.t; + recursive : Variable.Set.t Lazy.t; + size : int option Variable.Map.t Lazy.t; (** For functions that are very likely to be inlined, the size of the function's body. *) specialised_args : Flambda.specialised_to Variable.Map.t; @@ -178,11 +212,22 @@ val print_value_set_of_closures : Format.formatter -> value_set_of_closures -> unit +val print_function_declarations + : Format.formatter + -> function_declarations + -> unit + +val function_declarations_approx + : keep_body:(Variable.t -> Flambda.function_declaration -> bool) + -> Flambda.function_declarations + -> function_declarations val create_value_set_of_closures - : function_decls:Flambda.function_declarations + : function_decls:function_declarations -> bound_vars:t Var_within_closure.Map.t + -> free_vars:Flambda.specialised_to Variable.Map.t -> invariant_params:Variable.Set.t Variable.Map.t lazy_t + -> recursive:Variable.Set.t Lazy.t -> specialised_args:Flambda.specialised_to Variable.Map.t -> freshening:Freshening.Project_var.t -> direct_call_surrogates:Closure_id.t Closure_id.Map.t @@ -426,3 +471,31 @@ type switch_branch_selection = (** Check that the branch is compatible with the approximation *) val potentially_taken_const_switch_branch : t -> int -> switch_branch_selection val potentially_taken_block_switch_branch : t -> int -> switch_branch_selection + +val function_arity : function_declaration -> int + +(** Create a set of function declarations based on another set of function + declarations. *) +val update_function_declarations + : function_declarations + -> funs:function_declaration Variable.Map.t + -> function_declarations + +val import_function_declarations_for_pack + : function_declarations + -> (Set_of_closures_id.t -> Set_of_closures_id.t) + -> (Set_of_closures_origin.t -> Set_of_closures_origin.t) + -> function_declarations + +val update_function_declaration_body + : function_declaration + -> (Flambda.t -> Flambda.t) + -> function_declaration + +(** Creates a map from closure IDs to function declarations by iterating over + all sets of closures in the given map. *) +val make_closure_map + : function_declarations Set_of_closures_id.Map.t + -> function_declarations Closure_id.Map.t + +val clear_function_bodies : function_declarations -> function_declarations diff --git a/middle_end/simplify_boxed_integer_ops.ml b/middle_end/simplify_boxed_integer_ops.ml index 8fdc045d..31b66923 100644 --- a/middle_end/simplify_boxed_integer_ops.ml +++ b/middle_end/simplify_boxed_integer_ops.ml @@ -73,7 +73,7 @@ end) : Simplify_boxed_integer_ops_intf.S with type t := I.t = struct | Porbint kind when kind = I.kind -> eval I.logor | Pxorbint kind when kind = I.kind -> eval I.logxor | Pbintcomp (kind, c) when kind = I.kind -> - S.const_comparison_expr expr c n1 n2 + S.const_integer_comparison_expr expr c n1 n2 | _ -> expr, A.value_unknown Other, C.Benefit.zero let simplify_binop_int (p : Lambda.primitive) (kind : I.t A.boxed_int) diff --git a/middle_end/simplify_common.ml b/middle_end/simplify_common.ml index 8044621b..3b408be2 100644 --- a/middle_end/simplify_common.ml +++ b/middle_end/simplify_common.ml @@ -52,15 +52,32 @@ let const_boxed_int_expr expr t i = new_expr, approx, C.Benefit.remove_code_named expr C.Benefit.zero else expr, A.value_boxed_int t i, C.Benefit.zero -let const_comparison_expr expr (cmp : Lambda.comparison) x y = +let const_integer_comparison_expr expr (cmp : Lambda.integer_comparison) x y = (* Using the [Pervasives] comparison functions here in the compiler coincides with the definitions of such functions in the code compiled by the user, and is thus correct. *) const_bool_expr expr (match cmp with | Ceq -> x = y - | Cneq -> x <> y + | Cne -> x <> y | Clt -> x < y | Cgt -> x > y | Cle -> x <= y | Cge -> x >= y) + +let const_float_comparison_expr expr (cmp : Lambda.float_comparison) x y = + (* Using the [Pervasives] comparison functions here in the compiler + coincides with the definitions of such functions in the code + compiled by the user, and is thus correct. *) + const_bool_expr expr + (match cmp with + | CFeq -> x = y + | CFneq -> not (x = y) + | CFlt -> x < y + | CFnlt -> not (x < y) + | CFgt -> x > y + | CFngt -> not (x > y) + | CFle -> x <= y + | CFnle -> not (x <= y) + | CFge -> x >= y + | CFnge -> not (x >= y)) diff --git a/middle_end/simplify_common.mli b/middle_end/simplify_common.mli index 1ab90cce..ef0c0cf7 100644 --- a/middle_end/simplify_common.mli +++ b/middle_end/simplify_common.mli @@ -58,9 +58,16 @@ val const_boxed_int_expr -> 'a -> Flambda.named * Simple_value_approx.t * Inlining_cost.Benefit.t -val const_comparison_expr +val const_integer_comparison_expr : Flambda.named - -> Lambda.comparison + -> Lambda.integer_comparison + -> 'a + -> 'a + -> Flambda.named * Simple_value_approx.t * Inlining_cost.Benefit.t + +val const_float_comparison_expr + : Flambda.named + -> Lambda.float_comparison -> 'a -> 'a -> Flambda.named * Simple_value_approx.t * Inlining_cost.Benefit.t diff --git a/middle_end/simplify_primitives.ml b/middle_end/simplify_primitives.ml index 759728d9..75c6a7f3 100644 --- a/middle_end/simplify_primitives.ml +++ b/middle_end/simplify_primitives.ml @@ -115,7 +115,7 @@ let primitive (p : Lambda.primitive) (args, approxs) expr dbg ~size_int expr, approx, C.Benefit.zero | Pintcomp Ceq when phys_equal approxs -> S.const_bool_expr expr true - | Pintcomp Cneq when phys_equal approxs -> + | Pintcomp Cne when phys_equal approxs -> S.const_bool_expr expr false (* N.B. Having [not (phys_equal approxs)] would not on its own tell us anything about whether the two values concerned are unequal. To judge @@ -140,7 +140,7 @@ let primitive (p : Lambda.primitive) (args, approxs) expr dbg ~size_int invalid. *) | Pintcomp Ceq when phys_different approxs -> S.const_bool_expr expr false - | Pintcomp Cneq when phys_different approxs -> + | Pintcomp Cne when phys_different approxs -> S.const_bool_expr expr true (* If two values are structurally different we are certain they can never be shared*) @@ -174,13 +174,13 @@ let primitive (p : Lambda.primitive) (args, approxs) expr dbg ~size_int | Plslint when shift_precond -> S.const_int_expr expr (x lsl y) | Plsrint when shift_precond -> S.const_int_expr expr (x lsr y) | Pasrint when shift_precond -> S.const_int_expr expr (x asr y) - | Pintcomp cmp -> S.const_comparison_expr expr cmp x y + | Pintcomp cmp -> S.const_integer_comparison_expr expr cmp x y | Pisout -> S.const_bool_expr expr (y > x || y < 0) | _ -> expr, A.value_unknown Other, C.Benefit.zero end | [Value_char x; Value_char y] -> begin match p with - | Pintcomp cmp -> S.const_comparison_expr expr cmp x y + | Pintcomp cmp -> S.const_integer_comparison_expr expr cmp x y | _ -> expr, A.value_unknown Other, C.Benefit.zero end | [Value_constptr x] -> @@ -220,7 +220,7 @@ let primitive (p : Lambda.primitive) (args, approxs) expr dbg ~size_int | Psubfloat -> S.const_float_expr expr (n1 -. n2) | Pmulfloat -> S.const_float_expr expr (n1 *. n2) | Pdivfloat -> S.const_float_expr expr (n1 /. n2) - | Pfloatcomp c -> S.const_comparison_expr expr c n1 n2 + | Pfloatcomp c -> S.const_float_comparison_expr expr c n1 n2 | _ -> expr, A.value_unknown Other, C.Benefit.zero end | [A.Value_boxed_int(A.Nativeint, n)] -> diff --git a/middle_end/unbox_closures.ml b/middle_end/unbox_closures.ml index 43c22abe..00c696b2 100644 --- a/middle_end/unbox_closures.ml +++ b/middle_end/unbox_closures.ml @@ -22,7 +22,6 @@ module E = Inline_and_simplify_aux.Env module Transform = struct let pass_name = "unbox-closures" - let variable_suffix = "" let precondition ~env ~(set_of_closures : Flambda.set_of_closures) = !Clflags.unbox_closures diff --git a/middle_end/unbox_closures.mli b/middle_end/unbox_closures.mli index 6fa07a1b..fb935a62 100644 --- a/middle_end/unbox_closures.mli +++ b/middle_end/unbox_closures.mli @@ -26,6 +26,7 @@ val rewrite_set_of_closures env:Inline_and_simplify_aux.Env.t -> set_of_closures:Flambda.set_of_closures -> fun_var:Variable.t + -> new_fun_var:Variable.t -> Flambda.function_declaration * Flambda.specialised_to Variable.Map.t) -> set_of_closures:Flambda.set_of_closures diff --git a/middle_end/unbox_free_vars_of_closures.ml b/middle_end/unbox_free_vars_of_closures.ml index 41c3c4ff..be556c13 100644 --- a/middle_end/unbox_free_vars_of_closures.ml +++ b/middle_end/unbox_free_vars_of_closures.ml @@ -20,7 +20,6 @@ module B = Inlining_cost.Benefit let pass_name = "unbox-free-vars-of-closures" let () = Pass_wrapper.register ~pass_name -let variable_suffix = "" (* CR-someday mshinwell: Nearly but not quite the same as something that Augment_specialised_args uses. *) @@ -29,7 +28,7 @@ let add_lifted_projections_around_set_of_closures ~definitions_indexed_by_new_inner_vars = let body = Flambda_utils.name_expr (Set_of_closures set_of_closures) - ~name:pass_name + ~name:Internal_variable_names.unbox_free_vars_of_closures in Variable.Map.fold (fun new_inner_var (projection : Projection.t) (expr, benefit) -> @@ -104,14 +103,8 @@ let run ~env ~(set_of_closures : Flambda.set_of_closures) = "new inner" and a fresh "new outer" var, since we know the definition is not a duplicate. *) let projecting_from = Projection.projecting_from projection in - let new_inner_var = - Variable.rename projecting_from - ~append:variable_suffix - in - let new_outer_var = - Variable.rename projecting_from - ~append:variable_suffix - in + let new_inner_var = Variable.rename projecting_from in + let new_outer_var = Variable.rename projecting_from in let definitions_indexed_by_new_inner_vars = Variable.Map.add new_inner_var projection definitions_indexed_by_new_inner_vars diff --git a/middle_end/unbox_specialised_args.ml b/middle_end/unbox_specialised_args.ml index 32ce4088..64e54eaf 100755 --- a/middle_end/unbox_specialised_args.ml +++ b/middle_end/unbox_specialised_args.ml @@ -21,7 +21,6 @@ module W = ASA.What_to_specialise module Transform = struct let pass_name = "unbox-specialised-args" - let variable_suffix = "" let precondition ~env:_ ~(set_of_closures : Flambda.set_of_closures) = !Clflags.unbox_specialised_args diff --git a/middle_end/unbox_specialised_args.mli b/middle_end/unbox_specialised_args.mli index 1e079591..f0191764 100644 --- a/middle_end/unbox_specialised_args.mli +++ b/middle_end/unbox_specialised_args.mli @@ -43,6 +43,7 @@ val rewrite_set_of_closures env:Inline_and_simplify_aux.Env.t -> set_of_closures:Flambda.set_of_closures -> fun_var:Variable.t + -> new_fun_var:Variable.t -> Flambda.function_declaration * Flambda.specialised_to Variable.Map.t) -> set_of_closures:Flambda.set_of_closures diff --git a/ocamldoc/.depend b/ocamldoc/.depend index a811143b..ab7dcf5b 100644 --- a/ocamldoc/.depend +++ b/ocamldoc/.depend @@ -7,19 +7,17 @@ odoc_analyse.cmo : ../utils/warnings.cmi ../typing/types.cmi \ ../driver/pparse.cmi ../parsing/parse.cmi odoc_types.cmi odoc_text.cmi \ odoc_sig.cmi odoc_module.cmo odoc_misc.cmi odoc_messages.cmo \ odoc_merge.cmi odoc_global.cmi odoc_dep.cmo odoc_cross.cmi \ - odoc_comments.cmi odoc_class.cmo odoc_ast.cmi ../parsing/longident.cmi \ - ../parsing/location.cmi ../parsing/lexer.cmi ../typing/env.cmi \ - ../utils/config.cmi ../utils/clflags.cmi ../parsing/asttypes.cmi \ - odoc_analyse.cmi + odoc_comments.cmi odoc_class.cmo odoc_ast.cmi ../parsing/location.cmi \ + ../parsing/lexer.cmi ../typing/env.cmi ../utils/config.cmi \ + ../utils/clflags.cmi odoc_analyse.cmi odoc_analyse.cmx : ../utils/warnings.cmx ../typing/types.cmx \ ../typing/typemod.cmx ../typing/typedtree.cmx ../parsing/syntaxerr.cmx \ ../driver/pparse.cmx ../parsing/parse.cmx odoc_types.cmx odoc_text.cmx \ odoc_sig.cmx odoc_module.cmx odoc_misc.cmx odoc_messages.cmx \ odoc_merge.cmx odoc_global.cmx odoc_dep.cmx odoc_cross.cmx \ - odoc_comments.cmx odoc_class.cmx odoc_ast.cmx ../parsing/longident.cmx \ - ../parsing/location.cmx ../parsing/lexer.cmx ../typing/env.cmx \ - ../utils/config.cmx ../utils/clflags.cmx ../parsing/asttypes.cmi \ - odoc_analyse.cmi + odoc_comments.cmx odoc_class.cmx odoc_ast.cmx ../parsing/location.cmx \ + ../parsing/lexer.cmx ../typing/env.cmx ../utils/config.cmx \ + ../utils/clflags.cmx odoc_analyse.cmi odoc_analyse.cmi : odoc_module.cmo odoc_global.cmi odoc_args.cmo : ../utils/warnings.cmi odoc_types.cmi odoc_texi.cmo \ odoc_messages.cmo odoc_man.cmo odoc_latex.cmo odoc_html.cmo \ diff --git a/ocamldoc/Makefile b/ocamldoc/Makefile index dd45b59f..2757bde8 100644 --- a/ocamldoc/Makefile +++ b/ocamldoc/Makefile @@ -16,6 +16,8 @@ ROOTDIR = .. include $(ROOTDIR)/config/Makefile +include $(ROOTDIR)/Makefile.common + OCAMLRUN ?= $(ROOTDIR)/boot/ocamlrun OCAMLYACC ?= $(ROOTDIR)/boot/ocamlyacc @@ -38,7 +40,7 @@ OCAMLLEX = $(OCAMLRUN) $(ROOTDIR)/boot/ocamllex # If they are not, then the preprocessor logic (including the # remove_DEBUG script and the debug target) could be removed. # If they are, it may be better to be able to enable them at run-time -# rather than compile-time, e.g. through a -debug command-line option. +# rather than compile-time, e.g. through a -debug command-line option. # In the following line, "sh" is useful under Windows. Without it, # the ./remove_DEBUG command would be executed by cmd.exe which would not # know how to handle it. @@ -72,16 +74,9 @@ OCAMLDOC_LIBCMI=odoc_info.cmi OCAMLDOC_LIBCMXA=odoc_info.cmxa OCAMLDOC_LIBA=odoc_info.$(A) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR)/ocamldoc - -INSTALL_BINDIR=$(DESTDIR)$(BINDIR) - -#MANO: man ocamldoc -INSTALL_MANODIR=$(DESTDIR)$(MANDIR)/man3 - -INSTALL_MLIS=odoc_info.mli -INSTALL_CMIS=$(INSTALL_MLIS:.mli=.cmi) -INSTALL_CMTS=$(INSTALL_MLIS:.mli=.cmt) $(INSTALL_MLIS:.mli=.cmti) +OCAMLDOC_LIBMLIS=odoc_info.mli +OCAMLDOC_LIBCMIS=$(OCAMLDOC_LIBMLIS:.mli=.cmi) +OCAMLDOC_LIBCMTS=$(OCAMLDOC_LIBMLIS:.mli=.cmt) $(OCAMLDOC_LIBMLIS:.mli=.cmti) ODOC_TEST=odoc_test.cmo GENERATORS_CMOS= \ @@ -97,8 +92,8 @@ endif ############# INCLUDES_DEP=\ - -I $(ROOTDIR)/parsing \ -I $(ROOTDIR)/utils \ + -I $(ROOTDIR)/parsing \ -I $(ROOTDIR)/typing \ -I $(ROOTDIR)/driver \ -I $(ROOTDIR)/bytecomp \ @@ -179,12 +174,6 @@ LIBCMOFILES = $(CMOFILES) LIBCMXFILES = $(LIBCMOFILES:.cmo=.cmx) LIBCMIFILES = $(LIBCMOFILES:.cmo=.cmi) -STDLIB_MLIS=\ - ../stdlib/*.mli \ - ../parsing/*.mli \ - ../otherlibs/$(UNIXLIB)/unix.mli \ - ../otherlibs/str/str.mli \ - ../otherlibs/bigarray/bigarray.mli .PHONY: all all: lib exe generators manpages @@ -295,15 +284,23 @@ odoc_see_lexer.ml: odoc_see_lexer.mll # TODO: it may be good to split the following rule in several ones, e.g. # install-programs, install-doc, install-libs +INSTALL_MANODIR=$(INSTALL_MANDIR)/man3 + .PHONY: install install: $(MKDIR) "$(INSTALL_BINDIR)" - $(MKDIR) "$(INSTALL_LIBDIR)" + $(MKDIR) "$(INSTALL_LIBDIR)/ocamldoc" $(MKDIR) "$(INSTALL_MANODIR)" - $(CP) $(OCAMLDOC) "$(INSTALL_BINDIR)/$(OCAMLDOC)$(EXE)" - $(CP) ocamldoc.hva *.cmi $(OCAMLDOC_LIBCMA) "$(INSTALL_LIBDIR)" - $(CP) $(INSTALL_MLIS) $(INSTALL_CMIS) $(INSTALL_CMTS) "$(INSTALL_LIBDIR)" - if test -d stdlib_man; then $(CP) stdlib_man/* "$(INSTALL_MANODIR)"; else : ; fi + $(INSTALL_PROG) $(OCAMLDOC) "$(INSTALL_BINDIR)/$(OCAMLDOC)$(EXE)" + $(INSTALL_DATA) \ + ocamldoc.hva *.cmi $(OCAMLDOC_LIBCMA) \ + "$(INSTALL_LIBDIR)/ocamldoc" + $(INSTALL_DATA) \ + $(OCAMLDOC_LIBMLIS) $(OCAMLDOC_LIBCMIS) $(OCAMLDOC_LIBCMTS) \ + "$(INSTALL_LIBDIR)/ocamldoc" + if test -d stdlib_man; then \ + $(INSTALL_DATA) stdlib_man/* "$(INSTALL_MANODIR)"; \ + else : ; fi # Note: at the moment, $(INSTALL_MANODIR) is created even if the doc has # not been built. This is not clean and should be changed. @@ -315,11 +312,15 @@ installopt: .PHONY: installopt_really installopt_really: $(MKDIR) "$(INSTALL_BINDIR)" - $(MKDIR) "$(INSTALL_LIBDIR)" - $(CP) $(OCAMLDOC_OPT) "$(INSTALL_BINDIR)/$(OCAMLDOC_OPT)$(EXE)" - $(CP) $(INSTALL_MLIS) $(INSTALL_CMIS) $(INSTALL_CMTS) "$(INSTALL_LIBDIR)" - $(CP) ocamldoc.hva *.cmx $(OCAMLDOC_LIBA) $(OCAMLDOC_LIBCMXA) \ - "$(INSTALL_LIBDIR)" + $(MKDIR) "$(INSTALL_LIBDIR)/ocamldoc" + $(INSTALL_PROG) \ + $(OCAMLDOC_OPT) "$(INSTALL_BINDIR)/$(OCAMLDOC_OPT)$(EXE)" + $(INSTALL_DATA) \ + $(OCAMLDOC_LIBMLIS) $(OCAMLDOC_LIBCMIS) $(OCAMLDOC_LIBCMTS) \ + "$(INSTALL_LIBDIR)/ocamldoc" + $(INSTALL_DATA) \ + ocamldoc.hva *.cmx $(OCAMLDOC_LIBA) $(OCAMLDOC_LIBCMXA) \ + "$(INSTALL_LIBDIR)/ocamldoc" # TODO: also split into several rules @@ -339,7 +340,7 @@ test: test_stdlib: $(MKDIR) $@ $(OCAMLDOC_RUN) -html -colorize-code -sort -d $@ $(INCLUDES) -dump $@/stdlib.odoc -keep-code \ - ../stdlib/pervasives.ml ../stdlib/*.mli \ + ../stdlib/*.mli \ ../otherlibs/$(UNIXLIB)/unix.mli \ ../otherlibs/str/str.mli @@ -382,25 +383,70 @@ test_texi: $(MKDIR) $@ $(OCAMLDOC_RUN) -texi -sort -d $@ $(INCLUDES) odoc*.ml odoc*.mli -stdlib_man/Pervasives.3o: $(OCAMLDOC) $(STDLIB_MLIS) +# stdlib non-prefixed : +####################### +SRC=$(ROOTDIR) +include Makefile.unprefix + +stdlib_man/Pervasives.3o: $(OCAMLDOC) $(STDLIB_MLIS) $(STDLIB_CMIS) $(MKDIR) stdlib_man - $(OCAMLDOC_RUN) -man -d stdlib_man $(INCLUDES) \ - -t "OCaml library" -man-mini $(STDLIB_MLIS) + $(OCAMLDOC_RUN) -man -d stdlib_man -nostdlib -I stdlib_non_prefixed \ + -t "OCaml library" -man-mini $(STDLIB_MLIS) \ + -initially-opened-module Pervasives -stdlib_html/Pervasives.html: $(STDLIB_MLIS) +stdlib_html/Pervasives.html: $(OCAMLDOC) $(STDLIB_MLIS) $(STDLIB_CMIS) $(MKDIR) stdlib_html - $(OCAMLDOC_RUN) -d stdlib_html -html $(INCLUDES) \ - -t "OCaml library" $^ + $(OCAMLDOC_RUN) -d stdlib_html -html -nostdlib -I stdlib_non_prefixed \ + -t "OCaml library" $(STDLIB_MLIS) \ + -initially-opened-module Pervasives .PHONY: autotest_stdlib autotest_stdlib: $(MKDIR) $@ $(OCAMLDOC_RUN) -g autotest/odoc_test.cmo\ $(INCLUDES) -keep-code \ - ../stdlib/pervasives.ml ../stdlib/*.mli \ + ../stdlib/*.mli \ ../otherlibs/$(UNIXLIB)/unix.mli \ ../otherlibs/str/str.mli + +# odoc rules : +############## + +.PHONY: odoc +odoc: + rm -rf odoc + $(MKDIR) odoc + # .cmti --> .odoc + for fn in ../stdlib/stdlib*.cmti; do \ + odoc compile $(INCLUDES) --package stdlib ../stdlib/$$fn; \ + done + for lib in str bigarray; do \ + odoc compile $(INCLUDES) --package $$lib ../otherlibs/$$lib/$$lib.cmti; \ + done + odoc compile $(INCLUDES) --package unix ../otherlibs/$(UNIXLIB)/unix.cmti + for fn in ../parsing/*.cmti; do \ + odoc compile $(INCLUDES) --package parsing ../parsing/$$fn; \ + done + # .odoc --> .html + odoc html $(INCLUDES) --output-dir odoc ../stdlib/stdlib.odoc + for lib in str bigarray $(UNIXLIB); do \ + odoc html $(INCLUDES) --output-dir odoc ../otherlibs/$$lib/$$lib.odoc; \ + done + for fn in ../parsing/*.odoc; do \ + odoc html $(INCLUDES) --output-dir odoc $$fn; \ + done + for d in odoc/*; do \ + lib=`basename $$d`; \ + cd $$d; \ + echo -e The $$lib 'library.\n\nModules\n:{!modules:' * '}' > ../../index.mld; \ + cd ../..; \ + odoc html $(INCLUDES) --output-dir odoc --index-for=$$lib index.mld; \ + rm -f index.mld; \ + done + cp odoc_index.html odoc/index.html + odoc css -o odoc + # backup, clean and depend : ############################ @@ -411,8 +457,9 @@ clean: rm -f odoc_parser.output odoc_text_parser.output rm -f odoc_lexer.ml odoc_text_lexer.ml odoc_see_lexer.ml odoc_ocamlhtml.ml rm -f odoc_parser.ml odoc_parser.mli odoc_text_parser.ml odoc_text_parser.mli - rm -rf stdlib_man + rm -rf stdlib_man stdlib_html rm -f generators/*.cm[taiox] generators/*.$(A) generators/*.$(O) generators/*.cmx[as] + rm -f stdlib_non_prefixed/*.mli stdlib_non_prefixed/*.cmi .PHONY: depend depend: diff --git a/ocamldoc/Makefile.unprefix b/ocamldoc/Makefile.unprefix new file mode 100644 index 00000000..1b036773 --- /dev/null +++ b/ocamldoc/Makefile.unprefix @@ -0,0 +1,102 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Florian Angeletti * +#* * +#* Copyright 2017 * +#* * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + + +include $(SRC)/config/Makefile + +P := +VPATH=.:$(SRC) +include $(SRC)/stdlib/StdlibModules + +STDLIB_UNPREFIXED=$(SRC)/ocamldoc/stdlib_non_prefixed + +STDLIB_MODULES := pervasives $(filter-out stdlib,$(STDLIB_MODULES)) +PARSING_MLIS := $(wildcard $(SRC)/parsing/*.mli) +UTILS_MLIS := $(wildcard $(SRC)/utils/*.mli) +TYPING_MLIS := $(wildcard $(SRC)/typing/*.mli) +BYTECOMP_MLIS := $(wildcard $(SRC)/bytecomp/*.mli) + +# Documented modules: stdlib + otherlib + utils(?) + parsing(for compiler-libs) +STDLIB_MLIS=\ + $(STDLIB_MODULES:%=%.mli) \ + $(PARSING_MLIS:$(SRC)/parsing/%.mli=%.mli) \ + $(UTILS_MLIS:$(SRC)/utils/%.mli=%.mli) \ + str.mli \ + unix.mli unixLabels.mli \ + graphics.mli graphicsX11.mli \ + dynlink.mli \ + thread.mli mutex.mli condition.mli event.mli threadUnix.mli \ + pparse.mli + +STDLIB_MLIS:=$(addprefix $(STDLIB_UNPREFIXED)/, $(STDLIB_MLIS)) + +# Dependencies for the documented modules +STDLIB_DEPS:=$(STDLIB_MLIS) \ + $(TYPING_MLIS:$(SRC)/typing/%.mli=$(STDLIB_UNPREFIXED)/%.mli) \ + $(BYTECOMP_MLIS:$(SRC)/bytecomp/%.mli=$(STDLIB_UNPREFIXED)/%.mli) + +# Add back the isolated modules in typing and bytecomp +STDLIB_MLIS:= $(STDLIB_MLIS) \ +$(addprefix $(STDLIB_UNPREFIXED)/, typemod.mli simplif.mli) + + +STDLIB_CMIS=$(STDLIB_DEPS:%.mli=%.cmi) + + +# Copy mli files from the main source directory + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/stdlib/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/parsing/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/utils/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/$(UNIXLIB)/%.mli + sed 's/Stdlib\.//g' $< > $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/str/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/num/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/graph/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/threads/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/otherlibs/dynlink/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/driver/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/typing/%.mli + cp $< $@ + +$(STDLIB_UNPREFIXED)/%.mli: $(SRC)/bytecomp/%.mli + cp $< $@ + +#Extract the pervasives module from stdlib.mli +$(STDLIB_UNPREFIXED)/pervasives.mli: $(SRC)/stdlib/stdlib.mli $(STDLIB_UNPREFIXED)/extract_pervasives.awk + $(AWK) -f $(STDLIB_UNPREFIXED)/extract_pervasives.awk $< > $@ + +# Build cmis file inside the STDLIB_UNPREFIXED directories +$(STDLIB_CMIS): $(STDLIB_DEPS) + cd $(STDLIB_UNPREFIXED); $(MAKE) $(notdir $(STDLIB_CMIS)) diff --git a/ocamldoc/odoc_analyse.ml b/ocamldoc/odoc_analyse.ml index 1393d571..ff79ece7 100644 --- a/ocamldoc/odoc_analyse.ml +++ b/ocamldoc/odoc_analyse.ml @@ -28,30 +28,23 @@ open Typedtree then the standard library directory. *) let init_path () = Config.load_path := - "" :: List.rev (Config.standard_library :: !Clflags.include_dirs); + "" :: List.rev ( Clflags.std_include_dir () @ !Clflags.include_dirs); Env.reset_cache () (** Return the initial environment in which compilation proceeds. *) let initial_env () = - let initial = - if Config.safe_string then Env.initial_safe_string - else if !Clflags.unsafe_string then Env.initial_unsafe_string - else Env.initial_safe_string - in - let open_mod env m = - let open Asttypes in - let lid = {loc = Location.in_file "ocamldoc command line"; - txt = Longident.parse m } in - snd (Typemod.type_open_ Override env lid.loc lid) in - (* Open the list of modules given as arguments of the "-open" flag - The list is reversed to open the modules in the left-to-right order *) - let to_open = List.rev !Clflags.open_modules in - let to_open = - if Env.get_unit_name () = "Pervasives" - then to_open - else "Pervasives" :: to_open + let initially_opened_module = + let m = !Odoc_global.initially_opened_module in + if m = Env.get_unit_name () then + None + else + Some m in - List.fold_left open_mod initial to_open + Typemod.initial_env + ~loc:(Location.in_file "ocamldoc command line") + ~safe_string:(Config.safe_string || not !Clflags.unsafe_string) + ~initially_opened_module + ~open_implicit_modules:(List.rev !Clflags.open_modules) (** Optionally preprocess a source file *) let preprocess sourcefile = diff --git a/ocamldoc/odoc_args.ml b/ocamldoc/odoc_args.ml index ed14b4f9..cdaf1993 100644 --- a/ocamldoc/odoc_args.ml +++ b/ocamldoc/odoc_args.ml @@ -241,6 +241,8 @@ module Options = Main_args.Make_ocamldoc_options(struct let _where = Compenv.print_standard_library let _verbose = set Clflags.verbose let _nopervasives = set Clflags.nopervasives + let _dno_unique_ids = unset Clflags.unique_ids + let _dunique_ids = set Clflags.unique_ids let _dsource = set Clflags.dump_source let _dparsetree = set Clflags.dump_parsetree let _dtypedtree = set Clflags.dump_typedtree @@ -254,6 +256,8 @@ end) (** The default option list *) let default_options = Options.list @ [ + "-initially-opened-module", Arg.Set_string Odoc_global.initially_opened_module, + M.initially_opened_module; "-text", Arg.String (fun s -> Odoc_global.files := !Odoc_global.files @ [Odoc_global.Text_file s]), M.option_text ; diff --git a/ocamldoc/odoc_global.ml b/ocamldoc/odoc_global.ml index cd528bf2..92b9308e 100644 --- a/ocamldoc/odoc_global.ml +++ b/ocamldoc/odoc_global.ml @@ -77,3 +77,5 @@ let with_trailer = ref true let with_toc = ref true let with_index = ref true + +let initially_opened_module = ref "Stdlib" diff --git a/ocamldoc/odoc_global.mli b/ocamldoc/odoc_global.mli index 0a6ef0c7..509f0243 100644 --- a/ocamldoc/odoc_global.mli +++ b/ocamldoc/odoc_global.mli @@ -102,3 +102,6 @@ val with_header : bool ref (** The flag which indicates if we must generate a trailer.*) val with_trailer : bool ref + +(** Name of the module that is initially opened. *) +val initially_opened_module : string ref diff --git a/ocamldoc/odoc_html.ml b/ocamldoc/odoc_html.ml index 123cc7b5..93c279c1 100644 --- a/ocamldoc/odoc_html.ml +++ b/ocamldoc/odoc_html.ml @@ -1232,7 +1232,7 @@ class html = self#print_header b (self#inner_title in_title); bs b"\n"; self#html_of_code ~with_pre b code; - bs b ""; + bs b "\n"; Buffer.output_buffer chanout b; close_out chanout with @@ -1780,12 +1780,14 @@ class html = | Some _ -> "" ); bs b "\n"; - let print_one constr = + let print_bar () = bs b "\n\n" in - print_concat b "\n" print_one l; + if l = [] then print_bar () else + print_concat b "\n" print_one l; bs b "
      \n"; bs b ""; bs b (self#keyword "|"); bs b "\n"; - bs b ""; + bs b "" in + let print_one constr = + print_bar (); bp b "%s" (Naming.const_target t constr) (self#constructor constr.vc_name); @@ -1823,7 +1825,8 @@ class html = ); bs b "\n
      \n" | Type_record l -> @@ -2425,7 +2428,7 @@ class html = bs b "\n"; List.iter f_group groups ; bs b "
      \n" ; - bs b "\n"; + bs b "\n\n"; Buffer.output_buffer chanout b; close_out chanout with @@ -2479,7 +2482,7 @@ class html = (* the various elements *) List.iter (self#html_of_class_element b) (Class.class_elements ~trans:false cl); - bs b ""; + bs b "\n"; Buffer.output_buffer chanout b; close_out chanout; @@ -2525,7 +2528,7 @@ class html = (* the various elements *) List.iter (self#html_of_class_element b) (Class.class_type_elements ~trans: false clt); - bs b ""; + bs b "\n"; Buffer.output_buffer chanout b; close_out chanout; @@ -2577,7 +2580,7 @@ class html = (self#html_of_module_element b mt.mt_name) (Module.module_type_elements mt); - bs b ""; + bs b "\n"; Buffer.output_buffer chanout b; close_out chanout; @@ -2663,7 +2666,7 @@ class html = (self#html_of_module_element b modu.m_name) (Module.module_elements modu); - bs b ""; + bs b "\n"; Buffer.output_buffer chanout b; close_out chanout; @@ -2727,7 +2730,7 @@ class html = (List.map (fun m -> m.m_name) module_list); | Some _ -> self#html_of_info ~indent: false b info ); - bs b "\n"; + bs b "\n\n"; Buffer.output_buffer chanout b; close_out chanout with diff --git a/ocamldoc/odoc_index.html b/ocamldoc/odoc_index.html new file mode 100644 index 00000000..de9c9acf --- /dev/null +++ b/ocamldoc/odoc_index.html @@ -0,0 +1,40 @@ + + + + Libraries distributed with OCaml + + + + + + +

      The following libraries are distributed with the OCaml distribution.

      +
      + + + + + + + + + + + + + + + + + + + + + + + + + +
      stdlibThe OCaml Standard library.
      unixSystem programming.
      bigarrayLarge, multi-dimensional, numerical arrays.
      strRegular expressions.
      parsingThe OCaml compiler parsing frontend.
      numArbitrary precision integers (deprecated).
      + + diff --git a/ocamldoc/odoc_latex.ml b/ocamldoc/odoc_latex.ml index 1c6075e8..76f6d731 100644 --- a/ocamldoc/odoc_latex.ml +++ b/ocamldoc/odoc_latex.ml @@ -641,13 +641,14 @@ class latex = | None | Some (Other _) -> [] end | Type_variant l -> + if l = [] then (p fmt2 "@[ |"; [CodePre (flush2())]) else ( let constructors = List.map (fun {vc_name; vc_args; vc_ret; vc_text} -> p fmt2 "@[ | %s" vc_name ; let l = self#latex_of_cstr_args f mod_name (vc_args,vc_ret) in l @ (self#entry_comment f vc_text) ) l in - List.flatten constructors + List.flatten constructors) | Type_record l -> self#latex_of_record f mod_name l | Type_open -> diff --git a/ocamldoc/odoc_man.ml b/ocamldoc/odoc_man.ml index 9a4d3f1c..04e66e70 100644 --- a/ocamldoc/odoc_man.ml +++ b/ocamldoc/odoc_man.ml @@ -329,9 +329,9 @@ class man = self#man_of_text_element b (Odoc_info.Code (Odoc_info.use_hidden_modules name)) | Odoc_info.Superscript t -> - bs b "^{"; self#man_of_text2 b t + bs b "^"; self#man_of_text2 b t | Odoc_info.Subscript t -> - bs b "_{"; self#man_of_text2 b t + bs b "_"; self#man_of_text2 b t | Odoc_info.Module_list _ -> () | Odoc_info.Index_list -> diff --git a/ocamldoc/odoc_messages.ml b/ocamldoc/odoc_messages.ml index 6e14f116..0f72c800 100644 --- a/ocamldoc/odoc_messages.ml +++ b/ocamldoc/odoc_messages.ml @@ -238,6 +238,8 @@ let merge_options = merge_all ] ) +let initially_opened_module = " Name of the module that is initially opened" + let help = " Display this list of options" diff --git a/ocamldoc/odoc_print.ml b/ocamldoc/odoc_print.ml index e729fe35..0ce40dcc 100644 --- a/ocamldoc/odoc_print.ml +++ b/ocamldoc/odoc_print.ml @@ -83,7 +83,10 @@ let simpl_class_type t = | Types.Cty_signature cs -> (* we delete vals and methods in order to not print them when displaying the type *) - let tnil = { Types.desc = Types.Tnil ; Types.level = 0; Types.id = 0 } in + let tnil = + { Types.desc = Types.Tnil ; Types.level = 0; Types.scope = None + ; Types.id = 0 } + in Types.Cty_signature { Types.csig_self = { cs.Types.csig_self with Types.desc = Types.Tobject (tnil, ref None) }; csig_vars = Types.Vars.empty ; diff --git a/ocamldoc/odoc_sig.ml b/ocamldoc/odoc_sig.ml index f7d8e428..9f9396f6 100644 --- a/ocamldoc/odoc_sig.ml +++ b/ocamldoc/odoc_sig.ml @@ -248,7 +248,7 @@ module Analyser = let types = let open Types in - { name = (fun ld -> ld.ld_id.Ident.name ); + { name = (fun ld -> Ident.name ld.ld_id ); start = (fun ld -> Loc.start ld.ld_loc); end_ = (fun ld -> Loc.start ld.ld_loc); (* Beware, Loc.start is correct in the code above: @@ -265,7 +265,7 @@ module Analyser = let typedtree = let open Typedtree in - { name = (fun ld -> ld.ld_id.Ident.name ); + { name = (fun ld -> Ident.name ld.ld_id ); start = (fun ld -> Loc.start ld.ld_type.ctyp_loc); end_ = (fun ld -> Loc.end_ ld.ld_type.ctyp_loc); inline_record = begin diff --git a/ocamldoc/remove_DEBUG b/ocamldoc/remove_DEBUG index 3cb47bb8..0eee2df9 100755 --- a/ocamldoc/remove_DEBUG +++ b/ocamldoc/remove_DEBUG @@ -20,5 +20,4 @@ # respecting the cpp # line annotation conventions echo "# 1 \"$1\"" -LC_ALL=C sed -e '/DEBUG/c\ -(* DEBUG statement removed *)' "$1" +LC_ALL=C sed -e '/DEBUG/s/^.*$/(* DEBUG statement removed *)/' "$1" diff --git a/ocamldoc/stdlib_non_prefixed/.depend b/ocamldoc/stdlib_non_prefixed/.depend new file mode 100644 index 00000000..25c847fd --- /dev/null +++ b/ocamldoc/stdlib_non_prefixed/.depend @@ -0,0 +1,185 @@ +annot.cmi : location.cmi +arg.cmi : +arg_helper.cmi : map.cmi +array.cmi : seq.cmi +arrayLabels.cmi : seq.cmi +ast_helper.cmi : parsetree.cmi longident.cmi location.cmi docstrings.cmi \ + asttypes.cmi +ast_invariants.cmi : parsetree.cmi +ast_iterator.cmi : parsetree.cmi location.cmi +ast_mapper.cmi : parsetree.cmi location.cmi +asttypes.cmi : location.cmi +attr_helper.cmi : parsetree.cmi location.cmi format.cmi asttypes.cmi +bigarray.cmi : complex.cmi +btype.cmi : types.cmi set.cmi path.cmi map.cmi hashtbl.cmi format.cmi \ + asttypes.cmi +buffer.cmi : uchar.cmi seq.cmi +build_path_prefix_map.cmi : +builtin_attributes.cmi : parsetree.cmi location.cmi +bytegen.cmi : lambda.cmi instruct.cmi +bytelibrarian.cmi : format.cmi +bytelink.cmi : symtable.cmi format.cmi digest.cmi cmo_format.cmi +bytepackager.cmi : ident.cmi format.cmi env.cmi +bytes.cmi : seq.cmi +bytesLabels.cmi : seq.cmi +bytesections.cmi : +callback.cmi : +camlinternalFormat.cmi : camlinternalFormatBasics.cmi buffer.cmi +camlinternalFormatBasics.cmi : +camlinternalLazy.cmi : +camlinternalMod.cmi : obj.cmi +camlinternalOO.cmi : obj.cmi +ccomp.cmi : +char.cmi : +clflags.cmi : profile.cmi misc.cmi arg.cmi +cmi_format.cmi : types.cmi format.cmi digest.cmi +cmo_format.cmi : tbl.cmi lambda.cmi ident.cmi digest.cmi +cmt_format.cmi : types.cmi typedtree.cmi location.cmi env.cmi digest.cmi \ + cmi_format.cmi +complex.cmi : +condition.cmi : mutex.cmi +config.cmi : +consistbl.cmi : digest.cmi +ctype.cmi : types.cmi path.cmi longident.cmi ident.cmi env.cmi asttypes.cmi +datarepr.cmi : types.cmi path.cmi ident.cmi +depend.cmi : set.cmi parsetree.cmi map.cmi longident.cmi +digest.cmi : +dll.cmi : +docstrings.cmi : parsetree.cmi location.cmi lexing.cmi lazy.cmi +dynlink.cmi : digest.cmi +emitcode.cmi : instruct.cmi ident.cmi cmo_format.cmi +env.cmi : warnings.cmi types.cmi subst.cmi path.cmi misc.cmi map.cmi \ + longident.cmi location.cmi ident.cmi format.cmi digest.cmi consistbl.cmi \ + cmi_format.cmi asttypes.cmi +envaux.cmi : subst.cmi path.cmi format.cmi env.cmi +ephemeron.cmi : hashtbl.cmi +event.cmi : +filename.cmi : +float.cmi : pervasives.cmi +format.cmi : pervasives.cmi buffer.cmi +gc.cmi : +genlex.cmi : stream.cmi +graphics.cmi : +graphicsX11.cmi : +hashtbl.cmi : seq.cmi +ident.cmi : identifiable.cmi +identifiable.cmi : set.cmi map.cmi hashtbl.cmi format.cmi +includeclass.cmi : types.cmi location.cmi format.cmi env.cmi ctype.cmi +includecore.cmi : types.cmi typedtree.cmi location.cmi ident.cmi format.cmi \ + env.cmi +includemod.cmi : types.cmi typedtree.cmi path.cmi location.cmi \ + includecore.cmi ident.cmi format.cmi env.cmi ctype.cmi +instruct.cmi : types.cmi subst.cmi location.cmi lambda.cmi ident.cmi env.cmi +int32.cmi : +int64.cmi : +lambda.cmi : types.cmi primitive.cmi path.cmi location.cmi ident.cmi env.cmi \ + asttypes.cmi +lazy.cmi : +lexer.cmi : parser.cmi location.cmi lexing.cmi format.cmi +lexing.cmi : +list.cmi : seq.cmi +listLabels.cmi : seq.cmi +location.cmi : warnings.cmi lexing.cmi format.cmi +longident.cmi : +map.cmi : seq.cmi +marshal.cmi : +matching.cmi : typedtree.cmi location.cmi lambda.cmi ident.cmi +meta.cmi : obj.cmi instruct.cmi +misc.cmi : set.cmi map.cmi hashtbl.cmi format.cmi +moreLabels.cmi : set.cmi seq.cmi map.cmi hashtbl.cmi +mtype.cmi : types.cmi path.cmi ident.cmi env.cmi +mutex.cmi : +nativeint.cmi : +numbers.cmi : set.cmi int64.cmi identifiable.cmi +obj.cmi : int32.cmi +oo.cmi : camlinternalOO.cmi +oprint.cmi : outcometree.cmi format.cmi +outcometree.cmi : format.cmi asttypes.cmi +parmatch.cmi : types.cmi typedtree.cmi parsetree.cmi location.cmi \ + hashtbl.cmi env.cmi asttypes.cmi +parse.cmi : parsetree.cmi lexing.cmi +parser.cmi : parsetree.cmi location.cmi lexing.cmi docstrings.cmi +parsetree.cmi : longident.cmi location.cmi asttypes.cmi +parsing.cmi : obj.cmi lexing.cmi +path.cmi : ident.cmi +pervasives.cmi : camlinternalFormatBasics.cmi +pparse.cmi : parsetree.cmi misc.cmi lexing.cmi format.cmi +pprintast.cmi : parsetree.cmi format.cmi +predef.cmi : types.cmi path.cmi ident.cmi +primitive.cmi : parsetree.cmi outcometree.cmi location.cmi +printast.cmi : parsetree.cmi format.cmi +printexc.cmi : +printf.cmi : buffer.cmi +printinstr.cmi : instruct.cmi format.cmi +printlambda.cmi : lambda.cmi format.cmi +printpat.cmi : typedtree.cmi format.cmi asttypes.cmi +printtyp.cmi : types.cmi path.cmi outcometree.cmi longident.cmi ident.cmi \ + format.cmi env.cmi asttypes.cmi +printtyped.cmi : typedtree.cmi format.cmi +profile.cmi : format.cmi +queue.cmi : seq.cmi +random.cmi : nativeint.cmi int64.cmi int32.cmi +runtimedef.cmi : +scanf.cmi : pervasives.cmi +semantics_of_primitives.cmi : lambda.cmi +seq.cmi : +set.cmi : seq.cmi +simplif.cmi : misc.cmi location.cmi lambda.cmi ident.cmi +sort.cmi : +spacetime.cmi : +stack.cmi : seq.cmi +stdLabels.cmi : stringLabels.cmi listLabels.cmi bytesLabels.cmi \ + arrayLabels.cmi +str.cmi : +stream.cmi : +string.cmi : seq.cmi +stringLabels.cmi : seq.cmi +strongly_connected_components.cmi : identifiable.cmi +stypes.cmi : typedtree.cmi location.cmi annot.cmi +subst.cmi : types.cmi path.cmi ident.cmi +switch.cmi : location.cmi +symtable.cmi : obj.cmi misc.cmi lambda.cmi ident.cmi format.cmi digest.cmi \ + cmo_format.cmi +syntaxerr.cmi : location.cmi format.cmi +sys.cmi : +targetint.cmi : +tast_mapper.cmi : typedtree.cmi env.cmi asttypes.cmi +tbl.cmi : format.cmi +terminfo.cmi : +thread.cmi : unix.cmi +threadUnix.cmi : unix.cmi +translattribute.cmi : typedtree.cmi parsetree.cmi location.cmi lambda.cmi +translclass.cmi : typedtree.cmi location.cmi lambda.cmi ident.cmi format.cmi \ + asttypes.cmi +translcore.cmi : typedtree.cmi path.cmi location.cmi lambda.cmi ident.cmi \ + format.cmi env.cmi asttypes.cmi +translmod.cmi : typedtree.cmi primitive.cmi location.cmi lambda.cmi \ + ident.cmi format.cmi +translobj.cmi : lambda.cmi ident.cmi env.cmi +translprim.cmi : types.cmi typedtree.cmi primitive.cmi path.cmi location.cmi \ + lambda.cmi ident.cmi format.cmi env.cmi +typeclass.cmi : types.cmi typedtree.cmi parsetree.cmi longident.cmi \ + location.cmi ident.cmi format.cmi env.cmi ctype.cmi asttypes.cmi +typecore.cmi : types.cmi typedtree.cmi path.cmi parsetree.cmi longident.cmi \ + location.cmi ident.cmi format.cmi env.cmi asttypes.cmi annot.cmi +typedecl.cmi : types.cmi typedtree.cmi path.cmi parsetree.cmi longident.cmi \ + location.cmi includecore.cmi ident.cmi format.cmi env.cmi asttypes.cmi +typedtree.cmi : types.cmi primitive.cmi path.cmi parsetree.cmi longident.cmi \ + location.cmi ident.cmi env.cmi asttypes.cmi +typedtreeIter.cmi : typedtree.cmi asttypes.cmi +typedtreeMap.cmi : typedtree.cmi +typemod.cmi : types.cmi typedtree.cmi path.cmi parsetree.cmi misc.cmi \ + longident.cmi location.cmi includemod.cmi ident.cmi format.cmi env.cmi \ + cmi_format.cmi asttypes.cmi +typeopt.cmi : types.cmi typedtree.cmi path.cmi lambda.cmi env.cmi +types.cmi : set.cmi primitive.cmi path.cmi parsetree.cmi map.cmi \ + longident.cmi location.cmi ident.cmi asttypes.cmi +typetexp.cmi : types.cmi typedtree.cmi path.cmi parsetree.cmi longident.cmi \ + location.cmi includemod.cmi format.cmi env.cmi asttypes.cmi +uchar.cmi : +unix.cmi : bigarray.cmi +unixLabels.cmi : unix.cmi bigarray.cmi +untypeast.cmi : typedtree.cmi path.cmi parsetree.cmi longident.cmi \ + location.cmi asttypes.cmi +warnings.cmi : lexing.cmi lazy.cmi +weak.cmi : hashtbl.cmi diff --git a/ocamldoc/stdlib_non_prefixed/Makefile b/ocamldoc/stdlib_non_prefixed/Makefile new file mode 100644 index 00000000..801007ef --- /dev/null +++ b/ocamldoc/stdlib_non_prefixed/Makefile @@ -0,0 +1,25 @@ +TOPDIR=../.. +include $(TOPDIR)/Makefile.tools + +.SUFFIXES: + +OCAMLDEP= $(OCAMLRUN) $(TOPDIR)/tools/ocamldep -slash +OCAMLC_SNP= $(OCAMLRUN) $(TOPDIR)/ocamlc -nostdlib -nopervasives -I $(HERE) + +pervasives.cmi: pervasives.mli camlinternalFormatBasics.cmi + $(OCAMLC_SNP) -c $< + +camlinternalFormatBasics.cmi: \ +camlinternalFormatBasics.mli + $(OCAMLC_SNP) -c $< + +%.cmi: %.mli pervasives.cmi + $(OCAMLC_SNP) -c -open Pervasives $< + +depend: + $(OCAMLDEP) *.mli > .depend + +include .depend + +clean: + rm *.mli *.cmi diff --git a/ocamldoc/stdlib_non_prefixed/extract_pervasives.awk b/ocamldoc/stdlib_non_prefixed/extract_pervasives.awk new file mode 100644 index 00000000..e0f7f872 --- /dev/null +++ b/ocamldoc/stdlib_non_prefixed/extract_pervasives.awk @@ -0,0 +1,23 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Jeremie Dimino, Jane Street Europe * +#* * +#* Copyright 2017 Jane Street Group LLC * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# This script extract the Pervasives submodule from stdlib.mli into +# pervasives.mli, for ocamldoc +BEGIN { state=0 } +/^module Pervasives : sig\r?$/ && state == 0 { state=1 } +/^end\r?$/ && state == 2 { state=3 } +{ + if (state == 1) state=2; + else if (state == 2) print +} diff --git a/ocamltest/.depend b/ocamltest/.depend index 77a652a6..55dacc8d 100644 --- a/ocamltest/.depend +++ b/ocamltest/.depend @@ -8,65 +8,133 @@ run_stubs.$(O): run_stubs.c run.h ../byterun/caml/misc.h \ ../byterun/caml/freelist.h ../byterun/caml/minor_gc.h \ ../byterun/caml/address_class.h ../byterun/caml/io.h \ ../byterun/caml/osdeps.h -actions.cmo : environments.cmi actions.cmi -actions.cmx : environments.cmx actions.cmi -actions.cmi : environments.cmi -backends.cmo : backends.cmi -backends.cmx : backends.cmi -backends.cmi : -builtin_actions.cmo : variables.cmi testlib.cmi run_command.cmi \ - ocamltest_config.cmi filetype.cmi filecompare.cmi environments.cmi \ - builtin_variables.cmi builtin_modifiers.cmi backends.cmi actions.cmi \ +ocamltest_stdlib_stubs.$(O): ocamltest_stdlib_stubs.c \ + ../byterun/caml/config.h ../byterun/caml/m.h ../byterun/caml/s.h \ + ../byterun/caml/mlvalues.h ../byterun/caml/misc.h \ + ../byterun/caml/memory.h ../byterun/caml/gc.h \ + ../byterun/caml/major_gc.h ../byterun/caml/freelist.h \ + ../byterun/caml/minor_gc.h ../byterun/caml/address_class.h \ + ../byterun/caml/alloc.h ../byterun/caml/signals.h \ + ../byterun/caml/osdeps.h +actions.cmo : result.cmi environments.cmi actions.cmi +actions.cmx : result.cmx environments.cmx actions.cmi +actions.cmi : result.cmi environments.cmi +actions_helpers.cmo : variables.cmi run_command.cmi result.cmi \ + ocamltest_stdlib.cmi filecompare.cmi environments.cmi \ + builtin_variables.cmi actions_helpers.cmi +actions_helpers.cmx : variables.cmx run_command.cmx result.cmx \ + ocamltest_stdlib.cmx filecompare.cmx environments.cmx \ + builtin_variables.cmx actions_helpers.cmi +actions_helpers.cmi : variables.cmi result.cmi environments.cmi actions.cmi +builtin_actions.cmo : result.cmi ocamltest_stdlib.cmi ocamltest_config.cmi \ + environments.cmi builtin_variables.cmi actions_helpers.cmi actions.cmi \ builtin_actions.cmi -builtin_actions.cmx : variables.cmx testlib.cmx run_command.cmx \ - ocamltest_config.cmx filetype.cmx filecompare.cmx environments.cmx \ - builtin_variables.cmx builtin_modifiers.cmx backends.cmx actions.cmx \ +builtin_actions.cmx : result.cmx ocamltest_stdlib.cmx ocamltest_config.cmx \ + environments.cmx builtin_variables.cmx actions_helpers.cmx actions.cmx \ builtin_actions.cmi builtin_actions.cmi : actions.cmi -builtin_modifiers.cmo : ocamltest_config.cmi environments.cmi \ - builtin_variables.cmi builtin_modifiers.cmi -builtin_modifiers.cmx : ocamltest_config.cmx environments.cmx \ - builtin_variables.cmx builtin_modifiers.cmi -builtin_modifiers.cmi : environments.cmi -builtin_tests.cmo : tests.cmi ocamltest_config.cmi builtin_actions.cmi \ - builtin_tests.cmi -builtin_tests.cmx : tests.cmx ocamltest_config.cmx builtin_actions.cmx \ - builtin_tests.cmi -builtin_tests.cmi : tests.cmi builtin_variables.cmo : variables.cmi builtin_variables.cmi builtin_variables.cmx : variables.cmx builtin_variables.cmi builtin_variables.cmi : variables.cmi -environments.cmo : variables.cmi environments.cmi -environments.cmx : variables.cmx environments.cmi +environments.cmo : variables.cmi ocamltest_stdlib.cmi environments.cmi +environments.cmx : variables.cmx ocamltest_stdlib.cmx environments.cmi environments.cmi : variables.cmi -filecompare.cmo : testlib.cmi run_command.cmi filecompare.cmi -filecompare.cmx : testlib.cmx run_command.cmx filecompare.cmi +filecompare.cmo : run_command.cmi ocamltest_stdlib.cmi filecompare.cmi +filecompare.cmx : run_command.cmx ocamltest_stdlib.cmx filecompare.cmi filecompare.cmi : -filetype.cmo : filetype.cmi -filetype.cmx : filetype.cmi -filetype.cmi : main.cmo : tsl_semantics.cmi tsl_parser.cmi tsl_lexer.cmi tests.cmi \ - testlib.cmi options.cmi ocamltest_config.cmi environments.cmi \ - builtin_variables.cmi actions.cmi main.cmi + result.cmi options.cmi ocamltest_stdlib.cmi environments.cmi \ + builtin_variables.cmi actions_helpers.cmi actions.cmi main.cmi main.cmx : tsl_semantics.cmx tsl_parser.cmx tsl_lexer.cmx tests.cmx \ - testlib.cmx options.cmx ocamltest_config.cmx environments.cmx \ - builtin_variables.cmx actions.cmx main.cmi + result.cmx options.cmx ocamltest_stdlib.cmx environments.cmx \ + builtin_variables.cmx actions_helpers.cmx actions.cmx main.cmi main.cmi : +ocaml_actions.cmo : result.cmi ocamltest_stdlib.cmi ocamltest_config.cmi \ + ocaml_variables.cmi ocaml_toplevels.cmi ocaml_tools.cmi \ + ocaml_modifiers.cmi ocaml_flags.cmi ocaml_filetypes.cmi ocaml_files.cmi \ + ocaml_directories.cmi ocaml_compilers.cmi ocaml_commands.cmi \ + ocaml_backends.cmi filecompare.cmi environments.cmi builtin_variables.cmi \ + actions_helpers.cmi actions.cmi ocaml_actions.cmi +ocaml_actions.cmx : result.cmx ocamltest_stdlib.cmx ocamltest_config.cmx \ + ocaml_variables.cmx ocaml_toplevels.cmx ocaml_tools.cmx \ + ocaml_modifiers.cmx ocaml_flags.cmx ocaml_filetypes.cmx ocaml_files.cmx \ + ocaml_directories.cmx ocaml_compilers.cmx ocaml_commands.cmx \ + ocaml_backends.cmx filecompare.cmx environments.cmx builtin_variables.cmx \ + actions_helpers.cmx actions.cmx ocaml_actions.cmi +ocaml_actions.cmi : actions.cmi +ocaml_backends.cmo : ocaml_backends.cmi +ocaml_backends.cmx : ocaml_backends.cmi +ocaml_backends.cmi : +ocaml_commands.cmo : ocaml_files.cmi ocaml_commands.cmi +ocaml_commands.cmx : ocaml_files.cmx ocaml_commands.cmi +ocaml_commands.cmi : +ocaml_compilers.cmo : variables.cmi ocamltest_stdlib.cmi ocaml_variables.cmi \ + ocaml_tools.cmi ocaml_files.cmi ocaml_commands.cmi ocaml_backends.cmi \ + builtin_variables.cmi ocaml_compilers.cmi +ocaml_compilers.cmx : variables.cmx ocamltest_stdlib.cmx ocaml_variables.cmx \ + ocaml_tools.cmx ocaml_files.cmx ocaml_commands.cmx ocaml_backends.cmx \ + builtin_variables.cmx ocaml_compilers.cmi +ocaml_compilers.cmi : variables.cmi ocaml_tools.cmi ocaml_backends.cmi +ocaml_directories.cmo : ocamltest_stdlib.cmi ocamltest_config.cmi \ + ocaml_backends.cmi ocaml_directories.cmi +ocaml_directories.cmx : ocamltest_stdlib.cmx ocamltest_config.cmx \ + ocaml_backends.cmx ocaml_directories.cmi +ocaml_directories.cmi : ocaml_backends.cmi +ocaml_files.cmo : ocamltest_stdlib.cmi ocaml_files.cmi +ocaml_files.cmx : ocamltest_stdlib.cmx ocaml_files.cmi +ocaml_files.cmi : +ocaml_filetypes.cmo : ocaml_backends.cmi ocaml_filetypes.cmi +ocaml_filetypes.cmx : ocaml_backends.cmx ocaml_filetypes.cmi +ocaml_filetypes.cmi : ocaml_backends.cmi +ocaml_flags.cmo : ocaml_files.cmi ocaml_directories.cmi ocaml_backends.cmi \ + ocaml_flags.cmi +ocaml_flags.cmx : ocaml_files.cmx ocaml_directories.cmx ocaml_backends.cmx \ + ocaml_flags.cmi +ocaml_flags.cmi : ocaml_backends.cmi +ocaml_modifiers.cmo : ocamltest_stdlib.cmi ocamltest_config.cmi \ + ocaml_variables.cmi environments.cmi ocaml_modifiers.cmi +ocaml_modifiers.cmx : ocamltest_stdlib.cmx ocamltest_config.cmx \ + ocaml_variables.cmx environments.cmx ocaml_modifiers.cmi +ocaml_modifiers.cmi : environments.cmi +ocaml_tests.cmo : tests.cmi ocamltest_config.cmi ocaml_actions.cmi \ + builtin_actions.cmi ocaml_tests.cmi +ocaml_tests.cmx : tests.cmx ocamltest_config.cmx ocaml_actions.cmx \ + builtin_actions.cmx ocaml_tests.cmi +ocaml_tests.cmi : tests.cmi +ocaml_tools.cmo : variables.cmi ocamltest_stdlib.cmi ocaml_variables.cmi \ + ocaml_files.cmi environments.cmi actions_helpers.cmi ocaml_tools.cmi +ocaml_tools.cmx : variables.cmx ocamltest_stdlib.cmx ocaml_variables.cmx \ + ocaml_files.cmx environments.cmx actions_helpers.cmx ocaml_tools.cmi +ocaml_tools.cmi : variables.cmi environments.cmi +ocaml_toplevels.cmo : variables.cmi ocamltest_stdlib.cmi ocaml_variables.cmi \ + ocaml_tools.cmi ocaml_files.cmi ocaml_compilers.cmi ocaml_commands.cmi \ + ocaml_backends.cmi ocaml_toplevels.cmi +ocaml_toplevels.cmx : variables.cmx ocamltest_stdlib.cmx ocaml_variables.cmx \ + ocaml_tools.cmx ocaml_files.cmx ocaml_compilers.cmx ocaml_commands.cmx \ + ocaml_backends.cmx ocaml_toplevels.cmi +ocaml_toplevels.cmi : variables.cmi ocaml_tools.cmi ocaml_compilers.cmi \ + ocaml_backends.cmi +ocaml_variables.cmo : variables.cmi ocamltest_stdlib.cmi ocaml_variables.cmi +ocaml_variables.cmx : variables.cmx ocamltest_stdlib.cmx ocaml_variables.cmi +ocaml_variables.cmi : variables.cmi ocamltest_config.cmo : ocamltest_config.cmi ocamltest_config.cmx : ocamltest_config.cmi ocamltest_config.cmi : +ocamltest_stdlib.cmo : ocamltest_stdlib.cmi +ocamltest_stdlib.cmx : ocamltest_stdlib.cmi +ocamltest_stdlib.cmi : options.cmo : tests.cmi actions.cmi options.cmi options.cmx : tests.cmx actions.cmx options.cmi options.cmi : -run_command.cmo : testlib.cmi run_command.cmi -run_command.cmx : testlib.cmx run_command.cmi +result.cmo : result.cmi +result.cmx : result.cmi +result.cmi : +run_command.cmo : ocamltest_stdlib.cmi run_command.cmi +run_command.cmx : ocamltest_stdlib.cmx run_command.cmi run_command.cmi : -testlib.cmo : testlib.cmi -testlib.cmx : testlib.cmi -testlib.cmi : -tests.cmo : actions.cmi tests.cmi -tests.cmx : actions.cmx tests.cmi -tests.cmi : environments.cmi actions.cmi +tests.cmo : result.cmi actions.cmi tests.cmi +tests.cmx : result.cmx actions.cmx tests.cmi +tests.cmi : result.cmi environments.cmi actions.cmi tsl_ast.cmo : tsl_ast.cmi tsl_ast.cmx : tsl_ast.cmi tsl_ast.cmi : @@ -76,10 +144,10 @@ tsl_lexer.cmi : tsl_parser.cmi tsl_parser.cmo : tsl_ast.cmi tsl_parser.cmi tsl_parser.cmx : tsl_ast.cmx tsl_parser.cmi tsl_parser.cmi : tsl_ast.cmi -tsl_semantics.cmo : variables.cmi tsl_ast.cmi tests.cmi testlib.cmi \ - environments.cmi actions.cmi tsl_semantics.cmi -tsl_semantics.cmx : variables.cmx tsl_ast.cmx tests.cmx testlib.cmx \ - environments.cmx actions.cmx tsl_semantics.cmi +tsl_semantics.cmo : variables.cmi tsl_ast.cmi tests.cmi environments.cmi \ + actions.cmi tsl_semantics.cmi +tsl_semantics.cmx : variables.cmx tsl_ast.cmx tests.cmx environments.cmx \ + actions.cmx tsl_semantics.cmi tsl_semantics.cmi : tsl_ast.cmi tests.cmi environments.cmi actions.cmi variables.cmo : variables.cmi variables.cmx : variables.cmi diff --git a/ocamltest/Makefile b/ocamltest/Makefile index 64c24112..bbae0208 100644 --- a/ocamltest/Makefile +++ b/ocamltest/Makefile @@ -18,9 +18,34 @@ include ../config/Makefile ifeq "$(UNIX_OR_WIN32)" "win32" - ocamlsrcdir := $(shell echo "$(abspath $(shell pwd)/..)"|cygpath -m -f -) + unix := false + ocamlsrcdir := $(shell echo "$(abspath $(shell pwd)/..)"|cygpath -w -f - \ + | sed 's/\\/\\\\\\\\/g') + ifeq "$(wildcard ../flexdll/Makefile)" "" + FLEXLINK_ENV= + else + FLEXLINK_ENV=OCAML_FLEXLINK="../boot/ocamlrun ../flexdll/flexlink.exe" + endif else + unix := true ocamlsrcdir := $(abspath $(shell pwd)/..) + FLEXLINK_ENV= +endif + +ifeq "$(TOOLCHAIN)" "msvc" +CPP := $(CPP) 2> nul +endif + +ifeq "$(WITH_OCAMLDOC)" "ocamldoc" +WITH_OCAMLDOC := true +else +WITH_OCAMLDOC := false +endif + +ifeq "$(WITH_DEBUGGER)" "ocamldebugger" +WITH_OCAMLDEBUG := true +else +WITH_OCAMLDEBUG := false endif CPPFLAGS += -I../byterun -DCAML_INTERNALS @@ -30,27 +55,46 @@ run := run_$(UNIX_OR_WIN32) # List of source files from which ocamltest is compiled # (all the different sorts of files are derived from this) -sources := \ +# ocamltest has two components: its core and the OCaml "plugin" +# which is actually built into the tool but clearly separated from its core + +core := \ $(run).c \ run_stubs.c \ + ocamltest_stdlib_stubs.c \ ocamltest_config.mli ocamltest_config.ml.in \ - testlib.mli testlib.ml \ + ocamltest_stdlib.mli ocamltest_stdlib.ml \ run_command.mli run_command.ml \ - filetype.mli filetype.ml \ filecompare.mli filecompare.ml \ - backends.mli backends.ml \ variables.mli variables.ml \ environments.mli environments.ml \ - builtin_variables.mli builtin_variables.ml \ - builtin_modifiers.mli builtin_modifiers.ml \ + result.mli result.ml \ actions.mli actions.ml \ - builtin_actions.mli builtin_actions.ml \ tests.mli tests.ml \ - builtin_tests.mli builtin_tests.ml \ tsl_ast.mli tsl_ast.ml \ tsl_parser.mly \ tsl_lexer.mli tsl_lexer.mll \ tsl_semantics.mli tsl_semantics.ml \ + builtin_variables.mli builtin_variables.ml \ + actions_helpers.mli actions_helpers.ml \ + builtin_actions.mli builtin_actions.ml + +ocaml_plugin := \ + ocaml_backends.mli ocaml_backends.ml \ + ocaml_filetypes.mli ocaml_filetypes.ml \ + ocaml_variables.mli ocaml_variables.ml \ + ocaml_modifiers.mli ocaml_modifiers.ml \ + ocaml_directories.mli ocaml_directories.ml \ + ocaml_files.mli ocaml_files.ml \ + ocaml_flags.mli ocaml_flags.ml \ + ocaml_commands.mli ocaml_commands.ml \ + ocaml_tools.mli ocaml_tools.ml \ + ocaml_compilers.mli ocaml_compilers.ml \ + ocaml_toplevels.mli ocaml_toplevels.ml \ + ocaml_actions.mli ocaml_actions.ml \ + ocaml_tests.mli ocaml_tests.ml + +sources := $(core) $(ocaml_plugin) \ options.mli options.ml \ main.mli main.ml @@ -94,24 +138,14 @@ bytecode_modules := $(o_files) $(cmo_files) native_modules := $(o_files) $(cmx_files) -directories = ../utils ../parsing ../stdlib ../compilerlibs +directories := ../utils ../parsing ../stdlib ../compilerlibs -include_directories = $(addprefix -I , $(directories)) +include_directories := $(addprefix -I , $(directories)) -flags = -g -nostdlib $(include_directories) \ +flags := -g -nostdlib $(include_directories) \ -strict-sequence -safe-string -strict-formats \ -w +a-4-9-41-42-44-45-48 -warn-error A -ifeq "$(UNIX_OR_WIN32)" "unix" -FLEXLINK_ENV= -else # Windows - ifeq "$(wildcard ../flexdll/Makefile)" "" - FLEXLINK_ENV= - else - FLEXLINK_ENV=OCAML_FLEXLINK="../boot/ocamlrun ../flexdll/flexlink.exe" - endif -endif - ocamlc := $(FLEXLINK_ENV) ../byterun/ocamlrun ../ocamlc $(flags) ocamlopt := $(FLEXLINK_ENV) ../byterun/ocamlrun ../ocamlopt $(flags) @@ -152,13 +186,21 @@ ocamltest.opt$(EXE): $(native_modules) ocamltest_config.ml: ocamltest_config.ml.in sed \ + -e 's|@@AFL_INSTRUMENT@@|$(AFL_INSTRUMENT)|' \ -e 's|@@ARCH@@|$(ARCH)|' \ + -e 's|@@SHARED_LIBRARIES@@|$(SUPPORTS_SHARED_LIBRARIES)|' \ + -e 's|@@UNIX@@|$(unix)|' \ + -e 's|@@SYSTEM@@|$(SYSTEM)|' \ -e 's|@@CPP@@|$(CPP)|' \ -e 's|@@OCAMLCDEFAULTFLAGS@@|$(ocamlcdefaultflags)|' \ -e 's|@@OCAMLOPTDEFAULTFLAGS@@|$(ocamloptdefaultflags)|' \ -e 's|@@OCAMLSRCDIR@@|$(ocamlsrcdir)|' \ -e 's|@@FLAMBDA@@|$(FLAMBDA)|' \ + -e 's|@@SPACETIME@@|$(WITH_SPACETIME)|' \ -e 's|@@FORCE_SAFE_STRING@@|$(FORCE_SAFE_STRING)|' \ + -e 's|@@FLAT_FLOAT_ARRAY@@|$(FLAT_FLOAT_ARRAY)|' \ + -e 's|@@OCAMLDOC@@|$(WITH_OCAMLDOC)|' \ + -e 's|@@OCAMLDEBUG@@|$(WITH_OCAMLDEBUG)|' \ $< > $@ .PHONY: clean diff --git a/ocamltest/actions.ml b/ocamltest/actions.ml index 6df72c5c..cce0571e 100644 --- a/ocamltest/actions.ml +++ b/ocamltest/actions.ml @@ -15,37 +15,29 @@ (* Definition of actions, basic blocks for tests *) -type result = - | Pass of Environments.t - | Fail of string - | Skip of string +type code = out_channel -> Environments.t -> Result.t * Environments.t -let string_of_reason prefix reason = - if reason="" then prefix - else prefix ^ " (" ^ reason ^ ")" +type t = { + name : string; + body : code; + mutable hook : code option +} -let string_of_result = function - | Pass _ -> "Pass" - | Fail reason -> string_of_reason "Fail" reason - | Skip reason -> string_of_reason "Skip" reason +let action_name a = a.name -type body = out_channel -> Environments.t -> result +let make n c = { name = n; body = c; hook = None } -type t = { - action_name : string; - action_environment : Environments.t -> Environments.t; - action_body : body -} +let update action code = { action with body = code } -let compare a1 a2 = String.compare a1.action_name a2.action_name +let compare a1 a2 = String.compare a1.name a2.name let (actions : (string, t) Hashtbl.t) = Hashtbl.create 10 let register action = - Hashtbl.add actions action.action_name action + Hashtbl.add actions action.name action let get_registered_actions () = - let f _action_name action acc = action::acc in + let f _name action acc = action::acc in let unsorted_actions = Hashtbl.fold f actions [] in List.sort compare unsorted_actions @@ -53,15 +45,26 @@ let lookup name = try Some (Hashtbl.find actions name) with Not_found -> None +let set_hook name hook = + let action = (Hashtbl.find actions name) in + action.hook <- Some hook + +let clear_hook name = + let action = (Hashtbl.find actions name) in + action.hook <- None + +let clear_all_hooks () = + let f _name action = action.hook <- None in + Hashtbl.iter f actions + let run log env action = - action.action_body log env + let code = match action.hook with + | None -> action.body + | Some code -> code in + code log env module ActionSet = Set.Make (struct type nonrec t = t let compare = compare end) - -let update_environment initial_env actions = - let f act env = act.action_environment env in - ActionSet.fold f actions initial_env diff --git a/ocamltest/actions.mli b/ocamltest/actions.mli index e9bde853..941fc477 100644 --- a/ocamltest/actions.mli +++ b/ocamltest/actions.mli @@ -15,20 +15,15 @@ (* Definition of actions, basic blocks for tests *) -type result = - | Pass of Environments.t - | Fail of string - | Skip of string +type code = out_channel -> Environments.t -> Result.t * Environments.t -val string_of_result : result -> string +type t -type body = out_channel -> Environments.t -> result +val action_name : t -> string -type t = { - action_name : string; - action_environment : Environments.t -> Environments.t; - action_body : body -} +val update : t -> code -> t + +val make : string -> code -> t val compare : t -> t -> int @@ -38,8 +33,10 @@ val get_registered_actions : unit -> t list val lookup : string -> t option -val run : out_channel -> Environments.t -> t -> result +val set_hook : string -> code -> unit +val clear_hook : string -> unit +val clear_all_hooks : unit -> unit -module ActionSet : Set.S with type elt = t +val run : out_channel -> Environments.t -> t -> Result.t * Environments.t -val update_environment : Environments.t -> ActionSet.t -> Environments.t +module ActionSet : Set.S with type elt = t diff --git a/ocamltest/actions_helpers.ml b/ocamltest/actions_helpers.ml new file mode 100644 index 00000000..875ce1e2 --- /dev/null +++ b/ocamltest/actions_helpers.ml @@ -0,0 +1,291 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Helper functions when writing actions *) + +open Ocamltest_stdlib + +let pass_or_skip test pass_reason skip_reason _log env = + let open Result in + let result = + if test + then pass_with_reason pass_reason + else skip_with_reason skip_reason in + (result, env) + +let mkreason what commandline exitcode = + Printf.sprintf "%s: command\n%s\nfailed with exit code %d" + what commandline exitcode + +let testfile env = + match Environments.lookup Builtin_variables.test_file env with + | None -> assert false + | Some t -> t + +let test_source_directory env = + Environments.safe_lookup Builtin_variables.test_source_directory env + +let test_build_directory env = + Environments.safe_lookup Builtin_variables.test_build_directory env + +let test_build_directory_prefix env = + Environments.safe_lookup Builtin_variables.test_build_directory_prefix env + +let words_of_variable env variable = + String.words (Environments.safe_lookup variable env) + +let exit_status_of_variable env variable = + try int_of_string + (Environments.safe_lookup variable env) + with _ -> 0 + +let files env = words_of_variable env Builtin_variables.files + +let setup_symlinks test_source_directory build_directory files = + let symlink filename = + let src = Filename.concat test_source_directory filename in + let cmd = "ln -sf " ^ src ^" " ^ build_directory in + Sys.run_system_command cmd in + let copy filename = + let src = Filename.concat test_source_directory filename in + let dst = Filename.concat build_directory filename in + Sys.copy_file src dst in + let f = if Sys.os_type="Win32" then copy else symlink in + Sys.make_directory build_directory; + List.iter f files + +let setup_build_env add_testfile additional_files (_log : out_channel) env = + let build_dir = (test_build_directory env) in + let some_files = additional_files @ (files env) in + let files = + if add_testfile + then (testfile env) :: some_files + else some_files in + setup_symlinks (test_source_directory env) build_dir files; + Sys.chdir build_dir; + (Result.pass, env) + +let setup_simple_build_env add_testfile additional_files log env = + let build_env = Environments.add + Builtin_variables.test_build_directory + (test_build_directory_prefix env) env in + setup_build_env add_testfile additional_files log build_env + +let run_cmd + ?(environment=[||]) + ?(stdin_variable=Builtin_variables.stdin) + ?(stdout_variable=Builtin_variables.stdout) + ?(stderr_variable=Builtin_variables.stderr) + ?(append=false) + ?(timeout=0) + log env cmd + = + let log_redirection std filename = + if filename<>"" then + begin + Printf.fprintf log " Redirecting %s to %s \n%!" std filename + end in + let lst = List.concat (List.map String.words cmd) in + let quoted_lst = + if Sys.os_type="Win32" + then List.map Filename.maybe_quote lst + else lst in + let cmd' = String.concat " " quoted_lst in + Printf.fprintf log "Commandline: %s\n" cmd'; + let progname = List.hd quoted_lst in + let arguments = Array.of_list quoted_lst in + let stdin_filename = Environments.safe_lookup stdin_variable env in + let stdout_filename = Environments.safe_lookup stdout_variable env in + let stderr_filename = Environments.safe_lookup stderr_variable env in + log_redirection "stdin" stdin_filename; + log_redirection "stdout" stdout_filename; + log_redirection "stderr" stderr_filename; + let systemenv = + Array.append + environment + (Environments.to_system_env env) + in + Run_command.run { + Run_command.progname = progname; + Run_command.argv = arguments; + Run_command.envp = systemenv; + Run_command.stdin_filename = stdin_filename; + Run_command.stdout_filename = stdout_filename; + Run_command.stderr_filename = stderr_filename; + Run_command.append = append; + Run_command.timeout = timeout; + Run_command.log = log + } + +let run + (log_message : string) + (redirect_output : bool) + (can_skip : bool) + (prog_variable : Variables.t) + (args_variable : Variables.t option) + (log : out_channel) + (env : Environments.t) + = + match Environments.lookup prog_variable env with + | None -> + let msg = Printf.sprintf "%s: variable %s is undefined" + log_message (Variables.name_of_variable prog_variable) in + (Result.fail_with_reason msg, env) + | Some program -> + let arguments = match args_variable with + | None -> "" + | Some variable -> Environments.safe_lookup variable env in + let commandline = [program; arguments] in + let what = log_message ^ " " ^ program ^ " " ^ + begin if arguments="" then "without any argument" + else "with arguments " ^ arguments + end in + let env = + if redirect_output + then begin + let output = Environments.safe_lookup Builtin_variables.output env in + let env = + Environments.add_if_undefined Builtin_variables.stdout output env + in + Environments.add_if_undefined Builtin_variables.stderr output env + end else env + in + let expected_exit_status = + exit_status_of_variable env Builtin_variables.exit_status + in + let exit_status = run_cmd log env commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = mkreason what (String.concat " " commandline) exit_status in + if exit_status = 125 && can_skip + then (Result.skip_with_reason reason, env) + else (Result.fail_with_reason reason, env) + end + +let run_program = + run + "Running program" + true + false + Builtin_variables.program + (Some Builtin_variables.arguments) + +let run_script log env = + let response_file = Filename.temp_file "ocamltest-" ".response" in + Printf.fprintf log "Script should write its response to %s\n%!" + response_file; + let scriptenv = Environments.add + Builtin_variables.ocamltest_response response_file env in + let (result, newenv) = run + "Running script" + false + true + Builtin_variables.script + None + log scriptenv in + if Result.is_pass result then begin + let modifiers = Environments.modifiers_of_file response_file in + let modified_env = Environments.apply_modifiers newenv modifiers in + (result, modified_env) + end else begin + let reason = String.trim (Sys.string_of_file response_file) in + let newresult = { result with Result.reason = Some reason } in + (newresult, newenv) + end + +let run_hook hook_name log input_env = + Printf.fprintf log "Entering run_hook for hook %s\n%!" hook_name; + let response_file = Filename.temp_file "ocamltest-" ".response" in + Printf.fprintf log "Hook should write its response to %s\n%!" + response_file; + let hookenv = Environments.add + Builtin_variables.ocamltest_response response_file input_env in + let systemenv = + Environments.to_system_env hookenv in + let open Run_command in + let settings = { + progname = "sh"; + argv = [|"sh"; Filename.maybe_quote hook_name|]; + envp = systemenv; + stdin_filename = ""; + stdout_filename = ""; + stderr_filename = ""; + append = false; + timeout = 0; + log = log; + } in let exit_status = run settings in + match exit_status with + | 0 -> + let modifiers = Environments.modifiers_of_file response_file in + let modified_env = Environments.apply_modifiers hookenv modifiers in + (Result.pass, modified_env) + | _ -> + Printf.fprintf log "Hook returned %d" exit_status; + let reason = String.trim (Sys.string_of_file response_file) in + if exit_status=125 + then (Result.skip_with_reason reason, hookenv) + else (Result.fail_with_reason reason, hookenv) + +let check_output kind_of_output output_variable reference_variable log + env = + let to_int = function None -> 0 | Some s -> int_of_string s in + let skip_lines = + to_int (Environments.lookup Builtin_variables.skip_header_lines env) in + let skip_bytes = + to_int (Environments.lookup Builtin_variables.skip_header_bytes env) in + let reference_filename = Environments.safe_lookup reference_variable env in + let output_filename = Environments.safe_lookup output_variable env in + Printf.fprintf log "Comparing %s output %s to reference %s\n%!" + kind_of_output output_filename reference_filename; + let files = + { + Filecompare.filetype = Filecompare.Text; + Filecompare.reference_filename = reference_filename; + Filecompare.output_filename = output_filename + } in + let tool = + Filecompare.(make_cmp_tool ~ignore:{lines=skip_lines;bytes=skip_bytes}) in + match Filecompare.check_file ~tool files with + | Filecompare.Same -> (Result.pass, env) + | Filecompare.Different -> + let diff = Filecompare.diff files in + let diffstr = match diff with + | Ok difference -> difference + | Error diff_file -> ("See " ^ diff_file) in + let reason = + Printf.sprintf "%s output %s differs from reference %s: \n%s\n" + kind_of_output output_filename reference_filename diffstr in + if Environments.lookup_as_bool Builtin_variables.promote env = Some true + then begin + Printf.fprintf log "Promoting %s output %s to reference %s\n%!" + kind_of_output output_filename reference_filename; + Sys.copy_file output_filename reference_filename; + end; + (Result.fail_with_reason reason, env) + | Filecompare.Unexpected_output -> + let banner = String.make 40 '=' in + let unexpected_output = Sys.string_of_file output_filename in + let unexpected_output_with_banners = Printf.sprintf + "%s\n%s%s\n" banner unexpected_output banner in + let reason = Printf.sprintf + "The file %s was expected to be empty because there is no \ + reference file %s but it is not:\n%s\n" + output_filename reference_filename unexpected_output_with_banners in + (Result.fail_with_reason reason, env) + | Filecompare.Error (commandline, exitcode) -> + let reason = Printf.sprintf "The command %s failed with status %d" + commandline exitcode in + (Result.fail_with_reason reason, env) diff --git a/ocamltest/actions_helpers.mli b/ocamltest/actions_helpers.mli new file mode 100644 index 00000000..5e7d6904 --- /dev/null +++ b/ocamltest/actions_helpers.mli @@ -0,0 +1,60 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Helper functions when writing actions *) + +val pass_or_skip + : bool -> string -> string -> out_channel -> Environments.t + -> Result.t * Environments.t + +val mkreason : string -> string -> int -> string + +val testfile : Environments.t -> string + +val test_build_directory : Environments.t -> string + +val test_source_directory : Environments.t -> string + +val words_of_variable : Environments.t -> Variables.t -> string list + +val exit_status_of_variable : Environments.t -> Variables.t -> int + +val files : Environments.t -> string list + +val setup_symlinks : string -> string -> string list -> unit + +val setup_build_env : bool -> string list -> Actions.code + +val setup_simple_build_env : bool -> string list -> Actions.code + +val run_cmd : + ?environment : string array -> + ?stdin_variable : Variables.t -> + ?stdout_variable : Variables.t -> + ?stderr_variable : Variables.t -> + ?append : bool -> + ?timeout : int -> + out_channel -> Environments.t -> string list -> int + +val run : string -> bool -> bool -> Variables.t + -> Variables.t option -> Actions.code + +val run_program : Actions.code + +val run_script : Actions.code + +val run_hook : string -> Actions.code + +val check_output : string -> Variables.t -> Variables.t -> Actions.code diff --git a/ocamltest/backends.ml b/ocamltest/backends.ml deleted file mode 100644 index c92e9696..00000000 --- a/ocamltest/backends.ml +++ /dev/null @@ -1,39 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Backends of the OCaml compiler and their properties *) - -type t = Sys.backend_type - -let string_of_backend = function - | Sys.Bytecode -> "bytecode" - | Sys.Native -> "native" - | Sys.Other backend_name -> backend_name - -(* Creates a function that returns its first argument for Bytecode, *) -(* its second argument for Native code and fails for other backends *) -let make_backend_function bytecode_value native_value = function - | Sys.Bytecode -> bytecode_value - | Sys.Native -> native_value - | Sys.Other backend_name -> - let error_message = - ("Other backend " ^ backend_name ^ " not supported") in - raise (Invalid_argument error_message) - -let module_extension = make_backend_function "cmo" "cmx" - -let library_extension = make_backend_function "cma" "cmxa" - -let executable_extension = make_backend_function "byte" "opt" diff --git a/ocamltest/backends.mli b/ocamltest/backends.mli deleted file mode 100644 index 6d651ae0..00000000 --- a/ocamltest/backends.mli +++ /dev/null @@ -1,28 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Backends of the OCaml compiler and their properties *) - -type t = Sys.backend_type - -val string_of_backend : t -> string - -val make_backend_function : 'a -> 'a -> t -> 'a - -val module_extension : t -> string - -val library_extension : t -> string - -val executable_extension : t -> string diff --git a/ocamltest/builtin_actions.ml b/ocamltest/builtin_actions.ml index 0c090ec8..6d636583 100644 --- a/ocamltest/builtin_actions.ml +++ b/ocamltest/builtin_actions.ml @@ -15,849 +15,164 @@ (* Definition of a few built-in actions *) +open Ocamltest_stdlib open Actions -(* Miscellaneous functions *) - -let env_id env = env - -let run_command - ?(stdin_variable=Builtin_variables.stdin) - ?(stdout_variable=Builtin_variables.stdout) - ?(stderr_variable=Builtin_variables.stderr) - ?(append=false) - ?(timeout=0) - log env cmd - = - let log_redirection std filename = - if filename<>"" then +let reason_with_fallback env fallback = + match Environments.lookup Builtin_variables.reason env with + | None -> fallback + | Some reason -> reason + +let pass = make + "pass" + (fun _log env -> + let reason = reason_with_fallback env "the pass action always succeeds" in + let result = Result.pass_with_reason reason in + (result, env)) + +let skip = make + "skip" + (fun _log env -> + let reason = reason_with_fallback env "the skip action always skips" in + let result = Result.skip_with_reason reason in + (result, env)) + +let fail = make + "fail" + (fun _log env -> + let reason = reason_with_fallback env "the fail action always fails" in + let result = Result.fail_with_reason reason in + (result, env)) + +let cd = make + "cd" + (fun _log env -> + let cwd = Environments.safe_lookup Builtin_variables.cwd env in begin - Printf.fprintf log " Redirecting %s to %s \n%!" std filename - end in - let lst = List.concat (List.map Testlib.words cmd) in - let quoted_lst = - if Sys.os_type="Win32" - then List.map Testlib.maybe_quote lst - else lst in - let cmd' = String.concat " " quoted_lst in - Printf.fprintf log "Commandline: %s\n" cmd'; - let progname = List.hd quoted_lst in - let arguments = Array.of_list quoted_lst in - (* - let environment = - try [|Sys.getenv "PATH" |] - with Not_found -> [| |] in - *) - let stdin_filename = Environments.safe_lookup stdin_variable env in - let stdout_filename = Environments.safe_lookup stdout_variable env in - let stderr_filename = Environments.safe_lookup stderr_variable env in - log_redirection "stdin" stdin_filename; - log_redirection "stdout" stdout_filename; - log_redirection "stderr" stderr_filename; - Run_command.run { - Run_command.progname = progname; - Run_command.argv = arguments; - (* Run_command.envp = environment; *) - Run_command.stdin_filename = stdin_filename; - Run_command.stdout_filename = stdout_filename; - Run_command.stderr_filename = stderr_filename; - Run_command.append = append; - Run_command.timeout = timeout; - Run_command.log = log - } - -let mkreason what commandline exitcode = - Printf.sprintf "%s: command\n%s\nfailed with exit code %d" - what commandline exitcode - -let make_file_name name ext = String.concat "." [name; ext] - -let make_path components = List.fold_left Filename.concat "" components - -(* -let rec map_reduce_result f g init = function - | [] -> Ok init - | x::xs -> - (match f x with - | Ok fx -> - (match map_reduce_result f g init xs with - | Ok fxs -> Ok (g fx fxs) - | Error _ as e -> e - ) - | Error _ as e -> e - ) -*) - -let setup_symlinks test_source_directory build_directory files = - let symlink filename = - let src = Filename.concat test_source_directory filename in - let cmd = "ln -sf " ^ src ^" " ^ build_directory in - Testlib.run_system_command cmd in - let copy filename = - let src = Filename.concat test_source_directory filename in - let dst = Filename.concat build_directory filename in - Testlib.copy_file src dst in - let f = if Sys.os_type="Win32" then copy else symlink in - List.iter f files - -let mkexe = - if Sys.os_type="Win32" - then fun name -> make_file_name name "exe" - else fun name -> name - -(* Compilers and flags *) - -let ocamlsrcdir () = - try Sys.getenv "OCAMLSRCDIR" - with Not_found -> Ocamltest_config.ocamlsrcdir - -let ocamlrun ocamlsrcdir = - let ocamlrunfile = mkexe "ocamlrun" in - make_path [ocamlsrcdir; "byterun"; ocamlrunfile] - -let ocamlc ocamlsrcdir = - make_path [ocamlsrcdir; "ocamlc"] - -let ocaml ocamlsrcdir = - make_path [ocamlsrcdir; "ocaml"] - -let ocamlc_dot_byte ocamlsrcdir = - let ocamlrun = ocamlrun ocamlsrcdir in - let ocamlc = ocamlc ocamlsrcdir in - ocamlrun ^ " " ^ ocamlc - -let ocamlc_dot_opt ocamlsrcdir = - make_path [ocamlsrcdir; "ocamlc.opt"] - -let ocamlopt ocamlsrcdir = - make_path [ocamlsrcdir; "ocamlopt"] - -let ocamlopt_dot_byte ocamlsrcdir = - let ocamlrun = ocamlrun ocamlsrcdir in - let ocamlopt = ocamlopt ocamlsrcdir in - ocamlrun ^ " " ^ ocamlopt - -let ocamlopt_dot_opt ocamlsrcdir = - make_path [ocamlsrcdir; "ocamlopt.opt"] - -let ocaml_dot_byte ocamlsrcdir = - let ocamlrun = ocamlrun ocamlsrcdir in - let ocaml = ocaml ocamlsrcdir in - ocamlrun ^ " " ^ ocaml - -let ocaml_dot_opt ocamlsrcdir = - make_path [ocamlsrcdir; mkexe "ocamlnat"] - -let cmpbyt ocamlsrcdir = - make_path [ocamlsrcdir; "tools"; "cmpbyt"] - -let stdlib ocamlsrcdir = - make_path [ocamlsrcdir; "stdlib"] - -let stdlib_flags ocamlsrcdir = - let stdlib_path = stdlib ocamlsrcdir in - "-nostdlib -I " ^ stdlib_path - -let c_includes ocamlsrcdir = - make_path [ocamlsrcdir; "byterun"] - -let c_includes_flags ocamlsrcdir = - let dir = c_includes ocamlsrcdir in - "-ccopt -I" ^ dir - -let use_runtime backend ocamlsrcdir = match backend with - | Sys.Bytecode -> - let ocamlrun = ocamlrun ocamlsrcdir in - "-use-runtime " ^ ocamlrun - | _ -> "" - -(* Compiler descriptions *) - -type compiler_info = { - compiler_name : string -> string; - compiler_flags : string; - compiler_directory : string; - compiler_backend : Sys.backend_type; - compiler_exit_status_variabe : Variables.t; - compiler_reference_variable : Variables.t; - compiler_output_variable : Variables.t -} - -(* Compilers compiling byte-code programs *) - -let bytecode_bytecode_compiler = -{ - compiler_name = ocamlc_dot_byte; - compiler_flags = ""; - compiler_directory = "ocamlc.byte"; - compiler_backend = Sys.Bytecode; - compiler_exit_status_variabe = Builtin_variables.ocamlc_byte_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference; - compiler_output_variable = Builtin_variables.compiler_output; -} - -let bytecode_native_compiler = -{ - compiler_name = ocamlc_dot_opt; - compiler_flags = ""; - compiler_directory = "ocamlc.opt"; - compiler_backend = Sys.Bytecode; - compiler_exit_status_variabe = Builtin_variables.ocamlc_opt_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference2; - compiler_output_variable = Builtin_variables.compiler_output2; -} - -(* Compilers compiling native-code programs *) - -let native_bytecode_compiler = -{ - compiler_name = ocamlopt_dot_byte; - compiler_flags = ""; - compiler_directory = "ocamlopt.byte"; - compiler_backend = Sys.Native; - compiler_exit_status_variabe = Builtin_variables.ocamlopt_byte_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference; - compiler_output_variable = Builtin_variables.compiler_output; -} - -let native_native_compiler = -{ - compiler_name = ocamlopt_dot_opt; - compiler_flags = ""; - compiler_directory = "ocamlopt.opt"; - compiler_backend = Sys.Native; - compiler_exit_status_variabe = Builtin_variables.ocamlopt_opt_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference2; - compiler_output_variable = Builtin_variables.compiler_output2; -} - -(* Top-levels *) - -let ocaml = { - compiler_name = ocaml_dot_byte; - compiler_flags = ""; - compiler_directory = "ocaml"; - compiler_backend = Sys.Bytecode; - compiler_exit_status_variabe = Builtin_variables.ocaml_byte_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference; - compiler_output_variable = Builtin_variables.compiler_output; -} - -let ocamlnat = { - compiler_name = ocaml_dot_opt; - compiler_flags = "-S"; (* Keep intermediate assembly files *) - compiler_directory = "ocamlnat"; - compiler_backend = Sys.Native; - compiler_exit_status_variabe = Builtin_variables.ocaml_opt_exit_status; - compiler_reference_variable = Builtin_variables.compiler_reference2; - compiler_output_variable = Builtin_variables.compiler_output2; -} - -let expected_compiler_exit_status env compiler = - try int_of_string - (Environments.safe_lookup compiler.compiler_exit_status_variabe env) - with _ -> 0 - -let compiler_reference_filename env prefix compiler = - let compiler_reference_suffix = - Environments.safe_lookup Builtin_variables.compiler_reference_suffix env in - let suffix = - if compiler_reference_suffix<>"" - then compiler_reference_suffix ^ ".reference" - else ".reference" in - let mk s = (make_file_name prefix s) ^suffix in - let filename = mk compiler.compiler_directory in - if Sys.file_exists filename then filename else - let filename = mk (Backends.string_of_backend compiler.compiler_backend) in - if Sys.file_exists filename then filename else - mk "compilers" - -(* Extracting information from environment *) - -let get_backend_value_from_env env bytecode_var native_var = - Backends.make_backend_function - (Environments.safe_lookup bytecode_var env) - (Environments.safe_lookup native_var env) - -let testfile env = - match Environments.lookup Builtin_variables.test_file env with - | None -> assert false - | Some t -> t - -let words_of_variable variable env = - Testlib.words (Environments.safe_lookup variable env) - -let modules env = words_of_variable Builtin_variables.modules env - -let files env = words_of_variable Builtin_variables.files env - -let flags env = Environments.safe_lookup Builtin_variables.flags env - -let libraries backend env = - let value = Environments.safe_lookup Builtin_variables.libraries env in - let libs = Testlib.words value in - let extension = Backends.library_extension backend in - let add_extension lib = make_file_name lib extension in - String.concat " " (List.map add_extension libs) - -let backend_default_flags env = - get_backend_value_from_env env - Builtin_variables.ocamlc_default_flags - Builtin_variables.ocamlopt_default_flags - -let backend_flags env = - get_backend_value_from_env env - Builtin_variables.ocamlc_flags - Builtin_variables.ocamlopt_flags - -let test_source_directory env = - Environments.safe_lookup Builtin_variables.test_source_directory env - -let test_build_directory env = - Environments.safe_lookup Builtin_variables.test_build_directory env - -(* -let action_of_filetype = function - | Filetype.Implementation -> "Compiling implementation" - | Filetype.Interface -> "Compiling interface" - | Filetype.C -> "Compiling C source file" - | Filetype.C_minus_minus -> "Processing C minus minus file" - | Filetype.Lexer -> "Generating lexer" - | Filetype.Grammar -> "Generating parser" -*) - -let link_modules - ocamlsrcdir compiler compilername compileroutput program_variable - custom c_headers_flags log env modules - = - let backend = compiler.compiler_backend in - let expected_exit_status = expected_compiler_exit_status env compiler in - let executable_name = match Environments.lookup program_variable env with - | None -> assert false - | Some program -> program in - let module_names = - String.concat " " (List.map Filetype.make_filename modules) in - let what = Printf.sprintf "Linking modules %s into %s" - module_names executable_name in - Printf.fprintf log "%s\n%!" what; - let output = "-o " ^ executable_name in - let customstr = if custom then "-custom" else "" in - let commandline = - [ - compilername; - customstr; - c_headers_flags; - use_runtime backend ocamlsrcdir; - stdlib_flags ocamlsrcdir; - "-linkall"; - flags env; - libraries backend env; - backend_default_flags env backend; - backend_flags env backend; - output; - module_names - ] in - let exit_status = - run_command - ~stdout_variable:compileroutput - ~stderr_variable:compileroutput - ~append:true - log env commandline in - if exit_status=expected_exit_status - then Pass env - else Fail (mkreason what (String.concat " " commandline) exit_status) - -let compile_program - ocamlsrcdir compiler compilername compileroutput program_variable - log env modules - = - let is_c_file (_filename, filetype) = filetype=Filetype.C in - let has_c_file = List.exists is_c_file modules in - let backend = compiler.compiler_backend in - let custom = (backend = Sys.Bytecode) && has_c_file in - let c_headers_flags = - if has_c_file then c_includes_flags ocamlsrcdir else "" in - link_modules - ocamlsrcdir compiler compilername compileroutput - program_variable custom c_headers_flags log env modules - -let module_has_interface directory module_name = - let interface_name = - Filetype.make_filename (module_name, Filetype.Interface) in - let interface_fullpath = make_path [directory;interface_name] in - Sys.file_exists interface_fullpath - -let add_module_interface directory module_description = - match module_description with - | (filename, Filetype.Implementation) when - module_has_interface directory filename -> - [(filename, Filetype.Interface); module_description] - | _ -> [module_description] - -let print_module_names log description modules = - Printf.fprintf log "%s modules: %s\n%!" - description - (String.concat " " (List.map Filetype.make_filename modules)) - -let setup_build_environment - testfile source_directory build_directory log env - = - let specified_modules = - List.map Filetype.filetype ((modules env) @ [testfile]) in - print_module_names log "Specified" specified_modules; - let source_modules = - Testlib.concatmap - (add_module_interface source_directory) - specified_modules in - print_module_names log "Source" source_modules; - Testlib.make_directory build_directory; - setup_symlinks - source_directory - build_directory - (List.map Filetype.make_filename source_modules); - setup_symlinks source_directory build_directory (files env); - Sys.chdir build_directory; - source_modules - -let prepare_module (module_name, module_type) = - match module_type with - | Filetype.Implementation | Filetype.Interface | Filetype.C -> - [(module_name, module_type)] - | Filetype.C_minus_minus -> assert false - | Filetype.Lexer -> assert false - | Filetype.Grammar -> assert false - -let compile_test_program program_variable compiler log env = - let backend = compiler.compiler_backend in - let testfile = testfile env in - let testfile_basename = Filename.chop_extension testfile in - let source_directory = test_source_directory env in - let compiler_directory_suffix = - Environments.safe_lookup Builtin_variables.compiler_directory_suffix env in - let compiler_directory_name = - compiler.compiler_directory ^ compiler_directory_suffix in - let build_directory = - make_path [test_build_directory env; compiler_directory_name] in - let compilerreference_prefix = - make_path [source_directory; testfile_basename] in - let compilerreference_filename = - compiler_reference_filename env compilerreference_prefix compiler in - let compiler_reference_variable = compiler.compiler_reference_variable in - let executable_filename = - mkexe - (make_file_name - testfile_basename (Backends.executable_extension backend)) in - let executable_path = make_path [build_directory; executable_filename] in - let compiler_output_filename = - make_file_name compiler.compiler_directory "output" in - let compiler_output = - make_path [build_directory; compiler_output_filename] in - let compiler_output_variable = compiler.compiler_output_variable in - let newenv = Environments.add_bindings - [ - (program_variable, executable_path); - (compiler_reference_variable, compilerreference_filename); - (compiler_output_variable, compiler_output); - ] env in - if Sys.file_exists compiler_output_filename then - Sys.remove compiler_output_filename; - let ocamlsrcdir = ocamlsrcdir () in - let compilername = compiler.compiler_name ocamlsrcdir in - let source_modules = - setup_build_environment - testfile source_directory build_directory log env in - let prepared_modules = - Testlib.concatmap prepare_module source_modules in - compile_program - ocamlsrcdir - compiler - compilername - compiler_output_variable - program_variable log newenv prepared_modules - -(* Compile actions *) - -let compile_bytecode_with_bytecode_compiler = { - action_name = "compile-bytecode-with-bytecode-compiler"; - action_environment = env_id; - action_body = - compile_test_program - Builtin_variables.program bytecode_bytecode_compiler -} - -let compile_bytecode_with_native_compiler = { - action_name = "compile-bytecode-with-native-compiler"; - action_environment = env_id; - action_body = - compile_test_program - Builtin_variables.program2 bytecode_native_compiler -} - -let compile_native_with_bytecode_compiler = { - action_name = "compile-native-with-bytecode-compiler"; - action_environment = env_id; - action_body = - compile_test_program - Builtin_variables.program native_bytecode_compiler -} - -let compile_native_with_native_compiler = { - action_name = "compile-native-with-native-compiler"; - action_environment = env_id; - action_body = - compile_test_program - Builtin_variables.program2 native_native_compiler -} - -let exec log_message redirect_output prog_variable args_variable log env = - match Environments.lookup prog_variable env with - | None -> - let msg = Printf.sprintf "%s: variable %s is undefined" - log_message (Variables.name_of_variable prog_variable) in - Fail msg - | Some program -> - let arguments = Environments.safe_lookup args_variable env in - let commandline = [program; arguments] in - let what = log_message ^ " " ^ program ^ " " ^ - begin if arguments="" then "without any argument" - else "with arguments " ^ arguments - end in - let output = program ^ ".output" in - let bindings = - [ - Builtin_variables.stdout, output; - Builtin_variables.stderr, output - ] in - let execution_env = - if redirect_output then Environments.add_bindings bindings env - else env in - match run_command log execution_env commandline with - | 0 -> - let newenv = - if redirect_output - then Environments.add Builtin_variables.output output env - else env in - Pass newenv - | _ as exitcode -> - if exitcode = 125 - then Skip (mkreason what (String.concat " " commandline) exitcode) - else Fail (mkreason what (String.concat " " commandline) exitcode) - -let execute_program = - exec - "Executing program" - true - Builtin_variables.program - Builtin_variables.arguments - -let execute = { - action_name = "execute-program"; - action_environment = env_id; - action_body = execute_program -} - -let run_script log env = - let testfile = testfile env in - (* let testfile_basename = Filename.chop_extension testfile in *) - let source_directory = test_source_directory env in - let build_directory = test_build_directory env in - let _modules = - setup_build_environment - testfile source_directory build_directory log env in - exec - "Running script" - false - Builtin_variables.script - Builtin_variables.test_file - log env - -let script = { - action_name = "run-script"; - action_environment = env_id; - action_body = run_script -} - -let run_expect log env = - let newenv = Environments.apply_modifiers env Builtin_modifiers.expect in - run_script log newenv - -let expect = { - action_name = "run-expect"; - action_environment = env_id; - action_body = run_expect -} - -let check_output kind_of_output output_variable reference_variable log env = - let reference_filename = Environments.safe_lookup reference_variable env in - let output_filename = Environments.safe_lookup output_variable env in - Printf.fprintf log "Comparing %s output %s to reference %s\n%!" - kind_of_output output_filename reference_filename; - let files = - { - Filecompare.filetype = Filecompare.Text; - Filecompare.reference_filename = reference_filename; - Filecompare.output_filename = output_filename - } in - match Filecompare.check_file files with - | Filecompare.Same -> Pass env - | Filecompare.Different -> - let diff = Filecompare.diff files in - let diffstr = match diff with - | Ok difference -> difference - | Error diff_file -> ("See " ^ diff_file) in - let reason = - Printf.sprintf "%s output %s differs from reference %s: \n%s\n" - kind_of_output output_filename reference_filename diffstr in - (Actions.Fail reason) - | Filecompare.Unexpected_output -> - let banner = String.make 40 '=' in - let unexpected_output = Testlib.string_of_file output_filename in - let unexpected_output_with_banners = Printf.sprintf - "%s\n%s%s\n" banner unexpected_output banner in - let reason = Printf.sprintf - "The file %s was expected to be empty because there is no \ - reference file %s but it is not:\n%s\n" - output_filename reference_filename unexpected_output_with_banners in - (Actions.Fail reason) - | Filecompare.Error (commandline, exitcode) -> - let reason = Printf.sprintf "The command %s failed with status %d" - commandline exitcode in - (Actions.Fail reason) - -let make_check_compiler_output name compiler = { - action_name = name; - action_environment = env_id; - action_body = - check_output - "compiler" - compiler.compiler_output_variable - compiler.compiler_reference_variable -} - -let check_ocamlc_dot_byte_output = make_check_compiler_output - "check-ocamlc-byte-output" bytecode_bytecode_compiler - -let check_ocamlc_dot_opt_output = make_check_compiler_output - "check-ocamlc-opt-output" bytecode_native_compiler - -let check_ocamlopt_dot_byte_output = make_check_compiler_output - "check-ocamlopt-byte-output" native_bytecode_compiler - -let check_ocamlopt_dot_opt_output = make_check_compiler_output - "check-ocamlopt-opt-output" native_native_compiler - -let check_program_output = { - action_name = "check-program-output"; - action_environment = env_id; - action_body = check_output "program" + try + Sys.chdir cwd; (Result.pass, env) + with _ -> + let reason = "Could not chidir to \"" ^ cwd ^ "\"" in + let result = Result.fail_with_reason reason in + (result, env) + end) + +let dumpenv = make + "dumpenv" + (fun log env -> + Environments.dump log env; (Result.pass, env)) + +let libunix = make + "libunix" + (Actions_helpers.pass_or_skip Ocamltest_config.libunix + "libunix available" + "libunix not available") + +let libwin32unix = make + "libwin32unix" + (Actions_helpers.pass_or_skip (not Ocamltest_config.libunix) + "libwin32unix available" + "libwin32unix not available") + +let windows_OS = "Windows_NT" + +let get_OS () = Sys.safe_getenv "OS" + +let windows = make + "windows" + (Actions_helpers.pass_or_skip (get_OS () = windows_OS) + "running on Windows" + "not running on Windows") + +let not_windows = make + "not-windows" + (Actions_helpers.pass_or_skip (get_OS () <> windows_OS) + "not running on Windows" + "running on Windows") + +let bsd_system = "bsd_elf" + +let bsd = make + "bsd" + (Actions_helpers.pass_or_skip (Ocamltest_config.system = bsd_system) + "on a BSD system" + "not on a BSD system") + +let not_bsd = make + "not-bsd" + (Actions_helpers.pass_or_skip (Ocamltest_config.system <> bsd_system) + "not on a BSD system" + "on a BSD system") + +let arch32 = make + "arch32" + (Actions_helpers.pass_or_skip (Sys.word_size = 32) + "32-bit architecture" + "non-32-bit architecture") + +let arch64 = make + "arch64" + (Actions_helpers.pass_or_skip (Sys.word_size = 64) + "64-bit architecture" + "non-64-bit architecture") + +let has_symlink = make + "has_symlink" + (Actions_helpers.pass_or_skip (Sys.has_symlink () ) + "symlinks available" + "symlinks not available") + +let setup_build_env = make + "setup-build-env" + (Actions_helpers.setup_build_env true []) + +let setup_simple_build_env = make + "setup-simple-build-env" + (Actions_helpers.setup_simple_build_env true []) + +let run = make + "run" + Actions_helpers.run_program + +let script = make + "script" + Actions_helpers.run_script + +let check_program_output = make + "check-program-output" + (Actions_helpers.check_output "program" Builtin_variables.output - Builtin_variables.reference -} - -(* -let comparison_start_address portable_executable_filename = - let portable_executalbe_signature = "PE\000\000" in - let signature_length = String.length portable_executalbe_signature in - let address_length = 4 in - let start_address = 0x3c in - let ic = open_in portable_executable_filename in - seek_in ic start_address; - let portable_executable_signature_address_str = - really_input_string ic address_length in - let b0 = int_of_char portable_executable_signature_address_str.[0] in - let b1 = int_of_char portable_executable_signature_address_str.[1] in - let b2 = int_of_char portable_executable_signature_address_str.[2] in - let b3 = int_of_char portable_executable_signature_address_str.[3] in - let signature_address = - b0 + - b1 * 256 + - b2 * 256 * 256 + - b3 * 256 * 256 * 256 in - seek_in ic signature_address; - let signature = - really_input_string ic signature_length in - if signature<>portable_executalbe_signature - then failwith - (portable_executable_filename ^ " does not contain the PE signature"); - let result = signature_address + 12 in - (* 12 is 4-bytes signature, 2-bytes machine type, *) - (* 2-bytes number of sections, 4-bytes timestamp *) - close_in ic; - result -*) + Builtin_variables.reference) -let compare_programs backend comparison_tool log env = - let program = Environments.safe_lookup Builtin_variables.program env in - let program2 = Environments.safe_lookup Builtin_variables.program2 env in - let what = Printf.sprintf "Comparing %s programs %s and %s" - (Backends.string_of_backend backend) program program2 in - Printf.fprintf log "%s\n%!" what; - let files = { - Filecompare.filetype = Filecompare.Binary; - Filecompare.reference_filename = program; - Filecompare.output_filename = program2 - } in - if Ocamltest_config.flambda && backend = Sys.Native - then begin - Printf.fprintf log - "flambda temporarily disables comparison of native programs"; - Pass env - end else if backend = Sys.Native && (Sys.os_type="Win32" || Sys.os_type="Cygwin") - then begin - Printf.fprintf log - "comparison of native programs temporarily disabled under Windows"; - Pass env - end else begin - let comparison_tool = - if backend=Sys.Native && (Sys.os_type="Win32" || Sys.os_type="Cygwin") - then - let bytes_to_ignore = 512 (* comparison_start_address program *) in - Filecompare.make_cmp_tool bytes_to_ignore - else comparison_tool in - match Filecompare.compare_files ~tool:comparison_tool files with - | Filecompare.Same -> Pass env - | Filecompare.Different -> - let reason = Printf.sprintf "Files %s and %s are different" - program program2 in - Fail reason - | Filecompare.Unexpected_output -> assert false - | Filecompare.Error (commandline, exitcode) -> - let reason = mkreason what commandline exitcode in - Fail reason - end - -let make_bytecode_programs_comparison_tool ocamlsrcdir = - let ocamlrun = ocamlrun ocamlsrcdir in - let cmpbyt = cmpbyt ocamlsrcdir in - let tool_name = ocamlrun ^ " " ^ cmpbyt in - Filecompare.make_comparison_tool tool_name "" - -let native_programs_comparison_tool = Filecompare.default_comparison_tool - -let compare_bytecode_programs_body log env = - let ocamlsrcdir = ocamlsrcdir () in - let bytecode_programs_comparison_tool = - make_bytecode_programs_comparison_tool ocamlsrcdir in - compare_programs Sys.Bytecode bytecode_programs_comparison_tool log env - -let compare_bytecode_programs = { - action_name = "compare-bytecode-programs"; - action_environment = env_id; - action_body = compare_bytecode_programs_body -} - -let compare_native_programs = { - action_name = "compare-native-programs"; - action_environment = env_id; - action_body = compare_programs Sys.Native native_programs_comparison_tool -} - -let run_test_program_in_toplevel toplevel log env = - let testfile = testfile env in - let testfile_basename = Filename.chop_extension testfile in - let expected_exit_status = expected_compiler_exit_status env toplevel in - let what = - Printf.sprintf "Running %s in %s toplevel (expected exit status: %d)" - testfile - (Backends.string_of_backend toplevel.compiler_backend) - expected_exit_status in - Printf.fprintf log "%s\n%!" what; - let source_directory = test_source_directory env in - let compiler_directory_suffix = - Environments.safe_lookup Builtin_variables.compiler_directory_suffix env in - let compiler_directory_name = - toplevel.compiler_directory ^ compiler_directory_suffix in - let build_directory = - make_path [test_build_directory env; compiler_directory_name] in - let _modules = - setup_build_environment - testfile source_directory build_directory log env in - let compilerreference_prefix = - make_path [source_directory; testfile_basename] in - let compilerreference_filename = - compiler_reference_filename env compilerreference_prefix toplevel in - let compiler_reference_variable = toplevel.compiler_reference_variable in - let compiler_output_filename = - make_file_name toplevel.compiler_directory "output" in - let compiler_output = - make_path [build_directory; compiler_output_filename] in - let compiler_output_variable = toplevel.compiler_output_variable in - let newenv = Environments.add_bindings - [ - (compiler_reference_variable, compilerreference_filename); - (compiler_output_variable, compiler_output); - ] env in - if Sys.file_exists compiler_output_filename then - Sys.remove compiler_output_filename; - let ocamlsrcdir = ocamlsrcdir () in - let toplevel_name = toplevel.compiler_name ocamlsrcdir in - let toplevel_default_flags = "-noinit -no-version -noprompt" in - let commandline = +let initialize_test_exit_status_variables _log env = + Environments.add_bindings [ - toplevel_name; - toplevel_default_flags; - toplevel.compiler_flags; - stdlib_flags ocamlsrcdir; - flags env; - ] in - let exit_status = - run_command - ~stdin_variable:Builtin_variables.test_file - ~stdout_variable:compiler_output_variable - ~stderr_variable:compiler_output_variable - log newenv commandline in - if exit_status=expected_exit_status - then Pass newenv - else Fail (mkreason what (String.concat " " commandline) exit_status) - -let run_in_ocaml = -{ - action_name = "run-in-bytecode-toplevel"; - action_environment = env_id; - action_body = run_test_program_in_toplevel ocaml; -} - -let run_in_ocamlnat = -{ - action_name = "run-in-native-toplevel"; - action_environment = env_id; - action_body = run_test_program_in_toplevel ocamlnat; -} - -let check_ocaml_output = make_check_compiler_output - "check-bytecode-toplevel-output" ocaml - -let check_ocamlnat_output = make_check_compiler_output - "check-native-toplevel-output" ocamlnat - -let if_not_safe_string = { - action_name = "if_not_safe_string"; - action_environment = env_id; - action_body = fun _log env -> - if Ocamltest_config.safe_string - then Skip "safe strings enabled" - else Pass env -} + Builtin_variables.test_pass, "0"; + Builtin_variables.test_fail, "1"; + Builtin_variables.test_skip, "125"; + ] env let _ = + Environments.register_initializer + "test_exit_status_variables" initialize_test_exit_status_variables; List.iter register [ - compile_bytecode_with_bytecode_compiler; - compile_bytecode_with_native_compiler; - compile_native_with_bytecode_compiler; - compile_native_with_native_compiler; - execute; + pass; + skip; + fail; + cd; + dumpenv; + libunix; + libwin32unix; + windows; + not_windows; + bsd; + not_bsd; + arch32; + arch64; + has_symlink; + setup_build_env; + run; script; check_program_output; - compare_bytecode_programs; - compare_native_programs; - check_ocamlc_dot_byte_output; - check_ocamlc_dot_opt_output; - check_ocamlopt_dot_byte_output; - check_ocamlopt_dot_opt_output; - run_in_ocaml; - run_in_ocamlnat; - check_ocaml_output; - check_ocamlnat_output; - if_not_safe_string; ] diff --git a/ocamltest/builtin_actions.mli b/ocamltest/builtin_actions.mli index a61a5f06..ba82a428 100644 --- a/ocamltest/builtin_actions.mli +++ b/ocamltest/builtin_actions.mli @@ -15,29 +15,31 @@ (* Definition of a few built-in actions *) -val compile_bytecode_with_bytecode_compiler : Actions.t -val compile_bytecode_with_native_compiler : Actions.t -val compile_native_with_bytecode_compiler : Actions.t -val compile_native_with_native_compiler : Actions.t +val pass : Actions.t +val skip : Actions.t +val fail : Actions.t -val execute : Actions.t -val expect : Actions.t -val script : Actions.t -val check_program_output : Actions.t +val dumpenv : Actions.t + +val libunix : Actions.t +val libwin32unix : Actions.t + +val windows : Actions.t +val not_windows : Actions.t -val compare_bytecode_programs : Actions.t -val compare_native_programs : Actions.t +val bsd : Actions.t +val not_bsd : Actions.t -val check_ocamlc_dot_byte_output : Actions.t -val check_ocamlc_dot_opt_output : Actions.t -val check_ocamlopt_dot_byte_output : Actions.t -val check_ocamlopt_dot_opt_output : Actions.t +val arch32 : Actions.t +val arch64 : Actions.t -val run_in_ocaml : Actions.t +val has_symlink : Actions.t -val run_in_ocamlnat : Actions.t +val setup_build_env : Actions.t -val check_ocaml_output : Actions.t +val setup_simple_build_env : Actions.t -val check_ocamlnat_output : Actions.t -val if_not_safe_string : Actions.t +val run : Actions.t +val script : Actions.t + +val check_program_output : Actions.t diff --git a/ocamltest/builtin_modifiers.ml b/ocamltest/builtin_modifiers.ml deleted file mode 100644 index 9fc930d2..00000000 --- a/ocamltest/builtin_modifiers.ml +++ /dev/null @@ -1,44 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Definition of a few built-in environment modifiers *) - -open Environments -open Builtin_variables - -let expect = -[ - Replace (script, "bash ${OCAMLSRCDIR}/testsuite/tools/expect"); -] - -let principal = -[ - Append (flags, " -principal "); - Add (compiler_directory_suffix, ".principal"); - Add (compiler_reference_suffix, ".principal"); -] - -let testinglib_directory = Ocamltest_config.ocamlsrcdir ^ "/testsuite/lib" - -let testing = -[ - Append (flags, (" -I " ^ testinglib_directory ^ " ")); - Append (libraries, " testing "); -] - -let _ = - register expect "expect"; - register principal "principal"; - register testing "testing" diff --git a/ocamltest/builtin_modifiers.mli b/ocamltest/builtin_modifiers.mli deleted file mode 100644 index f35b8970..00000000 --- a/ocamltest/builtin_modifiers.mli +++ /dev/null @@ -1,22 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Definition of a few built-in environment modifiers *) - -val expect : Environments.modifiers - -val principal : Environments.modifiers - -val testing : Environments.modifiers diff --git a/ocamltest/builtin_tests.ml b/ocamltest/builtin_tests.ml deleted file mode 100644 index 59af5c51..00000000 --- a/ocamltest/builtin_tests.ml +++ /dev/null @@ -1,89 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Definitions of built-in tests *) - -open Tests -open Builtin_actions - -let bytecode = - let opt_actions = - [ - compile_bytecode_with_native_compiler; - check_ocamlc_dot_opt_output; - compare_bytecode_programs - ] in -{ - test_name = "bytecode"; - test_run_by_default = true; - test_actions = - [ - compile_bytecode_with_bytecode_compiler; - check_ocamlc_dot_byte_output; - execute; - check_program_output - ] @ (if Ocamltest_config.arch<>"none" then opt_actions else []) -} - -let expect = { - test_name = "expect"; - test_run_by_default = false; - test_actions = [expect]; -} - -let native = { - test_name = "native"; - test_run_by_default = true; - test_actions = - [ - compile_native_with_bytecode_compiler; - check_ocamlopt_dot_byte_output; - execute; - check_program_output; - compile_native_with_native_compiler; - check_ocamlopt_dot_opt_output; - compare_native_programs; - ] -} - -let script = { - test_name = "script"; - test_run_by_default = false; - test_actions = [script]; -} - -let toplevel = { - test_name = "toplevel"; - test_run_by_default = false; - test_actions = - [ - run_in_ocaml; - check_ocaml_output; -(* - run_in_ocamlnat; - check_ocamlnat_output; -*) - ] -} - -let _ = - List.iter register - [ - bytecode; - expect; - script; - toplevel; - ]; - if (Ocamltest_config.arch <> "none") then register native diff --git a/ocamltest/builtin_tests.mli b/ocamltest/builtin_tests.mli deleted file mode 100644 index 2a223d0b..00000000 --- a/ocamltest/builtin_tests.mli +++ /dev/null @@ -1,26 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Definitions of built-in tests *) - -val bytecode : Tests.t - -val expect : Tests.t - -val native : Tests.t - -val script : Tests.t - -val toplevel : Tests.t diff --git a/ocamltest/builtin_variables.ml b/ocamltest/builtin_variables.ml index 987da194..1bfd843c 100644 --- a/ocamltest/builtin_variables.ml +++ b/ocamltest/builtin_variables.ml @@ -27,68 +27,20 @@ open Variables (* Should not be necessary with a ppx *) let arguments = make ("arguments", "Arguments passed to executed programs and scripts") -let c_preprocessor = make ("c_preprocessor", - "Command to use to invoke the C preprocessor") +let cwd = make ("cwd", + "Used to change current working directory, but not updated") -let compiler_directory_suffix = make ("compiler_directory_suffix", - "Suffix to add to the directory where the test will be compiled") - -let compiler_reference = make ("compiler_reference", - "Reference file for compiler output for ocamlc.byte and ocamlopt.byte") - -let compiler_reference2 = make ("compiler_reference2", - "Reference file for compiler output for ocamlc.opt and ocamlopt.opt") - -let compiler_reference_suffix = make ("compiler_reference_suffix", - "Suffix to add to the file name containing the reference for compiler output") - -let compiler_output = make ("compiler_output", - "Where to log output of bytecode compilers") - -let compiler_output2 = make ("compiler_output2", - "Where to log output of native compilers") - -let ocamlc_flags = make ("ocamlc_flags", - "Flags passed to ocamlc.byte and ocamlc.opt") - -let ocamlc_default_flags = make ("ocamlc_default_flags", - "Flags passed by default to ocamlc.byte and ocamlc.opt") +let exit_status = make ("exit_status", + "Expected program exit status") let files = make ("files", "Files used by the tests") -let flags = make ("flags", - "Flags passed to all the compilers") - -let libraries = make ("libraries", - "Libraries the program should be linked with") - -let modules = make ("modules", - "Other modules of the test") - -let ocamlopt_flags = make ("ocamlopt_flags", - "Flags passed to ocamlopt.byte and ocamlopt.opt") - -let ocamlopt_default_flags = make ("ocamlopt_default_flags", - "Flags passed by default to ocamlopt.byte and ocamlopt.opt") - -let ocaml_byte_exit_status = make ("ocaml_byte_exit_status", - "Expected exit status of ocaml.byte") - -let ocamlc_byte_exit_status = make ("ocamlc_byte_exit_status", - "Expected exit status of ocac.byte") +let ocamltest_response = make ("ocamltest_response", + "File used by hooks to send back information.") -let ocamlopt_byte_exit_status = make ("ocamlopt_byte_exit_status", - "Expected exit status of ocamlopt.byte") - -let ocaml_opt_exit_status = make ("ocaml_opt_exit_status", - "Expected exit status of ocaml.opt") - -let ocamlc_opt_exit_status = make ("ocamlc_opt_exit_status", - "Expected exit status of ocac.opt") - -let ocamlopt_opt_exit_status = make ("ocamlopt_opt_exit_status", - "Expected exit status of ocamlopt.opt") +let ocamltest_log = make ("ocamltest_log", + "Path to log file for the current test") let output = make ("output", "Where the output of executing the program is saved") @@ -98,9 +50,25 @@ let program = make ("program", let program2 = make ("program2", "Name of program produced by ocamlc.opt and ocamlopt.opt") +let promote = make ("promote", + "Set to \"true\" to overwrite reference files with the test output") + +let reason = make ("reason", + "Let a test report why it passed/skipped/failed.") + let reference = make ("reference", "Path of file to which program output should be compared") +let skip_header_lines = + make ( "skip_header_lines", + "The number of lines to skip when comparing program output \ + with the reference file") + +let skip_header_bytes = + make ( "skip_header_bytes", + "The number of bytes to skip when comparing program output \ + with the reference file") + let script = make ("script", "External script to run") @@ -111,15 +79,48 @@ let stderr = make ("stderr", "Default standard error") let test_build_directory = make ("test_build_directory", "Directory for files produced during a test") +let test_build_directory_prefix = make ("test_build_directory_prefix", + "Directory under which all test directories should be created") + let test_file = make ("test_file", "Name of file containing the specification of which tests to run") let test_source_directory = make ("test_source_directory", "Directory containing the test source files") +let test_pass = make ("TEST_PASS", + "Exit code to let a script report success") + +let test_skip = make ("TEST_SKIP", + "Exit code to let a script report skipping") + +let test_fail = make ("TEST_FAIL", + "Exit code to let a script report failure") + + + let _ = List.iter register_variable [ - c_preprocessor; - ocamlc_default_flags; - ocamlopt_default_flags + arguments; + cwd; + exit_status; + files; + ocamltest_response; + ocamltest_log; + output; + program; program2; + reason; + reference; + skip_header_lines; + skip_header_bytes; + script; + stdin; + stdout; + stderr; + test_build_directory; + test_file; + test_source_directory; + test_pass; + test_skip; + test_fail; ] diff --git a/ocamltest/builtin_variables.mli b/ocamltest/builtin_variables.mli index 0b0c8aec..126a3968 100644 --- a/ocamltest/builtin_variables.mli +++ b/ocamltest/builtin_variables.mli @@ -19,53 +19,30 @@ val arguments : Variables.t -val c_preprocessor : Variables.t +val cwd : Variables.t -val compiler_directory_suffix : Variables.t - -val compiler_reference : Variables.t - -val compiler_reference2 : Variables.t - -val compiler_reference_suffix : Variables.t - -val compiler_output : Variables.t - -val compiler_output2 : Variables.t +val exit_status : Variables.t val files : Variables.t -val flags : Variables.t - -val libraries : Variables.t - -val modules : Variables.t - -val ocamlc_flags : Variables.t -val ocamlc_default_flags : Variables.t - -val ocamlopt_flags : Variables.t -val ocamlopt_default_flags : Variables.t - -val ocaml_byte_exit_status : Variables.t +val ocamltest_response : Variables.t -val ocamlc_byte_exit_status : Variables.t - -val ocamlopt_byte_exit_status : Variables.t - -val ocaml_opt_exit_status : Variables.t - -val ocamlc_opt_exit_status : Variables.t - -val ocamlopt_opt_exit_status : Variables.t +val ocamltest_log : Variables.t val output : Variables.t val program : Variables.t val program2 : Variables.t +val promote : Variables.t + +val reason : Variables.t + val reference : Variables.t +val skip_header_lines : Variables.t +val skip_header_bytes : Variables.t + val script : Variables.t val stdin : Variables.t @@ -73,7 +50,14 @@ val stdout : Variables.t val stderr : Variables.t val test_build_directory : Variables.t +val test_build_directory_prefix : Variables.t val test_file : Variables.t val test_source_directory : Variables.t + +val test_pass : Variables.t + +val test_skip : Variables.t + +val test_fail : Variables.t diff --git a/ocamltest/environments.ml b/ocamltest/environments.ml index fa239da9..17338682 100644 --- a/ocamltest/environments.ml +++ b/ocamltest/environments.ml @@ -15,7 +15,7 @@ (* Definition of environments, used to pass parameters to tests and actions *) -exception Variable_already_defined of Variables.t +open Ocamltest_stdlib module VariableMap = Map.Make (Variables) @@ -27,8 +27,7 @@ let to_bindings env = let f variable value lst = (variable, value) :: lst in VariableMap.fold f env [] -let expand env value = - +let expand_aux env value = let bindings = to_bindings env in let f (variable, value) = ((Variables.name_of_variable variable), value) in let simple_bindings = List.map f bindings in @@ -36,9 +35,33 @@ let expand env value = let b = Buffer.create 100 in try Buffer.add_substitute b subst value; Buffer.contents b with _ -> value +let rec expand env value = + let expanded = expand_aux env value in + if expanded=value then value else expand env expanded + +let to_system_env env = + let system_env = Array.make (VariableMap.cardinal env) "" in + let i = ref 0 in + let store variable value = + system_env.(!i) <- + Variables.string_of_binding variable (expand env value); + incr i in + VariableMap.iter store env; + system_env + let lookup variable env = try Some (expand env (VariableMap.find variable env)) with Not_found -> None +let lookup_nonempty variable env = match lookup variable env with + | None -> None + | Some x as t -> if String.words x = [] then None else t + +let lookup_as_bool variable env = + match lookup variable env with + | None -> None + | Some "true" -> Some true + | Some _ -> Some false + let safe_lookup variable env = match lookup variable env with | None -> "" | Some value -> value @@ -46,19 +69,18 @@ let safe_lookup variable env = match lookup variable env with let is_variable_defined variable env = VariableMap.mem variable env -let add variable value env = - if VariableMap.mem variable env - then raise (Variable_already_defined variable) - else VariableMap.add variable value env +let add variable value env = VariableMap.add variable value env -let replace variable value environment = - VariableMap.add variable value environment +let add_if_undefined variable value env = + if VariableMap.mem variable env then env else add variable value env let append variable appened_value environment = let previous_value = safe_lookup variable environment in let new_value = previous_value ^ appened_value in VariableMap.add variable new_value environment +let remove = VariableMap.remove + let add_bindings bindings env = let f env (variable, value) = add variable value env in List.fold_left f env bindings @@ -69,15 +91,30 @@ let dump_assignment log (variable, value) = Printf.fprintf log "%s = %s\n%!" (Variables.name_of_variable variable) value let dump log environment = - List.iter (dump_assignment log) (VariableMap.bindings environment); + List.iter (dump_assignment log) (VariableMap.bindings environment) + +(* Initializers *) -(* Environment modifiers *) +type env_initializer = out_channel -> t -> t + +let (initializers : (string, env_initializer) Hashtbl.t) = Hashtbl.create 10 + +let register_initializer name code = Hashtbl.add initializers name code + +let apply_initializer _log _name code env = + code _log env + +let initialize log env = + let f = apply_initializer log in + Hashtbl.fold f initializers env + +(* Modifiers *) type modifier = | Include of string | Add of Variables.t * string - | Replace of Variables.t * string | Append of Variables.t * string + | Remove of Variables.t type modifiers = modifier list @@ -87,7 +124,7 @@ exception Modifiers_name_not_found of string let (registered_modifiers : (string, modifiers) Hashtbl.t) = Hashtbl.create 20 -let register modifiers name = +let register_modifiers name modifiers = if name="" then raise Empty_modifiers_name else if Hashtbl.mem registered_modifiers name then raise (Modifiers_name_already_registered name) @@ -101,7 +138,49 @@ let rec apply_modifier environment = function | Include modifiers_name -> apply_modifiers environment (find_modifiers modifiers_name) | Add (variable, value) -> add variable value environment - | Replace (variable, value) -> replace variable value environment | Append (variable, value) -> append variable value environment + | Remove variable -> remove variable environment and apply_modifiers environment modifiers = List.fold_left apply_modifier environment modifiers + +let modifier_of_string str = + let invalid_argument = (Invalid_argument "modifier_of_string") in + if str="" then raise invalid_argument else begin + let l = String.length str in + if str.[0] = '-' then begin + let variable_name = String.sub str 1 (l-1) in + match Variables.find_variable variable_name with + | None -> raise (Variables.No_such_variable variable_name) + | Some variable -> Remove variable + end else begin match String.index_opt str '=' with + | None -> raise invalid_argument + | Some pos_eq -> if pos_eq <= 0 then raise invalid_argument else + let (append, varname_length) = + (match String.index_opt str '+' with + | None -> (false, pos_eq) + | Some pos_plus -> + if pos_plus = pos_eq-1 + then (true, pos_plus) + else raise invalid_argument) in + let variable_name = String.sub str 0 varname_length in + match Variables.find_variable variable_name with + | None -> raise (Variables.No_such_variable variable_name) + | Some variable -> + if pos_eq >= l-2 || str.[pos_eq+1]<>'"' || str.[l-1]<>'"' + then raise invalid_argument + else let value_length = l - pos_eq - 3 in + let value = String.sub str (pos_eq+2) value_length in + if append then Append (variable, value) + else Add (variable, value) + end + end + +let modifiers_of_file filename = + let ic = open_in filename in + let rec modifiers_of_lines acc = match input_line_opt ic with + | None -> acc + | Some line -> + modifiers_of_lines ((modifier_of_string (String.trim line)) :: acc) in + let modifiers = modifiers_of_lines [] in + close_in ic; + List.rev modifiers diff --git a/ocamltest/environments.mli b/ocamltest/environments.mli index be19f8e6..94d794bb 100644 --- a/ocamltest/environments.mli +++ b/ocamltest/environments.mli @@ -15,31 +15,47 @@ (* Definition of environments, used to pass parameters to tests and actions *) -exception Variable_already_defined of Variables.t - type t val empty : t val from_bindings : (Variables.t * string) list -> t val to_bindings : t -> (Variables.t * string) list +val to_system_env : t -> string array val lookup : Variables.t -> t -> string option +val lookup_nonempty : Variables.t -> t -> string option val safe_lookup : Variables.t -> t -> string val is_variable_defined : Variables.t -> t -> bool +val lookup_as_bool : Variables.t -> t -> bool option +(** returns [Some true] if the variable is set to ["true"], + [Some false] if it is set to another string, and + [None] if not set. *) + val add : Variables.t -> string -> t -> t +val add_if_undefined : Variables.t -> string -> t -> t val add_bindings : (Variables.t * string) list -> t -> t +val append : Variables.t -> string -> t -> t + val dump : out_channel -> t -> unit -(* Environment modifiers *) +(* Initializers *) + +type env_initializer = out_channel -> t -> t + +val register_initializer : string -> env_initializer -> unit + +val initialize : env_initializer + +(* Modifiers *) type modifier = | Include of string | Add of Variables.t * string - | Replace of Variables.t * string | Append of Variables.t * string + | Remove of Variables.t type modifiers = modifier list @@ -50,4 +66,8 @@ exception Empty_modifiers_name exception Modifiers_name_already_registered of string exception Modifiers_name_not_found of string -val register : modifiers -> string -> unit +val register_modifiers : string -> modifiers -> unit + +val modifier_of_string : string -> modifier + +val modifiers_of_file : string -> modifiers diff --git a/ocamltest/filecompare.ml b/ocamltest/filecompare.ml index 2fe59c29..9e88d31e 100644 --- a/ocamltest/filecompare.ml +++ b/ocamltest/filecompare.ml @@ -15,27 +15,30 @@ (* File comparison tools *) +open Ocamltest_stdlib + type result = | Same | Different | Unexpected_output | Error of string * int +type ignore = {bytes: int; lines: int} type tool = | External of { tool_name : string; tool_flags : string; result_of_exitcode : string -> int -> result } - | Internal of int + | Internal of ignore let cmp_result_of_exitcode commandline = function | 0 -> Same | 1 -> Different | exit_code -> (Error (commandline, exit_code)) -let make_cmp_tool bytes_to_ignore = - Internal bytes_to_ignore +let make_cmp_tool ~ignore = + Internal ignore let make_comparison_tool ?(result_of_exitcode = cmp_result_of_exitcode) name flags = @@ -46,7 +49,7 @@ let make_comparison_tool ?(result_of_exitcode = cmp_result_of_exitcode) result_of_exitcode } -let default_comparison_tool = make_cmp_tool 0 +let default_comparison_tool = make_cmp_tool ~ignore:{bytes=0;lines=0} type filetype = Binary | Text @@ -56,14 +59,20 @@ type files = { output_filename : string; } -let read_text_file fn = +let read_text_file lines_to_drop fn = let ic = open_in_bin fn in let drop_cr s = let l = String.length s in if l > 0 && s.[l - 1] = '\r' then String.sub s 0 (l - 1) else raise Exit in - let rec loop acc = + let rec drop k = + if k = 0 then + loop [] + else + let stop = try ignore (input_line ic); false with End_of_file -> true in + if stop then [] else drop (k-1) + and loop acc = match input_line ic with | s -> loop (s :: acc) | exception End_of_file -> @@ -71,10 +80,10 @@ let read_text_file fn = try List.rev_map drop_cr acc with Exit -> List.rev acc in - loop [] + drop lines_to_drop -let compare_text_files file1 file2 = - if read_text_file file1 = read_text_file file2 then +let compare_text_files dropped_lines file1 file2 = + if read_text_file 0 file1 = read_text_file dropped_lines file2 then Same else Different @@ -136,20 +145,21 @@ let compare_files ?(tool = default_comparison_tool) files = ~stdout_fname:dev_null ~stderr_fname:dev_null commandline in let status = Run_command.run settings in result_of_exitcode commandline status - | Internal bytes_to_ignore -> + | Internal ignore -> match files.filetype with | Text -> (* bytes_to_ignore is silently ignored for text files *) - compare_text_files files.reference_filename files.output_filename + compare_text_files ignore.lines + files.reference_filename files.output_filename | Binary -> - compare_binary_files bytes_to_ignore + compare_binary_files ignore.bytes files.reference_filename files.output_filename let check_file ?(tool = default_comparison_tool) files = if Sys.file_exists files.reference_filename then compare_files ~tool:tool files else begin - if Testlib.file_is_empty files.output_filename + if Sys.file_is_empty files.output_filename then Same else Unexpected_output end @@ -164,4 +174,4 @@ let diff files = "> " ^ temporary_file ] in if (Sys.command diff_commandline) = 2 then Pervasives.Error "diff" - else Ok (Testlib.string_of_file temporary_file) + else Ok (Sys.string_of_file temporary_file) diff --git a/ocamltest/filecompare.mli b/ocamltest/filecompare.mli index c7d8ff6b..b1cb8569 100644 --- a/ocamltest/filecompare.mli +++ b/ocamltest/filecompare.mli @@ -23,7 +23,8 @@ type result = type tool -val make_cmp_tool : int -> tool +type ignore = {bytes: int; lines: int} +val make_cmp_tool : ignore:ignore -> tool val make_comparison_tool : ?result_of_exitcode:(string -> int -> result) -> string -> string -> tool diff --git a/ocamltest/filetype.ml b/ocamltest/filetype.ml deleted file mode 100644 index ba625968..00000000 --- a/ocamltest/filetype.ml +++ /dev/null @@ -1,69 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Types of input files involved in an OCaml project and related functions *) - -type t = - | Implementation - | Interface - | C - | C_minus_minus - | Lexer - | Grammar - -let string_of_filetype = function - | Implementation -> "implementation" - | Interface -> "interface" - | C -> "C source file" - | C_minus_minus -> "C minus minus source file" - | Lexer -> "lexer" - | Grammar -> "grammar" - -let extension_of_filetype = function - | Implementation -> "ml" - | Interface -> "mli" - | C -> "c" - | C_minus_minus -> "cmm" - | Lexer -> "mll" - | Grammar -> "mly" - -let filetype_of_extension = function - | "ml" -> Implementation - | "mli" -> Interface - | "c" -> C - | "cmm" -> C_minus_minus - | "mll" -> Lexer - | "mly" -> Grammar - | _ -> raise Not_found - -let split_filename name = - let l = String.length name in - let is_dir_sep name i = name.[i] = Filename.dir_sep.[0] in - let rec search_dot i = - if i < 0 || is_dir_sep name i then (name, "") - else if name.[i] = '.' then - let basename = String.sub name 0 i in - let extension = String.sub name (i+1) (l-i-1) in - (basename, extension) - else search_dot (i - 1) in - search_dot (l - 1) - -let filetype filename = - let (basename, extension) = split_filename filename in - (basename, filetype_of_extension extension) - -let make_filename (basename, filetype) = - let extension = extension_of_filetype filetype in - basename ^ "." ^ extension diff --git a/ocamltest/filetype.mli b/ocamltest/filetype.mli deleted file mode 100644 index 69db0e2b..00000000 --- a/ocamltest/filetype.mli +++ /dev/null @@ -1,36 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Types of input files involved in an OCaml project and related functions *) - -type t = - | Implementation - | Interface - | C - | C_minus_minus - | Lexer - | Grammar - -val string_of_filetype : t -> string - -val extension_of_filetype : t -> string - -val filetype_of_extension : string -> t - -val split_filename : string -> string * string - -val filetype : string -> string * t - -val make_filename : string * t -> string diff --git a/ocamltest/main.ml b/ocamltest/main.ml index 21ca874c..22c16fcb 100644 --- a/ocamltest/main.ml +++ b/ocamltest/main.ml @@ -15,8 +15,13 @@ (* Main program of the ocamltest test driver *) +open Ocamltest_stdlib open Tsl_semantics +type behavior = + | Skip_all_tests + | Run of Environments.t + (* let first_token filename = let input_channel = open_in filename in @@ -29,10 +34,17 @@ let first_token filename = let is_test filename = match first_token filename with | exception _ -> false - | Tsl_parser.TSL_BEGIN -> true + | Tsl_parser.TSL_BEGIN_C_STYLE | TSL_BEGIN_OCAML_STYLE -> true | _ -> false *) +(* this primitive announce should be used for tests + that were aborted on system error before ocamltest + could parse them *) +let announce_test_error test_filename error = + Printf.printf " ... testing '%s' => unexpected error (%s)\n%!" + (Filename.basename test_filename) error + let tsl_block_of_file test_filename = let input_channel = open_in test_filename in let lexbuf = Lexing.from_channel input_channel in @@ -44,61 +56,54 @@ let tsl_block_of_file test_filename = let tsl_block_of_file_safe test_filename = try tsl_block_of_file test_filename with | Sys_error message -> - Printf.eprintf "%s\n" message; + Printf.eprintf "%s\n%!" message; + announce_test_error test_filename message; exit 1 | Parsing.Parse_error -> - Printf.eprintf "Could not read test block in %s\n" test_filename; + Printf.eprintf "Could not read test block in %s\n%!" test_filename; + announce_test_error test_filename "could not read test block"; exit 1 let print_usage () = Printf.printf "%s\n%!" Options.usage -let rec run_test log common_prefix path ancestor_result = function +let rec run_test log common_prefix path behavior = function Node (testenvspec, test, env_modifiers, subtrees) -> Printf.printf "%s %s (%s) => %!" common_prefix path test.Tests.test_name; - let print_test_result str = Printf.printf "%s\n%!" str in - let test_result = match ancestor_result with - | Actions.Pass env -> (* Ancestor succeded, really run the test *) + let (msg, b) = match behavior with + | Skip_all_tests -> "skipped", Skip_all_tests + | Run env -> let testenv0 = interprete_environment_statements env testenvspec in let testenv = List.fold_left apply_modifiers testenv0 env_modifiers in - Tests.run log testenv test - | Actions.Skip _ -> (Actions.Skip "ancestor test skipped") - | Actions.Fail _ -> (Actions.Skip "ancestor test failed") in - let result_to_pass = match test_result with - | Actions.Pass _ -> - print_test_result "passed"; - test_result - | Actions.Fail _ -> - print_test_result "failed"; - ancestor_result - | Actions.Skip _ -> - print_test_result "skipped"; - ancestor_result in - List.iteri (run_test_i log common_prefix path result_to_pass) subtrees -and run_test_i log common_prefix path ancestor_result i test_tree = + let (result, newenv) = Tests.run log testenv test in + let s = Result.string_of_result result in + if Result.is_pass result then (s, Run newenv) + else (s, Skip_all_tests) in + Printf.printf "%s\n%!" msg; + List.iteri (run_test_i log common_prefix path b) subtrees +and run_test_i log common_prefix path behavior i test_tree = let path_prefix = if path="" then "" else path ^ "." in let new_path = Printf.sprintf "%s%d" path_prefix (i+1) in - run_test log common_prefix new_path ancestor_result test_tree + run_test log common_prefix new_path behavior test_tree let get_test_source_directory test_dirname = - if not (Filename.is_relative test_dirname) then test_dirname - else let pwd = Sys.getcwd() in - Filename.concat pwd test_dirname + if (Filename.is_relative test_dirname) then + Sys.with_chdir test_dirname Sys.getcwd + else test_dirname -let get_test_build_directory test_dirname = +let get_test_build_directory_prefix test_dirname = let ocamltestdir_variable = "OCAMLTESTDIR" in - let root = try Sys.getenv ocamltestdir_variable with - | Not_found -> (Filename.concat (Sys.getcwd ()) "_ocamltest") in + let root = + Sys.getenv_with_default_value ocamltestdir_variable + (Filename.concat (Sys.getcwd ()) "_ocamltest") + in if test_dirname = "." then root else Filename.concat root test_dirname -let main () = - if !Options.testfile = "" then begin - print_usage(); - exit 1 - end; - let test_filename = !Options.testfile in +let test_file test_filename = (* Printf.printf "# reading test file %s\n%!" test_filename; *) + (* Save current working directory *) + let cwd = Sys.getcwd() in let tsl_block = tsl_block_of_file_safe test_filename in let (rootenv_statements, test_trees) = test_trees_of_tsl_block tsl_block in let test_trees = match test_trees with @@ -107,7 +112,11 @@ let main () = let make_tree test = Node ([], test, [], []) in List.map make_tree default_tests | _ -> test_trees in - let actions = actions_in_tests (tests_in_trees test_trees) in + let used_tests = tests_in_trees test_trees in + let used_actions = actions_in_tests used_tests in + let action_names = + let f act names = StringSet.add (Actions.action_name act) names in + Actions.ActionSet.fold f used_actions StringSet.empty in let test_dirname = Filename.dirname test_filename in let test_basename = Filename.basename test_filename in let test_prefix = Filename.chop_extension test_basename in @@ -115,32 +124,57 @@ let main () = if test_dirname="." then test_prefix else Filename.concat test_dirname test_prefix in let test_source_directory = get_test_source_directory test_dirname in - let test_build_directory = get_test_build_directory test_directory in - let reference_filename = Filename.concat - test_source_directory (test_prefix ^ ".reference") in - let initial_environment = Environments.from_bindings - [ - Builtin_variables.c_preprocessor, Ocamltest_config.c_preprocessor; - Builtin_variables.ocamlc_default_flags, - Ocamltest_config.ocamlc_default_flags; - Builtin_variables.ocamlopt_default_flags, - Ocamltest_config.ocamlopt_default_flags; - Builtin_variables.test_file, test_basename; - Builtin_variables.reference, reference_filename; - Builtin_variables.test_source_directory, test_source_directory; - Builtin_variables.test_build_directory, test_build_directory; - ] in - let root_environment = - interprete_environment_statements initial_environment rootenv_statements in - let rootenv = Actions.update_environment root_environment actions in - Testlib.make_directory test_build_directory; - Sys.chdir test_build_directory; - let log_filename = test_prefix ^ ".log" in - let log = open_out log_filename in - let common_prefix = " ... testing '" ^ test_basename ^ "' with" in - List.iteri - (run_test_i log common_prefix "" (Actions.Pass rootenv)) - test_trees; - close_out log + let hookname_prefix = Filename.concat test_source_directory test_prefix in + let test_build_directory_prefix = + get_test_build_directory_prefix test_directory in + ignore (Sys.command ("rm -rf " ^ test_build_directory_prefix)); + Sys.make_directory test_build_directory_prefix; + Sys.with_chdir test_build_directory_prefix + (fun () -> + let log = + if !Options.log_to_stderr then stderr else begin + let log_filename = test_prefix ^ ".log" in + open_out log_filename + end in + let promote = string_of_bool !Options.promote in + let install_hook name = + let hook_name = Filename.make_filename hookname_prefix name in + if Sys.file_exists hook_name then begin + let hook = Actions_helpers.run_hook hook_name in + Actions.set_hook name hook + end in + StringSet.iter install_hook action_names; + + let reference_filename = Filename.concat + test_source_directory (test_prefix ^ ".reference") in + let initial_environment = Environments.from_bindings + [ + Builtin_variables.test_file, test_basename; + Builtin_variables.reference, reference_filename; + Builtin_variables.test_source_directory, test_source_directory; + Builtin_variables.test_build_directory_prefix, + test_build_directory_prefix; + Builtin_variables.promote, promote; + ] in + let root_environment = + interprete_environment_statements + initial_environment rootenv_statements in + let rootenv = Environments.initialize log root_environment in + let common_prefix = " ... testing '" ^ test_basename ^ "' with" in + List.iteri + (run_test_i log common_prefix "" (Run rootenv)) + test_trees; + Actions.clear_all_hooks(); + if not !Options.log_to_stderr then close_out log + ); + (* Restore current working directory *) + Sys.chdir cwd + +let main () = + if !Options.files_to_test = [] then begin + print_usage(); + exit 1 + end; + List.iter test_file !Options.files_to_test let _ = main() diff --git a/ocamltest/ocaml_actions.ml b/ocamltest/ocaml_actions.ml new file mode 100644 index 00000000..4d9c7845 --- /dev/null +++ b/ocamltest/ocaml_actions.ml @@ -0,0 +1,1106 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2017 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Actions specific to the OCaml compilers *) + +open Ocamltest_stdlib +open Actions + +(* Extracting information from environment *) + +let native_support = Ocamltest_config.arch <> "none" + +let no_native_compilers _log env = + (Result.skip_with_reason "native compilers disabled", env) + +let native_action a = + if native_support then a else (Actions.update a no_native_compilers) + +let get_backend_value_from_env env bytecode_var native_var = + Ocaml_backends.make_backend_function + (Environments.safe_lookup bytecode_var env) + (Environments.safe_lookup native_var env) + +let modules env = + Actions_helpers.words_of_variable env Ocaml_variables.modules + +let plugins env = + Actions_helpers.words_of_variable env Ocaml_variables.plugins + +let directories env = + Actions_helpers.words_of_variable env Ocaml_variables.directories + +let directory_flags env = + let f dir = ("-I " ^ dir) in + let l = List.map f (directories env) in + String.concat " " l + +let flags env = Environments.safe_lookup Ocaml_variables.flags env + +let ocamllex_flags env = + Environments.safe_lookup Ocaml_variables.ocamllex_flags env + +let ocamlyacc_flags env = + Environments.safe_lookup Ocaml_variables.ocamlyacc_flags env + +let filelist env variable extension = + let value = Environments.safe_lookup variable env in + let filenames = String.words value in + let add_extension filename = Filename.make_filename filename extension in + String.concat " " (List.map add_extension filenames) + +let libraries backend env = + let extension = Ocaml_backends.library_extension backend in + filelist env Ocaml_variables.libraries extension + +let binary_modules backend env = + let extension = Ocaml_backends.module_extension backend in + filelist env Ocaml_variables.binary_modules extension + +let backend_default_flags env = + get_backend_value_from_env env + Ocaml_variables.ocamlc_default_flags + Ocaml_variables.ocamlopt_default_flags + +let backend_flags env = + get_backend_value_from_env env + Ocaml_variables.ocamlc_flags + Ocaml_variables.ocamlopt_flags + +let dumb_term = [|"TERM=dumb"|] + +type module_generator = { + description : string; + command : string -> string; + flags : Environments.t -> string; + generated_compilation_units : + string -> (string * Ocaml_filetypes.t) list +} + +let ocamllex = +{ + description = "lexer"; + command = Ocaml_commands.ocamlrun_ocamllex; + flags = ocamllex_flags; + generated_compilation_units = + fun lexer_name -> [(lexer_name, Ocaml_filetypes.Implementation)] +} + +let ocamlyacc = +{ + description = "parser"; + command = Ocaml_files.ocamlyacc; + flags = ocamlyacc_flags; + generated_compilation_units = + fun parser_name -> + [ + (parser_name, Ocaml_filetypes.Interface); + (parser_name, Ocaml_filetypes.Implementation) + ] +} + +let generate_module generator ocamlsrcdir output_variable input log env = + let basename = fst input in + let input_file = Ocaml_filetypes.make_filename input in + let what = + Printf.sprintf "Generating %s module from %s" + generator.description input_file + in + Printf.fprintf log "%s\n%!" what; + let commandline = + [ + generator.command ocamlsrcdir; + generator.flags env; + input_file + ] in + let expected_exit_status = 0 in + let exit_status = + Actions_helpers.run_cmd + ~environment:dumb_term + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:output_variable + ~stderr_variable:output_variable + ~append:true + log env commandline in + if exit_status=expected_exit_status + then generator.generated_compilation_units basename + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + Printf.fprintf log "%s\n%!" reason; + [] + end + +let generate_lexer = generate_module ocamllex + +let generate_parser = generate_module ocamlyacc + +let prepare_module ocamlsrcdir output_variable log env input = + let input_type = snd input in + let open Ocaml_filetypes in + match input_type with + | Implementation | Interface | C -> [input] + | Binary_interface -> [input] + | Backend_specific _ -> [input] + | C_minus_minus -> assert false + | Lexer -> + generate_lexer ocamlsrcdir output_variable input log env + | Grammar -> + generate_parser ocamlsrcdir output_variable input log env + | Text -> assert false + +let get_program_file backend env = + let testfile = Actions_helpers.testfile env in + let testfile_basename = Filename.chop_extension testfile in + let program_filename = + Filename.mkexe + (Filename.make_filename + testfile_basename (Ocaml_backends.executable_extension backend)) in + let test_build_directory = + Actions_helpers.test_build_directory env in + Filename.make_path [test_build_directory; program_filename] + +let compile_program ocamlsrcdir (compiler : Ocaml_compilers.compiler) log env = + let program_variable = compiler#program_variable in + let program_file = Environments.safe_lookup program_variable env in + let all_modules = + Actions_helpers.words_of_variable env Ocaml_variables.all_modules in + let output_variable = compiler#output_variable in + let prepare = prepare_module ocamlsrcdir output_variable log env in + let modules = + List.concatmap prepare (List.map Ocaml_filetypes.filetype all_modules) in + let is_c_file (_filename, filetype) = filetype=Ocaml_filetypes.C in + let has_c_file = List.exists is_c_file modules in + let c_headers_flags = + if has_c_file then Ocaml_flags.c_includes ocamlsrcdir else "" in + let expected_exit_status = + Ocaml_tools.expected_exit_status env (compiler :> Ocaml_tools.tool) in + let module_names = + (binary_modules compiler#target env) ^ " " ^ + (String.concat " " (List.map Ocaml_filetypes.make_filename modules)) in + let what = Printf.sprintf "Compiling program %s from modules %s" + program_file module_names in + Printf.fprintf log "%s\n%!" what; + let compile_only = + Environments.lookup_as_bool Ocaml_variables.compile_only env = Some true + in + let compile_flags = + if compile_only then " -c " else "" + in + let output = if compile_only then "" else "-o " ^ program_file in + let commandline = + [ + compiler#name ocamlsrcdir; + Ocaml_flags.runtime_flags ocamlsrcdir compiler#target has_c_file; + c_headers_flags; + Ocaml_flags.stdlib ocamlsrcdir; + directory_flags env; + flags env; + libraries compiler#target env; + backend_default_flags env compiler#target; + backend_flags env compiler#target; + compile_flags; + output; + module_names + ] in + let exit_status = + Actions_helpers.run_cmd + ~environment:dumb_term + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:compiler#output_variable + ~stderr_variable:compiler#output_variable + ~append:true + log env commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let compile_module ocamlsrcdir compiler module_ log env = + let expected_exit_status = + Ocaml_tools.expected_exit_status env (compiler :> Ocaml_tools.tool) in + let what = Printf.sprintf "Compiling module %s" module_ in + Printf.fprintf log "%s\n%!" what; + let commandline = + [ + compiler#name ocamlsrcdir; + Ocaml_flags.stdlib ocamlsrcdir; + directory_flags env; + flags env; + libraries compiler#target env; + backend_default_flags env compiler#target; + backend_flags env compiler#target; + "-c " ^ module_; + ] in + let exit_status = + Actions_helpers.run_cmd + ~environment:dumb_term + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:compiler#output_variable + ~stderr_variable:compiler#output_variable + ~append:true + log env commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let module_has_interface directory module_name = + let interface_name = + Ocaml_filetypes.make_filename (module_name, Ocaml_filetypes.Interface) in + let interface_fullpath = Filename.make_path [directory;interface_name] in + Sys.file_exists interface_fullpath + +let add_module_interface directory module_description = + match module_description with + | (filename, Ocaml_filetypes.Implementation) when + module_has_interface directory filename -> + [(filename, Ocaml_filetypes.Interface); module_description] + | _ -> [module_description] + +let print_module_names log description modules = + Printf.fprintf log "%s modules: %s\n%!" + description + (String.concat " " (List.map Ocaml_filetypes.make_filename modules)) + +let find_source_modules log env = + let source_directory = Actions_helpers.test_source_directory env in + let specified_modules = + List.map Ocaml_filetypes.filetype + ((plugins env) @ (modules env) @ [(Actions_helpers.testfile env)]) in + print_module_names log "Specified" specified_modules; + let source_modules = + List.concatmap + (add_module_interface source_directory) + specified_modules in + print_module_names log "Source" source_modules; + Environments.add + Ocaml_variables.all_modules + (String.concat " " (List.map Ocaml_filetypes.make_filename source_modules)) + env + +let setup_tool_build_env tool log env = + let source_directory = Actions_helpers.test_source_directory env in + let testfile = Actions_helpers.testfile env in + let testfile_basename = Filename.chop_extension testfile in + let tool_reference_variable = + tool#reference_variable in + let tool_reference_prefix = + Filename.make_path [source_directory; testfile_basename] in + let tool_reference_file = + tool#reference_file env tool_reference_prefix + in + let env = + Environments.add_if_undefined + tool_reference_variable + tool_reference_file env + in + let source_modules = + Actions_helpers.words_of_variable env Ocaml_variables.all_modules in + let tool_directory_suffix = + Environments.safe_lookup Ocaml_variables.compiler_directory_suffix env in + let tool_directory_name = + tool#directory ^ tool_directory_suffix in + let build_dir = Filename.concat + (Environments.safe_lookup + Builtin_variables.test_build_directory_prefix env) + tool_directory_name in + let tool_output_variable = tool#output_variable in + let tool_output_filename = + Filename.make_filename tool#directory "output" in + let tool_output_file = + Filename.make_path [build_dir; tool_output_filename] + in + let env = + Environments.add_if_undefined + tool_output_variable + tool_output_file env + in + Sys.force_remove tool_output_file; + let env = + Environments.add Builtin_variables.test_build_directory build_dir env in + Actions_helpers.setup_build_env false source_modules log env + +let setup_compiler_build_env (compiler : Ocaml_compilers.compiler) log env = + let (r, env) = setup_tool_build_env compiler log env in + if Result.is_pass r then + begin + let prog_var = compiler#program_variable in + let prog_output_var = compiler#program_output_variable in + let default_prog_file = get_program_file compiler#target env in + let env = Environments.add_if_undefined prog_var default_prog_file env in + let prog_file = Environments.safe_lookup prog_var env in + let prog_output_file = prog_file ^ ".output" in + let env = match prog_output_var with + | None -> env + | Some outputvar -> + Environments.add_if_undefined outputvar prog_output_file env + in + (r, env) + end else (r, env) + +let setup_toplevel_build_env (toplevel : Ocaml_toplevels.toplevel) log env = + setup_tool_build_env toplevel log env + +let mk_compiler_env_setup name (compiler : Ocaml_compilers.compiler) = + Actions.make name (setup_compiler_build_env compiler) + +let mk_toplevel_env_setup name (toplevel : Ocaml_toplevels.toplevel) = + Actions.make name (setup_toplevel_build_env toplevel) + +let setup_ocamlc_byte_build_env = + mk_compiler_env_setup + "setup-ocamlc.byte-build-env" + Ocaml_compilers.ocamlc_byte + +let setup_ocamlc_opt_build_env = + native_action + (mk_compiler_env_setup + "setup-ocamlc.opt-build-env" + Ocaml_compilers.ocamlc_opt) + +let setup_ocamlopt_byte_build_env = + native_action + (mk_compiler_env_setup + "setup-ocamlopt.byte-build-env" + Ocaml_compilers.ocamlopt_byte) + +let setup_ocamlopt_opt_build_env = + native_action + (mk_compiler_env_setup + "setup-ocamlopt.opt-build-env" + Ocaml_compilers.ocamlopt_opt) + +let setup_ocaml_build_env = + mk_toplevel_env_setup + "setup-ocaml-build-env" + Ocaml_toplevels.ocaml + +let setup_ocamlnat_build_env = + native_action + (mk_toplevel_env_setup + "setup-ocamlnat-build-env" + Ocaml_toplevels.ocamlnat) + +let compile (compiler : Ocaml_compilers.compiler) log env = + let ocamlsrcdir = Ocaml_directories.srcdir () in + match Environments.lookup_nonempty Ocaml_variables.module_ env with + | None -> compile_program ocamlsrcdir compiler log env + | Some module_ -> compile_module ocamlsrcdir compiler module_ log env + +(* Compile actions *) + +let ocamlc_byte = + Actions.make + "ocamlc.byte" + (compile Ocaml_compilers.ocamlc_byte) + +let ocamlc_opt = + native_action + (Actions.make + "ocamlc.opt" + (compile Ocaml_compilers.ocamlc_opt)) + +let ocamlopt_byte = + native_action + (Actions.make + "ocamlopt.byte" + (compile Ocaml_compilers.ocamlopt_byte)) + +let ocamlopt_opt = + native_action + (Actions.make + "ocamlopt.opt" + (compile Ocaml_compilers.ocamlopt_opt)) + +let env_with_lib_unix ocamlsrcdir env = + let libunixdir = Ocaml_directories.libunix ocamlsrcdir in + let newlibs = + match Environments.lookup Ocaml_variables.caml_ld_library_path env with + | None -> libunixdir + | Some libs -> libunixdir ^ " " ^ libs + in + Environments.add Ocaml_variables.caml_ld_library_path newlibs env + +let debug log env = + let ocamlsrcdir = Ocaml_directories.srcdir () in + let program = Environments.safe_lookup Builtin_variables.program env in + let what = Printf.sprintf "Debugging program %s" program in + Printf.fprintf log "%s\n%!" what; + let commandline = + [ + Ocaml_commands.ocamlrun_ocamldebug ocamlsrcdir; + Ocaml_flags.ocamldebug_default_flags ocamlsrcdir; + program + ] in + let systemenv = + Array.append + dumb_term + (Environments.to_system_env (env_with_lib_unix ocamlsrcdir env)) + in + let expected_exit_status = 0 in + let exit_status = + Actions_helpers.run_cmd + ~environment:systemenv + ~stdin_variable: Ocaml_variables.ocamldebug_script + ~stdout_variable:Builtin_variables.output + ~stderr_variable:Builtin_variables.output + ~append:true + log (env_with_lib_unix ocamlsrcdir env) commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let ocamldebug = Actions.make "ocamldebug" debug + +let objinfo log env = + let ocamlsrcdir = Ocaml_directories.srcdir () in + let tools_directory = Ocaml_directories.tools ocamlsrcdir in + let program = Environments.safe_lookup Builtin_variables.program env in + let what = Printf.sprintf "Running ocamlobjinfo on %s" program in + Printf.fprintf log "%s\n%!" what; + let commandline = + [ + Ocaml_commands.ocamlrun_ocamlobjinfo ocamlsrcdir; + Ocaml_flags.ocamlobjinfo_default_flags; + program + ] in + let ocamllib = [| (Printf.sprintf "OCAMLLIB=%s" tools_directory) |] in + let systemenv = + Array.concat + [ + dumb_term; + ocamllib; + (Environments.to_system_env (env_with_lib_unix ocamlsrcdir env)) + ] + in + let expected_exit_status = 0 in + let exit_status = + Actions_helpers.run_cmd + ~environment:systemenv + ~stdout_variable:Builtin_variables.output + ~stderr_variable:Builtin_variables.output + ~append:true + log (env_with_lib_unix ocamlsrcdir env) commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let ocamlobjinfo = Actions.make "ocamlobjinfo" objinfo + +let run_expect_once ocamlsrcdir input_file principal log env = + let expect_flags = Sys.safe_getenv "EXPECT_FLAGS" in + let repo_root = "-repo-root " ^ ocamlsrcdir in + let principal_flag = if principal then "-principal" else "" in + let commandline = + [ + Ocaml_commands.ocamlrun_expect_test ocamlsrcdir; + expect_flags; + flags env; + repo_root; + principal_flag; + input_file + ] in + let exit_status = + Actions_helpers.run_cmd ~environment:dumb_term log env commandline in + if exit_status=0 then (Result.pass, env) + else begin + let reason = (Actions_helpers.mkreason + "expect" (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let run_expect_twice ocamlsrcdir input_file log env = + let corrected filename = Filename.make_filename filename "corrected" in + let (result1, env1) = run_expect_once ocamlsrcdir input_file false log env in + if Result.is_pass result1 then begin + let intermediate_file = corrected input_file in + let (result2, env2) = + run_expect_once ocamlsrcdir intermediate_file true log env1 in + if Result.is_pass result2 then begin + let output_file = corrected intermediate_file in + let output_env = Environments.add_bindings + [ + Builtin_variables.reference, input_file; + Builtin_variables.output, output_file + ] env2 in + (Result.pass, output_env) + end else (result2, env2) + end else (result1, env1) + +let run_expect log env = + let ocamlsrcdir = Ocaml_directories.srcdir () in + let input_file = Actions_helpers.testfile env in + run_expect_twice ocamlsrcdir input_file log env + +let run_expect = Actions.make "run-expect" run_expect + +let make_check_tool_output name tool = Actions.make + name + (Actions_helpers.check_output + tool#family + tool#output_variable + tool#reference_variable) + +let check_ocamlc_byte_output = make_check_tool_output + "check-ocamlc.byte-output" Ocaml_compilers.ocamlc_byte + +let check_ocamlc_opt_output = + native_action + (make_check_tool_output + "check-ocamlc.opt-output" Ocaml_compilers.ocamlc_opt) + +let check_ocamlopt_byte_output = + native_action + (make_check_tool_output + "check-ocamlopt.byte-output" Ocaml_compilers.ocamlopt_byte) + +let check_ocamlopt_opt_output = + native_action + (make_check_tool_output + "check-ocamlopt.opt-output" Ocaml_compilers.ocamlopt_opt) + +let really_compare_programs backend comparison_tool log env = + let program = Environments.safe_lookup Builtin_variables.program env in + let program2 = Environments.safe_lookup Builtin_variables.program2 env in + let what = Printf.sprintf "Comparing %s programs %s and %s" + (Ocaml_backends.string_of_backend backend) program program2 in + Printf.fprintf log "%s\n%!" what; + let files = { + Filecompare.filetype = Filecompare.Binary; + Filecompare.reference_filename = program; + Filecompare.output_filename = program2 + } in + if Ocamltest_config.flambda && backend = Ocaml_backends.Native + then begin + let reason = + "flambda temporarily disables comparison of native programs" in + (Result.pass_with_reason reason, env) + end else + if backend = Ocaml_backends.Native && + (Sys.os_type="Win32" || Sys.os_type="Cygwin") + then begin + let reason = + "comparison of native programs temporarily disabled under Windows" in + (Result.pass_with_reason reason, env) + end else begin + let comparison_tool = + if backend=Ocaml_backends.Native && + (Sys.os_type="Win32" || Sys.os_type="Cygwin") + then + let bytes_to_ignore = 512 (* comparison_start_address program *) in + Filecompare.(make_cmp_tool ~ignore:{bytes=bytes_to_ignore; lines=0}) + else comparison_tool in + match Filecompare.compare_files ~tool:comparison_tool files with + | Filecompare.Same -> (Result.pass, env) + | Filecompare.Different -> + let reason = Printf.sprintf "Files %s and %s are different" + program program2 in + (Result.fail_with_reason reason, env) + | Filecompare.Unexpected_output -> assert false + | Filecompare.Error (commandline, exitcode) -> + let reason = Actions_helpers.mkreason what commandline exitcode in + (Result.fail_with_reason reason, env) + end + +let compare_programs backend comparison_tool log env = + let compare_programs = + Environments.lookup_as_bool Ocaml_variables.compare_programs env in + if compare_programs = Some false then begin + let reason = "program comparison disabled" in + (Result.pass_with_reason reason, env) + end else really_compare_programs backend comparison_tool log env + +let make_bytecode_programs_comparison_tool ocamlsrcdir = + let ocamlrun = Ocaml_files.ocamlrun ocamlsrcdir in + let cmpbyt = Ocaml_files.cmpbyt ocamlsrcdir in + let tool_name = ocamlrun ^ " " ^ cmpbyt in + Filecompare.make_comparison_tool tool_name "" + +let native_programs_comparison_tool = Filecompare.default_comparison_tool + +let compare_bytecode_programs_code log env = + let ocamlsrcdir = Ocaml_directories.srcdir () in + let bytecode_programs_comparison_tool = + make_bytecode_programs_comparison_tool ocamlsrcdir in + compare_programs + Ocaml_backends.Bytecode bytecode_programs_comparison_tool log env + +let compare_bytecode_programs = + native_action + (Actions.make + "compare-bytecode-programs" + compare_bytecode_programs_code) + +let compare_native_programs = + native_action + (Actions.make + "compare-native-programs" + (compare_programs Ocaml_backends.Native native_programs_comparison_tool)) + +let compile_module + ocamlsrcdir compiler compilername compileroutput log env + (module_basename, module_filetype) = + let backend = compiler#target in + let filename = + Ocaml_filetypes.make_filename (module_basename, module_filetype) in + let expected_exit_status = + Ocaml_tools.expected_exit_status env (compiler :> Ocaml_tools.tool) in + let what = Printf.sprintf "%s for file %s (expected exit status: %d)" + (Ocaml_filetypes.action_of_filetype module_filetype) filename + (expected_exit_status) in + let compile_commandline input_file output_file optional_flags = + let compile = "-c " ^ input_file in + let output = match output_file with + | None -> "" + | Some file -> "-o " ^ file in + [ + compilername; + Ocaml_flags.stdlib ocamlsrcdir; + flags env; + backend_flags env backend; + optional_flags; + compile; + output; + ] in + let exec commandline = + Printf.fprintf log "%s\n%!" what; + let exit_status = + Actions_helpers.run_cmd + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:compileroutput + ~stderr_variable:compileroutput + ~append:true log env commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end in + match module_filetype with + | Ocaml_filetypes.Interface -> + let interface_name = + Ocaml_filetypes.make_filename + (module_basename, Ocaml_filetypes.Interface) in + let commandline = compile_commandline interface_name None "" in + exec commandline + | Ocaml_filetypes.Implementation -> + let module_extension = Ocaml_backends.module_extension backend in + let module_output_name = + Filename.make_filename module_basename module_extension in + let commandline = + compile_commandline filename (Some module_output_name) "" in + exec commandline + | Ocaml_filetypes.C -> + let object_extension = Config.ext_obj in + let _object_filename = module_basename ^ object_extension in + let commandline = + compile_commandline filename None + (Ocaml_flags.c_includes ocamlsrcdir) in + exec commandline + | _ -> + let reason = Printf.sprintf "File %s of type %s not supported yet" + filename (Ocaml_filetypes.string_of_filetype module_filetype) in + (Result.fail_with_reason reason, env) + +let compile_modules + ocamlsrcdir compiler compilername compileroutput + modules_with_filetypes log initial_env + = + let compile_mod env mod_ = + compile_module ocamlsrcdir compiler compilername compileroutput + log env mod_ in + let rec compile_mods env = function + | [] -> (Result.pass, env) + | m::ms -> + (let (result, newenv) = compile_mod env m in + if Result.is_pass result then (compile_mods newenv ms) + else (result, newenv)) in + compile_mods initial_env modules_with_filetypes + +let run_test_program_in_toplevel (toplevel : Ocaml_toplevels.toplevel) log env = + let testfile = Actions_helpers.testfile env in + let expected_exit_status = + Ocaml_tools.expected_exit_status env (toplevel :> Ocaml_tools.tool) in + let compiler_output_variable = toplevel#output_variable in + let ocamlsrcdir = Ocaml_directories.srcdir () in + let compiler = toplevel#compiler in + let compiler_name = compiler#name ocamlsrcdir in + let modules_with_filetypes = + List.map Ocaml_filetypes.filetype (modules env) in + let (result, env) = compile_modules + ocamlsrcdir compiler compiler_name compiler_output_variable + modules_with_filetypes log env in + if Result.is_pass result then begin + let what = + Printf.sprintf "Running %s in %s toplevel (expected exit status: %d)" + testfile + (Ocaml_backends.string_of_backend toplevel#backend) + expected_exit_status in + Printf.fprintf log "%s\n%!" what; + let toplevel_name = toplevel#name ocamlsrcdir in + let ocaml_script_as_argument = + match + Environments.lookup_as_bool + Ocaml_variables.ocaml_script_as_argument env + with + | None -> false + | Some b -> b + in + let commandline = + [ + toplevel_name; + Ocaml_flags.toplevel_default_flags; + toplevel#flags; + Ocaml_flags.stdlib ocamlsrcdir; + directory_flags env; + Ocaml_flags.include_toplevel_directory ocamlsrcdir; + flags env; + libraries toplevel#backend env; + binary_modules toplevel#backend env; + if ocaml_script_as_argument then testfile else ""; + Environments.safe_lookup Builtin_variables.arguments env + ] in + let exit_status = + if ocaml_script_as_argument + then Actions_helpers.run_cmd + ~environment:dumb_term + ~stdout_variable:compiler_output_variable + ~stderr_variable:compiler_output_variable + log env commandline + else Actions_helpers.run_cmd + ~environment:dumb_term + ~stdin_variable:Builtin_variables.test_file + ~stdout_variable:compiler_output_variable + ~stderr_variable:compiler_output_variable + log env commandline + in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + end else (result, env) + +let ocaml = Actions.make + "ocaml" + (run_test_program_in_toplevel Ocaml_toplevels.ocaml) + +let ocamlnat = + native_action + (Actions.make + "ocamlnat" + (run_test_program_in_toplevel Ocaml_toplevels.ocamlnat)) + +let check_ocaml_output = make_check_tool_output + "check-ocaml-output" Ocaml_toplevels.ocaml + +let check_ocamlnat_output = + native_action + (make_check_tool_output + "check-ocamlnat-output" Ocaml_toplevels.ocamlnat) + +let config_variables _log env = Environments.add_bindings + [ + Ocaml_variables.c_preprocessor, Ocamltest_config.c_preprocessor; + Ocaml_variables.ocamlc_default_flags, + Ocamltest_config.ocamlc_default_flags; + Ocaml_variables.ocamlopt_default_flags, + Ocamltest_config.ocamlopt_default_flags; + Ocaml_variables.ocamlrunparam, Sys.safe_getenv "OCAMLRUNPARAM"; + Ocaml_variables.ocamlsrcdir, Ocaml_directories.srcdir(); + Ocaml_variables.os_type, Sys.os_type; + ] env + +let flat_float_array = Actions.make + "flat-float-array" + (Actions_helpers.pass_or_skip Ocamltest_config.flat_float_array + "compiler configured with -flat-float-array" + "compiler configured with -no-flat-float-array") + +let no_flat_float_array = make + "no-flat-float-array" + (Actions_helpers.pass_or_skip (not Ocamltest_config.flat_float_array) + "compiler configured with -no-flat-float-array" + "compiler configured with -flat-float-array") + +let flambda = Actions.make + "flambda" + (Actions_helpers.pass_or_skip Ocamltest_config.flambda + "support for flambda enabled" + "support for flambda disabled") + +let no_flambda = make + "no-flambda" + (Actions_helpers.pass_or_skip (not Ocamltest_config.flambda) + "support for flambda disabled" + "support for flambda enabled") + +let spacetime = Actions.make + "spacetime" + (Actions_helpers.pass_or_skip Ocamltest_config.spacetime + "support for spacetime enabled" + "support for spacetime disabled") + +let no_spacetime = make + "no-spacetime" + (Actions_helpers.pass_or_skip (not Ocamltest_config.spacetime) + "support for spacetime disabled" + "support for spacetime enabled") + +let shared_libraries = Actions.make + "shared-libraries" + (Actions_helpers.pass_or_skip Ocamltest_config.shared_libraries + "Shared libraries are supported." + "Shared libraries are not supported.") + +let native_compiler = Actions.make + "native-compiler" + (Actions_helpers.pass_or_skip (Ocamltest_config.arch <> "none") + "native compiler available" + "native compiler not available") + +let afl_instrument = Actions.make + "afl-instrument" + (Actions_helpers.pass_or_skip Ocamltest_config.afl_instrument + "AFL instrumentation enabled" + "AFL instrumentation disabled") + +let no_afl_instrument = Actions.make + "no-afl-instrument" + (Actions_helpers.pass_or_skip (not Ocamltest_config.afl_instrument) + "AFL instrumentation disabled" + "AFL instrumentation enabled") + +let ocamldoc = Ocaml_tools.ocamldoc + +let ocamldoc_output_file env prefix = + let backend = + Environments.safe_lookup Ocaml_variables.ocamldoc_backend env in + let suffix = match backend with + | "latex" -> ".tex" + | "html" -> ".html" + | "man" -> ".3o" + | _ -> ".result" in + prefix ^ suffix + +let check_ocamldoc_output = make_check_tool_output + "check-ocamldoc-output" ocamldoc + +let ocamldoc_flags env = + Environments.safe_lookup Ocaml_variables.ocamldoc_flags env + +let compiled_doc_name input = input ^ ".odoc" + +(* The compiler used for compiling both cmi file + and plugins *) +let compiler_for_ocamldoc ocamlsrcdir = + let compiler = Ocaml_compilers.ocamlc_byte in + compile_modules ocamlsrcdir compiler (compiler#name ocamlsrcdir) + compiler#output_variable + +(* Within ocamldoc tests, + modules="a.ml b.ml" is interpreted as a list of + secondaries documentation modules that need to be + compiled into cmi files and odoc file (serialized ocamldoc information) + before the main documentation is generated *) +let compile_ocamldoc ocamlsrcdir (basename,filetype as module_) log env = + let expected_exit_status = + Ocaml_tools.expected_exit_status env (ocamldoc :> Ocaml_tools.tool) in + let what = Printf.sprintf "Compiling documentation for module %s" basename in + Printf.fprintf log "%s\n%!" what; + let filename = + Ocaml_filetypes.make_filename (basename, filetype) in + let (r,env) = compiler_for_ocamldoc ocamlsrcdir [module_] log env in + if not (Result.is_pass r) then (r,env) else + let commandline = + (* currently, we are ignoring the global ocamldoc_flags, since we + don't have per-module flags *) + [ + Ocaml_commands.ocamlrun_ocamldoc ocamlsrcdir; + Ocaml_flags.stdlib ocamlsrcdir; + "-dump " ^ compiled_doc_name basename; + filename; + ] in + let exit_status = + Actions_helpers.run_cmd + ~environment:(Environments.to_system_env env) + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:ocamldoc#output_variable + ~stderr_variable:ocamldoc#output_variable + ~append:true + log env commandline in + if exit_status=expected_exit_status + then (Result.pass, env) + else begin + let reason = + (Actions_helpers.mkreason + what (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let rec ocamldoc_compile_all ocamlsrcdir log env = function + | [] -> (Result.pass, env) + | a :: q -> + let (r,env) = compile_ocamldoc ocamlsrcdir a log env in + if Result.is_pass r then + ocamldoc_compile_all ocamlsrcdir log env q + else + (r,env) + +let setup_ocamldoc_build_env = + Actions.make "setup_ocamldoc_build_env" @@ fun log env -> + let (r,env) = setup_tool_build_env ocamldoc log env in + if not (Result.is_pass r) then (r,env) else + let source_directory = Actions_helpers.test_source_directory env in + let root_file = Filename.chop_extension (Actions_helpers.testfile env) in + let reference_prefix = Filename.make_path [source_directory; root_file] in + let output = ocamldoc_output_file env root_file in + let reference= reference_prefix ^ ocamldoc#reference_filename_suffix env in + let backend = Environments.safe_lookup Ocaml_variables.ocamldoc_backend env in + let env = + Environments.apply_modifiers env Ocaml_modifiers.(str @ unix) + |> Environments.add Builtin_variables.reference reference + |> Environments.add Builtin_variables.output output in + let env = + if backend = "man" then Environments.add_if_undefined + Builtin_variables.skip_header_lines "1" env + else env in + Result.pass, env + +let ocamldoc_plugin name = name ^ ".cmo" + +let ocamldoc_backend_flag env = + let backend = Environments.safe_lookup Ocaml_variables.ocamldoc_backend env in + if backend = "" then "" else "-" ^ backend + +let ocamldoc_o_flag env = + let output = Environments.safe_lookup Builtin_variables.output env in + match Environments.safe_lookup Ocaml_variables.ocamldoc_backend env with + | "html" | "manual" -> "index" + | _ -> output + +let run_ocamldoc = + Actions.make "ocamldoc" @@ fun log env -> + (* modules corresponds to secondaries modules of which the + documentation and cmi files need to be build before the main + module documentation *) + let modules = List.map Ocaml_filetypes.filetype @@ modules env in + (* plugins are used for custom documentation generators *) + let plugins = List.map Ocaml_filetypes.filetype @@ plugins env in + let ocamlsrcdir = Ocaml_directories.srcdir () in + let (r,env) = compiler_for_ocamldoc ocamlsrcdir plugins log env in + if not (Result.is_pass r) then r, env else + let (r,env) = ocamldoc_compile_all ocamlsrcdir log env modules in + if not (Result.is_pass r) then r, env else + let input_file = Actions_helpers.testfile env in + Printf.fprintf log "Generating documentation for %s\n%!" input_file; + let load_all = + List.map (fun name -> "-load " ^ compiled_doc_name (fst name)) + @@ (* sort module in alphabetical order *) + List.sort Pervasives.compare modules in + let with_plugins = + List.map (fun name -> "-g " ^ ocamldoc_plugin (fst name)) plugins in + let commandline = + [ + Ocaml_commands.ocamlrun_ocamldoc ocamlsrcdir; + ocamldoc_backend_flag env; + Ocaml_flags.stdlib ocamlsrcdir; + ocamldoc_flags env] + @ load_all @ with_plugins @ + [ input_file; + "-o"; ocamldoc_o_flag env + ] in + let exit_status = + Actions_helpers.run_cmd ~environment:(Environments.to_system_env env) + ~stdin_variable: Ocaml_variables.compiler_stdin + ~stdout_variable:ocamldoc#output_variable + ~stderr_variable:ocamldoc#output_variable + ~append:true + log env commandline in + if exit_status=0 then + (Result.pass, env) + else begin + let reason = (Actions_helpers.mkreason + "ocamldoc" (String.concat " " commandline) exit_status) in + (Result.fail_with_reason reason, env) + end + +let _ = + Environments.register_initializer "find_source_modules" find_source_modules; + Environments.register_initializer "config_variables" config_variables; + List.iter register + [ + setup_ocamlc_byte_build_env; + ocamlc_byte; + check_ocamlc_byte_output; + setup_ocamlc_opt_build_env; + ocamlc_opt; + check_ocamlc_opt_output; + setup_ocamlopt_byte_build_env; + ocamlopt_byte; + check_ocamlopt_byte_output; + setup_ocamlopt_opt_build_env; + ocamlopt_opt; + check_ocamlopt_opt_output; + run_expect; + compare_bytecode_programs; + compare_native_programs; + setup_ocaml_build_env; + ocaml; + check_ocaml_output; + setup_ocamlnat_build_env; + ocamlnat; + check_ocamlnat_output; + flat_float_array; + no_flat_float_array; + flambda; + no_flambda; + spacetime; + no_spacetime; + shared_libraries; + native_compiler; + afl_instrument; + no_afl_instrument; + setup_ocamldoc_build_env; + run_ocamldoc; + check_ocamldoc_output; + ocamldebug; + ocamlobjinfo + ] diff --git a/ocamltest/ocaml_actions.mli b/ocamltest/ocaml_actions.mli new file mode 100644 index 00000000..ab4d302a --- /dev/null +++ b/ocamltest/ocaml_actions.mli @@ -0,0 +1,52 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2017 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Actions specific to the OCaml compilers *) + +val setup_ocamlc_byte_build_env : Actions.t +val ocamlc_byte : Actions.t +val check_ocamlc_byte_output : Actions.t +val setup_ocamlc_opt_build_env : Actions.t +val ocamlc_opt : Actions.t +val check_ocamlc_opt_output : Actions.t +val setup_ocamlopt_byte_build_env : Actions.t +val ocamlopt_byte : Actions.t +val check_ocamlopt_byte_output : Actions.t +val setup_ocamlopt_opt_build_env : Actions.t +val ocamlopt_opt : Actions.t +val check_ocamlopt_opt_output : Actions.t +val run_expect : Actions.t +val compare_bytecode_programs : Actions.t +val compare_native_programs : Actions.t +val setup_ocaml_build_env : Actions.t +val ocaml : Actions.t +val check_ocaml_output : Actions.t +val setup_ocamlnat_build_env : Actions.t +val ocamlnat : Actions.t +val check_ocamlnat_output : Actions.t + +val setup_ocamldoc_build_env : Actions.t +val run_ocamldoc: Actions.t +val check_ocamldoc_output: Actions.t + +val flat_float_array : Actions.t +val no_flat_float_array : Actions.t + +val shared_libraries : Actions.t + +val native_compiler : Actions.t + +val afl_instrument : Actions.t +val no_afl_instrument : Actions.t diff --git a/ocamltest/ocaml_backends.ml b/ocamltest/ocaml_backends.ml new file mode 100644 index 00000000..71e75a49 --- /dev/null +++ b/ocamltest/ocaml_backends.ml @@ -0,0 +1,38 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Backends of the OCaml compiler and their properties *) + +type t = Native | Bytecode + +let is_bytecode t = t=Bytecode + +let is_native t = t=Native + +let string_of_backend = function + | Native -> "native" + | Bytecode -> "bytecode" + +(* Creates a function that returns its first argument for Bytecode *) +(* and its second argument for Native code *) +let make_backend_function bytecode_value native_value = function + | Bytecode -> bytecode_value + | Native -> native_value + +let module_extension = make_backend_function "cmo" "cmx" + +let library_extension = make_backend_function "cma" "cmxa" + +let executable_extension = make_backend_function "byte" "opt" diff --git a/ocamltest/ocaml_backends.mli b/ocamltest/ocaml_backends.mli new file mode 100644 index 00000000..5cc48e85 --- /dev/null +++ b/ocamltest/ocaml_backends.mli @@ -0,0 +1,32 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Backends of the OCaml compiler and their properties *) + +type t = Native | Bytecode + +val is_bytecode : t -> bool + +val is_native : t -> bool + +val string_of_backend : t -> string + +val make_backend_function : 'a -> 'a -> t -> 'a + +val module_extension : t -> string + +val library_extension : t -> string + +val executable_extension : t -> string diff --git a/ocamltest/ocaml_commands.ml b/ocamltest/ocaml_commands.ml new file mode 100644 index 00000000..e0bf9aa0 --- /dev/null +++ b/ocamltest/ocaml_commands.ml @@ -0,0 +1,39 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Helper functions to build OCaml-related commands *) + +let ocamlrun ocamlsrcdir program = + (Ocaml_files.ocamlrun ocamlsrcdir) ^ " " ^ (program ocamlsrcdir) + +let ocamlrun_ocamlc ocamlsrcdir = ocamlrun ocamlsrcdir Ocaml_files.ocamlc + +let ocamlrun_ocamlopt ocamlsrcdir = ocamlrun ocamlsrcdir Ocaml_files.ocamlopt + +let ocamlrun_ocaml ocamlsrcdir = ocamlrun ocamlsrcdir Ocaml_files.ocaml + +let ocamlrun_expect_test ocamlsrcdir = + ocamlrun ocamlsrcdir Ocaml_files.expect_test + +let ocamlrun_ocamllex ocamlsrcdir = ocamlrun ocamlsrcdir Ocaml_files.ocamllex + +let ocamlrun_ocamldoc ocamlsrcdir = + ocamlrun ocamlsrcdir Ocaml_files.ocamldoc + +let ocamlrun_ocamldebug ocamlsrcdir = + ocamlrun ocamlsrcdir Ocaml_files.ocamldebug + +let ocamlrun_ocamlobjinfo ocamlsrcdir = + ocamlrun ocamlsrcdir Ocaml_files.ocamlobjinfo diff --git a/ocamltest/ocaml_commands.mli b/ocamltest/ocaml_commands.mli new file mode 100644 index 00000000..9adcad3a --- /dev/null +++ b/ocamltest/ocaml_commands.mli @@ -0,0 +1,32 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Helper functions to build OCaml-related commands *) + +val ocamlrun_ocamlc : string -> string + +val ocamlrun_ocamlopt : string -> string + +val ocamlrun_ocaml : string -> string + +val ocamlrun_expect_test : string -> string + +val ocamlrun_ocamllex : string -> string + +val ocamlrun_ocamldoc : string -> string + +val ocamlrun_ocamldebug : string -> string + +val ocamlrun_ocamlobjinfo : string -> string diff --git a/ocamltest/ocaml_compilers.ml b/ocamltest/ocaml_compilers.ml new file mode 100644 index 00000000..bb3ed6ae --- /dev/null +++ b/ocamltest/ocaml_compilers.ml @@ -0,0 +1,101 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Description of the OCaml compilers *) + +open Ocamltest_stdlib + +class compiler + ~(name : string -> string) + ~(flags : string) + ~(directory : string) + ~(exit_status_variable : Variables.t) + ~(reference_variable : Variables.t) + ~(output_variable : Variables.t) + ~(host : Ocaml_backends.t) + ~(target : Ocaml_backends.t) += object (self) inherit Ocaml_tools.tool + ~name:name + ~family:"compiler" + ~flags:flags + ~directory:directory + ~exit_status_variable:exit_status_variable + ~reference_variable:reference_variable + ~output_variable:output_variable + as tool + + method host = host + method target = target + + method program_variable = + if Ocaml_backends.is_native host + then Builtin_variables.program2 + else Builtin_variables.program + + method program_output_variable = + if Ocaml_backends.is_native host + then None + else Some Builtin_variables.output + + method ! reference_file env prefix = + let default = tool#reference_file env prefix in + if Sys.file_exists default then default else + let suffix = self#reference_filename_suffix env in + let mk s = (Filename.make_filename prefix s) ^ suffix in + let filename = mk + (Ocaml_backends.string_of_backend target) in + if Sys.file_exists filename then filename else + mk "compilers" +end + +let ocamlc_byte = new compiler + ~name: Ocaml_commands.ocamlrun_ocamlc + ~flags: "" + ~directory: "ocamlc.byte" + ~exit_status_variable: Ocaml_variables.ocamlc_byte_exit_status + ~reference_variable: Ocaml_variables.compiler_reference + ~output_variable: Ocaml_variables.compiler_output + ~host: Ocaml_backends.Bytecode + ~target: Ocaml_backends.Bytecode + +let ocamlc_opt = new compiler + ~name: Ocaml_files.ocamlc_dot_opt + ~flags: "" + ~directory: "ocamlc.opt" + ~exit_status_variable: Ocaml_variables.ocamlc_opt_exit_status + ~reference_variable: Ocaml_variables.compiler_reference2 + ~output_variable: Ocaml_variables.compiler_output2 + ~host: Ocaml_backends.Native + ~target: Ocaml_backends.Bytecode + +let ocamlopt_byte = new compiler + ~name: Ocaml_commands.ocamlrun_ocamlopt + ~flags: "" + ~directory: "ocamlopt.byte" + ~exit_status_variable: Ocaml_variables.ocamlopt_byte_exit_status + ~reference_variable: Ocaml_variables.compiler_reference + ~output_variable: Ocaml_variables.compiler_output + ~host: Ocaml_backends.Bytecode + ~target: Ocaml_backends.Native + +let ocamlopt_opt = new compiler + ~name: Ocaml_files.ocamlopt_dot_opt + ~flags: "" + ~directory: "ocamlopt.opt" + ~exit_status_variable: Ocaml_variables.ocamlopt_opt_exit_status + ~reference_variable: Ocaml_variables.compiler_reference2 + ~output_variable: Ocaml_variables.compiler_output2 + ~host: Ocaml_backends.Native + ~target: Ocaml_backends.Native diff --git a/ocamltest/ocaml_compilers.mli b/ocamltest/ocaml_compilers.mli new file mode 100644 index 00000000..e4eb638e --- /dev/null +++ b/ocamltest/ocaml_compilers.mli @@ -0,0 +1,40 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Descriptions of the OCaml compilers *) + +class compiler : + name : (string -> string) -> + flags : string -> + directory : string -> + exit_status_variable : Variables.t -> + reference_variable : Variables.t -> + output_variable : Variables.t -> + host : Ocaml_backends.t -> + target : Ocaml_backends.t -> +object inherit Ocaml_tools.tool + method host : Ocaml_backends.t + method target : Ocaml_backends.t + method program_variable : Variables.t + method program_output_variable : Variables.t option +end + +val ocamlc_byte : compiler + +val ocamlc_opt : compiler + +val ocamlopt_byte : compiler + +val ocamlopt_opt : compiler diff --git a/ocamltest/ocaml_directories.ml b/ocamltest/ocaml_directories.ml new file mode 100644 index 00000000..22ebef75 --- /dev/null +++ b/ocamltest/ocaml_directories.ml @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Locations of directories in the OCaml source tree *) + +open Ocamltest_stdlib + +let srcdir () = + Sys.getenv_with_default_value "OCAMLSRCDIR" Ocamltest_config.ocamlsrcdir + +let stdlib ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "stdlib"] + +let libunix ocamlsrcdir = + let subdir = if Sys.os_type="Win32" then "win32unix" else "unix" in + Filename.make_path [ocamlsrcdir; "otherlibs"; subdir] + +let toplevel ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "toplevel"] + +let runtime ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "byterun"] + +let runtime_library backend ocamlsrcdir = + let backend_lib_dir = match backend with + | Ocaml_backends.Native -> "asmrun" + | Ocaml_backends.Bytecode -> "byterun" in + Filename.make_path [ocamlsrcdir; backend_lib_dir] + +let tools ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "tools"] diff --git a/ocamltest/ocaml_directories.mli b/ocamltest/ocaml_directories.mli new file mode 100644 index 00000000..929e7b05 --- /dev/null +++ b/ocamltest/ocaml_directories.mli @@ -0,0 +1,30 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Locations of directories in the OCaml source tree *) + +val srcdir : unit -> string + +val stdlib : string -> string + +val libunix : string -> string + +val toplevel : string -> string + +val runtime : string -> string + +val runtime_library : Ocaml_backends.t -> string -> string + +val tools : string -> string diff --git a/ocamltest/ocaml_files.ml b/ocamltest/ocaml_files.ml new file mode 100644 index 00000000..288cdeb4 --- /dev/null +++ b/ocamltest/ocaml_files.ml @@ -0,0 +1,77 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Locations of files in the OCaml source tree *) + +open Ocamltest_stdlib + +type runtime_variant = + | Normal + | Debug + | Instrumented + +let runtime_variant() = + let use_runtime = Sys.safe_getenv "USE_RUNTIME" in + if use_runtime="d" then Debug + else if use_runtime="i" then Instrumented + else Normal + +let ocamlrun ocamlsrcdir = + let runtime = match runtime_variant () with + | Normal -> "ocamlrun" + | Debug -> "ocamlrund" + | Instrumented -> "ocamlruni" in + let ocamlrunfile = Filename.mkexe runtime in + Filename.make_path [ocamlsrcdir; "byterun"; ocamlrunfile] + +let ocamlc ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocamlc"] + +let ocaml ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocaml"] + +let ocamlc_dot_opt ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocamlc.opt"] + +let ocamlopt ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocamlopt"] + +let ocamlopt_dot_opt ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocamlopt.opt"] + +let ocamlnat ocamlsrcdir = + Filename.make_path [ocamlsrcdir; Filename.mkexe "ocamlnat"] + +let cmpbyt ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "tools"; "cmpbyt"] + +let expect_test ocamlsrcdir = + Filename.make_path + [ocamlsrcdir; "testsuite"; "tools"; Filename.mkexe "expect_test"] + +let ocamllex ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "lex"; "ocamllex"] + +let ocamlyacc ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "yacc"; Filename.mkexe "ocamlyacc"] + +let ocamldoc ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "ocamldoc"; "ocamldoc"] + +let ocamldebug ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "debugger"; Filename.mkexe "ocamldebug"] + +let ocamlobjinfo ocamlsrcdir = + Filename.make_path [ocamlsrcdir; "tools"; "ocamlobjinfo"] diff --git a/ocamltest/ocaml_files.mli b/ocamltest/ocaml_files.mli new file mode 100644 index 00000000..c30d990b --- /dev/null +++ b/ocamltest/ocaml_files.mli @@ -0,0 +1,49 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Locations of files in the OCaml source tree *) + +type runtime_variant = + | Normal + | Debug + | Instrumented + +val runtime_variant : unit -> runtime_variant + +val ocamlrun : string -> string + +val ocamlc : string -> string + +val ocaml : string -> string + +val ocamlc_dot_opt : string -> string + +val ocamlopt : string -> string + +val ocamlopt_dot_opt : string -> string + +val ocamlnat : string -> string + +val cmpbyt : string -> string + +val expect_test : string -> string + +val ocamllex : string -> string + +val ocamlyacc : string -> string + +val ocamldoc : string -> string +val ocamldebug : string -> string +val ocamlobjinfo : string -> string diff --git a/ocamltest/ocaml_filetypes.ml b/ocamltest/ocaml_filetypes.ml new file mode 100644 index 00000000..997cc1b7 --- /dev/null +++ b/ocamltest/ocaml_filetypes.ml @@ -0,0 +1,112 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Types of files involved in an OCaml project and related functions *) + +type backend_specific = Object | Library | Program + +type t = + | Implementation + | Interface + | C + | C_minus_minus + | Lexer + | Grammar + | Binary_interface + | Backend_specific of Ocaml_backends.t * backend_specific + | Text (* used by ocamldoc for text only documentation *) + +let string_of_backend_specific = function + | Object -> "object" + | Library -> "library" + | Program -> "program" + +let string_of_filetype = function + | Implementation -> "implementation" + | Interface -> "interface" + | C -> "C source file" + | C_minus_minus -> "C minus minus source file" + | Lexer -> "lexer" + | Grammar -> "grammar" + | Binary_interface -> "binary interface" + | Backend_specific (backend, filetype) -> + ((Ocaml_backends.string_of_backend backend) ^ " " ^ + (string_of_backend_specific filetype)) + | Text -> "text" + +let extension_of_filetype = function + | Implementation -> "ml" + | Interface -> "mli" + | C -> "c" + | C_minus_minus -> "cmm" + | Lexer -> "mll" + | Grammar -> "mly" + | Binary_interface -> "cmi" + | Backend_specific (backend, filetype) -> + begin match (backend, filetype) with + | (Ocaml_backends.Native, Object) -> "cmx" + | (Ocaml_backends.Native, Library) -> "cmxa" + | (Ocaml_backends.Native, Program) -> "opt" + | (Ocaml_backends.Bytecode, Object) -> "cmo" + | (Ocaml_backends.Bytecode, Library) -> "cma" + | (Ocaml_backends.Bytecode, Program) -> "byte" + end + | Text -> "txt" + +let filetype_of_extension = function + | "ml" -> Implementation + | "mli" -> Interface + | "c" -> C + | "cmm" -> C_minus_minus + | "mll" -> Lexer + | "mly" -> Grammar + | "cmi" -> Binary_interface + | "cmx" -> Backend_specific (Ocaml_backends.Native, Object) + | "cmxa" -> Backend_specific (Ocaml_backends.Native, Library) + | "opt" -> Backend_specific (Ocaml_backends.Native, Program) + | "cmo" -> Backend_specific (Ocaml_backends.Bytecode, Object) + | "cma" -> Backend_specific (Ocaml_backends.Bytecode, Library) + | "byte" -> Backend_specific (Ocaml_backends.Bytecode, Program) + | "txt" -> Text + | _ -> raise Not_found + +let split_filename name = + let l = String.length name in + let is_dir_sep name i = name.[i] = Filename.dir_sep.[0] in + let rec search_dot i = + if i < 0 || is_dir_sep name i then (name, "") + else if name.[i] = '.' then + let basename = String.sub name 0 i in + let extension = String.sub name (i+1) (l-i-1) in + (basename, extension) + else search_dot (i - 1) in + search_dot (l - 1) + +let filetype filename = + let (basename, extension) = split_filename filename in + (basename, filetype_of_extension extension) + +let make_filename (basename, filetype) = + let extension = extension_of_filetype filetype in + basename ^ "." ^ extension + +let action_of_filetype = function + | Implementation -> "Compiling implementation" + | Interface -> "Compiling interface" + | C -> "Compiling C source file" + | C_minus_minus -> "Processing C-- file" + | Lexer -> "Generating lexer" + | Grammar -> "Generating parser" + | filetype -> ("nothing to do for " ^ (string_of_filetype filetype)) diff --git a/ocamltest/ocaml_filetypes.mli b/ocamltest/ocaml_filetypes.mli new file mode 100644 index 00000000..89911d4b --- /dev/null +++ b/ocamltest/ocaml_filetypes.mli @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Types of files involved in an OCaml project and related functions *) + +type backend_specific = Object | Library | Program + +type t = + | Implementation + | Interface + | C + | C_minus_minus + | Lexer + | Grammar + | Binary_interface + | Backend_specific of Ocaml_backends.t * backend_specific + | Text (** text-only documentation file *) + +val string_of_filetype : t -> string + +val extension_of_filetype : t -> string + +val filetype_of_extension : string -> t + +val split_filename : string -> string * string + +val filetype : string -> string * t + +val make_filename : string * t -> string + +val action_of_filetype : t -> string diff --git a/ocamltest/ocaml_flags.ml b/ocamltest/ocaml_flags.ml new file mode 100644 index 00000000..b45dcf47 --- /dev/null +++ b/ocamltest/ocaml_flags.ml @@ -0,0 +1,55 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Flags used in OCaml commands *) + +let stdlib ocamlsrcdir = + let stdlib_path = Ocaml_directories.stdlib ocamlsrcdir in + "-nostdlib -I " ^ stdlib_path + +let include_toplevel_directory ocamlsrcdir = + "-I " ^ (Ocaml_directories.toplevel ocamlsrcdir) + +let c_includes ocamlsrcdir = + let dir = Ocaml_directories.runtime ocamlsrcdir in + "-ccopt -I" ^ dir + +let runtime_variant_flags () = match Ocaml_files.runtime_variant() with + | Ocaml_files.Normal -> "" + | Ocaml_files.Debug -> " -runtime-variant d" + | Ocaml_files.Instrumented -> " -runtime-variant i" + +let runtime_flags ocamlsrcdir backend c_files = + let runtime_library_flags = "-I " ^ + (Ocaml_directories.runtime_library backend ocamlsrcdir) in + let rt_flags = match backend with + | Ocaml_backends.Native -> runtime_variant_flags () + | Ocaml_backends.Bytecode -> + begin + if c_files then begin (* custom mode *) + "-custom " ^ (runtime_variant_flags ()) + end else begin (* non-custom mode *) + "-use-runtime " ^ (Ocaml_files.ocamlrun ocamlsrcdir) + end + end in + rt_flags ^ " " ^ runtime_library_flags + +let toplevel_default_flags = "-noinit -no-version -noprompt" + +let ocamldebug_default_flags ocamlsrcdir = + "-no-version -no-prompt -no-time -no-breakpoint-message " ^ + ("-topdirs-path " ^ (Ocaml_directories.toplevel ocamlsrcdir)) + +let ocamlobjinfo_default_flags = "-null-crc" diff --git a/ocamltest/ocaml_flags.mli b/ocamltest/ocaml_flags.mli new file mode 100644 index 00000000..a2513786 --- /dev/null +++ b/ocamltest/ocaml_flags.mli @@ -0,0 +1,30 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Flags used in OCaml commands *) + +val stdlib : string -> string + +val include_toplevel_directory : string -> string + +val c_includes : string -> string + +val runtime_flags : string -> Ocaml_backends.t -> bool -> string + +val toplevel_default_flags : string + +val ocamldebug_default_flags : string -> string + +val ocamlobjinfo_default_flags : string diff --git a/ocamltest/ocaml_modifiers.ml b/ocamltest/ocaml_modifiers.ml new file mode 100644 index 00000000..50d57a23 --- /dev/null +++ b/ocamltest/ocaml_modifiers.ml @@ -0,0 +1,119 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of a few OCaml-specific environment modifiers *) + +open Ocamltest_stdlib +open Environments + +let principal = +[ + Append (Ocaml_variables.flags, " -principal "); + Add (Ocaml_variables.compiler_directory_suffix, ".principal"); + Add (Ocaml_variables.compiler_reference_suffix, ".principal"); +] + +let latex = + [ + Add (Ocaml_variables.ocamldoc_backend, "latex"); + Append (Ocaml_variables.ocamldoc_flags, "-latex-type-prefix=TYP "); + Append (Ocaml_variables.ocamldoc_flags, "-latex-module-prefix= "); + Append (Ocaml_variables.ocamldoc_flags, "-latex-value-prefix= "); + Append (Ocaml_variables.ocamldoc_flags, "-latex-module-type-prefix= "); + Append (Ocaml_variables.ocamldoc_flags, "-latextitle=1,subsection* "); + Append (Ocaml_variables.ocamldoc_flags, "-latextitle=2,subsubsection* "); + Append (Ocaml_variables.ocamldoc_flags, "-latextitle=6,subsection* "); + Append (Ocaml_variables.ocamldoc_flags, "-latextitle=7,subsubsection* "); + ] + + +let html = + [ + Add (Ocaml_variables.ocamldoc_backend, "html"); + Append (Ocaml_variables.ocamldoc_flags, "-colorize-code "); + ] + +let man = + [ + Add (Ocaml_variables.ocamldoc_backend, "man"); + ] + +let wrap str = (" " ^ str ^ " ") + +let make_library_modifier library directory = +[ + Append (Ocaml_variables.directories, (wrap directory)); + Append (Ocaml_variables.libraries, (wrap library)); + Append (Ocaml_variables.caml_ld_library_path, (wrap directory)); +] + +let make_module_modifier unit_name directory = +[ + Append (Ocaml_variables.directories, (wrap directory)); + Append (Ocaml_variables.binary_modules, (wrap unit_name)); +] + +let compiler_subdir subdir = + Filename.make_path (Ocamltest_config.ocamlsrcdir :: subdir) + +let config = +[ + Append (Ocaml_variables.directories, (wrap (compiler_subdir ["utils"]))); +] + +let testing = make_library_modifier + "testing" (compiler_subdir ["testsuite"; "lib"]) + +let tool_ocaml_lib = make_module_modifier + "lib" (compiler_subdir ["testsuite"; "lib"]) + +let unixlibdir = if Sys.os_type="Win32" then "win32unix" else "unix" + +let unix = make_library_modifier + "unix" (compiler_subdir ["otherlibs"; unixlibdir]) + +let str = make_library_modifier + "str" (compiler_subdir ["otherlibs"; "str"]) + +let systhreads = + unix @ + (make_library_modifier + "threads" (compiler_subdir ["otherlibs"; "systhreads"])) + +let compilerlibs_subdirs = +[ + "utils"; "parsing"; "toplevel"; "typing"; "bytecomp"; "compilerlibs"; +] + +let add_compiler_subdir subdir = + Append (Ocaml_variables.directories, (wrap (compiler_subdir [subdir]))) + +let ocamlcommon = + (Append (Ocaml_variables.libraries, wrap "ocamlcommon")) :: + (List.map add_compiler_subdir compilerlibs_subdirs) + +let _ = + register_modifiers "principal" principal; + register_modifiers "config" config; + register_modifiers "testing" testing; + register_modifiers "unix" unix; + register_modifiers "str" str; + register_modifiers "ocamlcommon" ocamlcommon; + register_modifiers "systhreads" systhreads; + register_modifiers "latex" latex; + register_modifiers "html" html; + register_modifiers "man" man; + register_modifiers "tool-ocaml-lib" tool_ocaml_lib; + () diff --git a/ocamltest/ocaml_modifiers.mli b/ocamltest/ocaml_modifiers.mli new file mode 100644 index 00000000..a6d2adc2 --- /dev/null +++ b/ocamltest/ocaml_modifiers.mli @@ -0,0 +1,28 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of a few OCaml-specific environment modifiers *) + +val principal : Environments.modifiers + +val testing : Environments.modifiers + +val unix : Environments.modifiers + +val str : Environments.modifiers + +val latex: Environments.modifiers +val man: Environments.modifiers +val html: Environments.modifiers diff --git a/ocamltest/ocaml_tests.ml b/ocamltest/ocaml_tests.ml new file mode 100644 index 00000000..35cfa75d --- /dev/null +++ b/ocamltest/ocaml_tests.ml @@ -0,0 +1,116 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Tests specific to the OCaml compiler *) + +open Tests +open Builtin_actions +open Ocaml_actions + +let bytecode = + let opt_actions = + [ + setup_ocamlc_opt_build_env; + ocamlc_opt; + check_ocamlc_opt_output; + compare_bytecode_programs + ] in +{ + test_name = "bytecode"; + test_run_by_default = true; + test_actions = + [ + setup_ocamlc_byte_build_env; + ocamlc_byte; + check_ocamlc_byte_output; + run; + check_program_output; + ] @ (if Ocamltest_config.arch<>"none" then opt_actions else []) +} + +let native = + let opt_actions = + [ + setup_ocamlopt_byte_build_env; + ocamlopt_byte; + check_ocamlopt_byte_output; + run; + check_program_output; + setup_ocamlopt_opt_build_env; + ocamlopt_opt; + check_ocamlopt_opt_output; + compare_native_programs; + ] in + { + test_name = "native"; + test_run_by_default = true; + test_actions = + (if Ocamltest_config.arch<>"none" then opt_actions else [skip]) + } + +let toplevel = { + test_name = "toplevel"; + test_run_by_default = false; + test_actions = + [ + setup_ocaml_build_env; + ocaml; + check_ocaml_output; +(* + setup_ocamlnat_build_env; + ocamlnat; + check_ocamlnat_output; +*) + ] +} + +let expect = +{ + test_name = "expect"; + test_run_by_default = false; + test_actions = + [ + setup_simple_build_env; + run_expect; + check_program_output + ] +} + +let ocamldoc = +{ + test_name = "ocamldoc"; + test_run_by_default = false; + test_actions = + if Ocamltest_config.ocamldoc then + [ + shared_libraries; + setup_ocamldoc_build_env; + run_ocamldoc; + check_program_output; + check_ocamldoc_output + ] + else + [ skip ] +} + +let _ = + List.iter register + [ + bytecode; + native; + toplevel; + expect; + ocamldoc; + ] diff --git a/ocamltest/ocaml_tests.mli b/ocamltest/ocaml_tests.mli new file mode 100644 index 00000000..b9cd0225 --- /dev/null +++ b/ocamltest/ocaml_tests.mli @@ -0,0 +1,26 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Tests specific to the OCaml compiler *) + +val bytecode : Tests.t + +val native : Tests.t + +val toplevel : Tests.t + +val expect : Tests.t + +val ocamldoc : Tests.t diff --git a/ocamltest/ocaml_tools.ml b/ocamltest/ocaml_tools.ml new file mode 100644 index 00000000..4b98bc2d --- /dev/null +++ b/ocamltest/ocaml_tools.ml @@ -0,0 +1,71 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Descriptions of the OCaml tools *) + +open Ocamltest_stdlib + +class tool + ~(name : string -> string) + ~(family : string) + ~(flags : string) + ~(directory : string) + ~(exit_status_variable : Variables.t) + ~(reference_variable : Variables.t) + ~(output_variable : Variables.t) += object (self) + method name = name + method family = family + method flags = flags + method directory = directory + method exit_status_variable = exit_status_variable + method reference_variable = reference_variable + method output_variable = output_variable + + method reference_filename_suffix env = + let tool_reference_suffix = + Environments.safe_lookup Ocaml_variables.compiler_reference_suffix env + in + if tool_reference_suffix<>"" + then tool_reference_suffix ^ ".reference" + else ".reference" + + method reference_file env prefix = + let suffix = self#reference_filename_suffix env in + (Filename.make_filename prefix directory) ^ suffix +end + +let expected_exit_status env tool = + Actions_helpers.exit_status_of_variable env tool#exit_status_variable + + +let ocamldoc = + object inherit + tool + ~name:Ocaml_files.ocamldoc + ~family:"doc" + ~flags:"" + ~directory:"ocamldoc" + ~exit_status_variable:Ocaml_variables.ocamldoc_exit_status + ~reference_variable:Ocaml_variables.ocamldoc_reference + ~output_variable:Ocaml_variables.ocamldoc_output + + method ! reference_filename_suffix env = + let backend = + Environments.safe_lookup Ocaml_variables.ocamldoc_backend env in + if backend = "" then + ".reference" + else "." ^ backend ^ ".reference" + end diff --git a/ocamltest/ocaml_tools.mli b/ocamltest/ocaml_tools.mli new file mode 100644 index 00000000..c8acbee3 --- /dev/null +++ b/ocamltest/ocaml_tools.mli @@ -0,0 +1,40 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Descriptions of the OCaml tools *) + +class tool : + name : (string -> string) -> + family : string -> + flags : string -> + directory : string -> + exit_status_variable : Variables.t -> + reference_variable : Variables.t -> + output_variable : Variables.t -> +object + method name : string -> string + method family : string + method flags : string + method directory : string + method exit_status_variable : Variables.t + method reference_variable : Variables.t + method output_variable : Variables.t + method reference_filename_suffix : Environments.t -> string + method reference_file : Environments.t -> string -> string +end + +val expected_exit_status : Environments.t -> tool -> int + +val ocamldoc: tool diff --git a/ocamltest/ocaml_toplevels.ml b/ocamltest/ocaml_toplevels.ml new file mode 100644 index 00000000..9121cc0c --- /dev/null +++ b/ocamltest/ocaml_toplevels.ml @@ -0,0 +1,70 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Description of the OCaml toplevels *) + +open Ocamltest_stdlib + +class toplevel + ~(name : string -> string) + ~(flags : string) + ~(directory : string) + ~(exit_status_variable : Variables.t) + ~(reference_variable : Variables.t) + ~(output_variable : Variables.t) + ~(backend : Ocaml_backends.t) + ~(compiler : Ocaml_compilers.compiler) += object (self) inherit Ocaml_tools.tool + ~name:name + ~family:"toplevel" + ~flags:flags + ~directory:directory + ~exit_status_variable:exit_status_variable + ~reference_variable:reference_variable + ~output_variable:output_variable + as tool + method backend = backend + method compiler = compiler + method ! reference_file env prefix = + let default = tool#reference_file env prefix in + if Sys.file_exists default then default else + let suffix = self#reference_filename_suffix env in + let mk s = (Filename.make_filename prefix s) ^ suffix in + let filename = mk + (Ocaml_backends.string_of_backend self#backend) in + if Sys.file_exists filename then filename else + mk "compilers" + +end + +let ocaml = new toplevel + ~name: Ocaml_commands.ocamlrun_ocaml + ~flags: "" + ~directory: "ocaml" + ~exit_status_variable: Ocaml_variables.ocaml_exit_status + ~reference_variable: Ocaml_variables.compiler_reference + ~output_variable: Ocaml_variables.compiler_output + ~backend: Ocaml_backends.Bytecode + ~compiler: Ocaml_compilers.ocamlc_byte + +let ocamlnat = new toplevel + ~name: Ocaml_files.ocamlnat + ~flags: "-S" (* Keep intermediate assembly files *) + ~directory: "ocamlnat" + ~exit_status_variable: Ocaml_variables.ocamlnat_exit_status + ~reference_variable: Ocaml_variables.compiler_reference2 + ~output_variable: Ocaml_variables.compiler_output2 + ~backend: Ocaml_backends.Native + ~compiler: Ocaml_compilers.ocamlc_opt diff --git a/ocamltest/ocaml_toplevels.mli b/ocamltest/ocaml_toplevels.mli new file mode 100644 index 00000000..f29fbac7 --- /dev/null +++ b/ocamltest/ocaml_toplevels.mli @@ -0,0 +1,34 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Descriptions of the OCaml toplevels *) + +class toplevel : + name : (string -> string) -> + flags : string -> + directory : string -> + exit_status_variable : Variables.t -> + reference_variable : Variables.t -> + output_variable : Variables.t -> + backend : Ocaml_backends.t -> + compiler : Ocaml_compilers.compiler -> +object inherit Ocaml_tools.tool + method backend : Ocaml_backends.t + method compiler : Ocaml_compilers.compiler +end + +val ocaml : toplevel + +val ocamlnat : toplevel diff --git a/ocamltest/ocaml_variables.ml b/ocamltest/ocaml_variables.ml new file mode 100644 index 00000000..271d73f5 --- /dev/null +++ b/ocamltest/ocaml_variables.ml @@ -0,0 +1,221 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of variables used by built-in actions *) + +(* The variables are listed in alphabetical order *) + +(* + The name of the identifier representing a variable and its string name + should be similar. Is there a way to enforce this? +*) + +open Ocamltest_stdlib + +open Variables (* Should not be necessary with a ppx *) + +let all_modules = make ("all_modules", + "All the modules to compile and link") + +let binary_modules = make ("binary_modules", + "Additional binary modules to link") + +let c_preprocessor = make ("c_preprocessor", + "Command to use to invoke the C preprocessor") + +let caml_ld_library_path_name = "CAML_LD_LIBRARY_PATH" + +let export_caml_ld_library_path value = + let current_value = Sys.safe_getenv caml_ld_library_path_name in + let local_value = + (String.concat Filename.path_sep (String.words value)) in + let new_value = + if local_value="" then current_value else + if current_value="" then local_value else + String.concat Filename.path_sep [local_value; current_value] in + Printf.sprintf "%s=%s" caml_ld_library_path_name new_value + +let caml_ld_library_path = + make_with_exporter + export_caml_ld_library_path + ("ld_library_path", + "List of paths to lookup for loading dynamic libraries") + +let compare_programs = make ("compare_programs", + "Set to \"false\" to disable program comparison") + +let compiler_directory_suffix = make ("compiler_directory_suffix", + "Suffix to add to the directory where the test will be compiled") + +let compiler_reference = make ("compiler_reference", + "Reference file for compiler output for ocamlc.byte and ocamlopt.byte") + +let compiler_reference2 = make ("compiler_reference2", + "Reference file for compiler output for ocamlc.opt and ocamlopt.opt") + +let compiler_reference_suffix = make ("compiler_reference_suffix", + "Suffix to add to the file name containing the reference for compiler output") + +let compiler_output = make ("compiler_output", + "Where to log output of bytecode compilers") + +let compiler_output2 = make ("compiler_output2", + "Where to log output of native compilers") + +let compiler_stdin = make ("compiler_stdin", + "standard input of compilers") + +let compile_only = make ("compile_only", + "Compile only (do not link)") + +let ocamlc_flags = make ("ocamlc_flags", + "Flags passed to ocamlc.byte and ocamlc.opt") + +let ocamlc_default_flags = make ("ocamlc_default_flags", + "Flags passed by default to ocamlc.byte and ocamlc.opt") + +let directories = make ("directories", + "Directories to include by all the compilers") + +let flags = make ("flags", + "Flags passed to all the compilers") + +let libraries = make ("libraries", + "Libraries the program should be linked with") + +let module_ = make ("module", + "Compile one module at once") + +let modules = make ("modules", + "Other modules of the test") + +let ocamllex_flags = make ("ocamllex_flags", + "Flags passed to ocamllex") + +let ocamlopt_flags = make ("ocamlopt_flags", + "Flags passed to ocamlopt.byte and ocamlopt.opt") + +let ocamlopt_default_flags = make ("ocamlopt_default_flags", + "Flags passed by default to ocamlopt.byte and ocamlopt.opt") + +let ocamlyacc_flags = make ("ocamlyacc_flags", + "Flags passed to ocamlyacc") + +let ocaml_exit_status = make ("ocaml_exit_status", + "Expected exit status of ocaml") + +let ocamlc_byte_exit_status = make ("ocamlc_byte_exit_status", + "Expected exit status of ocac.byte") + +let ocamlopt_byte_exit_status = make ("ocamlopt_byte_exit_status", + "Expected exit status of ocamlopt.byte") + +let ocamlnat_exit_status = make ("ocamlnat_exit_status", + "Expected exit status of ocamlnat") + +let ocamlc_opt_exit_status = make ("ocamlc_opt_exit_status", + "Expected exit status of ocac.opt") + +let ocamlopt_opt_exit_status = make ("ocamlopt_opt_exit_status", + "Expected exit status of ocamlopt.opt") + +let export_ocamlrunparam value = + Printf.sprintf "%s=%s" "OCAMLRUNPARAM" value + +let ocamlrunparam = + make_with_exporter + export_ocamlrunparam + ("ocamlrunparam", + "Equivalent of OCAMLRUNPARAM") + +let ocamlsrcdir = make ("ocamlsrcdir", + "Where OCaml sources are") + +let ocamldebug_flags = make ("ocamldebug_flags", + "Flags for ocamldebug") + +let ocamldebug_script = make ("ocamldebug_script", + "Where ocamldebug should read its commands") + +let os_type = make ("os_type", + "The OS we are running on") + +let ocamldoc_flags = Variables.make ("ocamldoc_flags", + "ocamldoc flags") + +let ocamldoc_backend = Variables.make ("ocamldoc_backend", + "ocamldoc backend (html, latex, man, ... )") + +let ocamldoc_exit_status = + Variables.make ( "ocamldoc_exit_status", "expected ocamldoc exit status") + +let ocamldoc_output = + Variables.make ( "ocamldoc_output", "Where to log ocamldoc output") + +let ocamldoc_reference = + Variables.make ( "ocamldoc_reference", + "Where to find expected ocamldoc output") + +let ocaml_script_as_argument = + Variables.make ( "ocaml_script_as_argument", + "Whether the ocaml script should be passed as argument or on stdin") + +let plugins = + Variables.make ( "plugins", "plugins for ocamlc,ocamlopt or ocamldoc" ) + +let _ = List.iter register_variable + [ + all_modules; + binary_modules; + c_preprocessor; + caml_ld_library_path; + compare_programs; + compiler_directory_suffix; + compiler_reference; + compiler_reference2; + compiler_reference_suffix; + compiler_output; + compiler_output2; + compiler_stdin; + compile_only; + directories; + flags; + libraries; + module_; + modules; + ocamlc_flags; + ocamlc_default_flags; + ocamlopt_flags; + ocamlopt_default_flags; + ocaml_exit_status; + ocamlc_byte_exit_status; + ocamlopt_byte_exit_status; + ocamlnat_exit_status; + ocamlc_opt_exit_status; + ocamlopt_opt_exit_status; + ocamlrunparam; + os_type; + ocamllex_flags; + ocamlyacc_flags; + ocamldoc_flags; + ocamldoc_backend; + ocamldoc_output; + ocamldoc_reference; + ocamldoc_exit_status; + ocamldebug_flags; + ocamldebug_script; + ocaml_script_as_argument; + plugins + ] diff --git a/ocamltest/ocaml_variables.mli b/ocamltest/ocaml_variables.mli new file mode 100644 index 00000000..458fd4e3 --- /dev/null +++ b/ocamltest/ocaml_variables.mli @@ -0,0 +1,96 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of OCaml-specific variables *) + +(* The variables are listed in alphabetical order *) + +val all_modules : Variables.t + +val binary_modules : Variables.t + +val c_preprocessor : Variables.t + +val caml_ld_library_path : Variables.t + +val compare_programs : Variables.t + +val compiler_directory_suffix : Variables.t + +val compiler_reference : Variables.t + +val compiler_reference2 : Variables.t + +val compiler_reference_suffix : Variables.t + +val compiler_output : Variables.t + +val compiler_output2 : Variables.t + +val compiler_stdin : Variables.t + +val compile_only : Variables.t + +val directories : Variables.t + +val flags : Variables.t + +val libraries : Variables.t + +val module_ : Variables.t + +val modules : Variables.t + +val ocamlc_flags : Variables.t +val ocamlc_default_flags : Variables.t + +val ocamllex_flags : Variables.t + +val ocamlopt_flags : Variables.t +val ocamlopt_default_flags : Variables.t + +val ocamlyacc_flags : Variables.t + +val ocaml_exit_status : Variables.t + +val ocamlc_byte_exit_status : Variables.t + +val ocamlopt_byte_exit_status : Variables.t + +val ocamlnat_exit_status : Variables.t + +val ocamlc_opt_exit_status : Variables.t + +val ocamlopt_opt_exit_status : Variables.t + +val ocamlrunparam : Variables.t + +val ocamlsrcdir : Variables.t + +val ocamldebug_flags : Variables.t + +val ocamldebug_script : Variables.t + +val os_type : Variables.t + +val ocamldoc_flags : Variables.t +val ocamldoc_backend : Variables.t +val ocamldoc_exit_status : Variables.t +val ocamldoc_output : Variables.t +val ocamldoc_reference : Variables.t + +val ocaml_script_as_argument : Variables.t + +val plugins: Variables.t diff --git a/ocamltest/ocamltest_config.ml.in b/ocamltest/ocamltest_config.ml.in index 05f4b1eb..2ff85316 100644 --- a/ocamltest/ocamltest_config.ml.in +++ b/ocamltest/ocamltest_config.ml.in @@ -17,13 +17,29 @@ let arch = "@@ARCH@@" +let afl_instrument = @@AFL_INSTRUMENT@@ + +let shared_libraries = @@SHARED_LIBRARIES@@ + +let libunix = @@UNIX@@ + +let system = "@@SYSTEM@@" + let c_preprocessor = "@@CPP@@" let ocamlsrcdir = "@@OCAMLSRCDIR@@" let flambda = @@FLAMBDA@@ +let spacetime = @@SPACETIME@@ + let ocamlc_default_flags = "@@OCAMLCDEFAULTFLAGS@@" let ocamlopt_default_flags = "@@OCAMLOPTDEFAULTFLAGS@@" let safe_string = @@FORCE_SAFE_STRING@@ + +let flat_float_array = @@FLAT_FLOAT_ARRAY@@ + +let ocamldoc = @@OCAMLDOC@@ + +let ocamldebug = @@OCAMLDOC@@ diff --git a/ocamltest/ocamltest_config.mli b/ocamltest/ocamltest_config.mli index 51531c9f..d8199f62 100644 --- a/ocamltest/ocamltest_config.mli +++ b/ocamltest/ocamltest_config.mli @@ -18,10 +18,21 @@ val arch : string (** Architecture for the native compiler, "none" if it is disabled *) +val afl_instrument : bool +(** Whether AFL support has been enabled in the compiler *) + +val shared_libraries : bool +(** [true] if shared libraries are supported, [false] otherwise *) + +val libunix : bool +(** [true] for unix, [false] for win32unix *) + +val system : string +(** The content of the SYSTEM Make variable *) + val c_preprocessor : string (** Command to use to invoke the C preprocessor *) - val ocamlc_default_flags : string (** Flags passed by default to ocamlc.byte and ocamlc.opt *) @@ -34,5 +45,17 @@ val ocamlsrcdir : string val flambda : bool (** Whether flambda has been enabled at configure time *) +val spacetime : bool +(** Whether Spacetime profiling has been enabled at configure time *) + val safe_string : bool (** Whether the compiler was configured with -safe-string *) + +val flat_float_array : bool +(* Whether the compiler was configured with -flat-float-array *) + +val ocamldoc : bool +(** Whether ocamldoc has been enabled at configure time *) + +val ocamldebug : bool +(** Whether ocamldebug has been enabled at configure time *) diff --git a/ocamltest/ocamltest_stdlib.ml b/ocamltest/ocamltest_stdlib.ml new file mode 100644 index 00000000..24ff3452 --- /dev/null +++ b/ocamltest/ocamltest_stdlib.ml @@ -0,0 +1,184 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* A few extensions to OCaml's standard library *) + +(* Pervaisive *) + +let input_line_opt ic = + try Some (input_line ic) with End_of_file -> None + +module Char = struct + include Char + let is_blank c = + c = ' ' || c = '\012' || c = '\n' || c = '\r' || c = '\t' +end + +module Filename = struct + include Filename + let path_sep = if Sys.os_type="Win32" then ";" else ":" + (* This function comes from otherlibs/win32unix/unix.ml *) + let maybe_quote f = + if String.contains f ' ' || + String.contains f '\"' || + String.contains f '\t' || + f = "" + then Filename.quote f + else f + + let make_filename name ext = String.concat "." [name; ext] + + let make_path components = List.fold_left Filename.concat "" components + + let mkexe = + if Sys.os_type="Win32" + then fun name -> make_filename name "exe" + else fun name -> name +end + +module List = struct + include List + let rec concatmap f = function + | [] -> [] + | x::xs -> (f x) @ (concatmap f xs) +end + +module String = struct + include String + let string_of_char = String.make 1 + + let words s = + let l = String.length s in + let rec f quote w ws i = + if i>=l then begin + if w<>"" then List.rev (w::ws) + else List.rev ws + end else begin + let j = i+1 in + match s.[i] with + | '\'' -> f (not quote) w ws j + | ' ' -> + begin + if quote + then f true (w ^ (string_of_char ' ')) ws j + else begin + if w="" + then f false w ws j + else f false "" (w::ws) j + end + end + | _ as c -> f quote (w ^ (string_of_char c)) ws j + end in + if l=0 then [] else f false "" [] 0 +end + +module Sys = struct + include Sys + + let file_is_empty filename = + let ic = open_in filename in + let filesize = in_channel_length ic in + close_in ic; + filesize = 0 + + let run_system_command command = match Sys.command command with + | 0 -> () + | _ as exitcode -> + Printf.eprintf "Sysem command %s failed with status %d\n%!" + command exitcode; + exit 3 + + let mkdir dir = + if not (Sys.file_exists dir) then + let quoted_dir = "\"" ^ dir ^ "\"" in + run_system_command ("mkdir " ^ quoted_dir) + + let rec make_directory dir = + if Sys.file_exists dir then () + else (make_directory (Filename.dirname dir); mkdir dir) + + let string_of_file filename = + let chan = open_in_bin filename in + let filesize = in_channel_length chan in + if filesize > Sys.max_string_length then + begin + close_in chan; + failwith + ("The file " ^ filename ^ " is too large to be loaded into a string") + end else begin + let result = + try really_input_string chan filesize + with End_of_file -> + close_in chan; + failwith ("Got unexpected end of file while reading " ^ filename) in + close_in chan; + result + end + + let with_input_file ?(bin=false) x f = + let ic = (if bin then open_in_bin else open_in) x in + try let res = f ic in close_in ic; res with e -> (close_in ic; raise e) + + let with_output_file ?(bin=false) x f = + let oc = (if bin then open_out_bin else open_out) x in + try let res = f oc in close_out oc; res with e -> (close_out oc; raise e) + + let copy_chan ic oc = + let m = in_channel_length ic in + let m = (m lsr 12) lsl 12 in + let m = max 16384 (min Sys.max_string_length m) in + let buf = Bytes.create m in + let rec loop () = + let len = input ic buf 0 m in + if len > 0 then begin + output oc buf 0 len; + loop () + end + in loop () + + let copy_file src dest = + with_input_file ~bin:true src begin fun ic -> + with_output_file ~bin:true dest begin fun oc -> + copy_chan ic oc + end + end + + let force_remove file = + if file_exists file then remove file + + external has_symlink : unit -> bool = "caml_has_symlink" + + let with_chdir path f = + let oldcwd = Sys.getcwd () in + Sys.chdir path; + match f () with + | r -> + Sys.chdir oldcwd; + r + | exception e -> + Sys.chdir oldcwd; + raise e + + let getenv_with_default_value variable default_value = + try Sys.getenv variable with Not_found -> default_value + let safe_getenv variable = getenv_with_default_value variable "" +end + +module StringSet = struct + include Set.Make (String) + let string_of_stringset s = String.concat ", " (elements s) +end + +module StringMap : Map.S with type key = string = Map.Make (String) diff --git a/ocamltest/ocamltest_stdlib.mli b/ocamltest/ocamltest_stdlib.mli new file mode 100644 index 00000000..35420505 --- /dev/null +++ b/ocamltest/ocamltest_stdlib.mli @@ -0,0 +1,65 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2016 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* A few extensions to OCaml's standard library *) + +(* Pervasive *) + +val input_line_opt : in_channel -> string option + +module Char : sig + include module type of Char + val is_blank : char -> bool +end + +module Filename : sig + include module type of Filename + val path_sep : string + val maybe_quote : string -> string + val make_filename : string -> string -> string + val make_path : string list -> string + val mkexe : string -> string +end + +module List : sig + include module type of List + val concatmap : ('a -> 'b list) -> 'a list -> 'b list +end + +module String : sig + include module type of String + val words : string -> string list +end + +module Sys : sig + include module type of Sys + val file_is_empty : string -> bool + val run_system_command : string -> unit + val make_directory : string -> unit + val string_of_file : string -> string + val copy_file : string -> string -> unit + val force_remove : string -> unit + val has_symlink : unit -> bool + val with_chdir : string -> (unit -> 'a) -> 'a + val getenv_with_default_value : string -> string -> string + val safe_getenv : string -> string +end + +module StringSet : sig + include Set.S with type elt = string + val string_of_stringset : t -> string +end + +module StringMap : Map.S with type key = string diff --git a/ocamltest/ocamltest_stdlib_stubs.c b/ocamltest/ocamltest_stdlib_stubs.c new file mode 100644 index 00000000..125275ef --- /dev/null +++ b/ocamltest/ocamltest_stdlib_stubs.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Sebastien Hinderer, projet Gallium, INRIA Paris */ +/* */ +/* Copyright 2018 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +/* Stubs for ocamltest's standard library */ + +#include +#include + +#include +#include +#include +#include +/* +#include +*/ +#include +#include + + +#ifdef _WIN32 + +/* + * Windows Vista functions enabled + */ +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 + +#include +#include +#include +#include + +#define luid_eq(l, r) (l.LowPart == r.LowPart && l.HighPart == r.HighPart) + +CAMLprim value caml_has_symlink(value unit) +{ + CAMLparam1(unit); + HANDLE hProcess = GetCurrentProcess(); + BOOL result = FALSE; + + if (OpenProcessToken(hProcess, TOKEN_READ, &hProcess)) { + LUID seCreateSymbolicLinkPrivilege; + + if (LookupPrivilegeValue(NULL, + SE_CREATE_SYMBOLIC_LINK_NAME, + &seCreateSymbolicLinkPrivilege)) { + DWORD length; + + if (!GetTokenInformation(hProcess, TokenPrivileges, NULL, 0, &length)) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + TOKEN_PRIVILEGES* privileges = (TOKEN_PRIVILEGES*)caml_stat_alloc(length); + if (GetTokenInformation(hProcess, + TokenPrivileges, + privileges, + length, + &length)) { + DWORD count = privileges->PrivilegeCount; + + if (count) { + LUID_AND_ATTRIBUTES* privs = privileges->Privileges; + while (count-- && !(result = luid_eq(privs->Luid, seCreateSymbolicLinkPrivilege))) + privs++; + } + } + + caml_stat_free(privileges); + } + } + } + + CloseHandle(hProcess); + } + + CAMLreturn(Val_bool(result)); +} + + +#else /* _WIN32 */ + +#ifdef HAS_SYMLINK + +CAMLprim value caml_has_symlink(value unit) +{ + CAMLparam0(); + CAMLreturn(Val_true); +} + +#else /* HAS_SYMLINK */ + +CAMLprim value unix_symlink(value to_dir, value path1, value path2) +{ caml_invalid_argument("symlink not implemented"); } + +CAMLprim value caml_has_symlink(value unit) +{ + CAMLparam0(); + CAMLreturn(Val_false); +} + +#endif + +#endif /* _WIN32 */ diff --git a/ocamltest/options.ml b/ocamltest/options.ml index 04b2fbb0..782e314d 100644 --- a/ocamltest/options.ml +++ b/ocamltest/options.ml @@ -21,7 +21,7 @@ let show_objects title string_of_object objects = List.iter print_object objects; exit 0 -let string_of_action action = action.Actions.action_name +let string_of_action = Actions.action_name let string_of_test test = if test.Tests.test_run_by_default @@ -36,22 +36,24 @@ let show_tests () = let tests = Tests.get_registered_tests () in show_objects "Available tests are:" string_of_test tests +let log_to_stderr = ref false + +let promote = ref false + let commandline_options = [ + ("-e", Arg.Set log_to_stderr, "Log to stderr instead of a file."); + ("-promote", Arg.Set promote, + "Overwrite reference files with the test output (experimental, unstable)"); ("-show-actions", Arg.Unit show_actions, "Show available actions."); ("-show-tests", Arg.Unit show_tests, "Show available tests."); ] -let testfile = ref "" +let files_to_test = ref [] -let set_testfile name = - if !testfile<> "" then - begin - Printf.eprintf "Can't deal with more than one test file at the moment\n%!"; - exit 1 - end else testfile := name +let add_testfile name = files_to_test := !files_to_test @ [name] -let usage = "Usage: " ^ Sys.argv.(0) ^ " options testfile" +let usage = "Usage: " ^ Sys.argv.(0) ^ " options files to test" let _ = - Arg.parse commandline_options set_testfile usage + Arg.parse commandline_options add_testfile usage diff --git a/ocamltest/options.mli b/ocamltest/options.mli index 57fe7a3d..26d3796f 100644 --- a/ocamltest/options.mli +++ b/ocamltest/options.mli @@ -15,6 +15,10 @@ (* Description of ocamltest's command-line options *) -val testfile : string ref +val log_to_stderr : bool ref + +val files_to_test : string list ref + +val promote : bool ref val usage : string diff --git a/ocamltest/result.ml b/ocamltest/result.ml new file mode 100644 index 00000000..9e2b932f --- /dev/null +++ b/ocamltest/result.ml @@ -0,0 +1,57 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of test-result related types and functions *) + +type status = Pass | Skip | Fail + +type t = { + status : status; + reason : string option +} + +let result_of_status s = { status = s; reason = None } + +let pass = result_of_status Pass + +let skip = result_of_status Skip + +let fail = result_of_status Fail + +let result_with_reason s r = { status = s; reason = Some r } + +let pass_with_reason r = result_with_reason Pass r + +let skip_with_reason r = result_with_reason Skip r + +let fail_with_reason r = result_with_reason Fail r + +let string_of_status = function + | Pass -> "passed" + | Skip -> "skipped" + | Fail -> "failed" + +let string_of_reason = function + | None -> "" + | Some reason -> (" (" ^ reason ^ ")") + +let string_of_result r = + (string_of_status r.status) ^ (string_of_reason r.reason) + +let is_pass r = r.status = Pass + +let is_skip r = r.status = Skip + +let is_fail r = r.status = Fail diff --git a/ocamltest/result.mli b/ocamltest/result.mli new file mode 100644 index 00000000..2369e5f6 --- /dev/null +++ b/ocamltest/result.mli @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Sebastien Hinderer, projet Gallium, INRIA Paris *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Definition of test-result related types and functions *) + +type status = Pass | Skip | Fail + +type t = { + status : status; + reason : string option +} + +val pass : t + +val skip : t + +val fail : t + +val pass_with_reason : string -> t + +val skip_with_reason : string -> t + +val fail_with_reason : string -> t + +val string_of_result : t -> string + +val is_pass : t -> bool + +val is_skip : t -> bool + +val is_fail : t -> bool diff --git a/ocamltest/run.h b/ocamltest/run.h index 348d16da..7c13212e 100644 --- a/ocamltest/run.h +++ b/ocamltest/run.h @@ -29,7 +29,7 @@ typedef void Logger(void *, const char *, va_list ap); typedef struct { char_os *program; array argv; - /* array envp; */ + array envp; char_os *stdin_filename; char_os *stdout_filename; char_os *stderr_filename; diff --git a/ocamltest/run_command.ml b/ocamltest/run_command.ml index 55b4b139..1a1df614 100644 --- a/ocamltest/run_command.ml +++ b/ocamltest/run_command.ml @@ -15,10 +15,12 @@ (* Run programs and log their stdout/stderr, with a timer... *) +open Ocamltest_stdlib + type settings = { progname : string; argv : string array; - (* envp : string array; *) + envp : string array; stdin_filename : string; stdout_filename : string; stderr_filename : string; @@ -28,14 +30,15 @@ type settings = { } let settings_of_commandline ?(stdout_fname="") ?(stderr_fname="") commandline = - let words = Testlib.words commandline in + let words = String.words commandline in let quoted_words = if Sys.os_type="Win32" - then List.map Testlib.maybe_quote words + then List.map Filename.maybe_quote words else words in { progname = List.hd quoted_words; argv = Array.of_list quoted_words; + envp = [||]; stdin_filename = ""; stdout_filename = stdout_fname; stderr_filename = stderr_fname; diff --git a/ocamltest/run_command.mli b/ocamltest/run_command.mli index 9fcdadb1..30033ce3 100644 --- a/ocamltest/run_command.mli +++ b/ocamltest/run_command.mli @@ -18,7 +18,7 @@ type settings = { progname : string; argv : string array; - (* envp : string array; *) + envp : string array; stdin_filename : string; stdout_filename : string; stderr_filename : string; diff --git a/ocamltest/run_stubs.c b/ocamltest/run_stubs.c index 9505b076..2f89e83d 100644 --- a/ocamltest/run_stubs.c +++ b/ocamltest/run_stubs.c @@ -83,19 +83,24 @@ CAMLprim value caml_run_command(value caml_settings) command_settings settings; CAMLparam1(caml_settings); - settings.program = caml_stat_strdup_to_os(String_val(Field(caml_settings, 0))); + settings.program = + caml_stat_strdup_to_os(String_val(Field(caml_settings, 0))); settings.argv = cstringvect(Field(caml_settings, 1)); - /* settings.envp = cstringvect(Field(caml_settings, 2)); */ - settings.stdin_filename = caml_stat_strdup_to_os(String_val(Field(caml_settings, 2))); - settings.stdout_filename = caml_stat_strdup_to_os(String_val(Field(caml_settings, 4))); - settings.stderr_filename = caml_stat_strdup_to_os(String_val(Field(caml_settings, 4))); - settings.append = Bool_val(Field(caml_settings, 5)); - settings.timeout = Int_val(Field(caml_settings, 6)); + settings.envp = cstringvect(Field(caml_settings, 2)); + settings.stdin_filename = + caml_stat_strdup_to_os(String_val(Field(caml_settings, 3))); + settings.stdout_filename = + caml_stat_strdup_to_os(String_val(Field(caml_settings, 4))); + settings.stderr_filename = + caml_stat_strdup_to_os(String_val(Field(caml_settings, 5))); + settings.append = Bool_val(Field(caml_settings, 6)); + settings.timeout = Int_val(Field(caml_settings, 7)); settings.logger = logToChannel; - settings.loggerData = Channel(Field(caml_settings, 7)); + settings.loggerData = Channel(Field(caml_settings, 8)); res = run_command(&settings); caml_stat_free(settings.program); free_cstringvect(settings.argv); + free_cstringvect(settings.envp); caml_stat_free(settings.stdin_filename); caml_stat_free(settings.stdout_filename); caml_stat_free(settings.stderr_filename); diff --git a/ocamltest/run_unix.c b/ocamltest/run_unix.c index 5416016d..4a89ed87 100644 --- a/ocamltest/run_unix.c +++ b/ocamltest/run_unix.c @@ -64,6 +64,10 @@ myperror_with_location(__FILE__, __LINE__, settings, msg, ## __VA_ARGS__) /* Same remark as for the error macro. */ +#define child_error(msg, ...) \ + myperror(msg, ## __VA_ARGS__); \ + goto child_failed; + static void open_error_with_location( const char *file, int line, const command_settings *settings, @@ -122,33 +126,71 @@ static int paths_same_file( return same_file; } +static void update_environment(array local_env) +{ + array envp; + for (envp = local_env; *envp != NULL; envp++) { + char *pos_eq = strchr(*envp, '='); + if (pos_eq != NULL) { + char *name, *value; + int name_length = pos_eq - *envp; + int l = strlen(*envp); + int value_length = l - (name_length +1); + name = malloc(name_length+1); + value = malloc(value_length+1); + memcpy(name, *envp, name_length); + name[name_length] = '\0'; + memcpy(value, pos_eq + 1, value_length); + value[value_length] = '\0'; + setenv(name, value, 1); /* 1 means overwrite */ + } + } +} + +/* + This function should retunr an exitcode that can itslef be returned + to its father through the exit system call. + So it returns 0 to report success and 1 to report an error + + */ static int run_command_child(const command_settings *settings) { - int res; int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1; /* -1 = no redir */ int inputFlags = O_RDONLY; int outputFlags = O_CREAT | O_WRONLY | (settings->append ? O_APPEND : O_TRUNC); int inputMode = 0400, outputMode = 0666; - if (setpgid(0, 0) == -1) myperror("setpgid"); + if (setpgid(0, 0) == -1) + { + child_error("setpgid"); + } if (is_defined(settings->stdin_filename)) { stdin_fd = open(settings->stdin_filename, inputFlags, inputMode); if (stdin_fd < 0) + { open_error(settings->stdin_filename); - if ( dup2(stdin_fd, STDIN_FILENO) == -1 ) - myperror("dup2 for stdin"); + goto child_failed; + } + if (dup2(stdin_fd, STDIN_FILENO) == -1) + { + child_error("dup2 for stdin"); + } } if (is_defined(settings->stdout_filename)) { stdout_fd = open(settings->stdout_filename, outputFlags, outputMode); - if (stdout_fd < 0) + if (stdout_fd < 0) { open_error(settings->stdout_filename); - if ( dup2(stdout_fd, STDOUT_FILENO) == -1 ) - myperror("dup2 for stdout"); + goto child_failed; + } + if (dup2(stdout_fd, STDOUT_FILENO) == -1) + { + child_error("dup2 for stdout"); + } } if (is_defined(settings->stderr_filename)) @@ -162,16 +204,26 @@ static int run_command_child(const command_settings *settings) if (stderr_fd == -1) { stderr_fd = open(settings->stderr_filename, outputFlags, outputMode); - if (stderr_fd == -1) open_error(settings->stderr_filename); + if (stderr_fd == -1) + { + open_error(settings->stderr_filename); + goto child_failed; + } + } + if (dup2(stderr_fd, STDERR_FILENO) == -1) + { + child_error("dup2 for stderr"); } - if ( dup2(stderr_fd, STDERR_FILENO) == -1 ) - myperror("dup2 for stderr"); } - res = execvp(settings->program, settings->argv); /* , settings->envp); */ + update_environment(settings->envp); + + execvp(settings->program, settings->argv); myperror("Cannot execute %s", settings->program); - return res; + +child_failed: + return 1; } /* Handles the termination of a process. Arguments: @@ -273,7 +325,15 @@ static int run_command_parent(const command_settings *settings, pid_t child_pid) int run_command(const command_settings *settings) { pid_t child_pid = fork(); - if (child_pid == -1) myperror("fork"); - if (child_pid == 0) return run_command_child(settings); - else return run_command_parent(settings, child_pid); + + switch (child_pid) + { + case -1: + myperror("fork"); + return -1; + case 0: /* child process */ + exit( run_command_child(settings) ); + default: + return run_command_parent(settings, child_pid); + } } diff --git a/ocamltest/run_win32.c b/ocamltest/run_win32.c index b60e5dac..cd9e2512 100644 --- a/ocamltest/run_win32.c +++ b/ocamltest/run_win32.c @@ -36,19 +36,25 @@ static void report_error( const command_settings *settings, const char *message, const WCHAR *argument) { - WCHAR error_message[1024]; + WCHAR windows_error_message[1024]; DWORD error = GetLastError(); - char *error_message_c; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, - error_message, sizeof(error_message)/sizeof(WCHAR), NULL); - error_message_c = caml_stat_strdup_of_utf16(error_message); + char *caml_error_message, buf[256]; + if (FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, windows_error_message, + sizeof(windows_error_message)/sizeof(WCHAR), NULL) ) { + caml_error_message = caml_stat_strdup_of_utf16(windows_error_message); + } else { + caml_error_message = caml_stat_alloc(256); + sprintf(caml_error_message, "unknown Windows error #%lu", error); + } if ( is_defined(argument) ) error_with_location(file, line, - settings, "%s %s: %s", message, argument, error_message_c); + settings, "%s %s: %s", message, argument, caml_error_message); else error_with_location(file, line, - settings, "%s: %s", message, error_message_c); - caml_stat_free(error_message_c); + settings, "%s: %s", message, caml_error_message); + caml_stat_free(caml_error_message); } static WCHAR *find_program(const WCHAR *program_name) @@ -132,6 +138,61 @@ static WCHAR *commandline_of_arguments(WCHAR **arguments) return commandline; } +static LPVOID prepare_environment(WCHAR **localenv) +{ + LPTCH p, r, env, process_env = NULL; + WCHAR **q; + int l, process_env_length, localenv_length, env_length; + + if (localenv == NULL) return NULL; + + process_env = GetEnvironmentStrings(); + if (process_env == NULL) return NULL; + + /* Compute length of process environment */ + process_env_length = 0; + p = process_env; + while (*p != L'\0') { + l = wcslen(p) + 1; /* also count terminating '\0' */ + process_env_length += l; + p += l; + } + + /* Compute length of local environment */ + localenv_length = 0; + q = localenv; + while (*q != NULL) { + localenv_length += wcslen(*q) + 1; + q++; + } + + /* Build new env that contains both process and local env */ + env_length = process_env_length + localenv_length + 1; + env = malloc(env_length * sizeof(WCHAR)); + if (env == NULL) { + FreeEnvironmentStrings(process_env); + return NULL; + } + r = env; + p = process_env; + while (*p != L'\0') { + l = wcslen(p) + 1; /* also count terminating '\0' */ + memcpy(r, p, l * sizeof(WCHAR)); + p += l; + r += l; + } + FreeEnvironmentStrings(process_env); + q = localenv; + while (*q != NULL) { + l = wcslen(*q) + 1; + memcpy(r, *q, l * sizeof(WCHAR)); + r += l; + q++; + } + *r = L'\0'; + return env; +} + static SECURITY_ATTRIBUTES security_attributes = { sizeof(SECURITY_ATTRIBUTES), /* nLength */ NULL, /* lpSecurityDescriptor */ @@ -177,6 +238,11 @@ if ( (condition) ) \ goto cleanup; \ } else { } +static WCHAR *translate_finename(WCHAR *filename) +{ + if (!wcscmp(filename, L"/dev/null")) return L"NUL"; else return filename; +} + int run_command(const command_settings *settings) { BOOL process_created = FALSE; @@ -206,23 +272,27 @@ int run_command(const command_settings *settings) commandline = commandline_of_arguments(settings->argv); + environment = prepare_environment(settings->envp); + if (is_defined(settings->stdin_filename)) { - startup_info.hStdInput = create_input_handle(settings->stdin_filename); + WCHAR *stdin_filename = translate_finename(settings->stdin_filename); + startup_info.hStdInput = create_input_handle(stdin_filename); checkerr( (startup_info.hStdInput == INVALID_HANDLE_VALUE), "Could not redirect standard input", - settings->stdin_filename); + stdin_filename); stdin_redirected = 1; } else startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); if (is_defined(settings->stdout_filename)) { + WCHAR *stdout_filename = translate_finename(settings->stdout_filename); startup_info.hStdOutput = create_output_handle( - settings->stdout_filename, settings->append + stdout_filename, settings->append ); checkerr( (startup_info.hStdOutput == INVALID_HANDLE_VALUE), "Could not redirect standard output", - settings->stdout_filename); + stdout_filename); stdout_redirected = 1; } else startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); @@ -240,13 +310,14 @@ int run_command(const command_settings *settings) if (! stderr_redirected) { + WCHAR *stderr_filename = translate_finename(settings->stderr_filename); startup_info.hStdError = create_output_handle ( - settings->stderr_filename, settings->append + stderr_filename, settings->append ); checkerr( (startup_info.hStdError == INVALID_HANDLE_VALUE), "Could not redirect standard error", - settings->stderr_filename); + stderr_filename); stderr_redirected = 1; } } else startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -258,7 +329,7 @@ int run_command(const command_settings *settings) NULL, /* SECURITY_ATTRIBUTES thread_attributes */ TRUE, /* BOOL inherit_handles */ CREATE_UNICODE_ENVIRONMENT, /* DWORD creation_flags */ - NULL, /* LPVOID environment */ + environment, NULL, /* LPCSTR current_directory */ &startup_info, &process_info diff --git a/ocamltest/testlib.ml b/ocamltest/testlib.ml deleted file mode 100644 index e24e6abd..00000000 --- a/ocamltest/testlib.ml +++ /dev/null @@ -1,134 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Miscellaneous library functions *) - -let rec concatmap f = function - | [] -> [] - | x::xs -> (f x) @ (concatmap f xs) - -let is_blank c = - c = ' ' || c = '\012' || c = '\n' || c = '\r' || c = '\t' - -let string_of_char = String.make 1 - -(* This function comes from otherlibs/win32unix/unix.ml *) -let maybe_quote f = - if String.contains f ' ' || - String.contains f '\"' || - String.contains f '\t' || - f = "" - then Filename.quote f - else f - -let words s = - let l = String.length s in - let rec f quote w ws i = - if i>=l then begin - if w<>"" then List.rev (w::ws) - else List.rev ws - end else begin - let j = i+1 in - match s.[i] with - | '\'' -> f (not quote) w ws j - | ' ' -> - begin - if quote - then f true (w ^ (string_of_char ' ')) ws j - else begin - if w="" - then f false w ws j - else f false "" (w::ws) j - end - end - | _ as c -> f quote (w ^ (string_of_char c)) ws j - end in - if l=0 then [] else f false "" [] 0 - -let file_is_empty filename = - let ic = open_in filename in - let filesize = in_channel_length ic in - close_in ic; - filesize = 0 - -let string_of_location loc = - let buf = Buffer.create 64 in - let fmt = Format.formatter_of_buffer buf in - Location.print_loc fmt loc; - Format.pp_print_flush fmt (); - Buffer.contents buf - -let run_system_command command = match Sys.command command with - | 0 -> () - | _ as exitcode -> - Printf.eprintf "Sysem command %s failed with status %d\n%!" - command exitcode; - exit 3 - -let mkdir dir = - if not (Sys.file_exists dir) then - let quoted_dir = "\"" ^ dir ^ "\"" in - run_system_command ("mkdir " ^ quoted_dir) - -let rec make_directory dir = - if Sys.file_exists dir then () - else (make_directory (Filename.dirname dir); mkdir dir) - -let string_of_file filename = - let chan = open_in_bin filename in - let filesize = in_channel_length chan in - if filesize > Sys.max_string_length then - begin - close_in chan; - failwith - ("The file " ^ filename ^ " is too large to be loaded into a string") - end else begin - let result = - try really_input_string chan filesize - with End_of_file -> - close_in chan; - failwith ("Got unexpected end of file while reading " ^ filename) in - close_in chan; - result - end - -let with_input_file ?(bin=false) x f = - let ic = (if bin then open_in_bin else open_in) x in - try let res = f ic in close_in ic; res with e -> (close_in ic; raise e) - -let with_output_file ?(bin=false) x f = - let oc = (if bin then open_out_bin else open_out) x in - try let res = f oc in close_out oc; res with e -> (close_out oc; raise e) - - -let copy_chan ic oc = - let m = in_channel_length ic in - let m = (m lsr 12) lsl 12 in - let m = max 16384 (min Sys.max_string_length m) in - let buf = Bytes.create m in - let rec loop () = - let len = input ic buf 0 m in - if len > 0 then begin - output oc buf 0 len; - loop () - end - in loop () - -let copy_file src dest = - with_input_file ~bin:true src begin fun ic -> - with_output_file ~bin:true dest begin fun oc -> - copy_chan ic oc - end - end diff --git a/ocamltest/testlib.mli b/ocamltest/testlib.mli deleted file mode 100644 index 70ecc7e9..00000000 --- a/ocamltest/testlib.mli +++ /dev/null @@ -1,36 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Sebastien Hinderer, projet Gallium, INRIA Paris *) -(* *) -(* Copyright 2016 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Miscellaneous library functions *) - -val concatmap : ('a -> 'b list) -> 'a list -> 'b list - -val is_blank : char -> bool - -val maybe_quote : string -> string - -val words : string -> string list - -val file_is_empty : string -> bool - -val string_of_location: Location.t -> string - -val run_system_command : string -> unit - -val make_directory : string -> unit - -val string_of_file : string -> string - -val copy_file : string -> string -> unit diff --git a/ocamltest/tests.ml b/ocamltest/tests.ml index 0a93ac70..f360600e 100644 --- a/ocamltest/tests.ml +++ b/ocamltest/tests.ml @@ -43,7 +43,7 @@ let lookup name = let test_of_action action = { - test_name = action.Actions.action_name; + test_name = Actions.action_name action; test_run_by_default = false; test_actions = [action] } @@ -51,25 +51,18 @@ let test_of_action action = let run_actions log testenv actions = let total = List.length actions in let rec run_actions_aux action_number env = function - | [] -> Actions.Pass env + | [] -> (Result.pass, env) | action::remaining_actions -> begin Printf.fprintf log "Running action %d/%d (%s)\n%!" - action_number total action.Actions.action_name; - let result = Actions.run log env action in - let report = match result with - | Actions.Pass _ -> "succeded." - | Actions.Fail reason -> - ("failed for the following reason:\n" ^ reason) - | Actions.Skip reason -> - ("has been skipped for the following reason:\n" ^ reason) in + action_number total (Actions.action_name action); + let (result, env') = Actions.run log env action in Printf.fprintf log "Action %d/%d (%s) %s\n%!" - action_number total action.Actions.action_name - report; - match result with - | Actions.Pass env' -> - run_actions_aux (action_number+1) env' remaining_actions - | _ -> result + action_number total (Actions.action_name action) + (Result.string_of_result result); + if Result.is_pass result + then run_actions_aux (action_number+1) env' remaining_actions + else (result, env') end in run_actions_aux 1 testenv actions diff --git a/ocamltest/tests.mli b/ocamltest/tests.mli index 0093e457..eebc4bb4 100644 --- a/ocamltest/tests.mli +++ b/ocamltest/tests.mli @@ -31,7 +31,7 @@ val default_tests : unit -> t list val lookup : string -> t option -val run : out_channel -> Environments.t -> t -> Actions.result +val run : out_channel -> Environments.t -> t -> Result.t * Environments.t val test_of_action : Actions.t -> t diff --git a/ocamltest/tsl_ast.ml b/ocamltest/tsl_ast.ml index 36e7df7c..fda94cb6 100644 --- a/ocamltest/tsl_ast.ml +++ b/ocamltest/tsl_ast.ml @@ -21,7 +21,8 @@ type 'a located = { } type environment_statement = - | Assignment of string located * string located (* variable = value *) + | Assignment of bool * string located * string located (* variable = value *) + | Append of string located * string located | Include of string located (* include named environemnt *) type tsl_item = diff --git a/ocamltest/tsl_ast.mli b/ocamltest/tsl_ast.mli index c0530971..9fc47c21 100644 --- a/ocamltest/tsl_ast.mli +++ b/ocamltest/tsl_ast.mli @@ -21,7 +21,8 @@ type 'a located = { } type environment_statement = - | Assignment of string located * string located (* variable = value *) + | Assignment of bool * string located * string located (* variable = value *) + | Append of string located * string located (* variable += value *) | Include of string located (* include named environemnt *) type tsl_item = diff --git a/ocamltest/tsl_lexer.mll b/ocamltest/tsl_lexer.mll index b14cee89..966483a3 100644 --- a/ocamltest/tsl_lexer.mll +++ b/ocamltest/tsl_lexer.mll @@ -28,7 +28,7 @@ let lexer_error message = let newline = ('\013'* '\010') let blank = [' ' '\009' '\012'] -let identchar = ['A'-'Z' 'a'-'z' '_' '\'' '0'-'9'] +let identchar = ['A'-'Z' 'a'-'z' '_' '.' '-' '\'' '0'-'9'] rule token = parse | blank * { token lexbuf } @@ -39,11 +39,13 @@ rule token = parse | "*)" { TSL_END_OCAML_STYLE } | "," { COMA } | '*'+ { TEST_DEPTH (String.length (Lexing.lexeme lexbuf)) } + | "+=" { PLUSEQUAL } | "=" { EQUAL } | identchar * { let s = Lexing.lexeme lexbuf in match s with | "include" -> INCLUDE + | "set" -> SET | "with" -> WITH | _ -> IDENTIFIER s } diff --git a/ocamltest/tsl_parser.mly b/ocamltest/tsl_parser.mly index 7555b135..eb891f6a 100644 --- a/ocamltest/tsl_parser.mly +++ b/ocamltest/tsl_parser.mly @@ -35,9 +35,9 @@ let mkenvstmt envstmt = %token TSL_BEGIN_OCAML_STYLE TSL_END_OCAML_STYLE %token COMA %token TEST_DEPTH -%token EQUAL +%token EQUAL PLUSEQUAL /* %token COLON */ -%token INCLUDE WITH +%token INCLUDE SET WITH %token IDENTIFIER %token STRING @@ -71,7 +71,12 @@ opt_environment_modifiers: env_item: | identifier EQUAL string - { mkenvstmt (Assignment ($1, $3)) } + { mkenvstmt (Assignment (false, $1, $3)) } +| identifier PLUSEQUAL string + { mkenvstmt (Append ($1, $3)) } +| SET identifier EQUAL string + { mkenvstmt (Assignment (true, $2, $4)) } + | INCLUDE identifier { mkenvstmt (Include $2) } diff --git a/ocamltest/tsl_semantics.ml b/ocamltest/tsl_semantics.ml index ca4b7740..e9e163f2 100644 --- a/ocamltest/tsl_semantics.ml +++ b/ocamltest/tsl_semantics.ml @@ -17,16 +17,20 @@ open Tsl_ast -let variable_already_defined loc variable context = - let ctxt = match context with - | None -> "" - | Some envname -> " while including environment " ^ envname in - let locstr = Testlib.string_of_location loc in - Printf.eprintf "%s\nVariable %s already defined%s\n%!" locstr variable ctxt; +let string_of_location loc = + let buf = Buffer.create 64 in + let fmt = Format.formatter_of_buffer buf in + Location.print_loc fmt loc; + Format.pp_print_flush fmt (); + Buffer.contents buf + +let no_such_variable loc name = + let locstr = string_of_location loc in + Printf.eprintf "%s\nNo such variable %s\n%!" locstr name; exit 2 let no_such_modifiers loc name = - let locstr = Testlib.string_of_location loc in + let locstr = string_of_location loc in Printf.eprintf "%s\nNo such modifiers %s\n%!" locstr name; exit 2 @@ -36,23 +40,40 @@ let apply_modifiers env modifiers_name = try Environments.apply_modifier env modifier with | Environments.Modifiers_name_not_found name -> no_such_modifiers modifiers_name.loc name - | Environments.Variable_already_defined variable -> - variable_already_defined modifiers_name.loc - (Variables.name_of_variable variable) (Some name) + +let rec add_to_env decl loc variable_name value env = + match (Variables.find_variable variable_name, decl) with + | (None, true) -> + let newvar = Variables.make (variable_name,"User variable") in + Variables.register_variable newvar; + add_to_env false loc variable_name value env + | (Some variable, false) -> + Environments.add variable value env + | (None, false) -> + raise (Variables.No_such_variable variable_name) + | (Some _, true) -> + raise (Variables.Variable_already_registered variable_name) + +let append_to_env loc variable_name value env = + let variable = + match Variables.find_variable variable_name with + | None -> + raise (Variables.No_such_variable variable_name) + | Some variable -> + variable + in + try + Environments.append variable value env + with Variables.No_such_variable name -> + no_such_variable loc name let interprete_environment_statement env statement = match statement.node with - | Assignment (var, value) -> - begin - let variable_name = var.node in - let variable = match Variables.find_variable variable_name with - | None -> Variables.make (variable_name, "User variable") - | Some variable -> variable in - try Environments.add variable value.node env with - Environments.Variable_already_defined variable -> - variable_already_defined statement.loc - (Variables.name_of_variable variable) None - end - | Include modifiers_name -> apply_modifiers env modifiers_name + | Assignment (decl, var, value) -> + add_to_env decl statement.loc var.node value.node env + | Append (var, value) -> + append_to_env statement.loc var.node value.node env + | Include modifiers_name -> + apply_modifiers env modifiers_name let interprete_environment_statements env l = List.fold_left interprete_environment_statement env l @@ -70,12 +91,12 @@ let too_deep testname max_level real_level = exit 2 let unexpected_environment_statement s = - let locstr = Testlib.string_of_location s.loc in + let locstr = string_of_location s.loc in Printf.eprintf "%s\nUnexpected environment statement\n%!" locstr; exit 2 let no_such_test_or_action t = - let locstr = Testlib.string_of_location t.loc in + let locstr = string_of_location t.loc in Printf.eprintf "%s\nNo such test or action: %s\n%!" locstr t.node; exit 2 diff --git a/ocamltest/variables.ml b/ocamltest/variables.ml index 2762ef39..9f8fa1b4 100644 --- a/ocamltest/variables.ml +++ b/ocamltest/variables.ml @@ -13,23 +13,40 @@ (* *) (**************************************************************************) -(* Definition of environment variabless *) +(* Definition of environment variables *) + +type value = string + +type exporter = value -> string type t = { variable_name : string; - variable_description : string + variable_description : string; + variable_exporter : exporter } let compare v1 v2 = String.compare v1.variable_name v2.variable_name exception Empty_variable_name -exception Variable_already_registered +exception Variable_already_registered of string + +exception No_such_variable of string + +let default_exporter varname value = Printf.sprintf "%s=%s" varname value let make (name, description) = if name="" then raise Empty_variable_name else { variable_name = name; - variable_description = description + variable_description = description; + variable_exporter = default_exporter name + } + +let make_with_exporter exporter (name, description) = + if name="" then raise Empty_variable_name else { + variable_name = name; + variable_description = description; + variable_exporter = exporter } let name_of_variable v = v.variable_name @@ -40,9 +57,12 @@ let (variables : (string, t) Hashtbl.t) = Hashtbl.create 10 let register_variable variable = if Hashtbl.mem variables variable.variable_name - then raise Variable_already_registered + then raise (Variable_already_registered variable.variable_name) else Hashtbl.add variables variable.variable_name variable let find_variable variable_name = try Some (Hashtbl.find variables variable_name) with Not_found -> None + +let string_of_binding variable value = + variable.variable_exporter value diff --git a/ocamltest/variables.mli b/ocamltest/variables.mli index 4c63001f..86b093d9 100644 --- a/ocamltest/variables.mli +++ b/ocamltest/variables.mli @@ -13,7 +13,11 @@ (* *) (**************************************************************************) -(* Definition of environment variabless *) +(* Definition of environment variables *) + +type value = string + +type exporter = value -> string type t @@ -21,10 +25,14 @@ val compare : t -> t -> int exception Empty_variable_name -exception Variable_already_registered +exception Variable_already_registered of string + +exception No_such_variable of string val make : string * string -> t +val make_with_exporter : exporter -> string * string -> t + val name_of_variable : t -> string val description_of_variable : t -> string @@ -32,3 +40,5 @@ val description_of_variable : t -> string val register_variable : t -> unit val find_variable : string -> t option + +val string_of_binding : t -> value -> string diff --git a/otherlibs/Makefile b/otherlibs/Makefile index 0958d0c0..98d6d470 100644 --- a/otherlibs/Makefile +++ b/otherlibs/Makefile @@ -17,6 +17,8 @@ ROOTDIR=../.. include $(ROOTDIR)/config/Makefile +include $(ROOTDIR)/Makefile.common + CAMLRUN ?= $(ROOTDIR)/boot/ocamlrun CAMLYACC ?= $(ROOTDIR)/boot/ocamlyacc @@ -76,24 +78,30 @@ $(LIBNAME).cmxs: $(LIBNAME).cmxa lib$(CLIBNAME).$(A) lib$(CLIBNAME).$(A): $(COBJS) $(MKLIB) -oc $(CLIBNAME) $(COBJS) $(LDOPTS) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) -INSTALL_STUBLIBDIR=$(DESTDIR)$(STUBLIBDIR) - install:: if test -f dll$(CLIBNAME)$(EXT_DLL); then \ - cp dll$(CLIBNAME)$(EXT_DLL) "$(INSTALL_STUBLIBDIR)/"; fi - cp lib$(CLIBNAME).$(A) "$(INSTALL_LIBDIR)/" + $(INSTALL_PROG) \ + dll$(CLIBNAME)$(EXT_DLL) \ + "$(INSTALL_STUBLIBDIR)/"; \ + fi + $(INSTALL_DATA) lib$(CLIBNAME).$(A) "$(INSTALL_LIBDIR)/" cd "$(INSTALL_LIBDIR)"; $(RANLIB) lib$(CLIBNAME).$(A) - cp $(LIBNAME).cma $(CMIFILES) $(CMIFILES:.cmi=.mli) \ - $(CMIFILES:.cmi=.cmti) "$(INSTALL_LIBDIR)/" + $(INSTALL_DATA) \ + $(LIBNAME).cma $(CMIFILES) $(CMIFILES:.cmi=.mli) \ + $(CMIFILES:.cmi=.cmti) \ + "$(INSTALL_LIBDIR)/" if test -n "$(HEADERS)"; then \ - cp $(HEADERS) "$(INSTALL_LIBDIR)/caml/"; fi + $(INSTALL_DATA) $(HEADERS) "$(INSTALL_LIBDIR)/caml/"; \ + fi installopt: - cp $(CAMLOBJS_NAT) $(LIBNAME).cmxa $(LIBNAME).$(A) "$(INSTALL_LIBDIR)/" + $(INSTALL_DATA) \ + $(CAMLOBJS_NAT) $(LIBNAME).cmxa $(LIBNAME).$(A) \ + "$(INSTALL_LIBDIR)/" cd "$(INSTALL_LIBDIR)"; $(RANLIB) $(LIBNAME).a if test -f $(LIBNAME).cmxs; then \ - cp $(LIBNAME).cmxs "$(INSTALL_LIBDIR)/"; fi + $(INSTALL_PROG) $(LIBNAME).cmxs "$(INSTALL_LIBDIR)/"; \ + fi partialclean: rm -f *.cm* diff --git a/otherlibs/bigarray/.depend b/otherlibs/bigarray/.depend index ea433c07..a58e2688 100644 --- a/otherlibs/bigarray/.depend +++ b/otherlibs/bigarray/.depend @@ -1,13 +1,3 @@ -bigarray_stubs.$(O): bigarray_stubs.c ../../byterun/caml/alloc.h \ - ../../byterun/caml/misc.h ../../byterun/caml/config.h \ - ../../byterun/caml/m.h ../../byterun/caml/s.h \ - ../../byterun/caml/mlvalues.h ../../byterun/caml/bigarray.h \ - ../../byterun/caml/custom.h ../../byterun/caml/fail.h \ - ../../byterun/caml/intext.h ../../byterun/caml/io.h \ - ../../byterun/caml/hash.h ../../byterun/caml/memory.h \ - ../../byterun/caml/gc.h ../../byterun/caml/major_gc.h \ - ../../byterun/caml/freelist.h ../../byterun/caml/minor_gc.h \ - ../../byterun/caml/address_class.h ../../byterun/caml/signals.h bigarray.cmo : bigarray.cmi bigarray.cmx : bigarray.cmi bigarray.cmi : diff --git a/otherlibs/bigarray/Makefile b/otherlibs/bigarray/Makefile index 2094ad2f..f24de2d1 100644 --- a/otherlibs/bigarray/Makefile +++ b/otherlibs/bigarray/Makefile @@ -16,11 +16,15 @@ LIBNAME=bigarray EXTRACFLAGS=-I../$(UNIXLIB) -DIN_OCAML_BIGARRAY EXTRACAMLFLAGS=-I ../$(UNIXLIB) -COBJS=bigarray_stubs.$(O) mmap_ba.$(O) mmap.$(O) +COBJS=mmap_ba.$(O) mmap.$(O) CAMLOBJS=bigarray.cmo include ../Makefile +ifeq "$(SYSTEM)" "mingw" +LDOPTS=-ldopt "-link -static-libgcc" +endif + mmap.$(O): ../$(UNIXLIB)/mmap.c $(CC) -c $(CFLAGS) $(CPPFLAGS) $(OUTPUTOBJ)$@ $< mmap_ba.$(O): ../unix/mmap_ba.c @@ -29,11 +33,6 @@ mmap_ba.$(O): ../unix/mmap_ba.c .PHONY: depend depend: -ifeq "$(TOOLCHAIN)" "msvc" - $(error Dependencies cannot be regenerated using the MSVC ports) -else - $(CC) -MM $(CFLAGS) $(CPPFLAGS) *.c | sed -e 's/\.o/.$$(O)/g' > .depend - $(CAMLRUN) $(ROOTDIR)/tools/ocamldep -slash *.mli *.ml >> .depend -endif + $(CAMLRUN) $(ROOTDIR)/tools/ocamldep -slash *.mli *.ml > .depend include .depend diff --git a/otherlibs/bigarray/bigarray.ml b/otherlibs/bigarray/bigarray.ml index d5e66daf..e9dd59ff 100644 --- a/otherlibs/bigarray/bigarray.ml +++ b/otherlibs/bigarray/bigarray.ml @@ -2,10 +2,9 @@ (* *) (* OCaml *) (* *) -(* Manuel Serrano et Xavier Leroy, INRIA Rocquencourt *) +(* Jeremie Dimino, Jane Street Europe *) (* *) -(* Copyright 2000 Institut National de Recherche en Informatique et *) -(* en Automatique. *) +(* Copyright 2018 Jane Street Group LLC *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) @@ -13,312 +12,40 @@ (* *) (**************************************************************************) -(* Module [Bigarray]: large, multi-dimensional, numerical arrays *) +module Super = Stdlib.Bigarray -include CamlinternalBigarray - -(* Keep those constants in sync with the caml_ba_kind enumeration - in bigarray.h *) - -let float32 = Float32 -let float64 = Float64 -let int8_signed = Int8_signed -let int8_unsigned = Int8_unsigned -let int16_signed = Int16_signed -let int16_unsigned = Int16_unsigned -let int32 = Int32 -let int64 = Int64 -let int = Int -let nativeint = Nativeint -let complex32 = Complex32 -let complex64 = Complex64 -let char = Char - -let kind_size_in_bytes : type a b. (a, b) kind -> int = function - | Float32 -> 4 - | Float64 -> 8 - | Int8_signed -> 1 - | Int8_unsigned -> 1 - | Int16_signed -> 2 - | Int16_unsigned -> 2 - | Int32 -> 4 - | Int64 -> 8 - | Int -> Sys.word_size / 8 - | Nativeint -> Sys.word_size / 8 - | Complex32 -> 8 - | Complex64 -> 16 - | Char -> 1 - -(* Keep those constants in sync with the caml_ba_layout enumeration - in bigarray.h *) - -let c_layout = C_layout -let fortran_layout = Fortran_layout +include (Super : module type of struct include Super end + with module Genarray := Super.Genarray + with module Array1 := Super.Array1 + with module Array2 := Super.Array2 + with module Array3 := Super.Array3) module Genarray = struct - type ('a, 'b, 'c) t = ('a, 'b, 'c) genarray - external create: ('a, 'b) kind -> 'c layout -> int array -> ('a, 'b, 'c) t - = "caml_ba_create" - external get: ('a, 'b, 'c) t -> int array -> 'a - = "caml_ba_get_generic" - external set: ('a, 'b, 'c) t -> int array -> 'a -> unit - = "caml_ba_set_generic" - external num_dims: ('a, 'b, 'c) t -> int = "caml_ba_num_dims" - external nth_dim: ('a, 'b, 'c) t -> int -> int = "caml_ba_dim" - let dims a = - let n = num_dims a in - let d = Array.make n 0 in - for i = 0 to n-1 do d.(i) <- nth_dim a i done; - d - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - - let size_in_bytes arr = - (kind_size_in_bytes (kind arr)) * (Array.fold_left ( * ) 1 (dims arr)) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - external sub_right: ('a, 'b, fortran_layout) t -> int -> int -> - ('a, 'b, fortran_layout) t - = "caml_ba_sub" - external slice_left: ('a, 'b, c_layout) t -> int array -> - ('a, 'b, c_layout) t - = "caml_ba_slice" - external slice_right: ('a, 'b, fortran_layout) t -> int array -> - ('a, 'b, fortran_layout) t - = "caml_ba_slice" - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit - = "caml_ba_blit" - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + include Super.Genarray external map_internal: Unix.file_descr -> ('a, 'b) kind -> 'c layout -> - bool -> int array -> int64 -> ('a, 'b, 'c) t - = "caml_ba_map_file_bytecode" "caml_ba_map_file" + bool -> int array -> int64 -> ('a, 'b, 'c) t + = "caml_ba_map_file_bytecode" "caml_ba_map_file" let map_file fd ?(pos = 0L) kind layout shared dims = map_internal fd kind layout shared dims pos end -module Array0 = struct - type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t - let create kind layout = - Genarray.create kind layout [||] - let get arr = Genarray.get arr [||] - let set arr = Genarray.set arr [||] - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - - let size_in_bytes arr = kind_size_in_bytes (kind arr) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - - let of_value kind layout v = - let a = create kind layout in - set a v; - a -end - module Array1 = struct - type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t - let create kind layout dim = - Genarray.create kind layout [|dim|] - external get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_ref_1" - external set: ('a, 'b, 'c) t -> int -> 'a -> unit = "%caml_ba_set_1" - external unsafe_get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_unsafe_ref_1" - external unsafe_set: ('a, 'b, 'c) t -> int -> 'a -> unit - = "%caml_ba_unsafe_set_1" - external dim: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - - let size_in_bytes arr = - (kind_size_in_bytes (kind arr)) * (dim arr) - - external sub: ('a, 'b, 'c) t -> int -> int -> ('a, 'b, 'c) t = "caml_ba_sub" - let slice (type t) (a : (_, _, t) Genarray.t) n = - match layout a with - | C_layout -> (Genarray.slice_left a [|n|] : (_, _, t) Genarray.t) - | Fortran_layout -> (Genarray.slice_right a [|n|]: (_, _, t) Genarray.t) - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - let of_array (type t) kind (layout: t layout) data = - let ba = create kind layout (Array.length data) in - let ofs = - match layout with - C_layout -> 0 - | Fortran_layout -> 1 - in - for i = 0 to Array.length data - 1 do unsafe_set ba (i + ofs) data.(i) done; - ba + include Super.Array1 let map_file fd ?pos kind layout shared dim = - Genarray.map_file fd ?pos kind layout shared [|dim|] + array1_of_genarray + (Genarray.map_file fd ?pos kind layout shared [|dim|]) end module Array2 = struct - type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t - let create kind layout dim1 dim2 = - Genarray.create kind layout [|dim1; dim2|] - external get: ('a, 'b, 'c) t -> int -> int -> 'a = "%caml_ba_ref_2" - external set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit = "%caml_ba_set_2" - external unsafe_get: ('a, 'b, 'c) t -> int -> int -> 'a - = "%caml_ba_unsafe_ref_2" - external unsafe_set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit - = "%caml_ba_unsafe_set_2" - external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - - let size_in_bytes arr = - (kind_size_in_bytes (kind arr)) * (dim1 arr) * (dim2 arr) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - external sub_right: - ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t - = "caml_ba_sub" - let slice_left a n = Genarray.slice_left a [|n|] - let slice_right a n = Genarray.slice_right a [|n|] - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - let of_array (type t) kind (layout: t layout) data = - let dim1 = Array.length data in - let dim2 = if dim1 = 0 then 0 else Array.length data.(0) in - let ba = create kind layout dim1 dim2 in - let ofs = - match layout with - C_layout -> 0 - | Fortran_layout -> 1 - in - for i = 0 to dim1 - 1 do - let row = data.(i) in - if Array.length row <> dim2 then - invalid_arg("Bigarray.Array2.of_array: non-rectangular data"); - for j = 0 to dim2 - 1 do - unsafe_set ba (i + ofs) (j + ofs) row.(j) - done - done; - ba + include Super.Array2 let map_file fd ?pos kind layout shared dim1 dim2 = - Genarray.map_file fd ?pos kind layout shared [|dim1;dim2|] + array2_of_genarray + (Genarray.map_file fd ?pos kind layout shared [|dim1;dim2|]) end module Array3 = struct - type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t - let create kind layout dim1 dim2 dim3 = - Genarray.create kind layout [|dim1; dim2; dim3|] - external get: ('a, 'b, 'c) t -> int -> int -> int -> 'a = "%caml_ba_ref_3" - external set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit - = "%caml_ba_set_3" - external unsafe_get: ('a, 'b, 'c) t -> int -> int -> int -> 'a - = "%caml_ba_unsafe_ref_3" - external unsafe_set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit - = "%caml_ba_unsafe_set_3" - external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" - external dim3: ('a, 'b, 'c) t -> int = "%caml_ba_dim_3" - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - - let size_in_bytes arr = - (kind_size_in_bytes (kind arr)) * (dim1 arr) * (dim2 arr) * (dim3 arr) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - external sub_right: - ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t - = "caml_ba_sub" - let slice_left_1 a n m = Genarray.slice_left a [|n; m|] - let slice_right_1 a n m = Genarray.slice_right a [|n; m|] - let slice_left_2 a n = Genarray.slice_left a [|n|] - let slice_right_2 a n = Genarray.slice_right a [|n|] - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - let of_array (type t) kind (layout: t layout) data = - let dim1 = Array.length data in - let dim2 = if dim1 = 0 then 0 else Array.length data.(0) in - let dim3 = if dim2 = 0 then 0 else Array.length data.(0).(0) in - let ba = create kind layout dim1 dim2 dim3 in - let ofs = - match layout with - C_layout -> 0 - | Fortran_layout -> 1 - in - for i = 0 to dim1 - 1 do - let row = data.(i) in - if Array.length row <> dim2 then - invalid_arg("Bigarray.Array3.of_array: non-cubic data"); - for j = 0 to dim2 - 1 do - let col = row.(j) in - if Array.length col <> dim3 then - invalid_arg("Bigarray.Array3.of_array: non-cubic data"); - for k = 0 to dim3 - 1 do - unsafe_set ba (i + ofs) (j + ofs) (k + ofs) col.(k) - done - done - done; - ba + include Super.Array3 let map_file fd ?pos kind layout shared dim1 dim2 dim3 = - Genarray.map_file fd ?pos kind layout shared [|dim1;dim2;dim3|] + array3_of_genarray + (Genarray.map_file fd ?pos kind layout shared [|dim1;dim2;dim3|]) end - -external genarray_of_array0: ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t - = "%identity" -external genarray_of_array1: ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t - = "%identity" -external genarray_of_array2: ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t - = "%identity" -external genarray_of_array3: ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t - = "%identity" -let array0_of_genarray a = - if Genarray.num_dims a = 0 then a - else invalid_arg "Bigarray.array0_of_genarray" -let array1_of_genarray a = - if Genarray.num_dims a = 1 then a - else invalid_arg "Bigarray.array1_of_genarray" -let array2_of_genarray a = - if Genarray.num_dims a = 2 then a - else invalid_arg "Bigarray.array2_of_genarray" -let array3_of_genarray a = - if Genarray.num_dims a = 3 then a - else invalid_arg "Bigarray.array3_of_genarray" - -external reshape: - ('a, 'b, 'c) Genarray.t -> int array -> ('a, 'b, 'c) Genarray.t - = "caml_ba_reshape" -let reshape_0 a = reshape a [||] -let reshape_1 a dim1 = reshape a [|dim1|] -let reshape_2 a dim1 dim2 = reshape a [|dim1;dim2|] -let reshape_3 a dim1 dim2 dim3 = reshape a [|dim1;dim2;dim3|] - -(* Force caml_ba_get_{1,2,3,N} to be linked in, since we don't refer - to those primitives directly in this file *) - -let _ = - let _ = Genarray.get in - let _ = Array1.get in - let _ = Array2.get in - let _ = Array3.get in - () - -[@@@ocaml.warning "-32"] -external get1: unit -> unit = "caml_ba_get_1" -external get2: unit -> unit = "caml_ba_get_2" -external get3: unit -> unit = "caml_ba_get_3" -external set1: unit -> unit = "caml_ba_set_1" -external set2: unit -> unit = "caml_ba_set_2" -external set3: unit -> unit = "caml_ba_set_3" diff --git a/otherlibs/bigarray/bigarray.mli b/otherlibs/bigarray/bigarray.mli index cadd04a6..9b8952fc 100644 --- a/otherlibs/bigarray/bigarray.mli +++ b/otherlibs/bigarray/bigarray.mli @@ -2,10 +2,9 @@ (* *) (* OCaml *) (* *) -(* Manuel Serrano and Xavier Leroy, INRIA Rocquencourt *) +(* Jeremie Dimino, Jane Street Europe *) (* *) -(* Copyright 2000 Institut National de Recherche en Informatique et *) -(* en Automatique. *) +(* Copyright 2018 Jane Street Group LLC *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) @@ -13,431 +12,14 @@ (* *) (**************************************************************************) -(** Large, multi-dimensional, numerical arrays. - - This module implements multi-dimensional arrays of integers and - floating-point numbers, thereafter referred to as 'big arrays'. - The implementation allows efficient sharing of large numerical - arrays between OCaml code and C or Fortran numerical libraries. - - Concerning the naming conventions, users of this module are encouraged - to do [open Bigarray] in their source, then refer to array types and - operations via short dot notation, e.g. [Array1.t] or [Array2.sub]. - - Big arrays support all the OCaml ad-hoc polymorphic operations: - - comparisons ([=], [<>], [<=], etc, as well as {!Pervasives.compare}); - - hashing (module [Hash]); - - and structured input-output (the functions from the - {!Marshal} module, as well as {!Pervasives.output_value} - and {!Pervasives.input_value}). -*) - -(** {1 Element kinds} *) - -(** Big arrays can contain elements of the following kinds: -- IEEE single precision (32 bits) floating-point numbers - ({!Bigarray.float32_elt}), -- IEEE double precision (64 bits) floating-point numbers - ({!Bigarray.float64_elt}), -- IEEE single precision (2 * 32 bits) floating-point complex numbers - ({!Bigarray.complex32_elt}), -- IEEE double precision (2 * 64 bits) floating-point complex numbers - ({!Bigarray.complex64_elt}), -- 8-bit integers (signed or unsigned) - ({!Bigarray.int8_signed_elt} or {!Bigarray.int8_unsigned_elt}), -- 16-bit integers (signed or unsigned) - ({!Bigarray.int16_signed_elt} or {!Bigarray.int16_unsigned_elt}), -- OCaml integers (signed, 31 bits on 32-bit architectures, - 63 bits on 64-bit architectures) ({!Bigarray.int_elt}), -- 32-bit signed integers ({!Bigarray.int32_elt}), -- 64-bit signed integers ({!Bigarray.int64_elt}), -- platform-native signed integers (32 bits on 32-bit architectures, - 64 bits on 64-bit architectures) ({!Bigarray.nativeint_elt}). - - Each element kind is represented at the type level by one of the - [*_elt] types defined below (defined with a single constructor instead - of abstract types for technical injectivity reasons). -*) - -type float32_elt = CamlinternalBigarray.float32_elt = Float32_elt -type float64_elt = CamlinternalBigarray.float64_elt = Float64_elt -type int8_signed_elt = CamlinternalBigarray.int8_signed_elt = Int8_signed_elt -type int8_unsigned_elt = CamlinternalBigarray.int8_unsigned_elt = - Int8_unsigned_elt -type int16_signed_elt = CamlinternalBigarray.int16_signed_elt = - Int16_signed_elt -type int16_unsigned_elt = CamlinternalBigarray.int16_unsigned_elt = - Int16_unsigned_elt -type int32_elt = CamlinternalBigarray.int32_elt = Int32_elt -type int64_elt = CamlinternalBigarray.int64_elt = Int64_elt -type int_elt = CamlinternalBigarray.int_elt = Int_elt -type nativeint_elt = CamlinternalBigarray.nativeint_elt = Nativeint_elt -type complex32_elt = CamlinternalBigarray.complex32_elt = Complex32_elt -type complex64_elt = CamlinternalBigarray.complex64_elt = Complex64_elt - -type ('a, 'b) kind = ('a, 'b) CamlinternalBigarray.kind = - Float32 : (float, float32_elt) kind - | Float64 : (float, float64_elt) kind - | Int8_signed : (int, int8_signed_elt) kind - | Int8_unsigned : (int, int8_unsigned_elt) kind - | Int16_signed : (int, int16_signed_elt) kind - | Int16_unsigned : (int, int16_unsigned_elt) kind - | Int32 : (int32, int32_elt) kind - | Int64 : (int64, int64_elt) kind - | Int : (int, int_elt) kind - | Nativeint : (nativeint, nativeint_elt) kind - | Complex32 : (Complex.t, complex32_elt) kind - | Complex64 : (Complex.t, complex64_elt) kind - | Char : (char, int8_unsigned_elt) kind (**) -(** To each element kind is associated an OCaml type, which is - the type of OCaml values that can be stored in the big array - or read back from it. This type is not necessarily the same - as the type of the array elements proper: for instance, - a big array whose elements are of kind [float32_elt] contains - 32-bit single precision floats, but reading or writing one of - its elements from OCaml uses the OCaml type [float], which is - 64-bit double precision floats. - - The GADT type [('a, 'b) kind] captures this association - of an OCaml type ['a] for values read or written in the big array, - and of an element kind ['b] which represents the actual contents - of the big array. Its constructors list all possible associations - of OCaml types with element kinds, and are re-exported below for - backward-compatibility reasons. - - Using a generalized algebraic datatype (GADT) here allows to write - well-typed polymorphic functions whose return type depend on the - argument type, such as: - -{[ - let zero : type a b. (a, b) kind -> a = function - | Float32 -> 0.0 | Complex32 -> Complex.zero - | Float64 -> 0.0 | Complex64 -> Complex.zero - | Int8_signed -> 0 | Int8_unsigned -> 0 - | Int16_signed -> 0 | Int16_unsigned -> 0 - | Int32 -> 0l | Int64 -> 0L - | Int -> 0 | Nativeint -> 0n - | Char -> '\000' -]} -*) - -val float32 : (float, float32_elt) kind -(** See {!Bigarray.char}. *) - -val float64 : (float, float64_elt) kind -(** See {!Bigarray.char}. *) - -val complex32 : (Complex.t, complex32_elt) kind -(** See {!Bigarray.char}. *) - -val complex64 : (Complex.t, complex64_elt) kind -(** See {!Bigarray.char}. *) - -val int8_signed : (int, int8_signed_elt) kind -(** See {!Bigarray.char}. *) - -val int8_unsigned : (int, int8_unsigned_elt) kind -(** See {!Bigarray.char}. *) - -val int16_signed : (int, int16_signed_elt) kind -(** See {!Bigarray.char}. *) - -val int16_unsigned : (int, int16_unsigned_elt) kind -(** See {!Bigarray.char}. *) - -val int : (int, int_elt) kind -(** See {!Bigarray.char}. *) - -val int32 : (int32, int32_elt) kind -(** See {!Bigarray.char}. *) - -val int64 : (int64, int64_elt) kind -(** See {!Bigarray.char}. *) - -val nativeint : (nativeint, nativeint_elt) kind -(** See {!Bigarray.char}. *) - -val char : (char, int8_unsigned_elt) kind -(** As shown by the types of the values above, - big arrays of kind [float32_elt] and [float64_elt] are - accessed using the OCaml type [float]. Big arrays of complex kinds - [complex32_elt], [complex64_elt] are accessed with the OCaml type - {!Complex.t}. Big arrays of - integer kinds are accessed using the smallest OCaml integer - type large enough to represent the array elements: - [int] for 8- and 16-bit integer bigarrays, as well as OCaml-integer - bigarrays; [int32] for 32-bit integer bigarrays; [int64] - for 64-bit integer bigarrays; and [nativeint] for - platform-native integer bigarrays. Finally, big arrays of - kind [int8_unsigned_elt] can also be accessed as arrays of - characters instead of arrays of small integers, by using - the kind value [char] instead of [int8_unsigned]. *) - -val kind_size_in_bytes : ('a, 'b) kind -> int -(** [kind_size_in_bytes k] is the number of bytes used to store - an element of type [k]. - - @since 4.03.0 *) - -(** {1 Array layouts} *) - -type c_layout = CamlinternalBigarray.c_layout = C_layout_typ (**) -(** See {!Bigarray.fortran_layout}.*) - -type fortran_layout = CamlinternalBigarray.fortran_layout = - Fortran_layout_typ (**) -(** To facilitate interoperability with existing C and Fortran code, - this library supports two different memory layouts for big arrays, - one compatible with the C conventions, - the other compatible with the Fortran conventions. - - In the C-style layout, array indices start at 0, and - multi-dimensional arrays are laid out in row-major format. - That is, for a two-dimensional array, all elements of - row 0 are contiguous in memory, followed by all elements of - row 1, etc. In other terms, the array elements at [(x,y)] - and [(x, y+1)] are adjacent in memory. - - In the Fortran-style layout, array indices start at 1, and - multi-dimensional arrays are laid out in column-major format. - That is, for a two-dimensional array, all elements of - column 0 are contiguous in memory, followed by all elements of - column 1, etc. In other terms, the array elements at [(x,y)] - and [(x+1, y)] are adjacent in memory. - - Each layout style is identified at the type level by the - phantom types {!Bigarray.c_layout} and {!Bigarray.fortran_layout} - respectively. *) - -(** {7 Supported layouts} - - The GADT type ['a layout] represents one of the two supported - memory layouts: C-style or Fortran-style. Its constructors are - re-exported as values below for backward-compatibility reasons. -*) - -type 'a layout = 'a CamlinternalBigarray.layout = - C_layout: c_layout layout - | Fortran_layout: fortran_layout layout - -val c_layout : c_layout layout -val fortran_layout : fortran_layout layout - - -(** {1 Generic arrays (of arbitrarily many dimensions)} *) - -module Genarray : - sig - type ('a, 'b, 'c) t = ('a, 'b, 'c) CamlinternalBigarray.genarray - (** The type [Genarray.t] is the type of big arrays with variable - numbers of dimensions. Any number of dimensions between 0 and 16 - is supported. - - The three type parameters to [Genarray.t] identify the array element - kind and layout, as follows: - - the first parameter, ['a], is the OCaml type for accessing array - elements ([float], [int], [int32], [int64], [nativeint]); - - the second parameter, ['b], is the actual kind of array elements - ([float32_elt], [float64_elt], [int8_signed_elt], [int8_unsigned_elt], - etc); - - the third parameter, ['c], identifies the array layout - ([c_layout] or [fortran_layout]). - - For instance, [(float, float32_elt, fortran_layout) Genarray.t] - is the type of generic big arrays containing 32-bit floats - in Fortran layout; reads and writes in this array use the - OCaml type [float]. *) - - external create: ('a, 'b) kind -> 'c layout -> int array -> ('a, 'b, 'c) t - = "caml_ba_create" - (** [Genarray.create kind layout dimensions] returns a new big array - whose element kind is determined by the parameter [kind] (one of - [float32], [float64], [int8_signed], etc) and whose layout is - determined by the parameter [layout] (one of [c_layout] or - [fortran_layout]). The [dimensions] parameter is an array of - integers that indicate the size of the big array in each dimension. - The length of [dimensions] determines the number of dimensions - of the bigarray. - - For instance, [Genarray.create int32 c_layout [|4;6;8|]] - returns a fresh big array of 32-bit integers, in C layout, - having three dimensions, the three dimensions being 4, 6 and 8 - respectively. - - Big arrays returned by [Genarray.create] are not initialized: - the initial values of array elements is unspecified. - - [Genarray.create] raises [Invalid_argument] if the number of dimensions - is not in the range 0 to 16 inclusive, or if one of the dimensions - is negative. *) - - external num_dims: ('a, 'b, 'c) t -> int = "caml_ba_num_dims" - (** Return the number of dimensions of the given big array. *) - - val dims : ('a, 'b, 'c) t -> int array - (** [Genarray.dims a] returns all dimensions of the big array [a], - as an array of integers of length [Genarray.num_dims a]. *) - - external nth_dim: ('a, 'b, 'c) t -> int -> int = "caml_ba_dim" - (** [Genarray.nth_dim a n] returns the [n]-th dimension of the - big array [a]. The first dimension corresponds to [n = 0]; - the second dimension corresponds to [n = 1]; the last dimension, - to [n = Genarray.num_dims a - 1]. - Raise [Invalid_argument] if [n] is less than 0 or greater or equal than - [Genarray.num_dims a]. *) - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - (** Return the kind of the given big array. *) - - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - (** Return the layout of the given big array. *) - - external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - = "caml_ba_change_layout" - (** [Genarray.change_layout a layout] returns a bigarray with the - specified [layout], sharing the data with [a] (and hence having - the same dimensions as [a]). No copying of elements is involved: the - new array and the original array share the same storage space. - The dimensions are reversed, such that [get v [| a; b |]] in - C layout becomes [get v [| b+1; a+1 |]] in Fortran layout. - - @since 4.04.0 - *) - - val size_in_bytes : ('a, 'b, 'c) t -> int - (** [size_in_bytes a] is the number of elements in [a] multiplied - by [a]'s {!kind_size_in_bytes}. - - @since 4.03.0 *) - - external get: ('a, 'b, 'c) t -> int array -> 'a = "caml_ba_get_generic" - (** Read an element of a generic big array. - [Genarray.get a [|i1; ...; iN|]] returns the element of [a] - whose coordinates are [i1] in the first dimension, [i2] in - the second dimension, ..., [iN] in the [N]-th dimension. - - If [a] has C layout, the coordinates must be greater or equal than 0 - and strictly less than the corresponding dimensions of [a]. - If [a] has Fortran layout, the coordinates must be greater or equal - than 1 and less or equal than the corresponding dimensions of [a]. - Raise [Invalid_argument] if the array [a] does not have exactly [N] - dimensions, or if the coordinates are outside the array bounds. - - If [N > 3], alternate syntax is provided: you can write - [a.{i1, i2, ..., iN}] instead of [Genarray.get a [|i1; ...; iN|]]. - (The syntax [a.{...}] with one, two or three coordinates is - reserved for accessing one-, two- and three-dimensional arrays - as described below.) *) - - external set: ('a, 'b, 'c) t -> int array -> 'a -> unit - = "caml_ba_set_generic" - (** Assign an element of a generic big array. - [Genarray.set a [|i1; ...; iN|] v] stores the value [v] in the - element of [a] whose coordinates are [i1] in the first dimension, - [i2] in the second dimension, ..., [iN] in the [N]-th dimension. - - The array [a] must have exactly [N] dimensions, and all coordinates - must lie inside the array bounds, as described for [Genarray.get]; - otherwise, [Invalid_argument] is raised. - - If [N > 3], alternate syntax is provided: you can write - [a.{i1, i2, ..., iN} <- v] instead of - [Genarray.set a [|i1; ...; iN|] v]. - (The syntax [a.{...} <- v] with one, two or three coordinates is - reserved for updating one-, two- and three-dimensional arrays - as described below.) *) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - (** Extract a sub-array of the given big array by restricting the - first (left-most) dimension. [Genarray.sub_left a ofs len] - returns a big array with the same number of dimensions as [a], - and the same dimensions as [a], except the first dimension, - which corresponds to the interval [[ofs ... ofs + len - 1]] - of the first dimension of [a]. No copying of elements is - involved: the sub-array and the original array share the same - storage space. In other terms, the element at coordinates - [[|i1; ...; iN|]] of the sub-array is identical to the - element at coordinates [[|i1+ofs; ...; iN|]] of the original - array [a]. - - [Genarray.sub_left] applies only to big arrays in C layout. - Raise [Invalid_argument] if [ofs] and [len] do not designate - a valid sub-array of [a], that is, if [ofs < 0], or [len < 0], - or [ofs + len > Genarray.nth_dim a 0]. *) - - external sub_right: - ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t - = "caml_ba_sub" - (** Extract a sub-array of the given big array by restricting the - last (right-most) dimension. [Genarray.sub_right a ofs len] - returns a big array with the same number of dimensions as [a], - and the same dimensions as [a], except the last dimension, - which corresponds to the interval [[ofs ... ofs + len - 1]] - of the last dimension of [a]. No copying of elements is - involved: the sub-array and the original array share the same - storage space. In other terms, the element at coordinates - [[|i1; ...; iN|]] of the sub-array is identical to the - element at coordinates [[|i1; ...; iN+ofs|]] of the original - array [a]. - - [Genarray.sub_right] applies only to big arrays in Fortran layout. - Raise [Invalid_argument] if [ofs] and [len] do not designate - a valid sub-array of [a], that is, if [ofs < 1], or [len < 0], - or [ofs + len > Genarray.nth_dim a (Genarray.num_dims a - 1)]. *) - - external slice_left: - ('a, 'b, c_layout) t -> int array -> ('a, 'b, c_layout) t - = "caml_ba_slice" - (** Extract a sub-array of lower dimension from the given big array - by fixing one or several of the first (left-most) coordinates. - [Genarray.slice_left a [|i1; ... ; iM|]] returns the 'slice' - of [a] obtained by setting the first [M] coordinates to - [i1], ..., [iM]. If [a] has [N] dimensions, the slice has - dimension [N - M], and the element at coordinates - [[|j1; ...; j(N-M)|]] in the slice is identical to the element - at coordinates [[|i1; ...; iM; j1; ...; j(N-M)|]] in the original - array [a]. No copying of elements is involved: the slice and - the original array share the same storage space. - - [Genarray.slice_left] applies only to big arrays in C layout. - Raise [Invalid_argument] if [M >= N], or if [[|i1; ... ; iM|]] - is outside the bounds of [a]. *) - - external slice_right: - ('a, 'b, fortran_layout) t -> int array -> ('a, 'b, fortran_layout) t - = "caml_ba_slice" - (** Extract a sub-array of lower dimension from the given big array - by fixing one or several of the last (right-most) coordinates. - [Genarray.slice_right a [|i1; ... ; iM|]] returns the 'slice' - of [a] obtained by setting the last [M] coordinates to - [i1], ..., [iM]. If [a] has [N] dimensions, the slice has - dimension [N - M], and the element at coordinates - [[|j1; ...; j(N-M)|]] in the slice is identical to the element - at coordinates [[|j1; ...; j(N-M); i1; ...; iM|]] in the original - array [a]. No copying of elements is involved: the slice and - the original array share the same storage space. - - [Genarray.slice_right] applies only to big arrays in Fortran layout. - Raise [Invalid_argument] if [M >= N], or if [[|i1; ... ; iM|]] - is outside the bounds of [a]. *) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit - = "caml_ba_blit" - (** Copy all elements of a big array in another big array. - [Genarray.blit src dst] copies all elements of [src] into - [dst]. Both arrays [src] and [dst] must have the same number of - dimensions and equal dimensions. Copying a sub-array of [src] - to a sub-array of [dst] can be achieved by applying [Genarray.blit] - to sub-array or slices of [src] and [dst]. *) - - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - (** Set all elements of a big array to a given value. - [Genarray.fill a v] stores the value [v] in all elements of - the big array [a]. Setting only some elements of [a] to [v] - can be achieved by applying [Genarray.fill] to a sub-array - or a slice of [a]. *) +include module type of struct include Stdlib.Bigarray end + with module Genarray := Stdlib.Bigarray.Genarray + with module Array1 := Stdlib.Bigarray.Array1 + with module Array2 := Stdlib.Bigarray.Array2 + with module Array3 := Stdlib.Bigarray.Array3 +module Genarray : sig + include module type of struct include Stdlib.Bigarray.Genarray end val map_file: Unix.file_descr -> ?pos:int64 -> ('a, 'b) kind -> 'c layout -> bool -> int array -> ('a, 'b, 'c) t @@ -445,519 +27,34 @@ module Genarray : Use Unix.map_file instead.\n\ Note that Bigarray.Genarray.map_file raises Sys_error while\n\ Unix.map_file raises Unix_error."] - end - -(** {1 Zero-dimensional arrays} *) - -(** Zero-dimensional arrays. The [Array0] structure provides operations - similar to those of {!Bigarray.Genarray}, but specialized to the case - of zero-dimensional arrays that only contain a single scalar value. - Statically knowing the number of dimensions of the array allows - faster operations, and more precise static type-checking. - @since 4.05.0 *) -module Array0 : sig - type ('a, 'b, 'c) t - (** The type of zero-dimensional big arrays whose elements have - OCaml type ['a], representation kind ['b], and memory layout ['c]. *) - - val create: ('a, 'b) kind -> 'c layout -> ('a, 'b, 'c) t - (** [Array0.create kind layout] returns a new bigarray of zero dimension. - [kind] and [layout] determine the array element kind and the array - layout as described for {!Genarray.create}. *) - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - (** Return the kind of the given big array. *) - - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - (** Return the layout of the given big array. *) - - val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - (** [Array0.change_layout a layout] returns a big array with the - specified [layout], sharing the data with [a]. No copying of elements - is involved: the new array and the original array share the same - storage space. - - @since 4.06.0 - *) - - val size_in_bytes : ('a, 'b, 'c) t -> int - (** [size_in_bytes a] is [a]'s {!kind_size_in_bytes}. *) - - val get: ('a, 'b, 'c) t -> 'a - (** [Array0.get a] returns the only element in [a]. *) - - val set: ('a, 'b, 'c) t -> 'a -> unit - (** [Array0.set a x v] stores the value [v] in [a]. *) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" - (** Copy the first big array to the second big array. - See {!Genarray.blit} for more details. *) - - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - (** Fill the given big array with the given value. - See {!Genarray.fill} for more details. *) - - val of_value: ('a, 'b) kind -> 'c layout -> 'a -> ('a, 'b, 'c) t - (** Build a zero-dimensional big array initialized from the - given value. *) - end - -(** {1 One-dimensional arrays} *) - -(** One-dimensional arrays. The [Array1] structure provides operations - similar to those of - {!Bigarray.Genarray}, but specialized to the case of one-dimensional arrays. - (The {!Array2} and {!Array3} structures below provide operations - specialized for two- and three-dimensional arrays.) - Statically knowing the number of dimensions of the array allows - faster operations, and more precise static type-checking. *) module Array1 : sig - type ('a, 'b, 'c) t - (** The type of one-dimensional big arrays whose elements have - OCaml type ['a], representation kind ['b], and memory layout ['c]. *) - - val create: ('a, 'b) kind -> 'c layout -> int -> ('a, 'b, 'c) t - (** [Array1.create kind layout dim] returns a new bigarray of - one dimension, whose size is [dim]. [kind] and [layout] - determine the array element kind and the array layout - as described for {!Genarray.create}. *) - - external dim: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - (** Return the size (dimension) of the given one-dimensional - big array. *) - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - (** Return the kind of the given big array. *) - - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - (** Return the layout of the given big array. *) - - val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - (** [Array1.change_layout a layout] returns a bigarray with the - specified [layout], sharing the data with [a] (and hence having - the same dimension as [a]). No copying of elements is involved: the - new array and the original array share the same storage space. - - @since 4.06.0 - *) - - - val size_in_bytes : ('a, 'b, 'c) t -> int - (** [size_in_bytes a] is the number of elements in [a] - multiplied by [a]'s {!kind_size_in_bytes}. - - @since 4.03.0 *) - - external get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_ref_1" - (** [Array1.get a x], or alternatively [a.{x}], - returns the element of [a] at index [x]. - [x] must be greater or equal than [0] and strictly less than - [Array1.dim a] if [a] has C layout. If [a] has Fortran layout, - [x] must be greater or equal than [1] and less or equal than - [Array1.dim a]. Otherwise, [Invalid_argument] is raised. *) - - external set: ('a, 'b, 'c) t -> int -> 'a -> unit = "%caml_ba_set_1" - (** [Array1.set a x v], also written [a.{x} <- v], - stores the value [v] at index [x] in [a]. - [x] must be inside the bounds of [a] as described in - {!Bigarray.Array1.get}; - otherwise, [Invalid_argument] is raised. *) - - external sub: ('a, 'b, 'c) t -> int -> int -> ('a, 'b, 'c) t - = "caml_ba_sub" - (** Extract a sub-array of the given one-dimensional big array. - See {!Genarray.sub_left} for more details. *) - - val slice: ('a, 'b, 'c) t -> int -> ('a, 'b, 'c) Array0.t - (** Extract a scalar (zero-dimensional slice) of the given one-dimensional - big array. The integer parameter is the index of the scalar to - extract. See {!Bigarray.Genarray.slice_left} and - {!Bigarray.Genarray.slice_right} for more details. - @since 4.05.0 *) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit - = "caml_ba_blit" - (** Copy the first big array to the second big array. - See {!Genarray.blit} for more details. *) - - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - (** Fill the given big array with the given value. - See {!Genarray.fill} for more details. *) - - val of_array: ('a, 'b) kind -> 'c layout -> 'a array -> ('a, 'b, 'c) t - (** Build a one-dimensional big array initialized from the - given array. *) - + include module type of struct include Stdlib.Bigarray.Array1 end val map_file: Unix.file_descr -> ?pos:int64 -> ('a, 'b) kind -> 'c layout -> bool -> int -> ('a, 'b, 'c) t [@@ocaml.deprecated "\ Use [array1_of_genarray (Unix.map_file ...)] instead.\n\ Note that Bigarray.Array1.map_file raises Sys_error while\n\ Unix.map_file raises Unix_error."] - - external unsafe_get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_unsafe_ref_1" - (** Like {!Bigarray.Array1.get}, but bounds checking is not always performed. - Use with caution and only when the program logic guarantees that - the access is within bounds. *) - - external unsafe_set: ('a, 'b, 'c) t -> int -> 'a -> unit - = "%caml_ba_unsafe_set_1" - (** Like {!Bigarray.Array1.set}, but bounds checking is not always performed. - Use with caution and only when the program logic guarantees that - the access is within bounds. *) - end - -(** {1 Two-dimensional arrays} *) - -(** Two-dimensional arrays. The [Array2] structure provides operations - similar to those of {!Bigarray.Genarray}, but specialized to the - case of two-dimensional arrays. *) -module Array2 : - sig - type ('a, 'b, 'c) t - (** The type of two-dimensional big arrays whose elements have - OCaml type ['a], representation kind ['b], and memory layout ['c]. *) - - val create: ('a, 'b) kind -> 'c layout -> int -> int -> ('a, 'b, 'c) t - (** [Array2.create kind layout dim1 dim2] returns a new bigarray of - two dimension, whose size is [dim1] in the first dimension - and [dim2] in the second dimension. [kind] and [layout] - determine the array element kind and the array layout - as described for {!Bigarray.Genarray.create}. *) - - external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - (** Return the first dimension of the given two-dimensional big array. *) - - external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" - (** Return the second dimension of the given two-dimensional big array. *) - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - (** Return the kind of the given big array. *) - - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - (** Return the layout of the given big array. *) - - val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - (** [Array2.change_layout a layout] returns a bigarray with the - specified [layout], sharing the data with [a] (and hence having - the same dimensions as [a]). No copying of elements is involved: the - new array and the original array share the same storage space. - The dimensions are reversed, such that [get v [| a; b |]] in - C layout becomes [get v [| b+1; a+1 |]] in Fortran layout. - - @since 4.06.0 - *) - - - val size_in_bytes : ('a, 'b, 'c) t -> int - (** [size_in_bytes a] is the number of elements in [a] - multiplied by [a]'s {!kind_size_in_bytes}. - - @since 4.03.0 *) - - external get: ('a, 'b, 'c) t -> int -> int -> 'a = "%caml_ba_ref_2" - (** [Array2.get a x y], also written [a.{x,y}], - returns the element of [a] at coordinates ([x], [y]). - [x] and [y] must be within the bounds - of [a], as described for {!Bigarray.Genarray.get}; - otherwise, [Invalid_argument] is raised. *) - - external set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit = "%caml_ba_set_2" - (** [Array2.set a x y v], or alternatively [a.{x,y} <- v], - stores the value [v] at coordinates ([x], [y]) in [a]. - [x] and [y] must be within the bounds of [a], - as described for {!Bigarray.Genarray.set}; - otherwise, [Invalid_argument] is raised. *) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - (** Extract a two-dimensional sub-array of the given two-dimensional - big array by restricting the first dimension. - See {!Bigarray.Genarray.sub_left} for more details. - [Array2.sub_left] applies only to arrays with C layout. *) - - external sub_right: - ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t - = "caml_ba_sub" - (** Extract a two-dimensional sub-array of the given two-dimensional - big array by restricting the second dimension. - See {!Bigarray.Genarray.sub_right} for more details. - [Array2.sub_right] applies only to arrays with Fortran layout. *) - - val slice_left: ('a, 'b, c_layout) t -> int -> ('a, 'b, c_layout) Array1.t - (** Extract a row (one-dimensional slice) of the given two-dimensional - big array. The integer parameter is the index of the row to - extract. See {!Bigarray.Genarray.slice_left} for more details. - [Array2.slice_left] applies only to arrays with C layout. *) - - val slice_right: - ('a, 'b, fortran_layout) t -> int -> ('a, 'b, fortran_layout) Array1.t - (** Extract a column (one-dimensional slice) of the given - two-dimensional big array. The integer parameter is the - index of the column to extract. See {!Bigarray.Genarray.slice_right} - for more details. [Array2.slice_right] applies only to arrays - with Fortran layout. *) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit - = "caml_ba_blit" - (** Copy the first big array to the second big array. - See {!Bigarray.Genarray.blit} for more details. *) - - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - (** Fill the given big array with the given value. - See {!Bigarray.Genarray.fill} for more details. *) - - val of_array: ('a, 'b) kind -> 'c layout -> 'a array array -> ('a, 'b, 'c) t - (** Build a two-dimensional big array initialized from the - given array of arrays. *) - +module Array2 : sig + include module type of struct include Stdlib.Bigarray.Array2 end val map_file: Unix.file_descr -> ?pos:int64 -> ('a, 'b) kind -> 'c layout -> bool -> int -> int -> ('a, 'b, 'c) t [@@ocaml.deprecated "\ Use [array2_of_genarray (Unix.map_file ...)] instead.\n\ Note that Bigarray.Array2.map_file raises Sys_error while\n\ Unix.map_file raises Unix_error."] - - external unsafe_get: ('a, 'b, 'c) t -> int -> int -> 'a - = "%caml_ba_unsafe_ref_2" - (** Like {!Bigarray.Array2.get}, but bounds checking is not always - performed. *) - - external unsafe_set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit - = "%caml_ba_unsafe_set_2" - (** Like {!Bigarray.Array2.set}, but bounds checking is not always - performed. *) - end -(** {1 Three-dimensional arrays} *) - -(** Three-dimensional arrays. The [Array3] structure provides operations - similar to those of {!Bigarray.Genarray}, but specialized to the case - of three-dimensional arrays. *) -module Array3 : - sig - type ('a, 'b, 'c) t - (** The type of three-dimensional big arrays whose elements have - OCaml type ['a], representation kind ['b], and memory layout ['c]. *) - - val create: ('a, 'b) kind -> 'c layout -> int -> int -> int -> ('a, 'b, 'c) t - (** [Array3.create kind layout dim1 dim2 dim3] returns a new bigarray of - three dimension, whose size is [dim1] in the first dimension, - [dim2] in the second dimension, and [dim3] in the third. - [kind] and [layout] determine the array element kind and - the array layout as described for {!Bigarray.Genarray.create}. *) - - external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" - (** Return the first dimension of the given three-dimensional big array. *) - - external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" - (** Return the second dimension of the given three-dimensional big array. *) - - external dim3: ('a, 'b, 'c) t -> int = "%caml_ba_dim_3" - (** Return the third dimension of the given three-dimensional big array. *) - - external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" - (** Return the kind of the given big array. *) - - external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" - (** Return the layout of the given big array. *) - - - val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t - (** [Array3.change_layout a layout] returns a bigarray with the - specified [layout], sharing the data with [a] (and hence having - the same dimensions as [a]). No copying of elements is involved: the - new array and the original array share the same storage space. - The dimensions are reversed, such that [get v [| a; b; c |]] in - C layout becomes [get v [| c+1; b+1; a+1 |]] in Fortran layout. - - @since 4.06.0 - *) - - val size_in_bytes : ('a, 'b, 'c) t -> int - (** [size_in_bytes a] is the number of elements in [a] - multiplied by [a]'s {!kind_size_in_bytes}. - - @since 4.03.0 *) - - external get: ('a, 'b, 'c) t -> int -> int -> int -> 'a = "%caml_ba_ref_3" - (** [Array3.get a x y z], also written [a.{x,y,z}], - returns the element of [a] at coordinates ([x], [y], [z]). - [x], [y] and [z] must be within the bounds of [a], - as described for {!Bigarray.Genarray.get}; - otherwise, [Invalid_argument] is raised. *) - - external set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit - = "%caml_ba_set_3" - (** [Array3.set a x y v], or alternatively [a.{x,y,z} <- v], - stores the value [v] at coordinates ([x], [y], [z]) in [a]. - [x], [y] and [z] must be within the bounds of [a], - as described for {!Bigarray.Genarray.set}; - otherwise, [Invalid_argument] is raised. *) - - external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t - = "caml_ba_sub" - (** Extract a three-dimensional sub-array of the given - three-dimensional big array by restricting the first dimension. - See {!Bigarray.Genarray.sub_left} for more details. [Array3.sub_left] - applies only to arrays with C layout. *) - - external sub_right: - ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t - = "caml_ba_sub" - (** Extract a three-dimensional sub-array of the given - three-dimensional big array by restricting the second dimension. - See {!Bigarray.Genarray.sub_right} for more details. [Array3.sub_right] - applies only to arrays with Fortran layout. *) - - val slice_left_1: - ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) Array1.t - (** Extract a one-dimensional slice of the given three-dimensional - big array by fixing the first two coordinates. - The integer parameters are the coordinates of the slice to - extract. See {!Bigarray.Genarray.slice_left} for more details. - [Array3.slice_left_1] applies only to arrays with C layout. *) - - val slice_right_1: - ('a, 'b, fortran_layout) t -> - int -> int -> ('a, 'b, fortran_layout) Array1.t - (** Extract a one-dimensional slice of the given three-dimensional - big array by fixing the last two coordinates. - The integer parameters are the coordinates of the slice to - extract. See {!Bigarray.Genarray.slice_right} for more details. - [Array3.slice_right_1] applies only to arrays with Fortran - layout. *) - - val slice_left_2: ('a, 'b, c_layout) t -> int -> ('a, 'b, c_layout) Array2.t - (** Extract a two-dimensional slice of the given three-dimensional - big array by fixing the first coordinate. - The integer parameter is the first coordinate of the slice to - extract. See {!Bigarray.Genarray.slice_left} for more details. - [Array3.slice_left_2] applies only to arrays with C layout. *) - - val slice_right_2: - ('a, 'b, fortran_layout) t -> int -> ('a, 'b, fortran_layout) Array2.t - (** Extract a two-dimensional slice of the given - three-dimensional big array by fixing the last coordinate. - The integer parameter is the coordinate of the slice - to extract. See {!Bigarray.Genarray.slice_right} for more details. - [Array3.slice_right_2] applies only to arrays with Fortran - layout. *) - - external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit - = "caml_ba_blit" - (** Copy the first big array to the second big array. - See {!Bigarray.Genarray.blit} for more details. *) - - external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" - (** Fill the given big array with the given value. - See {!Bigarray.Genarray.fill} for more details. *) - - val of_array: - ('a, 'b) kind -> 'c layout -> 'a array array array -> ('a, 'b, 'c) t - (** Build a three-dimensional big array initialized from the - given array of arrays of arrays. *) - +module Array3 : sig + include module type of struct include Stdlib.Bigarray.Array3 end val map_file: Unix.file_descr -> ?pos:int64 -> ('a, 'b) kind -> 'c layout -> bool -> int -> int -> int -> ('a, 'b, 'c) t [@@ocaml.deprecated "\ Use [array3_of_genarray (Unix.map_file ...)] instead.\n\ Note that Bigarray.Array3.map_file raises Sys_error while\n\ Unix.map_file raises Unix_error."] - - external unsafe_get: ('a, 'b, 'c) t -> int -> int -> int -> 'a - = "%caml_ba_unsafe_ref_3" - (** Like {!Bigarray.Array3.get}, but bounds checking is not always - performed. *) - - external unsafe_set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit - = "%caml_ba_unsafe_set_3" - (** Like {!Bigarray.Array3.set}, but bounds checking is not always - performed. *) - end - -(** {1 Coercions between generic big arrays and fixed-dimension big arrays} *) - -external genarray_of_array0 : - ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t = "%identity" -(** Return the generic big array corresponding to the given zero-dimensional - big array. @since 4.05.0 *) - -external genarray_of_array1 : - ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t = "%identity" -(** Return the generic big array corresponding to the given one-dimensional - big array. *) - -external genarray_of_array2 : - ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t = "%identity" -(** Return the generic big array corresponding to the given two-dimensional - big array. *) - -external genarray_of_array3 : - ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t = "%identity" -(** Return the generic big array corresponding to the given three-dimensional - big array. *) - -val array0_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t -(** Return the zero-dimensional big array corresponding to the given - generic big array. Raise [Invalid_argument] if the generic big array - does not have exactly zero dimension. - @since 4.05.0 *) - -val array1_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t -(** Return the one-dimensional big array corresponding to the given - generic big array. Raise [Invalid_argument] if the generic big array - does not have exactly one dimension. *) - -val array2_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t -(** Return the two-dimensional big array corresponding to the given - generic big array. Raise [Invalid_argument] if the generic big array - does not have exactly two dimensions. *) - -val array3_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t -(** Return the three-dimensional big array corresponding to the given - generic big array. Raise [Invalid_argument] if the generic big array - does not have exactly three dimensions. *) - - -(** {1 Re-shaping big arrays} *) - -val reshape : ('a, 'b, 'c) Genarray.t -> int array -> ('a, 'b, 'c) Genarray.t -(** [reshape b [|d1;...;dN|]] converts the big array [b] to a - [N]-dimensional array of dimensions [d1]...[dN]. The returned - array and the original array [b] share their data - and have the same layout. For instance, assuming that [b] - is a one-dimensional array of dimension 12, [reshape b [|3;4|]] - returns a two-dimensional array [b'] of dimensions 3 and 4. - If [b] has C layout, the element [(x,y)] of [b'] corresponds - to the element [x * 3 + y] of [b]. If [b] has Fortran layout, - the element [(x,y)] of [b'] corresponds to the element - [x + (y - 1) * 4] of [b]. - The returned big array must have exactly the same number of - elements as the original big array [b]. That is, the product - of the dimensions of [b] must be equal to [i1 * ... * iN]. - Otherwise, [Invalid_argument] is raised. *) - -val reshape_0 : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t -(** Specialized version of {!Bigarray.reshape} for reshaping to - zero-dimensional arrays. - @since 4.05.0 *) - -val reshape_1 : ('a, 'b, 'c) Genarray.t -> int -> ('a, 'b, 'c) Array1.t -(** Specialized version of {!Bigarray.reshape} for reshaping to - one-dimensional arrays. *) - -val reshape_2 : ('a, 'b, 'c) Genarray.t -> int -> int -> ('a, 'b, 'c) Array2.t -(** Specialized version of {!Bigarray.reshape} for reshaping to - two-dimensional arrays. *) - -val reshape_3 : - ('a, 'b, 'c) Genarray.t -> int -> int -> int -> ('a, 'b, 'c) Array3.t -(** Specialized version of {!Bigarray.reshape} for reshaping to - three-dimensional arrays. *) diff --git a/otherlibs/bigarray/bigarray_stubs.c b/otherlibs/bigarray/bigarray_stubs.c deleted file mode 100644 index 9f89184c..00000000 --- a/otherlibs/bigarray/bigarray_stubs.c +++ /dev/null @@ -1,820 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Manuel Serrano and Xavier Leroy, INRIA Rocquencourt */ -/* */ -/* Copyright 2000 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -#define CAML_INTERNALS - -#include -#include -#include -#include "caml/alloc.h" -#include "caml/bigarray.h" -#include "caml/custom.h" -#include "caml/fail.h" -#include "caml/intext.h" -#include "caml/hash.h" -#include "caml/memory.h" -#include "caml/mlvalues.h" -#include "caml/signals.h" - -#define int8 caml_ba_int8 -#define uint8 caml_ba_uint8 -#define int16 caml_ba_int16 -#define uint16 caml_ba_uint16 - -/* Allocate a bigarray from OCaml */ - -CAMLprim value caml_ba_create(value vkind, value vlayout, value vdim) -{ - intnat dim[CAML_BA_MAX_NUM_DIMS]; - mlsize_t num_dims; - int i, flags; - - num_dims = Wosize_val(vdim); - /* here num_dims is unsigned (mlsize_t) so no need to check (num_dims >= 0) */ - if (num_dims > CAML_BA_MAX_NUM_DIMS) - caml_invalid_argument("Bigarray.create: bad number of dimensions"); - for (i = 0; i < num_dims; i++) { - dim[i] = Long_val(Field(vdim, i)); - if (dim[i] < 0) - caml_invalid_argument("Bigarray.create: negative dimension"); - } - flags = Caml_ba_kind_val(vkind) | Caml_ba_layout_val(vlayout); - return caml_ba_alloc(flags, num_dims, NULL, dim); -} - -/* Given a big array and a vector of indices, check that the indices - are within the bounds and return the offset of the corresponding - array element in the data part of the array. */ - -static long caml_ba_offset(struct caml_ba_array * b, intnat * index) -{ - intnat offset; - int i; - - offset = 0; - if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { - /* C-style layout: row major, indices start at 0 */ - for (i = 0; i < b->num_dims; i++) { - if ((uintnat) index[i] >= (uintnat) b->dim[i]) - caml_array_bound_error(); - offset = offset * b->dim[i] + index[i]; - } - } else { - /* Fortran-style layout: column major, indices start at 1 */ - for (i = b->num_dims - 1; i >= 0; i--) { - if ((uintnat) (index[i] - 1) >= (uintnat) b->dim[i]) - caml_array_bound_error(); - offset = offset * b->dim[i] + (index[i] - 1); - } - } - return offset; -} - -/* Helper function to allocate a record of two double floats */ - -static value copy_two_doubles(double d0, double d1) -{ - value res = caml_alloc_small(2 * Double_wosize, Double_array_tag); - Store_double_field(res, 0, d0); - Store_double_field(res, 1, d1); - return res; -} - -/* Generic code to read from a big array */ - -value caml_ba_get_N(value vb, value * vind, int nind) -{ - struct caml_ba_array * b = Caml_ba_array_val(vb); - intnat index[CAML_BA_MAX_NUM_DIMS]; - int i; - intnat offset; - - /* Check number of indices = number of dimensions of array - (maybe not necessary if ML typing guarantees this) */ - if (nind != b->num_dims) - caml_invalid_argument("Bigarray.get: wrong number of indices"); - /* Compute offset and check bounds */ - for (i = 0; i < b->num_dims; i++) index[i] = Long_val(vind[i]); - offset = caml_ba_offset(b, index); - /* Perform read */ - switch ((b->flags) & CAML_BA_KIND_MASK) { - default: - CAMLassert(0); - case CAML_BA_FLOAT32: - return caml_copy_double(((float *) b->data)[offset]); - case CAML_BA_FLOAT64: - return caml_copy_double(((double *) b->data)[offset]); - case CAML_BA_SINT8: - return Val_int(((int8 *) b->data)[offset]); - case CAML_BA_UINT8: - return Val_int(((uint8 *) b->data)[offset]); - case CAML_BA_SINT16: - return Val_int(((int16 *) b->data)[offset]); - case CAML_BA_UINT16: - return Val_int(((uint16 *) b->data)[offset]); - case CAML_BA_INT32: - return caml_copy_int32(((int32_t *) b->data)[offset]); - case CAML_BA_INT64: - return caml_copy_int64(((int64_t *) b->data)[offset]); - case CAML_BA_NATIVE_INT: - return caml_copy_nativeint(((intnat *) b->data)[offset]); - case CAML_BA_CAML_INT: - return Val_long(((intnat *) b->data)[offset]); - case CAML_BA_COMPLEX32: - { float * p = ((float *) b->data) + offset * 2; - return copy_two_doubles(p[0], p[1]); } - case CAML_BA_COMPLEX64: - { double * p = ((double *) b->data) + offset * 2; - return copy_two_doubles(p[0], p[1]); } - case CAML_BA_CHAR: - return Val_int(((unsigned char *) b->data)[offset]); - } -} - -CAMLprim value caml_ba_get_1(value vb, value vind1) -{ - return caml_ba_get_N(vb, &vind1, 1); -} - -CAMLprim value caml_ba_get_2(value vb, value vind1, value vind2) -{ - value vind[2]; - vind[0] = vind1; vind[1] = vind2; - return caml_ba_get_N(vb, vind, 2); -} - -CAMLprim value caml_ba_get_3(value vb, value vind1, value vind2, value vind3) -{ - value vind[3]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - return caml_ba_get_N(vb, vind, 3); -} - -#if 0 -CAMLprim value caml_ba_get_4(value vb, value vind1, value vind2, - value vind3, value vind4) -{ - value vind[4]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; vind[3] = vind4; - return caml_ba_get_N(vb, vind, 4); -} - -CAMLprim value caml_ba_get_5(value vb, value vind1, value vind2, - value vind3, value vind4, value vind5) -{ - value vind[5]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - vind[3] = vind4; vind[4] = vind5; - return caml_ba_get_N(vb, vind, 5); -} - -CAMLprim value caml_ba_get_6(value vb, value vind1, value vind2, - value vind3, value vind4, value vind5, value vind6) -{ - value vind[6]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - vind[3] = vind4; vind[4] = vind5; vind[5] = vind6; - return caml_ba_get_N(vb, vind, 6); -} -#endif - -CAMLprim value caml_ba_get_generic(value vb, value vind) -{ - return caml_ba_get_N(vb, &Field(vind, 0), Wosize_val(vind)); -} - - -CAMLprim value caml_ba_uint8_get16(value vb, value vind) -{ - intnat res; - unsigned char b1, b2; - intnat idx = Long_val(vind); - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 1) caml_array_bound_error(); - b1 = ((unsigned char*) b->data)[idx]; - b2 = ((unsigned char*) b->data)[idx+1]; -#ifdef ARCH_BIG_ENDIAN - res = b1 << 8 | b2; -#else - res = b2 << 8 | b1; -#endif - return Val_int(res); -} - -CAMLprim value caml_ba_uint8_get32(value vb, value vind) -{ - intnat res; - unsigned char b1, b2, b3, b4; - intnat idx = Long_val(vind); - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 3) caml_array_bound_error(); - b1 = ((unsigned char*) b->data)[idx]; - b2 = ((unsigned char*) b->data)[idx+1]; - b3 = ((unsigned char*) b->data)[idx+2]; - b4 = ((unsigned char*) b->data)[idx+3]; -#ifdef ARCH_BIG_ENDIAN - res = b1 << 24 | b2 << 16 | b3 << 8 | b4; -#else - res = b4 << 24 | b3 << 16 | b2 << 8 | b1; -#endif - return caml_copy_int32(res); -} - -CAMLprim value caml_ba_uint8_get64(value vb, value vind) -{ - uint64_t res; - unsigned char b1, b2, b3, b4, b5, b6, b7, b8; - intnat idx = Long_val(vind); - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 7) caml_array_bound_error(); - b1 = ((unsigned char*) b->data)[idx]; - b2 = ((unsigned char*) b->data)[idx+1]; - b3 = ((unsigned char*) b->data)[idx+2]; - b4 = ((unsigned char*) b->data)[idx+3]; - b5 = ((unsigned char*) b->data)[idx+4]; - b6 = ((unsigned char*) b->data)[idx+5]; - b7 = ((unsigned char*) b->data)[idx+6]; - b8 = ((unsigned char*) b->data)[idx+7]; -#ifdef ARCH_BIG_ENDIAN - res = (uint64_t) b1 << 56 | (uint64_t) b2 << 48 - | (uint64_t) b3 << 40 | (uint64_t) b4 << 32 - | (uint64_t) b5 << 24 | (uint64_t) b6 << 16 - | (uint64_t) b7 << 8 | (uint64_t) b8; -#else - res = (uint64_t) b8 << 56 | (uint64_t) b7 << 48 - | (uint64_t) b6 << 40 | (uint64_t) b5 << 32 - | (uint64_t) b4 << 24 | (uint64_t) b3 << 16 - | (uint64_t) b2 << 8 | (uint64_t) b1; -#endif - return caml_copy_int64(res); -} - -/* Generic write to a big array */ - -static value caml_ba_set_aux(value vb, value * vind, intnat nind, value newval) -{ - struct caml_ba_array * b = Caml_ba_array_val(vb); - intnat index[CAML_BA_MAX_NUM_DIMS]; - int i; - intnat offset; - - /* Check number of indices = number of dimensions of array - (maybe not necessary if ML typing guarantees this) */ - if (nind != b->num_dims) - caml_invalid_argument("Bigarray.set: wrong number of indices"); - /* Compute offset and check bounds */ - for (i = 0; i < b->num_dims; i++) index[i] = Long_val(vind[i]); - offset = caml_ba_offset(b, index); - /* Perform write */ - switch (b->flags & CAML_BA_KIND_MASK) { - default: - CAMLassert(0); - case CAML_BA_FLOAT32: - ((float *) b->data)[offset] = Double_val(newval); break; - case CAML_BA_FLOAT64: - ((double *) b->data)[offset] = Double_val(newval); break; - case CAML_BA_CHAR: - case CAML_BA_SINT8: - case CAML_BA_UINT8: - ((int8 *) b->data)[offset] = Int_val(newval); break; - case CAML_BA_SINT16: - case CAML_BA_UINT16: - ((int16 *) b->data)[offset] = Int_val(newval); break; - case CAML_BA_INT32: - ((int32_t *) b->data)[offset] = Int32_val(newval); break; - case CAML_BA_INT64: - ((int64_t *) b->data)[offset] = Int64_val(newval); break; - case CAML_BA_NATIVE_INT: - ((intnat *) b->data)[offset] = Nativeint_val(newval); break; - case CAML_BA_CAML_INT: - ((intnat *) b->data)[offset] = Long_val(newval); break; - case CAML_BA_COMPLEX32: - { float * p = ((float *) b->data) + offset * 2; - p[0] = Double_field(newval, 0); - p[1] = Double_field(newval, 1); - break; } - case CAML_BA_COMPLEX64: - { double * p = ((double *) b->data) + offset * 2; - p[0] = Double_field(newval, 0); - p[1] = Double_field(newval, 1); - break; } - } - return Val_unit; -} - -CAMLprim value caml_ba_set_1(value vb, value vind1, value newval) -{ - return caml_ba_set_aux(vb, &vind1, 1, newval); -} - -CAMLprim value caml_ba_set_2(value vb, value vind1, value vind2, value newval) -{ - value vind[2]; - vind[0] = vind1; vind[1] = vind2; - return caml_ba_set_aux(vb, vind, 2, newval); -} - -CAMLprim value caml_ba_set_3(value vb, value vind1, value vind2, value vind3, - value newval) -{ - value vind[3]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - return caml_ba_set_aux(vb, vind, 3, newval); -} - -#if 0 -CAMLprim value caml_ba_set_4(value vb, value vind1, value vind2, - value vind3, value vind4, value newval) -{ - value vind[4]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; vind[3] = vind4; - return caml_ba_set_aux(vb, vind, 4, newval); -} - -CAMLprim value caml_ba_set_5(value vb, value vind1, value vind2, - value vind3, value vind4, value vind5, value newval) -{ - value vind[5]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - vind[3] = vind4; vind[4] = vind5; - return caml_ba_set_aux(vb, vind, 5, newval); -} - -CAMLprim value caml_ba_set_6(value vb, value vind1, value vind2, - value vind3, value vind4, value vind5, - value vind6, value newval) -{ - value vind[6]; - vind[0] = vind1; vind[1] = vind2; vind[2] = vind3; - vind[3] = vind4; vind[4] = vind5; vind[5] = vind6; - return caml_ba_set_aux(vb, vind, 6, newval); -} - -value caml_ba_set_N(value vb, value * vind, int nargs) -{ - return caml_ba_set_aux(vb, vind, nargs - 1, vind[nargs - 1]); -} -#endif - -CAMLprim value caml_ba_set_generic(value vb, value vind, value newval) -{ - return caml_ba_set_aux(vb, &Field(vind, 0), Wosize_val(vind), newval); -} - -CAMLprim value caml_ba_uint8_set16(value vb, value vind, value newval) -{ - unsigned char b1, b2; - intnat val; - intnat idx = Long_val(vind); - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 1) caml_array_bound_error(); - val = Long_val(newval); -#ifdef ARCH_BIG_ENDIAN - b1 = 0xFF & val >> 8; - b2 = 0xFF & val; -#else - b2 = 0xFF & val >> 8; - b1 = 0xFF & val; -#endif - ((unsigned char*) b->data)[idx] = b1; - ((unsigned char*) b->data)[idx+1] = b2; - return Val_unit; -} - -CAMLprim value caml_ba_uint8_set32(value vb, value vind, value newval) -{ - unsigned char b1, b2, b3, b4; - intnat idx = Long_val(vind); - intnat val; - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 3) caml_array_bound_error(); - val = Int32_val(newval); -#ifdef ARCH_BIG_ENDIAN - b1 = 0xFF & val >> 24; - b2 = 0xFF & val >> 16; - b3 = 0xFF & val >> 8; - b4 = 0xFF & val; -#else - b4 = 0xFF & val >> 24; - b3 = 0xFF & val >> 16; - b2 = 0xFF & val >> 8; - b1 = 0xFF & val; -#endif - ((unsigned char*) b->data)[idx] = b1; - ((unsigned char*) b->data)[idx+1] = b2; - ((unsigned char*) b->data)[idx+2] = b3; - ((unsigned char*) b->data)[idx+3] = b4; - return Val_unit; -} - -CAMLprim value caml_ba_uint8_set64(value vb, value vind, value newval) -{ - unsigned char b1, b2, b3, b4, b5, b6, b7, b8; - intnat idx = Long_val(vind); - int64_t val; - struct caml_ba_array * b = Caml_ba_array_val(vb); - if (idx < 0 || idx >= b->dim[0] - 7) caml_array_bound_error(); - val = Int64_val(newval); -#ifdef ARCH_BIG_ENDIAN - b1 = 0xFF & val >> 56; - b2 = 0xFF & val >> 48; - b3 = 0xFF & val >> 40; - b4 = 0xFF & val >> 32; - b5 = 0xFF & val >> 24; - b6 = 0xFF & val >> 16; - b7 = 0xFF & val >> 8; - b8 = 0xFF & val; -#else - b8 = 0xFF & val >> 56; - b7 = 0xFF & val >> 48; - b6 = 0xFF & val >> 40; - b5 = 0xFF & val >> 32; - b4 = 0xFF & val >> 24; - b3 = 0xFF & val >> 16; - b2 = 0xFF & val >> 8; - b1 = 0xFF & val; -#endif - ((unsigned char*) b->data)[idx] = b1; - ((unsigned char*) b->data)[idx+1] = b2; - ((unsigned char*) b->data)[idx+2] = b3; - ((unsigned char*) b->data)[idx+3] = b4; - ((unsigned char*) b->data)[idx+4] = b5; - ((unsigned char*) b->data)[idx+5] = b6; - ((unsigned char*) b->data)[idx+6] = b7; - ((unsigned char*) b->data)[idx+7] = b8; - return Val_unit; -} - -/* Return the number of dimensions of a big array */ - -CAMLprim value caml_ba_num_dims(value vb) -{ - struct caml_ba_array * b = Caml_ba_array_val(vb); - return Val_long(b->num_dims); -} - -/* Return the n-th dimension of a big array */ - -CAMLprim value caml_ba_dim(value vb, value vn) -{ - struct caml_ba_array * b = Caml_ba_array_val(vb); - intnat n = Long_val(vn); - if (n < 0 || n >= b->num_dims) caml_invalid_argument("Bigarray.dim"); - return Val_long(b->dim[n]); -} - -CAMLprim value caml_ba_dim_1(value vb) -{ - return caml_ba_dim(vb, Val_int(0)); -} - -CAMLprim value caml_ba_dim_2(value vb) -{ - return caml_ba_dim(vb, Val_int(1)); -} - -CAMLprim value caml_ba_dim_3(value vb) -{ - return caml_ba_dim(vb, Val_int(2)); -} - -/* Return the kind of a big array */ - -CAMLprim value caml_ba_kind(value vb) -{ - return Val_caml_ba_kind(Caml_ba_array_val(vb)->flags & CAML_BA_KIND_MASK); -} - -/* Return the layout of a big array */ - -CAMLprim value caml_ba_layout(value vb) -{ - int layout = Caml_ba_array_val(vb)->flags & CAML_BA_LAYOUT_MASK; - return Val_caml_ba_layout(layout); -} - -/* Create / update proxy to indicate that b2 is a sub-array of b1 */ - -static void caml_ba_update_proxy(struct caml_ba_array * b1, - struct caml_ba_array * b2) -{ - struct caml_ba_proxy * proxy; - /* Nothing to do for un-managed arrays */ - if ((b1->flags & CAML_BA_MANAGED_MASK) == CAML_BA_EXTERNAL) return; - if (b1->proxy != NULL) { - /* If b1 is already a proxy for a larger array, increment refcount of - proxy */ - b2->proxy = b1->proxy; - ++ b1->proxy->refcount; - } else { - /* Otherwise, create proxy and attach it to both b1 and b2 */ - proxy = malloc(sizeof(struct caml_ba_proxy)); - if (proxy == NULL) caml_raise_out_of_memory(); - proxy->refcount = 2; /* original array + sub array */ - proxy->data = b1->data; - proxy->size = - b1->flags & CAML_BA_MAPPED_FILE ? caml_ba_byte_size(b1) : 0; - b1->proxy = proxy; - b2->proxy = proxy; - } -} - -/* Slicing */ - -CAMLprim value caml_ba_slice(value vb, value vind) -{ - CAMLparam2 (vb, vind); - #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) - CAMLlocal1 (res); - intnat index[CAML_BA_MAX_NUM_DIMS]; - int num_inds, i; - intnat offset; - intnat * sub_dims; - char * sub_data; - - /* Check number of indices <= number of dimensions of array */ - num_inds = Wosize_val(vind); - if (num_inds > b->num_dims) - caml_invalid_argument("Bigarray.slice: too many indices"); - /* Compute offset and check bounds */ - if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { - /* We slice from the left */ - for (i = 0; i < num_inds; i++) index[i] = Long_val(Field(vind, i)); - for (/*nothing*/; i < b->num_dims; i++) index[i] = 0; - offset = caml_ba_offset(b, index); - sub_dims = b->dim + num_inds; - } else { - /* We slice from the right */ - for (i = 0; i < num_inds; i++) - index[b->num_dims - num_inds + i] = Long_val(Field(vind, i)); - for (i = 0; i < b->num_dims - num_inds; i++) index[i] = 1; - offset = caml_ba_offset(b, index); - sub_dims = b->dim; - } - sub_data = - (char *) b->data + - offset * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK]; - /* Allocate an OCaml bigarray to hold the result */ - res = caml_ba_alloc(b->flags, b->num_dims - num_inds, sub_data, sub_dims); - /* Create or update proxy in case of managed bigarray */ - caml_ba_update_proxy(b, Caml_ba_array_val(res)); - /* Return result */ - CAMLreturn (res); - - #undef b -} - -/* Changing the layout of an array (memory is shared) */ - -CAMLprim value caml_ba_change_layout(value vb, value vlayout) -{ - CAMLparam2 (vb, vlayout); - CAMLlocal1 (res); - #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) - /* if the layout is different, change the flags and reverse the dimensions */ - if (Caml_ba_layout_val(vlayout) != (b->flags & CAML_BA_LAYOUT_MASK)) { - /* change the flags to reflect the new layout */ - int flags = (b->flags & (CAML_BA_KIND_MASK | CAML_BA_MANAGED_MASK)) - | Caml_ba_layout_val(vlayout); - /* reverse the dimensions */ - intnat new_dim[CAML_BA_MAX_NUM_DIMS]; - unsigned int i; - for(i = 0; i < b->num_dims; i++) new_dim[i] = b->dim[b->num_dims - i - 1]; - res = caml_ba_alloc(flags, b->num_dims, b->data, new_dim); - caml_ba_update_proxy(b, Caml_ba_array_val(res)); - CAMLreturn(res); - } else { - /* otherwise, do nothing */ - CAMLreturn(vb); - } - #undef b -} - - -/* Extracting a sub-array of same number of dimensions */ - -CAMLprim value caml_ba_sub(value vb, value vofs, value vlen) -{ - CAMLparam3 (vb, vofs, vlen); - CAMLlocal1 (res); - #define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) - intnat ofs = Long_val(vofs); - intnat len = Long_val(vlen); - int i, changed_dim; - intnat mul; - char * sub_data; - - /* Compute offset and check bounds */ - if ((b->flags & CAML_BA_LAYOUT_MASK) == CAML_BA_C_LAYOUT) { - /* We reduce the first dimension */ - mul = 1; - for (i = 1; i < b->num_dims; i++) mul *= b->dim[i]; - changed_dim = 0; - } else { - /* We reduce the last dimension */ - mul = 1; - for (i = 0; i < b->num_dims - 1; i++) mul *= b->dim[i]; - changed_dim = b->num_dims - 1; - ofs--; /* Fortran arrays start at 1 */ - } - if (ofs < 0 || len < 0 || ofs + len > b->dim[changed_dim]) - caml_invalid_argument("Bigarray.sub: bad sub-array"); - sub_data = - (char *) b->data + - ofs * mul * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK]; - /* Allocate an OCaml bigarray to hold the result */ - res = caml_ba_alloc(b->flags, b->num_dims, sub_data, b->dim); - /* Doctor the changed dimension */ - Caml_ba_array_val(res)->dim[changed_dim] = len; - /* Create or update proxy in case of managed bigarray */ - caml_ba_update_proxy(b, Caml_ba_array_val(res)); - /* Return result */ - CAMLreturn (res); - - #undef b -} - -/* Copying a big array into another one */ - -#define LEAVE_RUNTIME_OP_CUTOFF 4096 -#define is_mmapped(ba) ((ba)->flags & CAML_BA_MAPPED_FILE) - -CAMLprim value caml_ba_blit(value vsrc, value vdst) -{ - CAMLparam2(vsrc, vdst); - struct caml_ba_array * src = Caml_ba_array_val(vsrc); - struct caml_ba_array * dst = Caml_ba_array_val(vdst); - void *src_data = src->data; - void *dst_data = dst->data; - int i; - intnat num_bytes; - int leave_runtime; - - /* Check same numbers of dimensions and same dimensions */ - if (src->num_dims != dst->num_dims) goto blit_error; - for (i = 0; i < src->num_dims; i++) - if (src->dim[i] != dst->dim[i]) goto blit_error; - /* Compute number of bytes in array data */ - num_bytes = - caml_ba_num_elts(src) - * caml_ba_element_size[src->flags & CAML_BA_KIND_MASK]; - leave_runtime = - ( - (num_bytes >= LEAVE_RUNTIME_OP_CUTOFF*sizeof(long)) - || is_mmapped(src) - || is_mmapped(dst) - ); - /* Do the copying */ - if (leave_runtime) caml_enter_blocking_section(); - memmove (dst_data, src_data, num_bytes); - if (leave_runtime) caml_leave_blocking_section(); - CAMLreturn (Val_unit); - blit_error: - caml_invalid_argument("Bigarray.blit: dimension mismatch"); - CAMLreturn (Val_unit); /* not reached */ -} - -/* Filling a big array with a given value */ - -#define FILL_GEN_LOOP(n_ops, loop) do{ \ - int leave_runtime = ((n_ops >= LEAVE_RUNTIME_OP_CUTOFF) || is_mmapped(b)); \ - if (leave_runtime) caml_enter_blocking_section(); \ - loop; \ - if (leave_runtime) caml_leave_blocking_section(); \ -}while(0) - -#define FILL_SCALAR_LOOP \ - FILL_GEN_LOOP(num_elts, \ - for (p = data; num_elts > 0; p++, num_elts--) *p = init) - -#define FILL_COMPLEX_LOOP \ - FILL_GEN_LOOP(num_elts + num_elts, \ - for (p = data; num_elts > 0; num_elts--) { *p++ = init0; *p++ = init1; }) - -CAMLprim value caml_ba_fill(value vb, value vinit) -{ - CAMLparam1(vb); - struct caml_ba_array * b = Caml_ba_array_val(vb); - void *data = b->data; - intnat num_elts = caml_ba_num_elts(b); - - switch (b->flags & CAML_BA_KIND_MASK) { - default: - CAMLassert(0); - case CAML_BA_FLOAT32: { - float init = Double_val(vinit); - float * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_FLOAT64: { - double init = Double_val(vinit); - double * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_CHAR: - case CAML_BA_SINT8: - case CAML_BA_UINT8: { - int init = Int_val(vinit); - unsigned char * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_SINT16: - case CAML_BA_UINT16: { - int init = Int_val(vinit); - int16 * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_INT32: { - int32_t init = Int32_val(vinit); - int32_t * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_INT64: { - int64_t init = Int64_val(vinit); - int64_t * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_NATIVE_INT: { - intnat init = Nativeint_val(vinit); - intnat * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_CAML_INT: { - intnat init = Long_val(vinit); - intnat * p; - FILL_SCALAR_LOOP; - break; - } - case CAML_BA_COMPLEX32: { - float init0 = Double_field(vinit, 0); - float init1 = Double_field(vinit, 1); - float * p; - FILL_COMPLEX_LOOP; - break; - } - case CAML_BA_COMPLEX64: { - double init0 = Double_field(vinit, 0); - double init1 = Double_field(vinit, 1); - double * p; - FILL_COMPLEX_LOOP; - break; - } - } - CAMLreturn (Val_unit); -} - -/* Reshape an array: change dimensions and number of dimensions, preserving - array contents */ - -CAMLprim value caml_ba_reshape(value vb, value vdim) -{ - CAMLparam2 (vb, vdim); - CAMLlocal1 (res); -#define b ((struct caml_ba_array *) Caml_ba_array_val(vb)) - intnat dim[CAML_BA_MAX_NUM_DIMS]; - mlsize_t num_dims; - uintnat num_elts; - int i; - - num_dims = Wosize_val(vdim); - /* here num_dims is unsigned (mlsize_t) so no need to check (num_dims >= 0) */ - if (num_dims > CAML_BA_MAX_NUM_DIMS) - caml_invalid_argument("Bigarray.reshape: bad number of dimensions"); - num_elts = 1; - for (i = 0; i < num_dims; i++) { - dim[i] = Long_val(Field(vdim, i)); - if (dim[i] < 0) - caml_invalid_argument("Bigarray.reshape: negative dimension"); - num_elts *= dim[i]; - } - /* Check that sizes agree */ - if (num_elts != caml_ba_num_elts(b)) - caml_invalid_argument("Bigarray.reshape: size mismatch"); - /* Create bigarray with same data and new dimensions */ - res = caml_ba_alloc(b->flags, num_dims, b->data, dim); - /* Create or update proxy in case of managed bigarray */ - caml_ba_update_proxy(b, Caml_ba_array_val(res)); - /* Return result */ - CAMLreturn (res); - -#undef b -} diff --git a/otherlibs/dynlink/Makefile b/otherlibs/dynlink/Makefile index 8c8c3ae4..6ed6c34c 100644 --- a/otherlibs/dynlink/Makefile +++ b/otherlibs/dynlink/Makefile @@ -18,6 +18,8 @@ # FIXME reduce redundancy by including ../Makefile include ../../config/Makefile +include ../../Makefile.common + CAMLRUN ?= ../../boot/ocamlrun CAMLYACC ?= ../../boot/ocamlyacc @@ -43,6 +45,7 @@ COMPILEROBJS=\ ../../utils/arg_helper.cmo ../../utils/clflags.cmo \ ../../utils/tbl.cmo ../../utils/consistbl.cmo \ ../../utils/terminfo.cmo ../../utils/warnings.cmo \ + ../../utils/build_path_prefix_map.cmo \ ../../parsing/asttypes.cmi \ ../../parsing/location.cmo ../../parsing/longident.cmo \ ../../parsing/docstrings.cmo ../../parsing/syntaxerr.cmo \ @@ -87,15 +90,18 @@ dynlink.cmx: dynlink.cmi natdynlink.ml extract_crc: dynlink.cma extract_crc.cmo $(OCAMLC) -o extract_crc dynlink.cma extract_crc.cmo -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) - install: - cp dynlink.cmi dynlink.cmti dynlink.cma dynlink.mli "$(INSTALL_LIBDIR)" - cp extract_crc "$(INSTALL_LIBDIR)/extract_crc$(EXE)" + $(INSTALL_DATA) \ + dynlink.cmi dynlink.cmti dynlink.cma dynlink.mli \ + "$(INSTALL_LIBDIR)" + $(INSTALL_PROG) \ + extract_crc "$(INSTALL_LIBDIR)/extract_crc$(EXE)" installopt: if $(NATDYNLINK); then \ - cp $(NATOBJS) dynlink.cmxa dynlink.$(A) "$(INSTALL_LIBDIR)" && \ + $(INSTALL_DATA) \ + $(NATOBJS) dynlink.cmxa dynlink.$(A) \ + "$(INSTALL_LIBDIR)" && \ cd "$(INSTALL_LIBDIR)" && $(RANLIB) dynlink.$(A); \ fi diff --git a/otherlibs/dynlink/natdynlink.ml b/otherlibs/dynlink/natdynlink.ml index 71aec3f1..fcf748c4 100644 --- a/otherlibs/dynlink/natdynlink.ml +++ b/otherlibs/dynlink/natdynlink.ml @@ -51,7 +51,7 @@ type error = exception Error of error (* Copied from config.ml to avoid dependencies *) -let cmxs_magic_number = "Caml1999D022" +let cmxs_magic_number = "Caml1999D023" let dll_filename fname = if Filename.is_implicit fname then Filename.concat (Sys.getcwd ()) fname diff --git a/otherlibs/raw_spacetime_lib/.depend b/otherlibs/raw_spacetime_lib/.depend index 18fc1804..ea80dabb 100644 --- a/otherlibs/raw_spacetime_lib/.depend +++ b/otherlibs/raw_spacetime_lib/.depend @@ -1,3 +1,14 @@ +spacetime_offline.$(O): spacetime_offline.c ../../byterun/caml/alloc.h \ + ../../byterun/caml/misc.h ../../byterun/caml/config.h \ + ../../byterun/caml/m.h ../../byterun/caml/s.h \ + ../../byterun/caml/mlvalues.h ../../byterun/caml/fail.h \ + ../../byterun/caml/gc.h ../../byterun/caml/intext.h \ + ../../byterun/caml/io.h ../../byterun/caml/major_gc.h \ + ../../byterun/caml/freelist.h ../../byterun/caml/memory.h \ + ../../byterun/caml/minor_gc.h ../../byterun/caml/address_class.h \ + ../../byterun/caml/roots.h ../../byterun/caml/signals.h \ + ../../byterun/caml/stack.h ../../byterun/caml/sys.h \ + ../../byterun/caml/spacetime.h raw_spacetime_lib.cmo : raw_spacetime_lib.cmi raw_spacetime_lib.cmx : raw_spacetime_lib.cmi raw_spacetime_lib.cmi : diff --git a/otherlibs/raw_spacetime_lib/Makefile b/otherlibs/raw_spacetime_lib/Makefile index 4b40cabb..5ba21859 100644 --- a/otherlibs/raw_spacetime_lib/Makefile +++ b/otherlibs/raw_spacetime_lib/Makefile @@ -15,67 +15,19 @@ # Makefile for Raw_spacetime_lib -ROOTDIR=../.. -include $(ROOTDIR)/config/Makefile - -CAMLRUN ?= $(ROOTDIR)/boot/ocamlrun -CAMLC=$(CAMLRUN) $(ROOTDIR)/ocamlc -nostdlib -I $(ROOTDIR)/stdlib -CAMLOPT=$(CAMLRUN) $(ROOTDIR)/ocamlopt -nostdlib \ - -I $(ROOTDIR)/stdlib - -# The remainder of this file could probably be simplified by including -# ../Makefile. - LIBNAME=raw_spacetime_lib +COBJS=spacetime_offline.$(O) CAMLOBJS=raw_spacetime_lib.cmo -COMPFLAGS=-w +33..39 -warn-error A -bin-annot -g -safe-string $(EXTRACAMLFLAGS) - -CMIFILES=$(CAMLOBJS:.cmo=.cmi) -CAMLOBJS_NAT=$(CAMLOBJS:.cmo=.cmx) - -all: $(LIBNAME).cma $(CMIFILES) - -allopt: $(LIBNAME).cmxa $(LIBNAME).$(CMXS) $(CMIFILES) - -$(LIBNAME).cma: $(CAMLOBJS) - $(CAMLC) -a -o $(LIBNAME).cma -linkall $(CAMLOBJS) - -$(LIBNAME).cmxa: $(CAMLOBJS_NAT) - $(CAMLOPT) -a -o $(LIBNAME).cmxa -linkall $(CAMLOBJS_NAT) - -$(LIBNAME).cmxs: $(LIBNAME).cmxa - $(CAMLOPT) -shared -o $(LIBNAME).cmxs -I . $(LIBNAME).cmxa - -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) - -install:: - cp $(LIBNAME).cma $(CMIFILES) $(CMIFILES:.cmi=.mli) $(INSTALL_LIBDIR) - -installopt: - cp $(CAMLOBJS_NAT) $(LIBNAME).cmxa $(LIBNAME).$(A) $(INSTALL_LIBDIR)/ - if test -f $(LIBNAME).cmxs; then \ - cp $(LIBNAME).cmxs $(INSTALL_LIBDIR)/; \ - fi - -partialclean: - rm -f *.cm* - -clean:: partialclean - rm -f *.a *.o - -.SUFFIXES: .ml .mli .cmi .cmo .cmx - -.mli.cmi: - $(CAMLC) -c $(COMPFLAGS) $< - -.ml.cmo: - $(CAMLC) -c $(COMPFLAGS) $< - -.ml.cmx: - $(CAMLOPT) -c $(COMPFLAGS) $< +include ../Makefile +.PHONY: depend depend: - $(CAMLRUN) $(ROOTDIR)/tools/ocamldep *.mli *.ml > .depend +ifeq "$(TOOLCHAIN)" "msvc" + $(error Dependencies cannot be regenerated using the MSVC ports) +else + $(CC) -MM $(CPPFLAGS) *.c | sed -e 's/\.o/.$$(O)/g' > .depend + $(CAMLRUN) $(ROOTDIR)/tools/ocamldep -slash *.mli *.ml >> .depend +endif include .depend diff --git a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml index 2592d393..5ee81fc2 100644 --- a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml +++ b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml @@ -146,8 +146,7 @@ module Trace = struct (* This function unmarshals into malloc blocks, which mean that we obtain a straightforward means of writing [compare] on [node]s. *) external unmarshal : in_channel -> 'a - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_unmarshal_trie" + = "caml_spacetime_unmarshal_trie" let unmarshal in_channel = let trace = unmarshal in_channel in @@ -156,15 +155,11 @@ module Trace = struct else Some ((Obj.magic trace) : node) - let node_is_null (node : node) = - ((Obj.magic node) : unit) == () - let foreign_node_is_null (node : foreign_node) = ((Obj.magic node) : unit) == () external node_num_header_words : unit -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_node_num_header_words" "noalloc" + = "caml_spacetime_node_num_header_words" [@@noalloc] let num_header_words = lazy (node_num_header_words ()) @@ -186,16 +181,14 @@ module Trace = struct | _ -> assert false external annotation : ocaml_node -> int -> Annotation.t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_allocation_point_annotation" - "noalloc" + = "caml_spacetime_ocaml_allocation_point_annotation" + [@@noalloc] let annotation t = annotation t.node t.offset external count : ocaml_node -> int -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_allocation_point_count" - "noalloc" + = "caml_spacetime_ocaml_allocation_point_count" + [@@noalloc] let num_words_including_headers t = count t.node t.offset end @@ -214,15 +207,13 @@ module Trace = struct | _ -> assert false external callee_node : ocaml_node -> int -> 'target - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_direct_call_point_callee_node" + = "caml_spacetime_ocaml_direct_call_point_callee_node" let callee_node (type target) (t : target t) : target = callee_node t.node t.offset external call_count : ocaml_node -> int -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_direct_call_point_call_count" + = "caml_spacetime_ocaml_direct_call_point_call_count" let call_count t = if Shape_table.call_counts t.shape_table then @@ -252,30 +243,26 @@ module Trace = struct (* CR-soon mshinwell: maybe rename ...c_node_call_site -> c_node_pc, since it isn't a call site in this case. *) external callee : foreign_node -> Function_entry_point.t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_call_site" + = "caml_spacetime_c_node_call_site" let callee t = callee t.node (* This can return a node satisfying "is_null" in the case of an uninitialised tail call point. See the comment in the C code. *) external callee_node : foreign_node -> node - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_callee_node" "noalloc" + = "caml_spacetime_c_node_callee_node" [@@noalloc] let callee_node t = callee_node t.node external call_count : foreign_node -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_call_count" + = "caml_spacetime_c_node_call_count" let call_count t = if t.call_counts then Some (call_count t.node) else None external next : foreign_node -> foreign_node - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_next" "noalloc" + = "caml_spacetime_c_node_next" [@@noalloc] let next t = let next = { t with node = next t.node; } in @@ -284,9 +271,8 @@ module Trace = struct end external callees : ocaml_node -> int -> foreign_node - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_indirect_call_point_callees" - "noalloc" + = "caml_spacetime_ocaml_indirect_call_point_callees" + [@@noalloc] let callees t = let callees = @@ -314,13 +300,12 @@ module Trace = struct | Indirect_call of Indirect_call_point.t external classify_direct_call_point : ocaml_node -> int -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_classify_direct_call_point" - "noalloc" + = "caml_spacetime_classify_direct_call_point" + [@@noalloc] let classify t = match t.part_of_shape with - | Shape_table.Direct_call callee -> + | Shape_table.Direct_call _callee -> let direct_call_point = match classify_direct_call_point t.node t.offset with | 0 -> @@ -381,16 +366,13 @@ module Trace = struct type t = ocaml_node external function_identifier : t -> Function_identifier.t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_function_identifier" + = "caml_spacetime_ocaml_function_identifier" external next_in_tail_call_chain : t -> t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_ocaml_tail_chain" "noalloc" + = "caml_spacetime_ocaml_tail_chain" [@@noalloc] external compare : t -> t -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_compare_node" "noalloc" + = "caml_spacetime_compare_node" [@@noalloc] let fields t ~shape_table = let id = function_identifier t in @@ -415,8 +397,7 @@ module Trace = struct type t = foreign_node external compare : t -> t -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_compare_node" "noalloc" + = "caml_spacetime_compare_node" [@@noalloc] let fields t = if foreign_node_is_null t then None @@ -428,29 +409,24 @@ module Trace = struct external program_counter : t -> Program_counter.Foreign.t (* This is not a mistake; the same C function works. *) - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_call_site" + = "caml_spacetime_c_node_call_site" external annotation : t -> Annotation.t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_profinfo" "noalloc" + = "caml_spacetime_c_node_profinfo" [@@noalloc] external num_words_including_headers : t -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_allocation_count" "noalloc" + = "caml_spacetime_c_node_allocation_count" [@@noalloc] end module Call_point = struct type t = foreign_node external call_site : t -> Program_counter.Foreign.t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_call_site" + = "caml_spacetime_c_node_call_site" (* May return a null node. See comment above and the C code. *) external callee_node : t -> node - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_callee_node" "noalloc" + = "caml_spacetime_c_node_callee_node" [@@noalloc] end module Field = struct @@ -461,16 +437,14 @@ module Trace = struct | Call of Call_point.t external is_call : t -> bool - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_is_call" "noalloc" + = "caml_spacetime_c_node_is_call" [@@noalloc] let classify t = if is_call t then Call t else Allocation t external next : t -> t - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_c_node_next" "noalloc" + = "caml_spacetime_c_node_next" [@@noalloc] let next t = let next = next t in @@ -484,8 +458,7 @@ module Trace = struct type t = node external compare : t -> t -> int - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_compare_node" "noalloc" + = "caml_spacetime_compare_node" [@@noalloc] end include T @@ -494,10 +467,8 @@ module Trace = struct | OCaml of OCaml.Node.t | Foreign of Foreign.Node.t - (* CR-soon lwhite: These functions should work in bytecode *) external is_ocaml_node : t -> bool - = "caml_spacetime_only_works_for_native_code" - "caml_spacetime_is_ocaml_node" "noalloc" + = "caml_spacetime_is_ocaml_node" [@@noalloc] let classify t = if is_ocaml_node t then OCaml ((Obj.magic t) : ocaml_node) @@ -601,8 +572,6 @@ module Heap_snapshot = struct call_counts : bool; } - let pathname_suffix_trace = "trace" - (* The order of these constructors must match the C code. *) type what_comes_next = | Snapshot @@ -627,7 +596,7 @@ module Heap_snapshot = struct (Array.of_list (List.rev snapshots)), List.rev events let read ~path = - let chn = open_in path in + let chn = open_in_bin path in let magic_number : int = Marshal.from_channel chn in let magic_number_base = magic_number land 0xffff_ffff in let version_number = (magic_number lsr 32) land 0xffff in diff --git a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli index 051057dd..6bdffffe 100644 --- a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli +++ b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli @@ -324,6 +324,7 @@ module Heap_snapshot : sig val num_words_including_headers : t -> int val next : t -> t option end + (** Total allocations across *all threads*. *) (* CR-someday mshinwell: change the relevant variables to be thread-local *) val total_allocations : t -> Total_allocation.t option diff --git a/asmrun/spacetime_offline.c b/otherlibs/raw_spacetime_lib/spacetime_offline.c similarity index 100% rename from asmrun/spacetime_offline.c rename to otherlibs/raw_spacetime_lib/spacetime_offline.c diff --git a/otherlibs/systhreads/Makefile b/otherlibs/systhreads/Makefile index b641f484..6b163d8f 100644 --- a/otherlibs/systhreads/Makefile +++ b/otherlibs/systhreads/Makefile @@ -16,6 +16,7 @@ ROOTDIR=../.. include $(ROOTDIR)/config/Makefile +include $(ROOTDIR)/Makefile.common CAMLRUN ?= $(ROOTDIR)/boot/ocamlrun CAMLYACC ?= $(ROOTDIR)/boot/ocamlyacc @@ -112,25 +113,29 @@ partialclean: clean: partialclean rm -f dllthreads*$(EXT_DLL) *.$(A) *.$(O) -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) -THREADS_LIBDIR=$(INSTALL_LIBDIR)/$(LIBNAME) -INSTALL_STUBLIBDIR=$(DESTDIR)$(STUBLIBDIR) +INSTALL_THREADSLIBDIR=$(INSTALL_LIBDIR)/$(LIBNAME) install: if test -f dllthreads$(EXT_DLL); then \ - cp dllthreads$(EXT_DLL) "$(INSTALL_STUBLIBDIR)/dllthreads$(EXT_DLL)"; fi - cp libthreads.$(A) "$(INSTALL_LIBDIR)" + $(INSTALL_PROG) \ + dllthreads$(EXT_DLL) "$(INSTALL_STUBLIBDIR)/dllthreads$(EXT_DLL)"; \ + fi + $(INSTALL_DATA) libthreads.$(A) "$(INSTALL_LIBDIR)" cd "$(INSTALL_LIBDIR)"; $(RANLIB) libthreads.$(A) - mkdir -p "$(THREADS_LIBDIR)" - cp $(CMIFILES) $(CMIFILES:.cmi=.cmti) threads.cma "$(THREADS_LIBDIR)" - cp $(MLIFILES) "$(INSTALL_LIBDIR)" - cp threads.h "$(INSTALL_LIBDIR)/caml" + mkdir -p "$(INSTALL_THREADSLIBDIR)" + $(INSTALL_DATA) \ + $(CMIFILES) $(CMIFILES:.cmi=.cmti) threads.cma \ + "$(INSTALL_THREADSLIBDIR)" + $(INSTALL_DATA) $(MLIFILES) "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) threads.h "$(INSTALL_LIBDIR)/caml" installopt: - cp libthreadsnat.$(A) "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) libthreadsnat.$(A) "$(INSTALL_LIBDIR)" cd "$(INSTALL_LIBDIR)"; $(RANLIB) libthreadsnat.$(A) - cp $(THREADS_NCOBJS) threads.cmxa threads.$(A) "$(THREADS_LIBDIR)" - cd "$(THREADS_LIBDIR)" && $(RANLIB) threads.$(A) + $(INSTALL_DATA) \ + $(THREADS_NCOBJS) threads.cmxa threads.$(A) \ + "$(INSTALL_THREADSLIBDIR)" + cd "$(INSTALL_THREADSLIBDIR)" && $(RANLIB) threads.$(A) .SUFFIXES: .ml .mli .cmo .cmi .cmx diff --git a/otherlibs/systhreads/st_posix.h b/otherlibs/systhreads/st_posix.h index e42b50c4..55199338 100644 --- a/otherlibs/systhreads/st_posix.h +++ b/otherlibs/systhreads/st_posix.h @@ -24,6 +24,7 @@ #define _POSIX_PTHREAD_SEMANTICS #endif #include +#include #include #ifdef __linux__ #include @@ -90,8 +91,14 @@ static void st_thread_join(st_thread_id thr) static void INLINE st_thread_yield(void) { -#ifndef __linux__ +#ifdef __linux__ /* sched_yield() doesn't do what we want in Linux 2.6 and up (PR#2663) */ + /* but not doing anything here would actually disable preemption (PR#7669) */ + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 1; + nanosleep(&t, NULL); +#else sched_yield(); #endif } diff --git a/otherlibs/systhreads/thread.ml b/otherlibs/systhreads/thread.ml index ec05f395..bf47d75b 100644 --- a/otherlibs/systhreads/thread.ml +++ b/otherlibs/systhreads/thread.ml @@ -71,7 +71,7 @@ let () = (* Wait functions *) -let delay time = ignore(Unix.select [] [] [] time) +let delay = Unix.sleepf let wait_read fd = () let wait_write fd = () diff --git a/otherlibs/systhreads/thread.mli b/otherlibs/systhreads/thread.mli index 2eb38599..2373e58d 100644 --- a/otherlibs/systhreads/thread.mli +++ b/otherlibs/systhreads/thread.mli @@ -65,11 +65,11 @@ val wait_write : Unix.file_descr -> unit (** This function does nothing in this implementation. *) val wait_timed_read : Unix.file_descr -> float -> bool -(** See {!Thread.wait_timed_read}.*) +(** See {!Thread.wait_timed_write}.*) val wait_timed_write : Unix.file_descr -> float -> bool (** Suspend the execution of the calling thread until at least - one character is available for reading ([wait_read]) or + one character or EOF is available for reading ([wait_read]) or one character can be written without blocking ([wait_write]) on the given Unix file descriptor. Wait for at most the amount of time given as second argument (in seconds). diff --git a/otherlibs/threads/.depend b/otherlibs/threads/.depend index 4e5534c2..af34b81b 100644 --- a/otherlibs/threads/.depend +++ b/otherlibs/threads/.depend @@ -21,13 +21,15 @@ marshal.cmx : mutex.cmo : thread.cmi mutex.cmi mutex.cmx : thread.cmx mutex.cmi mutex.cmi : -pervasives.cmo : unix.cmo -pervasives.cmx : unix.cmx -thread.cmo : unix.cmo thread.cmi +stdlib.cmo : unix.cmi marshal.cmo stdlib.cmi +stdlib.cmx : unix.cmx marshal.cmx stdlib.cmi +stdlib.cmi : marshal.cmo +thread.cmo : unix.cmi thread.cmi thread.cmx : unix.cmx thread.cmi -thread.cmi : unix.cmo -threadUnix.cmo : unix.cmo thread.cmi threadUnix.cmi +thread.cmi : unix.cmi +threadUnix.cmo : unix.cmi thread.cmi threadUnix.cmi threadUnix.cmx : unix.cmx thread.cmx threadUnix.cmi -threadUnix.cmi : unix.cmo -unix.cmo : -unix.cmx : +threadUnix.cmi : unix.cmi +unix.cmo : stdlib.cmi unix.cmi +unix.cmx : stdlib.cmx unix.cmi +unix.cmi : stdlib.cmi diff --git a/otherlibs/threads/Makefile b/otherlibs/threads/Makefile index e6ccbf44..aca35887 100644 --- a/otherlibs/threads/Makefile +++ b/otherlibs/threads/Makefile @@ -16,6 +16,8 @@ # FIXME reduce redundancy by including ../Makefile include ../../config/Makefile +include ../../Makefile.common + CAMLRUN ?= ../../boot/ocamlrun CAMLYACC ?= ../../boot/ocamlyacc @@ -33,22 +35,25 @@ CAML_OBJS=thread.cmo mutex.cmo condition.cmo event.cmo threadUnix.cmo LIB=../../stdlib -LIB_OBJS=$(LIB)/camlinternalFormatBasics.cmo pervasives.cmo \ - $(LIB)/array.cmo $(LIB)/list.cmo $(LIB)/char.cmo $(LIB)/bytes.cmo \ - $(LIB)/string.cmo $(LIB)/sys.cmo $(LIB)/sort.cmo marshal.cmo \ - $(LIB)/obj.cmo $(LIB)/int32.cmo $(LIB)/int64.cmo \ - $(LIB)/nativeint.cmo $(LIB)/lexing.cmo $(LIB)/parsing.cmo \ - $(LIB)/set.cmo $(LIB)/map.cmo $(LIB)/stack.cmo $(LIB)/queue.cmo \ - $(LIB)/camlinternalLazy.cmo $(LIB)/lazy.cmo $(LIB)/stream.cmo \ - $(LIB)/buffer.cmo $(LIB)/camlinternalFormat.cmo $(LIB)/printf.cmo \ - $(LIB)/arg.cmo $(LIB)/printexc.cmo $(LIB)/gc.cmo $(LIB)/digest.cmo \ - $(LIB)/random.cmo $(LIB)/hashtbl.cmo $(LIB)/format.cmo \ - $(LIB)/scanf.cmo $(LIB)/callback.cmo $(LIB)/camlinternalOO.cmo \ - $(LIB)/oo.cmo $(LIB)/camlinternalMod.cmo $(LIB)/genlex.cmo \ - $(LIB)/weak.cmo $(LIB)/ephemeron.cmo $(LIB)/filename.cmo \ - $(LIB)/complex.cmo $(LIB)/arrayLabels.cmo $(LIB)/listLabels.cmo \ - $(LIB)/bytesLabels.cmo $(LIB)/stringLabels.cmo \ - $(LIB)/moreLabels.cmo $(LIB)/stdLabels.cmo +# Object file prefix +P=stdlib__ + +LIB_OBJS=$(LIB)/camlinternalFormatBasics.cmo stdlib.cmo \ + $(LIB)/$(P)seq.cmo $(LIB)/$(P)array.cmo $(LIB)/$(P)list.cmo $(LIB)/$(P)char.cmo $(LIB)/$(P)bytes.cmo \ + $(LIB)/$(P)string.cmo $(LIB)/$(P)sys.cmo $(LIB)/$(P)sort.cmo marshal.cmo \ + $(LIB)/$(P)obj.cmo $(LIB)/$(P)int32.cmo $(LIB)/$(P)int64.cmo \ + $(LIB)/$(P)nativeint.cmo $(LIB)/$(P)lexing.cmo $(LIB)/$(P)parsing.cmo \ + $(LIB)/$(P)set.cmo $(LIB)/$(P)map.cmo $(LIB)/$(P)stack.cmo $(LIB)/$(P)queue.cmo \ + $(LIB)/camlinternalLazy.cmo $(LIB)/$(P)lazy.cmo $(LIB)/$(P)stream.cmo \ + $(LIB)/$(P)buffer.cmo $(LIB)/camlinternalFormat.cmo $(LIB)/$(P)printf.cmo \ + $(LIB)/$(P)arg.cmo $(LIB)/$(P)printexc.cmo $(LIB)/$(P)gc.cmo $(LIB)/$(P)digest.cmo \ + $(LIB)/$(P)random.cmo $(LIB)/$(P)hashtbl.cmo $(LIB)/$(P)format.cmo \ + $(LIB)/$(P)scanf.cmo $(LIB)/$(P)callback.cmo $(LIB)/camlinternalOO.cmo \ + $(LIB)/$(P)oo.cmo $(LIB)/camlinternalMod.cmo $(LIB)/$(P)genlex.cmo \ + $(LIB)/$(P)weak.cmo $(LIB)/$(P)ephemeron.cmo $(LIB)/$(P)filename.cmo \ + $(LIB)/$(P)complex.cmo $(LIB)/$(P)arrayLabels.cmo $(LIB)/$(P)listLabels.cmo \ + $(LIB)/$(P)bytesLabels.cmo $(LIB)/$(P)stringLabels.cmo \ + $(LIB)/$(P)moreLabels.cmo $(LIB)/$(P)stdLabels.cmo UNIXLIB=../unix @@ -70,23 +75,25 @@ stdlib.cma: $(LIB_OBJS) unix.cma: $(UNIXLIB_OBJS) $(MKLIB) -ocamlc '$(CAMLC)' -o unix -linkall $(UNIXLIB_OBJS) -pervasives.cmo: pervasives.mli pervasives.cmi pervasives.ml - $(CAMLC) ${COMPFLAGS} -nopervasives -c pervasives.ml +stdlib.cmo: stdlib.mli stdlib.cmi stdlib.ml + $(CAMLC) ${COMPFLAGS} -nopervasives \ + -pp "$(AWK) -f $(LIB)/expand_module_aliases.awk" -o $@ -c stdlib.ml -pervasives.mli: $(LIB)/pervasives.mli - ln -s $(LIB)/pervasives.mli pervasives.mli +stdlib.mli: $(LIB)/stdlib.mli + ln -s $(LIB)/stdlib.mli stdlib.mli -pervasives.cmi: $(LIB)/pervasives.cmi - ln -s $(LIB)/pervasives.cmi pervasives.cmi +stdlib.cmi: $(LIB)/stdlib.cmi + rm -f stdlib.cmi + ln -s $(LIB)/stdlib.cmi stdlib.cmi -marshal.cmo: marshal.mli marshal.cmi marshal.ml - $(CAMLC) ${COMPFLAGS} -c marshal.ml +$(P)marshal.cmo: marshal.mli $(P)marshal.cmi marshal.ml + $(CAMLC) ${COMPFLAGS} -o$@ -c marshal.ml marshal.mli: $(LIB)/marshal.mli ln -s $(LIB)/marshal.mli marshal.mli -marshal.cmi: $(LIB)/marshal.cmi - ln -s $(LIB)/marshal.cmi marshal.cmi +$(P)marshal.cmi: $(LIB)/$(P)marshal.cmi + ln -s $(LIB)/$(P)marshal.cmi $(P)marshal.cmi unix.mli: $(UNIXLIB)/unix.mli ln -s -f $(UNIXLIB)/unix.mli unix.mli @@ -102,22 +109,21 @@ partialclean: clean: partialclean rm -f libvmthreads.a dllvmthreads.so *.o - rm -f pervasives.mli marshal.mli unix.mli - -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) -INSTALL_STUBLIBDIR=$(DESTDIR)$(STUBLIBDIR) + rm -f stdlib.mli marshal.mli unix.mli CMIFILES=thread.cmi mutex.cmi condition.cmi event.cmi threadUnix.cmi install: if test -f dllvmthreads.so; then \ - cp dllvmthreads.so "$(INSTALL_STUBLIBDIR)"; \ + $(INSTALL_PROG) dllvmthreads.so "$(INSTALL_STUBLIBDIR)"; \ fi mkdir -p "$(INSTALL_LIBDIR)/vmthreads" - cp libvmthreads.a "$(INSTALL_LIBDIR)/vmthreads" + $(INSTALL_DATA) libvmthreads.a "$(INSTALL_LIBDIR)/vmthreads" cd "$(INSTALL_LIBDIR)/vmthreads"; $(RANLIB) libvmthreads.a - cp $(CMIFILES) $(CMIFILES:.cmi=.mli) $(CMIFILES:.cmi=.cmti) \ - threads.cma stdlib.cma unix.cma "$(INSTALL_LIBDIR)/vmthreads" + $(INSTALL_DATA) \ + $(CMIFILES) $(CMIFILES:.cmi=.mli) $(CMIFILES:.cmi=.cmti) \ + threads.cma stdlib.cma unix.cma \ + "$(INSTALL_LIBDIR)/vmthreads" installopt: diff --git a/otherlibs/threads/marshal.ml b/otherlibs/threads/marshal.ml index 88660680..f09be91c 100644 --- a/otherlibs/threads/marshal.ml +++ b/otherlibs/threads/marshal.ml @@ -19,7 +19,7 @@ type extern_flags = | Compat_32 external to_bytes: 'a -> extern_flags list -> bytes - = "caml_output_value_to_string" + = "caml_output_value_to_bytes" external to_string: 'a -> extern_flags list -> string = "caml_output_value_to_string" @@ -37,8 +37,7 @@ let to_buffer buff ofs len v flags = else to_buffer_unsafe buff ofs len v flags external from_channel: in_channel -> 'a = "caml_input_value" -external from_bytes_unsafe: bytes -> int -> 'a - = "caml_input_value_from_string" +external from_bytes_unsafe: bytes -> int -> 'a = "caml_input_value_from_bytes" external data_size_unsafe: bytes -> int -> int = "caml_marshal_data_size" let header_size = 20 diff --git a/otherlibs/threads/pervasives.ml b/otherlibs/threads/pervasives.ml deleted file mode 100644 index 470a1c5c..00000000 --- a/otherlibs/threads/pervasives.ml +++ /dev/null @@ -1,636 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) -(* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Same as ../../stdlib/pervasives.ml, except that I/O functions have - been redefined to not block the whole process, but only the calling - thread. *) - -(* type 'a option = None | Some of 'a *) - -(* Exceptions *) - -external register_named_value : string -> 'a -> unit - = "caml_register_named_value" - -let () = - (* for asmrun/fail.c *) - register_named_value "Pervasives.array_bound_error" - (Invalid_argument "index out of bounds") - - -external raise : exn -> 'a = "%raise" -external raise_notrace : exn -> 'a = "%raise_notrace" - -let failwith s = raise(Failure s) -let invalid_arg s = raise(Invalid_argument s) - -exception Exit - -(* Composition operators *) - -external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" -external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" - -(* Debugging *) - -external __LOC__ : string = "%loc_LOC" -external __FILE__ : string = "%loc_FILE" -external __LINE__ : int = "%loc_LINE" -external __MODULE__ : string = "%loc_MODULE" -external __POS__ : string * int * int * int = "%loc_POS" - -external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" -external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" -external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" - -(* Comparisons *) - -external ( = ) : 'a -> 'a -> bool = "%equal" -external ( <> ) : 'a -> 'a -> bool = "%notequal" -external ( < ) : 'a -> 'a -> bool = "%lessthan" -external ( > ) : 'a -> 'a -> bool = "%greaterthan" -external ( <= ) : 'a -> 'a -> bool = "%lessequal" -external ( >= ) : 'a -> 'a -> bool = "%greaterequal" -external compare : 'a -> 'a -> int = "%compare" - -let min x y = if x <= y then x else y -let max x y = if x >= y then x else y - -external ( == ) : 'a -> 'a -> bool = "%eq" -external ( != ) : 'a -> 'a -> bool = "%noteq" - -(* Boolean operations *) - -external not : bool -> bool = "%boolnot" -external ( & ) : bool -> bool -> bool = "%sequand" -external ( && ) : bool -> bool -> bool = "%sequand" -external ( or ) : bool -> bool -> bool = "%sequor" -external ( || ) : bool -> bool -> bool = "%sequor" - -(* Integer operations *) - -external ( ~- ) : int -> int = "%negint" -external ( ~+ ) : int -> int = "%identity" -external succ : int -> int = "%succint" -external pred : int -> int = "%predint" -external ( + ) : int -> int -> int = "%addint" -external ( - ) : int -> int -> int = "%subint" -external ( * ) : int -> int -> int = "%mulint" -external ( / ) : int -> int -> int = "%divint" -external ( mod ) : int -> int -> int = "%modint" - -let abs x = if x >= 0 then x else -x - -external ( land ) : int -> int -> int = "%andint" -external ( lor ) : int -> int -> int = "%orint" -external ( lxor ) : int -> int -> int = "%xorint" - -let lnot x = x lxor (-1) - -external ( lsl ) : int -> int -> int = "%lslint" -external ( lsr ) : int -> int -> int = "%lsrint" -external ( asr ) : int -> int -> int = "%asrint" - -let max_int = (-1) lsr 1 -let min_int = max_int + 1 - -(* Floating-point operations *) - -external ( ~-. ) : float -> float = "%negfloat" -external ( ~+. ) : float -> float = "%identity" -external ( +. ) : float -> float -> float = "%addfloat" -external ( -. ) : float -> float -> float = "%subfloat" -external ( *. ) : float -> float -> float = "%mulfloat" -external ( /. ) : float -> float -> float = "%divfloat" -external ( ** ) : float -> float -> float = "caml_power_float" "pow" - [@@unboxed] [@@noalloc] -external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] -external expm1 : float -> float = "caml_expm1_float" "caml_expm1" - [@@unboxed] [@@noalloc] -external acos : float -> float = "caml_acos_float" "acos" - [@@unboxed] [@@noalloc] -external asin : float -> float = "caml_asin_float" "asin" - [@@unboxed] [@@noalloc] -external atan : float -> float = "caml_atan_float" "atan" - [@@unboxed] [@@noalloc] -external atan2 : float -> float -> float = "caml_atan2_float" "atan2" - [@@unboxed] [@@noalloc] -external hypot : float -> float -> float - = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] -external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] -external cosh : float -> float = "caml_cosh_float" "cosh" - [@@unboxed] [@@noalloc] -external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] -external log10 : float -> float = "caml_log10_float" "log10" - [@@unboxed] [@@noalloc] -external log1p : float -> float = "caml_log1p_float" "caml_log1p" - [@@unboxed] [@@noalloc] -external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] -external sinh : float -> float = "caml_sinh_float" "sinh" - [@@unboxed] [@@noalloc] -external sqrt : float -> float = "caml_sqrt_float" "sqrt" - [@@unboxed] [@@noalloc] -external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] -external tanh : float -> float = "caml_tanh_float" "tanh" - [@@unboxed] [@@noalloc] -external ceil : float -> float = "caml_ceil_float" "ceil" - [@@unboxed] [@@noalloc] -external floor : float -> float = "caml_floor_float" "floor" - [@@unboxed] [@@noalloc] -external abs_float : float -> float = "%absfloat" -external copysign : float -> float -> float - = "caml_copysign_float" "caml_copysign" - [@@unboxed] [@@noalloc] -external mod_float : float -> float -> float = "caml_fmod_float" "fmod" - [@@unboxed] [@@noalloc] -external frexp : float -> float * int = "caml_frexp_float" -external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = - "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] -external modf : float -> float * float = "caml_modf_float" -external float : int -> float = "%floatofint" -external float_of_int : int -> float = "%floatofint" -external truncate : float -> int = "%intoffloat" -external int_of_float : float -> int = "%intoffloat" -external float_of_bits : int64 -> float - = "caml_int64_float_of_bits" "caml_int64_float_of_bits_unboxed" - [@@unboxed] [@@noalloc] -let infinity = - float_of_bits 0x7F_F0_00_00_00_00_00_00L -let neg_infinity = - float_of_bits 0xFF_F0_00_00_00_00_00_00L -let nan = - float_of_bits 0x7F_F0_00_00_00_00_00_01L -let max_float = - float_of_bits 0x7F_EF_FF_FF_FF_FF_FF_FFL -let min_float = - float_of_bits 0x00_10_00_00_00_00_00_00L -let epsilon_float = - float_of_bits 0x3C_B0_00_00_00_00_00_00L - -type fpclass = - FP_normal - | FP_subnormal - | FP_zero - | FP_infinite - | FP_nan -external classify_float : (float [@unboxed]) -> fpclass = - "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] - -(* String and byte sequence operations -- more in modules String and Bytes *) - -external string_length : string -> int = "%string_length" -external bytes_length : bytes -> int = "%bytes_length" -external bytes_create : int -> bytes = "caml_create_bytes" -external string_blit : string -> int -> bytes -> int -> int -> unit - = "caml_blit_string" [@@noalloc] -external bytes_blit : bytes -> int -> bytes -> int -> int -> unit - = "caml_blit_bytes" [@@noalloc] -external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string" -external bytes_unsafe_of_string : string -> bytes = "%bytes_of_string" - -let ( ^ ) s1 s2 = - let l1 = string_length s1 and l2 = string_length s2 in - let s = bytes_create (l1 + l2) in - string_blit s1 0 s 0 l1; - string_blit s2 0 s l1 l2; - bytes_unsafe_to_string s - -(* Character operations -- more in module Char *) - -external int_of_char : char -> int = "%identity" -external unsafe_char_of_int : int -> char = "%identity" -let char_of_int n = - if n < 0 || n > 255 then invalid_arg "char_of_int" else unsafe_char_of_int n - -(* Unit operations *) - -external ignore : 'a -> unit = "%ignore" - -(* Pair operations *) - -external fst : 'a * 'b -> 'a = "%field0" -external snd : 'a * 'b -> 'b = "%field1" - -(* References *) - -type 'a ref = { mutable contents : 'a } -external ref : 'a -> 'a ref = "%makemutable" -external ( ! ) : 'a ref -> 'a = "%field0" -external ( := ) : 'a ref -> 'a -> unit = "%setfield0" -external incr : int ref -> unit = "%incr" -external decr : int ref -> unit = "%decr" - -(* Result type *) - -type ('a,'b) result = Ok of 'a | Error of 'b - -(* String conversion functions *) - -external format_int : string -> int -> string = "caml_format_int" -external format_float : string -> float -> string = "caml_format_float" - -let string_of_bool b = - if b then "true" else "false" -let bool_of_string = function - | "true" -> true - | "false" -> false - | _ -> invalid_arg "bool_of_string" - -let bool_of_string_opt = function - | "true" -> Some true - | "false" -> Some false - | _ -> None - -let string_of_int n = - format_int "%d" n - -external int_of_string : string -> int = "caml_int_of_string" - -let int_of_string_opt s = - (* TODO: provide this directly as a non-raising primitive. *) - try Some (int_of_string s) - with Failure _ -> None - -external string_get : string -> int -> char = "%string_safe_get" - -let valid_float_lexem s = - let l = string_length s in - let rec loop i = - if i >= l then s ^ "." else - match string_get s i with - | '0' .. '9' | '-' -> loop (i + 1) - | _ -> s - in - loop 0 - -let string_of_float f = valid_float_lexem (format_float "%.12g" f) - -external float_of_string : string -> float = "caml_float_of_string" - -let float_of_string_opt s = - (* TODO: provide this directly as a non-raising primitive. *) - try Some (float_of_string s) - with Failure _ -> None - -(* List operations -- more in module List *) - -let rec ( @ ) l1 l2 = - match l1 with - [] -> l2 - | hd :: tl -> hd :: (tl @ l2) - -(* I/O operations *) - -type in_channel -type out_channel - -external open_descriptor_out : int -> out_channel - = "caml_ml_open_descriptor_out" -external open_descriptor_in : int -> in_channel = "caml_ml_open_descriptor_in" - -let stdin = open_descriptor_in 0 -let stdout = open_descriptor_out 1 -let stderr = open_descriptor_out 2 - -(* Non-blocking stuff *) - -external thread_wait_read_prim : Unix.file_descr -> unit = "thread_wait_read" -external thread_wait_write_prim : Unix.file_descr -> unit = "thread_wait_write" - -let thread_wait_read fd = thread_wait_read_prim fd -let thread_wait_write fd = thread_wait_write_prim fd - -external descr_inchan : in_channel -> Unix.file_descr - = "caml_channel_descriptor" -external descr_outchan : out_channel -> Unix.file_descr - = "caml_channel_descriptor" - -let wait_inchan ic = thread_wait_read (descr_inchan ic) - -let wait_outchan oc len = thread_wait_write (descr_outchan oc) - -(* General output functions *) - -type open_flag = - Open_rdonly | Open_wronly | Open_append - | Open_creat | Open_trunc | Open_excl - | Open_binary | Open_text | Open_nonblock - -external open_desc : string -> open_flag list -> int -> int = "caml_sys_open" - -external set_out_channel_name: out_channel -> string -> unit = - "caml_ml_set_channel_name" - -let open_out_gen mode perm name = - let c = open_descriptor_out(open_desc name mode perm) in - set_out_channel_name c name; - c - -let open_out name = - open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o666 name - -let open_out_bin name = - open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_binary] 0o666 name - -external flush_partial : out_channel -> bool = "caml_ml_flush_partial" - -let rec flush oc = - let success = - try - flush_partial oc - with Sys_blocked_io -> - wait_outchan oc (-1); false in - if success then () else flush oc - -external out_channels_list : unit -> out_channel list - = "caml_ml_out_channels_list" - -let flush_all () = - let rec iter = function - [] -> () - | a::l -> - begin try - flush a - with Sys_error _ -> - () (* ignore channels closed during a preceding flush. *) - end; - iter l - in iter (out_channels_list ()) - -external unsafe_output_partial : out_channel -> bytes -> int -> int -> int - = "caml_ml_output_partial" - -let rec unsafe_output oc buf pos len = - if len > 0 then begin - let written = - try - unsafe_output_partial oc buf pos len - with Sys_blocked_io -> - wait_outchan oc len; 0 in - unsafe_output oc buf (pos + written) (len - written) - end - -external output_char_blocking : out_channel -> char -> unit - = "caml_ml_output_char" -external output_byte_blocking : out_channel -> int -> unit - = "caml_ml_output_char" - -let rec output_char oc c = - try - output_char_blocking oc c - with Sys_blocked_io -> - wait_outchan oc 1; output_char oc c - -let output_bytes oc s = - unsafe_output oc s 0 (bytes_length s) - -let output_string oc s = - unsafe_output oc (bytes_unsafe_of_string s) 0 (string_length s) - -let output oc s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "output" - else unsafe_output oc s ofs len - -let output_substring oc s ofs len = - output oc (bytes_unsafe_of_string s) ofs len - -let rec output_byte oc b = - try - output_byte_blocking oc b - with Sys_blocked_io -> - wait_outchan oc 1; output_byte oc b - -let output_binary_int oc n = - output_byte oc (n asr 24); - output_byte oc (n asr 16); - output_byte oc (n asr 8); - output_byte oc n - -external marshal_to_string : 'a -> unit list -> string - = "caml_output_value_to_string" - -let output_value oc v = output_string oc (marshal_to_string v []) - -external seek_out_blocking : out_channel -> int -> unit = "caml_ml_seek_out" - -let seek_out oc pos = flush oc; seek_out_blocking oc pos - -external pos_out : out_channel -> int = "caml_ml_pos_out" -external out_channel_length : out_channel -> int = "caml_ml_channel_size" -external close_out_channel : out_channel -> unit = "caml_ml_close_channel" -let close_out oc = flush oc; close_out_channel oc -let close_out_noerr oc = - (try flush oc with _ -> ()); - (try close_out_channel oc with _ -> ()) -external set_binary_mode_out : out_channel -> bool -> unit - = "caml_ml_set_binary_mode" - -(* General input functions *) - -external set_in_channel_name: in_channel -> string -> unit = - "caml_ml_set_channel_name" - -let open_in_gen mode perm name = - let c = open_descriptor_in(open_desc name mode perm) in - set_in_channel_name c name; - c - -let open_in name = - open_in_gen [Open_rdonly; Open_text] 0 name - -let open_in_bin name = - open_in_gen [Open_rdonly; Open_binary] 0 name - -external input_char_blocking : in_channel -> char = "caml_ml_input_char" -external input_byte_blocking : in_channel -> int = "caml_ml_input_char" - -let rec input_char ic = - try - input_char_blocking ic - with Sys_blocked_io -> - wait_inchan ic; input_char ic - -external unsafe_input_blocking : in_channel -> bytes -> int -> int -> int - = "caml_ml_input" - -let rec unsafe_input ic s ofs len = - try - unsafe_input_blocking ic s ofs len - with Sys_blocked_io -> - wait_inchan ic; unsafe_input ic s ofs len - -let input ic s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "input" - else unsafe_input ic s ofs len - -let rec unsafe_really_input ic s ofs len = - if len <= 0 then () else begin - let r = unsafe_input ic s ofs len in - if r = 0 - then raise End_of_file - else unsafe_really_input ic s (ofs + r) (len - r) - end - -let really_input ic s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "really_input" - else unsafe_really_input ic s ofs len - -let really_input_string ic len = - let s = bytes_create len in - really_input ic s 0 len; - bytes_unsafe_to_string s - -external bytes_set : bytes -> int -> char -> unit = "%bytes_safe_set" - -let input_line ic = - let buf = ref (bytes_create 128) in - let pos = ref 0 in - begin try - while true do - if !pos = bytes_length !buf then begin - let newbuf = bytes_create (2 * !pos) in - bytes_blit !buf 0 newbuf 0 !pos; - buf := newbuf - end; - let c = input_char ic in - if c = '\n' then raise Exit; - bytes_set !buf !pos c; - incr pos - done - with Exit -> () - | End_of_file -> if !pos = 0 then raise End_of_file - end; - let res = bytes_create !pos in - bytes_blit !buf 0 res 0 !pos; - bytes_unsafe_to_string res - -let rec input_byte ic = - try - input_byte_blocking ic - with Sys_blocked_io -> - wait_inchan ic; input_byte ic - -let input_binary_int ic = - let b1 = input_byte ic in - let n1 = if b1 >= 128 then b1 - 256 else b1 in - let b2 = input_byte ic in - let b3 = input_byte ic in - let b4 = input_byte ic in - (n1 lsl 24) + (b2 lsl 16) + (b3 lsl 8) + b4 - -external unmarshal : bytes -> int -> 'a = "caml_input_value_from_string" -external marshal_data_size : bytes -> int -> int = "caml_marshal_data_size" - -let input_value ic = - let header = bytes_create 20 in - really_input ic header 0 20; - let bsize = marshal_data_size header 0 in - let buffer = bytes_create (20 + bsize) in - bytes_blit header 0 buffer 0 20; - really_input ic buffer 20 bsize; - unmarshal buffer 0 - -external seek_in : in_channel -> int -> unit = "caml_ml_seek_in" -external pos_in : in_channel -> int = "caml_ml_pos_in" -external in_channel_length : in_channel -> int = "caml_ml_channel_size" -external close_in : in_channel -> unit = "caml_ml_close_channel" -let close_in_noerr ic = (try close_in ic with _ -> ()) -external set_binary_mode_in : in_channel -> bool -> unit - = "caml_ml_set_binary_mode" - -(* Output functions on standard output *) - -let print_char c = output_char stdout c -let print_string s = output_string stdout s -let print_bytes s = output_bytes stdout s -let print_int i = output_string stdout (string_of_int i) -let print_float f = output_string stdout (string_of_float f) -let print_endline s = - output_string stdout s; output_char stdout '\n'; flush stdout -let print_newline () = output_char stdout '\n'; flush stdout - -(* Output functions on standard error *) - -let prerr_char c = output_char stderr c -let prerr_string s = output_string stderr s -let prerr_bytes s = output_bytes stderr s -let prerr_int i = output_string stderr (string_of_int i) -let prerr_float f = output_string stderr (string_of_float f) -let prerr_endline s = - output_string stderr s; output_char stderr '\n'; flush stderr -let prerr_newline () = output_char stderr '\n'; flush stderr - -(* Input functions on standard input *) - -let read_line () = flush stdout; input_line stdin -let read_int () = int_of_string(read_line()) -let read_int_opt () = int_of_string_opt(read_line()) -let read_float () = float_of_string(read_line()) -let read_float_opt () = float_of_string_opt(read_line()) - -(* Operations on large files *) - -module LargeFile = - struct - external seek_out : out_channel -> int64 -> unit = "caml_ml_seek_out_64" - external pos_out : out_channel -> int64 = "caml_ml_pos_out_64" - external out_channel_length : out_channel -> int64 - = "caml_ml_channel_size_64" - external seek_in : in_channel -> int64 -> unit = "caml_ml_seek_in_64" - external pos_in : in_channel -> int64 = "caml_ml_pos_in_64" - external in_channel_length : in_channel -> int64 = "caml_ml_channel_size_64" - end - -(* Formats *) - -type ('a, 'b, 'c, 'd, 'e, 'f) format6 - = ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 - = Format of ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.fmt - * string - -type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 - -type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 - -let string_of_format (Format (_fmt, str)) = str - -external format_of_string : - ('a, 'b, 'c, 'd, 'e, 'f) format6 -> - ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" - -let ( ^^ ) (Format (fmt1, str1)) (Format (fmt2, str2)) = - Format (CamlinternalFormatBasics.concat_fmt fmt1 fmt2, - str1 ^ "%," ^ str2) - -(* Miscellaneous *) - -external sys_exit : int -> 'a = "caml_sys_exit" - -let exit_function = ref flush_all - -let at_exit f = - let g = !exit_function in - exit_function := (fun () -> f(); g()) - -let do_at_exit () = (!exit_function) () - -let exit retcode = - do_at_exit (); - sys_exit retcode - -let _ = register_named_value "Pervasives.do_at_exit" do_at_exit diff --git a/otherlibs/threads/stdlib.ml b/otherlibs/threads/stdlib.ml new file mode 100644 index 00000000..a2d2c859 --- /dev/null +++ b/otherlibs/threads/stdlib.ml @@ -0,0 +1,695 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Same as ../../stdlib/stdlib.ml, except that I/O functions have + been redefined to not block the whole process, but only the calling + thread. *) + +module Pervasives = struct +(* type 'a option = None | Some of 'a *) + +(* Exceptions *) + +external register_named_value : string -> 'a -> unit + = "caml_register_named_value" + +let () = + (* for asmrun/fail.c *) + register_named_value "Pervasives.array_bound_error" + (Invalid_argument "index out of bounds") + + +external raise : exn -> 'a = "%raise" +external raise_notrace : exn -> 'a = "%raise_notrace" + +let failwith s = raise(Failure s) +let invalid_arg s = raise(Invalid_argument s) + +exception Exit + +(* Composition operators *) + +external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" +external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" + +(* Debugging *) + +external __LOC__ : string = "%loc_LOC" +external __FILE__ : string = "%loc_FILE" +external __LINE__ : int = "%loc_LINE" +external __MODULE__ : string = "%loc_MODULE" +external __POS__ : string * int * int * int = "%loc_POS" + +external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" +external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" +external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" + +(* Comparisons *) + +external ( = ) : 'a -> 'a -> bool = "%equal" +external ( <> ) : 'a -> 'a -> bool = "%notequal" +external ( < ) : 'a -> 'a -> bool = "%lessthan" +external ( > ) : 'a -> 'a -> bool = "%greaterthan" +external ( <= ) : 'a -> 'a -> bool = "%lessequal" +external ( >= ) : 'a -> 'a -> bool = "%greaterequal" +external compare : 'a -> 'a -> int = "%compare" + +let min x y = if x <= y then x else y +let max x y = if x >= y then x else y + +external ( == ) : 'a -> 'a -> bool = "%eq" +external ( != ) : 'a -> 'a -> bool = "%noteq" + +(* Boolean operations *) + +external not : bool -> bool = "%boolnot" +external ( & ) : bool -> bool -> bool = "%sequand" +external ( && ) : bool -> bool -> bool = "%sequand" +external ( or ) : bool -> bool -> bool = "%sequor" +external ( || ) : bool -> bool -> bool = "%sequor" + +(* Integer operations *) + +external ( ~- ) : int -> int = "%negint" +external ( ~+ ) : int -> int = "%identity" +external succ : int -> int = "%succint" +external pred : int -> int = "%predint" +external ( + ) : int -> int -> int = "%addint" +external ( - ) : int -> int -> int = "%subint" +external ( * ) : int -> int -> int = "%mulint" +external ( / ) : int -> int -> int = "%divint" +external ( mod ) : int -> int -> int = "%modint" + +let abs x = if x >= 0 then x else -x + +external ( land ) : int -> int -> int = "%andint" +external ( lor ) : int -> int -> int = "%orint" +external ( lxor ) : int -> int -> int = "%xorint" + +let lnot x = x lxor (-1) + +external ( lsl ) : int -> int -> int = "%lslint" +external ( lsr ) : int -> int -> int = "%lsrint" +external ( asr ) : int -> int -> int = "%asrint" + +let max_int = (-1) lsr 1 +let min_int = max_int + 1 + +(* Floating-point operations *) + +external ( ~-. ) : float -> float = "%negfloat" +external ( ~+. ) : float -> float = "%identity" +external ( +. ) : float -> float -> float = "%addfloat" +external ( -. ) : float -> float -> float = "%subfloat" +external ( *. ) : float -> float -> float = "%mulfloat" +external ( /. ) : float -> float -> float = "%divfloat" +external ( ** ) : float -> float -> float = "caml_power_float" "pow" + [@@unboxed] [@@noalloc] +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +external expm1 : float -> float = "caml_expm1_float" "caml_expm1" + [@@unboxed] [@@noalloc] +external acos : float -> float = "caml_acos_float" "acos" + [@@unboxed] [@@noalloc] +external asin : float -> float = "caml_asin_float" "asin" + [@@unboxed] [@@noalloc] +external atan : float -> float = "caml_atan_float" "atan" + [@@unboxed] [@@noalloc] +external atan2 : float -> float -> float = "caml_atan2_float" "atan2" + [@@unboxed] [@@noalloc] +external hypot : float -> float -> float + = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] +external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] +external cosh : float -> float = "caml_cosh_float" "cosh" + [@@unboxed] [@@noalloc] +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +external log10 : float -> float = "caml_log10_float" "log10" + [@@unboxed] [@@noalloc] +external log1p : float -> float = "caml_log1p_float" "caml_log1p" + [@@unboxed] [@@noalloc] +external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] +external sinh : float -> float = "caml_sinh_float" "sinh" + [@@unboxed] [@@noalloc] +external sqrt : float -> float = "caml_sqrt_float" "sqrt" + [@@unboxed] [@@noalloc] +external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] +external tanh : float -> float = "caml_tanh_float" "tanh" + [@@unboxed] [@@noalloc] +external ceil : float -> float = "caml_ceil_float" "ceil" + [@@unboxed] [@@noalloc] +external floor : float -> float = "caml_floor_float" "floor" + [@@unboxed] [@@noalloc] +external abs_float : float -> float = "%absfloat" +external copysign : float -> float -> float + = "caml_copysign_float" "caml_copysign" + [@@unboxed] [@@noalloc] +external mod_float : float -> float -> float = "caml_fmod_float" "fmod" + [@@unboxed] [@@noalloc] +external frexp : float -> float * int = "caml_frexp_float" +external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = + "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] +external modf : float -> float * float = "caml_modf_float" +external float : int -> float = "%floatofint" +external float_of_int : int -> float = "%floatofint" +external truncate : float -> int = "%intoffloat" +external int_of_float : float -> int = "%intoffloat" +external float_of_bits : int64 -> float + = "caml_int64_float_of_bits" "caml_int64_float_of_bits_unboxed" + [@@unboxed] [@@noalloc] +let infinity = + float_of_bits 0x7F_F0_00_00_00_00_00_00L +let neg_infinity = + float_of_bits 0xFF_F0_00_00_00_00_00_00L +let nan = + float_of_bits 0x7F_F0_00_00_00_00_00_01L +let max_float = + float_of_bits 0x7F_EF_FF_FF_FF_FF_FF_FFL +let min_float = + float_of_bits 0x00_10_00_00_00_00_00_00L +let epsilon_float = + float_of_bits 0x3C_B0_00_00_00_00_00_00L + +type fpclass = + FP_normal + | FP_subnormal + | FP_zero + | FP_infinite + | FP_nan +external classify_float : (float [@unboxed]) -> fpclass = + "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] + +(* String and byte sequence operations -- more in modules String and Bytes *) + +external string_length : string -> int = "%string_length" +external bytes_length : bytes -> int = "%bytes_length" +external bytes_create : int -> bytes = "caml_create_bytes" +external string_blit : string -> int -> bytes -> int -> int -> unit + = "caml_blit_string" [@@noalloc] +external bytes_blit : bytes -> int -> bytes -> int -> int -> unit + = "caml_blit_bytes" [@@noalloc] +external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string" +external bytes_unsafe_of_string : string -> bytes = "%bytes_of_string" + +let ( ^ ) s1 s2 = + let l1 = string_length s1 and l2 = string_length s2 in + let s = bytes_create (l1 + l2) in + string_blit s1 0 s 0 l1; + string_blit s2 0 s l1 l2; + bytes_unsafe_to_string s + +(* Character operations -- more in module Char *) + +external int_of_char : char -> int = "%identity" +external unsafe_char_of_int : int -> char = "%identity" +let char_of_int n = + if n < 0 || n > 255 then invalid_arg "char_of_int" else unsafe_char_of_int n + +(* Unit operations *) + +external ignore : 'a -> unit = "%ignore" + +(* Pair operations *) + +external fst : 'a * 'b -> 'a = "%field0" +external snd : 'a * 'b -> 'b = "%field1" + +(* References *) + +type 'a ref = { mutable contents : 'a } +external ref : 'a -> 'a ref = "%makemutable" +external ( ! ) : 'a ref -> 'a = "%field0" +external ( := ) : 'a ref -> 'a -> unit = "%setfield0" +external incr : int ref -> unit = "%incr" +external decr : int ref -> unit = "%decr" + +(* Result type *) + +type ('a,'b) result = Ok of 'a | Error of 'b + +(* String conversion functions *) + +external format_int : string -> int -> string = "caml_format_int" +external format_float : string -> float -> string = "caml_format_float" + +let string_of_bool b = + if b then "true" else "false" +let bool_of_string = function + | "true" -> true + | "false" -> false + | _ -> invalid_arg "bool_of_string" + +let bool_of_string_opt = function + | "true" -> Some true + | "false" -> Some false + | _ -> None + +let string_of_int n = + format_int "%d" n + +external int_of_string : string -> int = "caml_int_of_string" + +let int_of_string_opt s = + (* TODO: provide this directly as a non-raising primitive. *) + try Some (int_of_string s) + with Failure _ -> None + +external string_get : string -> int -> char = "%string_safe_get" + +let valid_float_lexem s = + let l = string_length s in + let rec loop i = + if i >= l then s ^ "." else + match string_get s i with + | '0' .. '9' | '-' -> loop (i + 1) + | _ -> s + in + loop 0 + +let string_of_float f = valid_float_lexem (format_float "%.12g" f) + +external float_of_string : string -> float = "caml_float_of_string" + +let float_of_string_opt s = + (* TODO: provide this directly as a non-raising primitive. *) + try Some (float_of_string s) + with Failure _ -> None + +(* List operations -- more in module List *) + +let rec ( @ ) l1 l2 = + match l1 with + [] -> l2 + | hd :: tl -> hd :: (tl @ l2) + +(* I/O operations *) + +type in_channel +type out_channel + +external open_descriptor_out : int -> out_channel + = "caml_ml_open_descriptor_out" +external open_descriptor_in : int -> in_channel = "caml_ml_open_descriptor_in" + +let stdin = open_descriptor_in 0 +let stdout = open_descriptor_out 1 +let stderr = open_descriptor_out 2 + +(* Non-blocking stuff *) + +external thread_wait_read_prim : Unix.file_descr -> unit = "thread_wait_read" +external thread_wait_write_prim : Unix.file_descr -> unit = "thread_wait_write" + +let thread_wait_read fd = thread_wait_read_prim fd +let thread_wait_write fd = thread_wait_write_prim fd + +external descr_inchan : in_channel -> Unix.file_descr + = "caml_channel_descriptor" +external descr_outchan : out_channel -> Unix.file_descr + = "caml_channel_descriptor" + +let wait_inchan ic = thread_wait_read (descr_inchan ic) + +let wait_outchan oc len = thread_wait_write (descr_outchan oc) + +(* General output functions *) + +type open_flag = + Open_rdonly | Open_wronly | Open_append + | Open_creat | Open_trunc | Open_excl + | Open_binary | Open_text | Open_nonblock + +external open_desc : string -> open_flag list -> int -> int = "caml_sys_open" + +external set_out_channel_name: out_channel -> string -> unit = + "caml_ml_set_channel_name" + +let open_out_gen mode perm name = + let c = open_descriptor_out(open_desc name mode perm) in + set_out_channel_name c name; + c + +let open_out name = + open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o666 name + +let open_out_bin name = + open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_binary] 0o666 name + +external flush_partial : out_channel -> bool = "caml_ml_flush_partial" + +let rec flush oc = + let success = + try + flush_partial oc + with Sys_blocked_io -> + wait_outchan oc (-1); false in + if success then () else flush oc + +external out_channels_list : unit -> out_channel list + = "caml_ml_out_channels_list" + +let flush_all () = + let rec iter = function + [] -> () + | a::l -> + begin try + flush a + with Sys_error _ -> + () (* ignore channels closed during a preceding flush. *) + end; + iter l + in iter (out_channels_list ()) + +external unsafe_output_partial : out_channel -> bytes -> int -> int -> int + = "caml_ml_output_partial" + +let rec unsafe_output oc buf pos len = + if len > 0 then begin + let written = + try + unsafe_output_partial oc buf pos len + with Sys_blocked_io -> + wait_outchan oc len; 0 in + unsafe_output oc buf (pos + written) (len - written) + end + +external output_char_blocking : out_channel -> char -> unit + = "caml_ml_output_char" +external output_byte_blocking : out_channel -> int -> unit + = "caml_ml_output_char" + +let rec output_char oc c = + try + output_char_blocking oc c + with Sys_blocked_io -> + wait_outchan oc 1; output_char oc c + +let output_bytes oc s = + unsafe_output oc s 0 (bytes_length s) + +let output_string oc s = + unsafe_output oc (bytes_unsafe_of_string s) 0 (string_length s) + +let output oc s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "output" + else unsafe_output oc s ofs len + +let output_substring oc s ofs len = + output oc (bytes_unsafe_of_string s) ofs len + +let rec output_byte oc b = + try + output_byte_blocking oc b + with Sys_blocked_io -> + wait_outchan oc 1; output_byte oc b + +let output_binary_int oc n = + output_byte oc (n asr 24); + output_byte oc (n asr 16); + output_byte oc (n asr 8); + output_byte oc n + +external marshal_to_string : 'a -> unit list -> string + = "caml_output_value_to_string" + +let output_value oc v = output_string oc (marshal_to_string v []) + +external seek_out_blocking : out_channel -> int -> unit = "caml_ml_seek_out" + +let seek_out oc pos = flush oc; seek_out_blocking oc pos + +external pos_out : out_channel -> int = "caml_ml_pos_out" +external out_channel_length : out_channel -> int = "caml_ml_channel_size" +external close_out_channel : out_channel -> unit = "caml_ml_close_channel" +let close_out oc = flush oc; close_out_channel oc +let close_out_noerr oc = + (try flush oc with _ -> ()); + (try close_out_channel oc with _ -> ()) +external set_binary_mode_out : out_channel -> bool -> unit + = "caml_ml_set_binary_mode" + +(* General input functions *) + +external set_in_channel_name: in_channel -> string -> unit = + "caml_ml_set_channel_name" + +let open_in_gen mode perm name = + let c = open_descriptor_in(open_desc name mode perm) in + set_in_channel_name c name; + c + +let open_in name = + open_in_gen [Open_rdonly; Open_text] 0 name + +let open_in_bin name = + open_in_gen [Open_rdonly; Open_binary] 0 name + +external input_char_blocking : in_channel -> char = "caml_ml_input_char" +external input_byte_blocking : in_channel -> int = "caml_ml_input_char" + +let rec input_char ic = + try + input_char_blocking ic + with Sys_blocked_io -> + wait_inchan ic; input_char ic + +external unsafe_input_blocking : in_channel -> bytes -> int -> int -> int + = "caml_ml_input" + +let rec unsafe_input ic s ofs len = + try + unsafe_input_blocking ic s ofs len + with Sys_blocked_io -> + wait_inchan ic; unsafe_input ic s ofs len + +let input ic s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "input" + else unsafe_input ic s ofs len + +let rec unsafe_really_input ic s ofs len = + if len <= 0 then () else begin + let r = unsafe_input ic s ofs len in + if r = 0 + then raise End_of_file + else unsafe_really_input ic s (ofs + r) (len - r) + end + +let really_input ic s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "really_input" + else unsafe_really_input ic s ofs len + +let really_input_string ic len = + let s = bytes_create len in + really_input ic s 0 len; + bytes_unsafe_to_string s + +external bytes_set : bytes -> int -> char -> unit = "%bytes_safe_set" + +let input_line ic = + let buf = ref (bytes_create 128) in + let pos = ref 0 in + begin try + while true do + if !pos = bytes_length !buf then begin + let newbuf = bytes_create (2 * !pos) in + bytes_blit !buf 0 newbuf 0 !pos; + buf := newbuf + end; + let c = input_char ic in + if c = '\n' then raise Exit; + bytes_set !buf !pos c; + incr pos + done + with Exit -> () + | End_of_file -> if !pos = 0 then raise End_of_file + end; + let res = bytes_create !pos in + bytes_blit !buf 0 res 0 !pos; + bytes_unsafe_to_string res + +let rec input_byte ic = + try + input_byte_blocking ic + with Sys_blocked_io -> + wait_inchan ic; input_byte ic + +let input_binary_int ic = + let b1 = input_byte ic in + let n1 = if b1 >= 128 then b1 - 256 else b1 in + let b2 = input_byte ic in + let b3 = input_byte ic in + let b4 = input_byte ic in + (n1 lsl 24) + (b2 lsl 16) + (b3 lsl 8) + b4 + +external unmarshal : bytes -> int -> 'a = "caml_input_value_from_string" +external marshal_data_size : bytes -> int -> int = "caml_marshal_data_size" + +let input_value ic = + let header = bytes_create 20 in + really_input ic header 0 20; + let bsize = marshal_data_size header 0 in + let buffer = bytes_create (20 + bsize) in + bytes_blit header 0 buffer 0 20; + really_input ic buffer 20 bsize; + unmarshal buffer 0 + +external seek_in : in_channel -> int -> unit = "caml_ml_seek_in" +external pos_in : in_channel -> int = "caml_ml_pos_in" +external in_channel_length : in_channel -> int = "caml_ml_channel_size" +external close_in : in_channel -> unit = "caml_ml_close_channel" +let close_in_noerr ic = (try close_in ic with _ -> ()) +external set_binary_mode_in : in_channel -> bool -> unit + = "caml_ml_set_binary_mode" + +(* Output functions on standard output *) + +let print_char c = output_char stdout c +let print_string s = output_string stdout s +let print_bytes s = output_bytes stdout s +let print_int i = output_string stdout (string_of_int i) +let print_float f = output_string stdout (string_of_float f) +let print_endline s = + output_string stdout s; output_char stdout '\n'; flush stdout +let print_newline () = output_char stdout '\n'; flush stdout + +(* Output functions on standard error *) + +let prerr_char c = output_char stderr c +let prerr_string s = output_string stderr s +let prerr_bytes s = output_bytes stderr s +let prerr_int i = output_string stderr (string_of_int i) +let prerr_float f = output_string stderr (string_of_float f) +let prerr_endline s = + output_string stderr s; output_char stderr '\n'; flush stderr +let prerr_newline () = output_char stderr '\n'; flush stderr + +(* Input functions on standard input *) + +let read_line () = flush stdout; input_line stdin +let read_int () = int_of_string(read_line()) +let read_int_opt () = int_of_string_opt(read_line()) +let read_float () = float_of_string(read_line()) +let read_float_opt () = float_of_string_opt(read_line()) + +(* Operations on large files *) + +module LargeFile = + struct + external seek_out : out_channel -> int64 -> unit = "caml_ml_seek_out_64" + external pos_out : out_channel -> int64 = "caml_ml_pos_out_64" + external out_channel_length : out_channel -> int64 + = "caml_ml_channel_size_64" + external seek_in : in_channel -> int64 -> unit = "caml_ml_seek_in_64" + external pos_in : in_channel -> int64 = "caml_ml_pos_in_64" + external in_channel_length : in_channel -> int64 = "caml_ml_channel_size_64" + end + +(* Formats *) + +type ('a, 'b, 'c, 'd, 'e, 'f) format6 + = ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 + = Format of ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.fmt + * string + +type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 + +type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 + +let string_of_format (Format (_fmt, str)) = str + +external format_of_string : + ('a, 'b, 'c, 'd, 'e, 'f) format6 -> + ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" + +let ( ^^ ) (Format (fmt1, str1)) (Format (fmt2, str2)) = + Format (CamlinternalFormatBasics.concat_fmt fmt1 fmt2, + str1 ^ "%," ^ str2) + +(* Miscellaneous *) + +external sys_exit : int -> 'a = "caml_sys_exit" + +let exit_function = ref flush_all + +let at_exit f = + let g = !exit_function in + (* MPR#7253, MPR#7796: make sure "f" is executed only once *) + let f_already_ran = ref false in + exit_function := + (fun () -> + if not !f_already_ran then begin f_already_ran := true; f() end; + g()) + +let do_at_exit () = (!exit_function) () + +let exit retcode = + do_at_exit (); + sys_exit retcode + +let _ = register_named_value "Pervasives.do_at_exit" do_at_exit +end + +include Pervasives + +(*MODULE_ALIASES*) +module Arg = Arg +module Array = Array +module ArrayLabels = ArrayLabels +module Bigarray = Bigarray +module Buffer = Buffer +module Bytes = Bytes +module BytesLabels = BytesLabels +module Callback = Callback +module Char = Char +module Complex = Complex +module Digest = Digest +module Ephemeron = Ephemeron +module Filename = Filename +module Float = Float +module Format = Format +module Gc = Gc +module Genlex = Genlex +module Hashtbl = Hashtbl +module Int32 = Int32 +module Int64 = Int64 +module Lazy = Lazy +module Lexing = Lexing +module List = List +module ListLabels = ListLabels +module Map = Map +module Marshal = Marshal +module MoreLabels = MoreLabels +module Nativeint = Nativeint +module Obj = Obj +module Oo = Oo +module Parsing = Parsing +module Printexc = Printexc +module Printf = Printf +module Queue = Queue +module Random = Random +module Scanf = Scanf +module Seq = Seq +module Set = Set +module Sort = Sort +module Spacetime = Spacetime +module Stack = Stack +module StdLabels = StdLabels +module Stream = Stream +module String = String +module StringLabels = StringLabels +module Sys = Sys +module Uchar = Uchar +module Weak = Weak diff --git a/otherlibs/threads/thread.mli b/otherlibs/threads/thread.mli index bd9b19e7..a835a0fb 100644 --- a/otherlibs/threads/thread.mli +++ b/otherlibs/threads/thread.mli @@ -65,7 +65,7 @@ val wait_read : Unix.file_descr -> unit val wait_write : Unix.file_descr -> unit (** Suspend the execution of the calling thread until at least - one character is available for reading ({!Thread.wait_read}) or + one character or EOF is available for reading ({!Thread.wait_read}) or one character can be written without blocking ([wait_write]) on the given Unix file descriptor. *) diff --git a/otherlibs/threads/unix.ml b/otherlibs/threads/unix.ml index 28d5a1dc..b4635570 100644 --- a/otherlibs/threads/unix.ml +++ b/otherlibs/threads/unix.ml @@ -321,10 +321,10 @@ module LargeFile = end external map_internal: - file_descr -> ('a, 'b) CamlinternalBigarray.kind - -> 'c CamlinternalBigarray.layout + file_descr -> ('a, 'b) Stdlib.Bigarray.kind + -> 'c Stdlib.Bigarray.layout -> bool -> int array -> int64 - -> ('a, 'b, 'c) CamlinternalBigarray.genarray + -> ('a, 'b, 'c) Stdlib.Bigarray.Genarray.t = "caml_unix_map_file_bytecode" "caml_unix_map_file" let map_file fd ?(pos=0L) kind layout shared dims = diff --git a/otherlibs/unix/getgr.c b/otherlibs/unix/getgr.c index 5aa8762b..5c26fb7a 100644 --- a/otherlibs/unix/getgr.c +++ b/otherlibs/unix/getgr.c @@ -18,6 +18,7 @@ #include #include #include "unixsupport.h" +#include #include #include @@ -44,15 +45,29 @@ CAMLprim value unix_getgrnam(value name) { struct group * entry; if (! caml_string_is_c_safe(name)) caml_raise_not_found(); + errno = 0; entry = getgrnam(String_val(name)); - if (entry == NULL) caml_raise_not_found(); + if (entry == NULL) { + if (errno == EINTR) { + uerror("getgrnam", Nothing); + } else { + caml_raise_not_found(); + } + } return alloc_group_entry(entry); } CAMLprim value unix_getgrgid(value gid) { struct group * entry; + errno = 0; entry = getgrgid(Int_val(gid)); - if (entry == NULL) caml_raise_not_found(); + if (entry == NULL) { + if (errno == EINTR) { + uerror("getgrgid", Nothing); + } else { + caml_raise_not_found(); + } + } return alloc_group_entry(entry); } diff --git a/otherlibs/unix/getpw.c b/otherlibs/unix/getpw.c index b49c23f3..0c0ec80d 100644 --- a/otherlibs/unix/getpw.c +++ b/otherlibs/unix/getpw.c @@ -18,6 +18,7 @@ #include #include #include "unixsupport.h" +#include #include static value alloc_passwd_entry(struct passwd *entry) @@ -52,15 +53,29 @@ CAMLprim value unix_getpwnam(value name) { struct passwd * entry; if (! caml_string_is_c_safe(name)) caml_raise_not_found(); + errno = 0; entry = getpwnam(String_val(name)); - if (entry == (struct passwd *) NULL) caml_raise_not_found(); + if (entry == (struct passwd *) NULL) { + if (errno == EINTR) { + uerror("getpwnam", Nothing); + } else { + caml_raise_not_found(); + } + } return alloc_passwd_entry(entry); } CAMLprim value unix_getpwuid(value uid) { struct passwd * entry; + errno = 0; entry = getpwuid(Int_val(uid)); - if (entry == (struct passwd *) NULL) caml_raise_not_found(); + if (entry == (struct passwd *) NULL) { + if (errno == EINTR) { + uerror("getpwuid", Nothing); + } else { + caml_raise_not_found(); + } + } return alloc_passwd_entry(entry); } diff --git a/otherlibs/unix/unix.ml b/otherlibs/unix/unix.ml index 77a48d1f..95e825b2 100644 --- a/otherlibs/unix/unix.ml +++ b/otherlibs/unix/unix.ml @@ -406,10 +406,10 @@ module LargeFile = end external map_internal: - file_descr -> ('a, 'b) CamlinternalBigarray.kind - -> 'c CamlinternalBigarray.layout + file_descr -> ('a, 'b) Stdlib.Bigarray.kind + -> 'c Stdlib.Bigarray.layout -> bool -> int array -> int64 - -> ('a, 'b, 'c) CamlinternalBigarray.genarray + -> ('a, 'b, 'c) Stdlib.Bigarray.Genarray.t = "caml_unix_map_file_bytecode" "caml_unix_map_file" let map_file fd ?(pos=0L) kind layout shared dims = diff --git a/otherlibs/unix/unix.mli b/otherlibs/unix/unix.mli index bf968126..1e6b475a 100644 --- a/otherlibs/unix/unix.mli +++ b/otherlibs/unix/unix.mli @@ -493,9 +493,9 @@ module LargeFile : (** {6 Mapping files into memory} *) val map_file : - file_descr -> ?pos:int64 -> ('a, 'b) CamlinternalBigarray.kind -> - 'c CamlinternalBigarray.layout -> bool -> int array -> - ('a, 'b, 'c) CamlinternalBigarray.genarray + file_descr -> ?pos:int64 -> ('a, 'b) Stdlib.Bigarray.kind -> + 'c Stdlib.Bigarray.layout -> bool -> int array -> + ('a, 'b, 'c) Stdlib.Bigarray.Genarray.t (** Memory mapping of a file as a big array. [map_file fd kind layout shared dims] returns a big array of kind [kind], layout [layout], diff --git a/otherlibs/unix/unixLabels.mli b/otherlibs/unix/unixLabels.mli index 08b388b3..a78738bb 100644 --- a/otherlibs/unix/unixLabels.mli +++ b/otherlibs/unix/unixLabels.mli @@ -433,9 +433,9 @@ module LargeFile : (** {1 Mapping files into memory} *) val map_file : - file_descr -> ?pos:int64 -> kind:('a, 'b) CamlinternalBigarray.kind -> - layout:'c CamlinternalBigarray.layout -> shared:bool -> dims:int array -> - ('a, 'b, 'c) CamlinternalBigarray.genarray + file_descr -> ?pos:int64 -> kind:('a, 'b) Stdlib.Bigarray.kind -> + layout:'c Stdlib.Bigarray.layout -> shared:bool -> dims:int array -> + ('a, 'b, 'c) Stdlib.Bigarray.Genarray.t (** Memory mapping of a file as a big array. [map_file fd kind layout shared dims] returns a big array of kind [kind], layout [layout], @@ -956,19 +956,19 @@ val getlogin : unit -> string val getpwnam : string -> passwd_entry (** Find an entry in [passwd] with the given name, or raise - [Not_found]. *) + [Not_found] if the matching entry is not found. *) val getgrnam : string -> group_entry (** Find an entry in [group] with the given name, or raise - [Not_found]. *) + [Not_found] if the matching entry is not found. *) val getpwuid : int -> passwd_entry (** Find an entry in [passwd] with the given user id, or raise - [Not_found]. *) + [Not_found] if the matching entry is not found. *) val getgrgid : int -> group_entry (** Find an entry in [group] with the given group id, or raise - [Not_found]. *) + [Not_found] if the matching entry is not found. *) (** {1 Internet addresses} *) diff --git a/otherlibs/unix/utimes.c b/otherlibs/unix/utimes.c index e90555b8..a706fdf6 100644 --- a/otherlibs/unix/utimes.c +++ b/otherlibs/unix/utimes.c @@ -58,21 +58,13 @@ CAMLprim value unix_utimes(value path, value atime, value mtime) #elif defined(HAS_UTIME) #include -#ifndef _WIN32 #include -#else -#include -#endif CAMLprim value unix_utimes(value path, value atime, value mtime) { CAMLparam3(path, atime, mtime); -#ifdef _WIN32 - struct _utimbuf times, * t; -#else struct utimbuf times, * t; -#endif - char_os * p; + char * p; int ret; double at, mt; caml_unix_check_path(path, "utimes"); @@ -85,9 +77,9 @@ CAMLprim value unix_utimes(value path, value atime, value mtime) times.modtime = mt; t = × } - p = caml_stat_strdup_to_os(String_val(path)); + p = caml_stat_strdup(String_val(path)); caml_enter_blocking_section(); - ret = utime_os(p, t); + ret = utime(p, t); caml_leave_blocking_section(); caml_stat_free(p); if (ret == -1) uerror("utimes", path); diff --git a/otherlibs/win32graph/open.c b/otherlibs/win32graph/open.c index e5e988d1..d1db56e0 100644 --- a/otherlibs/win32graph/open.c +++ b/otherlibs/win32graph/open.c @@ -107,7 +107,7 @@ static LRESULT CALLBACK GraphicsWndProc(HWND hwnd,UINT msg,WPARAM wParam, break; } caml_gr_handle_event(msg, wParam, lParam); - return DefWindowProc(hwnd, msg, wParam, lParam); + return DefWindowProcA(hwnd, msg, wParam, lParam); } int DoRegisterClass(void) diff --git a/otherlibs/win32unix/Makefile b/otherlibs/win32unix/Makefile index d2b4ef4b..31607eed 100644 --- a/otherlibs/win32unix/Makefile +++ b/otherlibs/win32unix/Makefile @@ -26,7 +26,7 @@ WIN_FILES = accept.c bind.c channels.c close.c \ select.c sendrecv.c \ shutdown.c sleep.c socket.c sockopt.c startup.c stat.c \ symlink.c system.c times.c unixsupport.c windir.c winwait.c write.c \ - winlist.c winworker.c windbug.c + winlist.c winworker.c windbug.c utimes.c # Files from the ../unix directory UNIX_FILES = access.c addrofstr.c chdir.c chmod.c cst2constr.c \ @@ -34,19 +34,17 @@ UNIX_FILES = access.c addrofstr.c chdir.c chmod.c cst2constr.c \ exit.c getaddrinfo.c getcwd.c gethost.c gethostname.c \ getnameinfo.c getproto.c \ getserv.c gmtime.c mmap_ba.c putenv.c rmdir.c \ - socketaddr.c strofaddr.c time.c unlink.c utimes.c + socketaddr.c strofaddr.c time.c unlink.c UNIX_CAML_FILES = unix.mli unixLabels.mli unixLabels.ml ALL_FILES=$(WIN_FILES) $(UNIX_FILES) -WSOCKLIB=$(call SYSLIB,ws2_32) -ADVAPI32LIB=$(call SYSLIB,advapi32) LIBNAME=unix COBJS=$(ALL_FILES:.c=.$(O)) CAMLOBJS=unix.cmo unixLabels.cmo -LINKOPTS=-cclib $(WSOCKLIB) -cclib $(ADVAPI32LIB) -LDOPTS=-ldopt $(WSOCKLIB) -ldopt $(ADVAPI32LIB) +WIN32_LIBS=$(call SYSLIB,ws2_32) $(call SYSLIB,advapi32) +LINKOPTS=$(addprefix -cclib ,$(WIN32_LIBS)) EXTRACAMLFLAGS=-nolabels EXTRACFLAGS=-I../unix HEADERS=unixsupport.h socketaddr.h @@ -54,6 +52,12 @@ HEADERS=unixsupport.h socketaddr.h include ../Makefile +ifeq "$(SYSTEM)" "mingw" +LDOPTS=-ldopt "-link -static-libgcc" $(addprefix -ldopt ,$(WIN32_LIBS)) +else +LDOPTS=$(addprefix -ldopt ,$(WIN32_LIBS)) +endif + clean:: rm -f $(UNIX_FILES) $(UNIX_CAML_FILES) diff --git a/otherlibs/win32unix/channels.c b/otherlibs/win32unix/channels.c index 2749a766..5dbc86f4 100644 --- a/otherlibs/win32unix/channels.c +++ b/otherlibs/win32unix/channels.c @@ -23,11 +23,6 @@ #include #include -#if defined(_MSC_VER) && !defined(_INTPTR_T_DEFINED) -typedef int intptr_t; -#define _INTPTR_T_DEFINED -#endif - int win_CRT_fd_of_filedescr(value handle) { if (CRT_fd_val(handle) != NO_CRT_FD) { diff --git a/otherlibs/win32unix/envir.c b/otherlibs/win32unix/envir.c index 3324d6d2..5432cb11 100644 --- a/otherlibs/win32unix/envir.c +++ b/otherlibs/win32unix/envir.c @@ -20,15 +20,24 @@ #include #include -#include -#include +#include +/* Win32 doesn't have a notion of setuid bit. */ CAMLprim value unix_environment(value unit) { - /* Win32 doesn't have a notion of setuid bit, so accessing environ is safe. */ - if (_wenviron != NULL) { - return caml_alloc_array((void *)caml_copy_string_of_utf16, (const char**)_wenviron); - } else { - return Atom(0); + CAMLparam0(); + CAMLlocal2(v, result); + wchar_t * envp, * p; + int size, i; + + envp = GetEnvironmentStrings(); + for (p = envp, size = 0; *p; p += wcslen(p) + 1) size++; + result = caml_alloc(size, 0); + for (p = envp, i = 0; *p; p += wcslen(p) + 1) { + v = caml_copy_string_of_utf16(p); + Store_field(result, i ++, v); } + FreeEnvironmentStrings(envp); + + CAMLreturn(result); } diff --git a/otherlibs/win32unix/isatty.c b/otherlibs/win32unix/isatty.c index 5f0999eb..56f6f093 100644 --- a/otherlibs/win32unix/isatty.c +++ b/otherlibs/win32unix/isatty.c @@ -12,13 +12,13 @@ /* */ /**************************************************************************/ +#define CAML_INTERNALS + #include +#include #include "unixsupport.h" CAMLprim value unix_isatty(value fd) { - DWORD lpMode; - HANDLE hFile = Handle_val(fd); - return (Val_bool((GetFileType(hFile) == FILE_TYPE_CHAR) - && GetConsoleMode(hFile, &lpMode))); + return Val_bool(caml_win32_isatty(win_CRT_fd_of_filedescr(fd))); } diff --git a/otherlibs/win32unix/stat.c b/otherlibs/win32unix/stat.c index 94c2490b..bb0381de 100644 --- a/otherlibs/win32unix/stat.c +++ b/otherlibs/win32unix/stat.c @@ -127,8 +127,8 @@ static int convert_time(FILETIME* time, __time64_t* result, __time64_t def) ULARGE_INTEGER utime = {{time->dwLowDateTime, time->dwHighDateTime}}; if (utime.QuadPart) { - /* There are 11644473600000 seconds between 1 January 1601 (the NT Epoch) - * and 1 January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks. + /* There are 11644473600 seconds between 1 January 1601 (the NT Epoch) and 1 + * January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks. */ *result = (utime.QuadPart - INT64_LITERAL(116444736000000000U)); } diff --git a/otherlibs/win32unix/unix.ml b/otherlibs/win32unix/unix.ml index 9d53a8e5..b999dd72 100644 --- a/otherlibs/win32unix/unix.ml +++ b/otherlibs/win32unix/unix.ml @@ -299,10 +299,10 @@ module LargeFile = (* Mapping files into memory *) external map_internal: - file_descr -> ('a, 'b) CamlinternalBigarray.kind - -> 'c CamlinternalBigarray.layout + file_descr -> ('a, 'b) Stdlib.Bigarray.kind + -> 'c Stdlib.Bigarray.layout -> bool -> int array -> int64 - -> ('a, 'b, 'c) CamlinternalBigarray.genarray + -> ('a, 'b, 'c) Stdlib.Bigarray.Genarray.t = "caml_unix_map_file_bytecode" "caml_unix_map_file" let map_file fd ?(pos=0L) kind layout shared dims = diff --git a/otherlibs/win32unix/utimes.c b/otherlibs/win32unix/utimes.c new file mode 100644 index 00000000..486119d4 --- /dev/null +++ b/otherlibs/win32unix/utimes.c @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Nicolas Ojeda Bar, LexiFi */ +/* */ +/* Copyright 2017 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#define CAML_INTERNALS + +#include +#include +#include +#include +#include +#include "unixsupport.h" + +#include + +static void convert_time(double unixTime, FILETIME* ft) +{ + ULARGE_INTEGER u; + /* There are 11644473600 seconds between 1 January 1601 (the NT Epoch) and 1 + * January 1970 (the Unix Epoch). FILETIME is measured in 100ns ticks. + */ + u.QuadPart = (ULONGLONG)(unixTime * 10000000.0) + INT64_LITERAL(116444736000000000U); + ft->dwLowDateTime = u.LowPart; + ft->dwHighDateTime = u.HighPart; +} + +CAMLprim value unix_utimes(value path, value atime, value mtime) +{ + CAMLparam3(path, atime, mtime); + WCHAR *wpath; + HANDLE hFile; + FILETIME lastAccessTime, lastModificationTime; + SYSTEMTIME systemTime; + double at, mt; + BOOL res; + + caml_unix_check_path(path, "utimes"); + at = Double_val(atime); + mt = Double_val(mtime); + wpath = caml_stat_strdup_to_utf16(String_val(path)); + caml_enter_blocking_section(); + hFile = CreateFile(wpath, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + caml_leave_blocking_section(); + caml_stat_free(wpath); + if (hFile == INVALID_HANDLE_VALUE) { + win32_maperr(GetLastError()); + uerror("utimes", path); + } + if (at == 0.0 && mt == 0.0) { + GetSystemTime(&systemTime); + SystemTimeToFileTime(&systemTime, &lastAccessTime); + memcpy(&lastModificationTime, &lastAccessTime, sizeof(FILETIME)); + } else { + convert_time(at, &lastAccessTime); + convert_time(mt, &lastModificationTime); + } + caml_enter_blocking_section(); + res = SetFileTime(hFile, NULL, &lastAccessTime, &lastModificationTime); + caml_leave_blocking_section(); + if (res == 0) { + win32_maperr(GetLastError()); + CloseHandle(hFile); + uerror("utimes", path); + } + CloseHandle(hFile); + CAMLreturn(Val_unit); +} diff --git a/parsing/ast_invariants.ml b/parsing/ast_invariants.ml index 31ee17eb..32e5f8fc 100644 --- a/parsing/ast_invariants.ml +++ b/parsing/ast_invariants.ml @@ -19,7 +19,6 @@ open Ast_iterator let err = Syntaxerr.ill_formed_ast let empty_record loc = err loc "Records cannot be empty." -let empty_variant loc = err loc "Variant types cannot be empty." let invalid_tuple loc = err loc "Tuples must have at least 2 components." let no_args loc = err loc "Function application with no argument." let empty_let loc = err loc "Let with no bindings." @@ -41,7 +40,6 @@ let iterator = let loc = td.ptype_loc in match td.ptype_kind with | Ptype_record [] -> empty_record loc - | Ptype_variant [] -> empty_variant loc | _ -> () in let typ self ty = diff --git a/parsing/depend.ml b/parsing/depend.ml index e0851d76..9e872fbc 100644 --- a/parsing/depend.ml +++ b/parsing/depend.ml @@ -87,7 +87,7 @@ let add_parent bv lid = let add = add_parent -let addmodule bv lid = add_path bv lid.txt +let add_module_path bv lid = add_path bv lid.txt let handle_extension ext = match (fst ext).txt with @@ -266,7 +266,7 @@ let rec add_expr bv exp = | Pexp_object { pcstr_self = pat; pcstr_fields = fieldl } -> let bv = add_pattern bv pat in List.iter (add_class_field bv) fieldl | Pexp_newtype (_, e) -> add_expr bv e - | Pexp_pack m -> add_module bv m + | Pexp_pack m -> add_module_expr bv m | Pexp_open (_ovf, m, e) -> let bv = open_module bv m.txt in add_expr bv e | Pexp_extension (({ txt = ("ocaml.extension_constructor"| @@ -296,7 +296,7 @@ and add_bindings recf bv pel = and add_modtype bv mty = match mty.pmty_desc with Pmty_ident l -> add bv l - | Pmty_alias l -> addmodule bv l + | Pmty_alias l -> add_module_path bv l | Pmty_signature s -> add_signature bv s | Pmty_functor(id, mty1, mty2) -> Misc.may (add_modtype bv) mty1; @@ -306,25 +306,26 @@ and add_modtype bv mty = List.iter (function | Pwith_type (_, td) -> add_type_declaration bv td - | Pwith_module (_, lid) -> addmodule bv lid + | Pwith_module (_, lid) -> add_module_path bv lid | Pwith_typesubst (_, td) -> add_type_declaration bv td - | Pwith_modsubst (_, lid) -> addmodule bv lid + | Pwith_modsubst (_, lid) -> add_module_path bv lid ) cstrl - | Pmty_typeof m -> add_module bv m + | Pmty_typeof m -> add_module_expr bv m | Pmty_extension e -> handle_extension e and add_module_alias bv l = + (* If we are in delayed dependencies mode, we delay the dependencies + induced by "Lident s" *) + (if !Clflags.transparent_modules then add_parent else add_module_path) bv l; try - add_parent bv l; lookup_map l.txt bv with Not_found -> match l.txt with Lident s -> make_leaf s - | _ -> addmodule bv l; bound (* cannot delay *) + | _ -> add_module_path bv l; bound (* cannot delay *) and add_modtype_binding bv mty = - if not !Clflags.transparent_modules then add_modtype bv mty; match mty.pmty_desc with Pmty_alias l -> add_module_alias bv l @@ -333,7 +334,7 @@ and add_modtype_binding bv mty = | Pmty_typeof modl -> add_module_binding bv modl | _ -> - if !Clflags.transparent_modules then add_modtype bv mty; bound + add_modtype bv mty; bound and add_signature bv sg = ignore (add_signature_binding bv sg) @@ -386,33 +387,23 @@ and add_sig_item (bv, m) item = (bv, m) and add_module_binding bv modl = - if not !Clflags.transparent_modules then add_module bv modl; match modl.pmod_desc with - Pmod_ident l -> - begin try - add_parent bv l; - lookup_map l.txt bv - with Not_found -> - match l.txt with - Lident s -> make_leaf s - | _ -> addmodule bv l; bound - end + Pmod_ident l -> add_module_alias bv l | Pmod_structure s -> - make_node (snd (add_structure_binding bv s)) - | _ -> - if !Clflags.transparent_modules then add_module bv modl; bound + make_node (snd @@ add_structure_binding bv s) + | _ -> add_module_expr bv modl; bound -and add_module bv modl = +and add_module_expr bv modl = match modl.pmod_desc with - Pmod_ident l -> addmodule bv l + Pmod_ident l -> add_module_path bv l | Pmod_structure s -> ignore (add_structure bv s) | Pmod_functor(id, mty, modl) -> Misc.may (add_modtype bv) mty; - add_module (StringMap.add id.txt bound bv) modl + add_module_expr (StringMap.add id.txt bound bv) modl | Pmod_apply(mod1, mod2) -> - add_module bv mod1; add_module bv mod2 + add_module_expr bv mod1; add_module_expr bv mod2 | Pmod_constraint(modl, mty) -> - add_module bv modl; add_modtype bv mty + add_module_expr bv modl; add_modtype bv mty | Pmod_unpack(e) -> add_expr bv e | Pmod_extension e -> @@ -451,7 +442,7 @@ and add_struct_item (bv, m) item : _ StringMap.t * _ StringMap.t = in let bv' = add bv and m = add m in List.iter - (fun x -> add_module bv' x.pmb_expr) + (fun x -> add_module_expr bv' x.pmb_expr) bindings; (bv', m) | Pstr_modtype x -> @@ -467,8 +458,13 @@ and add_struct_item (bv, m) item : _ StringMap.t * _ StringMap.t = | Pstr_class_type cdtl -> List.iter (add_class_type_declaration bv) cdtl; (bv, m) | Pstr_include incl -> - let Node (s, m') = add_module_binding bv incl.pincl_mod in - add_names s; + let Node (s, m') as n = add_module_binding bv incl.pincl_mod in + if !Clflags.transparent_modules then + add_names s + else + (* If we are not in the delayed dependency mode, we need to + collect all delayed dependencies imported by the include statement *) + add_names (collect_free n); let add = StringMap.fold StringMap.add m' in (add bv, add m) | Pstr_attribute _ -> (bv, m) @@ -480,9 +476,7 @@ and add_use_file bv top_phrs = ignore (List.fold_left add_top_phrase bv top_phrs) and add_implementation bv l = - if !Clflags.transparent_modules then ignore (add_structure_binding bv l) - else ignore (add_structure bv l) and add_implementation_binding bv l = snd (add_structure_binding bv l) diff --git a/parsing/docstrings.ml b/parsing/docstrings.ml index 5de6d4d4..d70b0bfa 100644 --- a/parsing/docstrings.ml +++ b/parsing/docstrings.ml @@ -243,6 +243,12 @@ let get_text pos = get_docstrings dsl with Not_found -> [] +let get_post_text pos = + try + let dsl = Hashtbl.find post_table pos in + get_docstrings dsl + with Not_found -> [] + (* Maps from positions to extra docstrings *) let pre_extra_table : (Lexing.position, docstring list) Hashtbl.t = @@ -315,6 +321,9 @@ let symbol_text_lazy () = let rhs_text pos = get_text (Parsing.rhs_start_pos pos) +let rhs_post_text pos = + get_post_text (Parsing.rhs_end_pos pos) + let rhs_text_lazy pos = let pos = Parsing.rhs_start_pos pos in lazy (get_text pos) diff --git a/parsing/docstrings.mli b/parsing/docstrings.mli index 892a80e2..49cea954 100644 --- a/parsing/docstrings.mli +++ b/parsing/docstrings.mli @@ -155,3 +155,6 @@ val rhs_pre_extra_text : int -> text (** Fetch additional text following the symbol at the given position *) val rhs_post_extra_text : int -> text + +(** Fetch text following the symbol at the given position *) +val rhs_post_text : int -> text diff --git a/parsing/lexer.mll b/parsing/lexer.mll index 1e385a04..89079d4b 100644 --- a/parsing/lexer.mll +++ b/parsing/lexer.mll @@ -439,25 +439,12 @@ rule token = parse lexbuf.lex_curr_p <- { curpos with pos_cnum = curpos.pos_cnum - 1 }; STAR } - | ("#" [' ' '\t']* (['0'-'9']+ as num) [' ' '\t']* - ("\"" ([^ '\010' '\013' '\"' ] * as name) "\"")?) as directive - [^ '\010' '\013'] * newline - { - match int_of_string num with - | exception _ -> - (* PR#7165 *) - let loc = Location.curr lexbuf in - let explanation = "line number out of range" in - let error = Invalid_directive (directive, Some explanation) in - raise (Error (error, loc)) - | line_num -> - (* Documentation says that the line number should be - positive, but we have never guarded against this and it - might have useful hackish uses. *) - update_loc lexbuf name line_num true 0; - token lexbuf + | "#" + { let at_beginning_of_line pos = (pos.pos_cnum = pos.pos_bol) in + if not (at_beginning_of_line lexbuf.lex_start_p) + then HASH + else try directive lexbuf with Failure _ -> HASH } - | "#" { HASH } | "&" { AMPERSAND } | "&&" { AMPERAMPER } | "`" { BACKQUOTE } @@ -529,6 +516,25 @@ rule token = parse Location.curr lexbuf)) } +and directive = parse + | ([' ' '\t']* (['0'-'9']+ as num) [' ' '\t']* + ("\"" ([^ '\010' '\013' '\"' ] * as name) "\"") as directive) + [^ '\010' '\013'] * + { + match int_of_string num with + | exception _ -> + (* PR#7165 *) + let loc = Location.curr lexbuf in + let explanation = "line number out of range" in + let error = Invalid_directive ("#" ^ directive, Some explanation) in + raise (Error (error, loc)) + | line_num -> + (* Documentation says that the line number should be + positive, but we have never guarded against this and it + might have useful hackish uses. *) + update_loc lexbuf (Some name) (line_num - 1) true 0; + token lexbuf + } and comment = parse "(*" { comment_start_loc := (Location.curr lexbuf) :: !comment_start_loc; diff --git a/parsing/location.ml b/parsing/location.ml index 7fd915ce..35184547 100644 --- a/parsing/location.ml +++ b/parsing/location.ml @@ -93,7 +93,7 @@ let print_updating_num_loc_lines ppf f arg = (* Highlight the locations using standout mode. *) -let highlight_terminfo ppf num_lines lb locs = +let highlight_terminfo ppf lb locs = Format.pp_print_flush ppf (); (* avoid mixing Format and normal output *) (* Char 0 is at offset -lb.lex_abs_pos in lb.lex_buffer. *) let pos0 = -lb.lex_abs_pos in @@ -105,31 +105,31 @@ let highlight_terminfo ppf num_lines lb locs = if Bytes.get lb.lex_buffer i = '\n' then incr lines done; (* If too many lines, give up *) - if !lines >= num_lines - 2 then raise Exit; + if !lines >= Terminfo.num_lines stdout - 2 then raise Exit; (* Move cursor up that number of lines *) - flush stdout; Terminfo.backup !lines; + flush stdout; Terminfo.backup stdout !lines; (* Print the input, switching to standout for the location *) let bol = ref false in print_string "# "; for pos = 0 to lb.lex_buffer_len - pos0 - 1 do if !bol then (print_string " "; bol := false); if List.exists (fun loc -> pos = loc.loc_start.pos_cnum) locs then - Terminfo.standout true; + Terminfo.standout stdout true; if List.exists (fun loc -> pos = loc.loc_end.pos_cnum) locs then - Terminfo.standout false; + Terminfo.standout stdout false; let c = Bytes.get lb.lex_buffer (pos + pos0) in print_char c; bol := (c = '\n') done; (* Make sure standout mode is over *) - Terminfo.standout false; + Terminfo.standout stdout false; (* Position cursor back to original location *) - Terminfo.resume !num_loc_lines; + Terminfo.resume stdout !num_loc_lines; flush stdout (* Highlight the location by printing it again. *) -let highlight_dumb ppf lb loc = +let highlight_dumb ~print_chars ppf lb loc = (* Char 0 is at offset -lb.lex_abs_pos in lb.lex_buffer. *) let pos0 = -lb.lex_abs_pos in (* Do nothing if the buffer does not contain the whole phrase. *) @@ -143,9 +143,12 @@ let highlight_dumb ppf lb loc = if loc.loc_end.pos_cnum > pos then incr line_end; end done; + Format.fprintf ppf "@["; (* Print character location (useful for Emacs) *) - Format.fprintf ppf "@[Characters %i-%i:@," - loc.loc_start.pos_cnum loc.loc_end.pos_cnum; + if print_chars then begin + Format.fprintf ppf "Characters %i-%i:@," + loc.loc_start.pos_cnum loc.loc_end.pos_cnum + end; (* Print the input, underlining the location *) Format.pp_print_string ppf " "; let line = ref 0 in @@ -194,6 +197,9 @@ let highlight_dumb ppf lb loc = done; Format.fprintf ppf "@]" +let show_code_at_location ppf lb loc = + highlight_dumb ~print_chars:false ppf lb loc + (* Highlight the location using one of the supported modes. *) let rec highlight_locations ppf locs = @@ -208,14 +214,14 @@ let rec highlight_locations ppf locs = try Sys.getenv "TERM" = "norepeat" with Not_found -> false in if norepeat then false else let loc1 = List.hd locs in - try highlight_dumb ppf lb loc1; true + try highlight_dumb ~print_chars:true ppf lb loc1; true with Exit -> false end - | Terminfo.Good_term num_lines -> + | Terminfo.Good_term -> begin match !input_lexbuf with None -> false | Some lb -> - try highlight_terminfo ppf num_lines lb locs; true + try highlight_terminfo ppf lb locs; true with Exit -> false end @@ -223,9 +229,32 @@ let rec highlight_locations ppf locs = open Format +let rewrite_absolute_path = + let init = ref false in + let map_cache = ref None in + fun path -> + if not !init then begin + init := true; + match Sys.getenv "BUILD_PATH_PREFIX_MAP" with + | exception Not_found -> () + | encoded_map -> + match Build_path_prefix_map.decode_map encoded_map with + | Error err -> + Misc.fatal_errorf + "Invalid value for the environment variable \ + BUILD_PATH_PREFIX_MAP: %s" err + | Ok map -> map_cache := Some map + end; + match !map_cache with + | None -> path + | Some map -> Build_path_prefix_map.rewrite map path + let absolute_path s = (* This function could go into Filename *) let open Filename in - let s = if is_relative s then concat (Sys.getcwd ()) s else s in + let s = + if not (is_relative s) then s + else (rewrite_absolute_path (concat (Sys.getcwd ()) s)) + in (* Now simplify . and .. components *) let rec aux s = let base = basename s in diff --git a/parsing/location.mli b/parsing/location.mli index c3e7c653..bf93f168 100644 --- a/parsing/location.mli +++ b/parsing/location.mli @@ -55,6 +55,7 @@ val input_lexbuf: Lexing.lexbuf option ref val get_pos_info: Lexing.position -> string * int * int (* file, line, char *) val print_loc: formatter -> t -> unit +val print_error_prefix: formatter -> unit val print_error: formatter -> t -> unit val print_error_cur_file: formatter -> unit -> unit val print_warning: t -> formatter -> Warnings.t -> unit @@ -74,6 +75,8 @@ val default_warning_printer : t -> formatter -> Warnings.t -> unit val highlight_locations: formatter -> t list -> bool +val show_code_at_location: formatter -> Lexing.lexbuf -> t -> unit + type 'a loc = { txt : 'a; loc : t; @@ -86,6 +89,11 @@ val print: formatter -> t -> unit val print_compact: formatter -> t -> unit val print_filename: formatter -> string -> unit +val rewrite_absolute_path: string -> string + (** rewrite absolute path to honor the BUILD_PATH_PREFIX_MAP + variable (https://reproducible-builds.org/specs/build-path-prefix-map/) + if it is set. *) + val absolute_path: string -> string val show_filename: string -> string diff --git a/parsing/parser.mly b/parsing/parser.mly index 3da1669b..65e364e6 100644 --- a/parsing/parser.mly +++ b/parsing/parser.mly @@ -290,9 +290,15 @@ let text_csig pos = Ctf.text (rhs_text pos) let text_def pos = [Ptop_def (Str.text (rhs_text pos))] let extra_text text pos items = - let pre_extras = rhs_pre_extra_text pos in - let post_extras = rhs_post_extra_text pos in - text pre_extras @ items @ text post_extras + match items with + | [] -> + let post = rhs_post_text pos in + let post_extras = rhs_post_extra_text pos in + text post @ text post_extras + | _ :: _ -> + let pre_extras = rhs_pre_extra_text pos in + let post_extras = rhs_post_extra_text pos in + text pre_extras @ items @ text post_extras let extra_str pos items = extra_text Str.text pos items let extra_sig pos items = extra_text Sig.text pos items @@ -648,7 +654,7 @@ top_structure_tail: | structure_item top_structure_tail { (text_str 1) @ $1 :: $2 } ; use_file: - use_file_body { extra_def 1 $1 } + use_file_body EOF { extra_def 1 $1 } ; use_file_body: use_file_tail { $1 } @@ -656,18 +662,10 @@ use_file_body: { (text_def 1) @ Ptop_def[mkstrexp $1 $2] :: $3 } ; use_file_tail: - EOF + /* empty */ { [] } - | SEMISEMI EOF - { text_def 1 } - | SEMISEMI seq_expr post_item_attributes use_file_tail - { mark_rhs_docs 2 3; - (text_def 1) @ (text_def 2) @ Ptop_def[mkstrexp $2 $3] :: $4 } - | SEMISEMI structure_item use_file_tail - { (text_def 1) @ (text_def 2) @ Ptop_def[$2] :: $3 } - | SEMISEMI toplevel_directive use_file_tail - { mark_rhs_docs 2 3; - (text_def 1) @ (text_def 2) @ $2 :: $3 } + | SEMISEMI use_file_body + { $2 } | structure_item use_file_tail { (text_def 1) @ Ptop_def[$1] :: $2 } | toplevel_directive use_file_tail @@ -2020,7 +2018,8 @@ type_parameter_list: | type_parameter_list COMMA type_parameter { $3 :: $1 } ; constructor_declarations: - constructor_declaration { [$1] } + | BAR { [ ] } + | constructor_declaration { [$1] } | bar_constructor_declaration { [$1] } | constructor_declarations bar_constructor_declaration { $2 :: $1 } ; diff --git a/parsing/parsetree.mli b/parsing/parsetree.mli index 852a526b..9f5de197 100644 --- a/parsing/parsetree.mli +++ b/parsing/parsetree.mli @@ -407,7 +407,6 @@ and type_declaration = and type_kind = | Ptype_abstract | Ptype_variant of constructor_declaration list - (* Invariant: non-empty list *) | Ptype_record of label_declaration list (* Invariant: non-empty list *) | Ptype_open diff --git a/parsing/pprintast.ml b/parsing/pprintast.ml index 998365a7..30a90644 100644 --- a/parsing/pprintast.ml +++ b/parsing/pprintast.ml @@ -959,22 +959,16 @@ and module_type ctxt f x = (attributes ctxt) x.pmty_attributes end else match x.pmty_desc with - | Pmty_ident li -> - pp f "%a" longident_loc li; - | Pmty_alias li -> - pp f "(module %a)" longident_loc li; - | Pmty_signature (s) -> - pp f "@[@[sig@ %a@]@ end@]" (* "@[sig@ %a@ end@]" *) - (list (signature_item ctxt)) s (* FIXME wrong indentation*) | Pmty_functor (_, None, mt2) -> pp f "@[functor () ->@ %a@]" (module_type ctxt) mt2 | Pmty_functor (s, Some mt1, mt2) -> if s.txt = "_" then pp f "@[%a@ ->@ %a@]" - (module_type ctxt) mt1 (module_type ctxt) mt2 + (module_type1 ctxt) mt1 (module_type ctxt) mt2 else pp f "@[functor@ (%s@ :@ %a)@ ->@ %a@]" s.txt (module_type ctxt) mt1 (module_type ctxt) mt2 + | Pmty_with (mt, []) -> module_type ctxt f mt | Pmty_with (mt, l) -> let with_constraint f = function | Pwith_type (li, ({ptype_params= ls ;_} as td)) -> @@ -992,13 +986,24 @@ and module_type ctxt f x = (type_declaration ctxt) td | Pwith_modsubst (li, li2) -> pp f "module %a :=@ %a" longident_loc li longident_loc li2 in - (match l with - | [] -> pp f "@[%a@]" (module_type ctxt) mt - | _ -> pp f "@[(%a@ with@ %a)@]" - (module_type ctxt) mt (list with_constraint ~sep:"@ and@ ") l) + pp f "@[%a@ with@ %a@]" + (module_type1 ctxt) mt (list with_constraint ~sep:"@ and@ ") l + | _ -> module_type1 ctxt f x + +and module_type1 ctxt f x = + if x.pmty_attributes <> [] then module_type ctxt f x + else match x.pmty_desc with + | Pmty_ident li -> + pp f "%a" longident_loc li; + | Pmty_alias li -> + pp f "(module %a)" longident_loc li; + | Pmty_signature (s) -> + pp f "@[@[sig@ %a@]@ end@]" (* "@[sig@ %a@ end@]" *) + (list (signature_item ctxt)) s (* FIXME wrong indentation*) | Pmty_typeof me -> pp f "@[module@ type@ of@ %a@]" (module_expr ctxt) me | Pmty_extension e -> extension ctxt f e + | _ -> paren true (module_type ctxt) f x and signature ctxt f x = list ~sep:"@\n" (signature_item ctxt) f x @@ -1069,11 +1074,11 @@ and signature_item ctxt f x : unit = | pmd :: tl -> if not first then pp f "@ @[and@ %s:@ %a@]%a" pmd.pmd_name.txt - (module_type ctxt) pmd.pmd_type + (module_type1 ctxt) pmd.pmd_type (item_attributes ctxt) pmd.pmd_attributes else pp f "@[module@ rec@ %s:@ %a@]%a" pmd.pmd_name.txt - (module_type ctxt) pmd.pmd_type + (module_type1 ctxt) pmd.pmd_type (item_attributes ctxt) pmd.pmd_attributes; string_x_module_type_list f ~first:false tl in @@ -1397,8 +1402,10 @@ and type_declaration ctxt f x = in match x.ptype_kind with | Ptype_variant xs -> - pp f "%t%t@\n%a" intro priv - (list ~sep:"@\n" constructor_declaration) xs + let variants fmt xs = + if xs = [] then pp fmt " |" else + pp fmt "@\n%a" (list ~sep:"@\n" constructor_declaration) xs + in pp f "%t%t%a" intro priv variants xs | Ptype_abstract -> () | Ptype_record l -> pp f "%t%t@;%a" intro priv (record_declaration ctxt) l diff --git a/stdlib/.depend b/stdlib/.depend index 4ac015ad..2e53ef70 100644 --- a/stdlib/.depend +++ b/stdlib/.depend @@ -1,324 +1,331 @@ -arg.cmo : sys.cmi string.cmi printf.cmi list.cmi buffer.cmi array.cmi \ - arg.cmi -arg.cmx : sys.cmx string.cmx printf.cmx list.cmx buffer.cmx array.cmx \ - arg.cmi -arg.cmi : -array.cmo : array.cmi -array.cmx : array.cmi -array.cmi : -arrayLabels.cmo : array.cmi arrayLabels.cmi -arrayLabels.cmx : array.cmx arrayLabels.cmi -arrayLabels.cmi : -buffer.cmo : uchar.cmi sys.cmi string.cmi char.cmi bytes.cmi buffer.cmi -buffer.cmx : uchar.cmx sys.cmx string.cmx char.cmx bytes.cmx buffer.cmi -buffer.cmi : uchar.cmi -bytes.cmo : pervasives.cmi char.cmi bytes.cmi -bytes.cmx : pervasives.cmx char.cmx bytes.cmi -bytes.cmi : -bytesLabels.cmo : bytes.cmi bytesLabels.cmi -bytesLabels.cmx : bytes.cmx bytesLabels.cmi -bytesLabels.cmi : -callback.cmo : obj.cmi callback.cmi -callback.cmx : obj.cmx callback.cmi -callback.cmi : -camlinternalBigarray.cmo : complex.cmi -camlinternalBigarray.cmx : complex.cmx -camlinternalFormat.cmo : sys.cmi string.cmi char.cmi \ - camlinternalFormatBasics.cmi bytes.cmi buffer.cmi camlinternalFormat.cmi -camlinternalFormat.cmx : sys.cmx string.cmx char.cmx \ - camlinternalFormatBasics.cmx bytes.cmx buffer.cmx camlinternalFormat.cmi -camlinternalFormat.cmi : camlinternalFormatBasics.cmi buffer.cmi +stdlib__arg.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__printf.cmi stdlib__list.cmi stdlib__buffer.cmi stdlib__array.cmi \ + stdlib__arg.cmi +stdlib__arg.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__printf.cmx stdlib__list.cmx stdlib__buffer.cmx stdlib__array.cmx \ + stdlib__arg.cmi +stdlib__arg.cmi : +stdlib__array.cmo : stdlib__seq.cmi stdlib__array.cmi +stdlib__array.cmx : stdlib__seq.cmx stdlib__array.cmi +stdlib__array.cmi : stdlib__seq.cmi +stdlib__arrayLabels.cmo : stdlib__array.cmi stdlib__arrayLabels.cmi +stdlib__arrayLabels.cmx : stdlib__array.cmx stdlib__arrayLabels.cmi +stdlib__arrayLabels.cmi : stdlib__seq.cmi +stdlib__bigarray.cmo : stdlib__sys.cmi stdlib__complex.cmi stdlib__array.cmi stdlib__bigarray.cmi +stdlib__bigarray.cmx : stdlib__sys.cmx stdlib__complex.cmx stdlib__array.cmx stdlib__bigarray.cmi +stdlib__bigarray.cmi : stdlib__complex.cmi +stdlib__buffer.cmo : stdlib__uchar.cmi stdlib__sys.cmi stdlib__string.cmi stdlib__seq.cmi stdlib__char.cmi stdlib__bytes.cmi \ + stdlib__buffer.cmi +stdlib__buffer.cmx : stdlib__uchar.cmx stdlib__sys.cmx stdlib__string.cmx stdlib__seq.cmx stdlib__char.cmx stdlib__bytes.cmx \ + stdlib__buffer.cmi +stdlib__buffer.cmi : stdlib__uchar.cmi stdlib__seq.cmi +stdlib__bytes.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__char.cmi stdlib__bytes.cmi +stdlib__bytes.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__char.cmx stdlib__bytes.cmi +stdlib__bytes.cmi : stdlib__seq.cmi +stdlib__bytesLabels.cmo : stdlib__bytes.cmi stdlib__bytesLabels.cmi +stdlib__bytesLabels.cmx : stdlib__bytes.cmx stdlib__bytesLabels.cmi +stdlib__bytesLabels.cmi : stdlib__seq.cmi +stdlib__callback.cmo : stdlib__obj.cmi stdlib__callback.cmi +stdlib__callback.cmx : stdlib__obj.cmx stdlib__callback.cmi +stdlib__callback.cmi : +camlinternalFormat.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__char.cmi \ + camlinternalFormatBasics.cmi stdlib__bytes.cmi stdlib__buffer.cmi camlinternalFormat.cmi +camlinternalFormat.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__char.cmx \ + camlinternalFormatBasics.cmx stdlib__bytes.cmx stdlib__buffer.cmx camlinternalFormat.cmi +camlinternalFormat.cmi : camlinternalFormatBasics.cmi stdlib__buffer.cmi camlinternalFormatBasics.cmo : camlinternalFormatBasics.cmi camlinternalFormatBasics.cmx : camlinternalFormatBasics.cmi camlinternalFormatBasics.cmi : -camlinternalLazy.cmo : obj.cmi camlinternalLazy.cmi -camlinternalLazy.cmx : obj.cmx camlinternalLazy.cmi +camlinternalLazy.cmo : stdlib__obj.cmi camlinternalLazy.cmi +camlinternalLazy.cmx : stdlib__obj.cmx camlinternalLazy.cmi camlinternalLazy.cmi : -camlinternalMod.cmo : obj.cmi camlinternalOO.cmi array.cmi \ +camlinternalMod.cmo : stdlib__obj.cmi camlinternalOO.cmi stdlib__array.cmi \ camlinternalMod.cmi -camlinternalMod.cmx : obj.cmx camlinternalOO.cmx array.cmx \ +camlinternalMod.cmx : stdlib__obj.cmx camlinternalOO.cmx stdlib__array.cmx \ camlinternalMod.cmi -camlinternalMod.cmi : obj.cmi -camlinternalOO.cmo : sys.cmi string.cmi obj.cmi map.cmi list.cmi char.cmi \ - array.cmi camlinternalOO.cmi -camlinternalOO.cmx : sys.cmx string.cmx obj.cmx map.cmx list.cmx char.cmx \ - array.cmx camlinternalOO.cmi -camlinternalOO.cmi : obj.cmi -char.cmo : char.cmi -char.cmx : char.cmi -char.cmi : -complex.cmo : complex.cmi -complex.cmx : complex.cmi -complex.cmi : -digest.cmo : string.cmi char.cmi bytes.cmi digest.cmi -digest.cmx : string.cmx char.cmx bytes.cmx digest.cmi -digest.cmi : -ephemeron.cmo : sys.cmi random.cmi obj.cmi lazy.cmi hashtbl.cmi array.cmi \ - ephemeron.cmi -ephemeron.cmx : sys.cmx random.cmx obj.cmx lazy.cmx hashtbl.cmx array.cmx \ - ephemeron.cmi -ephemeron.cmi : hashtbl.cmi -filename.cmo : sys.cmi string.cmi random.cmi printf.cmi lazy.cmi buffer.cmi \ - filename.cmi -filename.cmx : sys.cmx string.cmx random.cmx printf.cmx lazy.cmx buffer.cmx \ - filename.cmi -filename.cmi : -format.cmo : string.cmi pervasives.cmi list.cmi camlinternalFormatBasics.cmi \ - camlinternalFormat.cmi buffer.cmi format.cmi -format.cmx : string.cmx pervasives.cmx list.cmx camlinternalFormatBasics.cmx \ - camlinternalFormat.cmx buffer.cmx format.cmi -format.cmi : pervasives.cmi buffer.cmi -gc.cmo : sys.cmi string.cmi printf.cmi gc.cmi -gc.cmx : sys.cmx string.cmx printf.cmx gc.cmi -gc.cmi : -genlex.cmo : string.cmi stream.cmi list.cmi hashtbl.cmi char.cmi bytes.cmi \ - genlex.cmi -genlex.cmx : string.cmx stream.cmx list.cmx hashtbl.cmx char.cmx bytes.cmx \ - genlex.cmi -genlex.cmi : stream.cmi -hashtbl.cmo : sys.cmi string.cmi random.cmi obj.cmi lazy.cmi array.cmi \ - hashtbl.cmi -hashtbl.cmx : sys.cmx string.cmx random.cmx obj.cmx lazy.cmx array.cmx \ - hashtbl.cmi -hashtbl.cmi : -int32.cmo : pervasives.cmi int32.cmi -int32.cmx : pervasives.cmx int32.cmi -int32.cmi : -int64.cmo : pervasives.cmi int64.cmi -int64.cmx : pervasives.cmx int64.cmi -int64.cmi : -lazy.cmo : obj.cmi camlinternalLazy.cmi lazy.cmi -lazy.cmx : obj.cmx camlinternalLazy.cmx lazy.cmi -lazy.cmi : -lexing.cmo : sys.cmi string.cmi bytes.cmi array.cmi lexing.cmi -lexing.cmx : sys.cmx string.cmx bytes.cmx array.cmx lexing.cmi -lexing.cmi : -list.cmo : list.cmi -list.cmx : list.cmi -list.cmi : -listLabels.cmo : list.cmi listLabels.cmi -listLabels.cmx : list.cmx listLabels.cmi -listLabels.cmi : -map.cmo : map.cmi -map.cmx : map.cmi -map.cmi : -marshal.cmo : bytes.cmi marshal.cmi -marshal.cmx : bytes.cmx marshal.cmi -marshal.cmi : -moreLabels.cmo : set.cmi map.cmi hashtbl.cmi moreLabels.cmi -moreLabels.cmx : set.cmx map.cmx hashtbl.cmx moreLabels.cmi -moreLabels.cmi : set.cmi map.cmi hashtbl.cmi -nativeint.cmo : sys.cmi pervasives.cmi nativeint.cmi -nativeint.cmx : sys.cmx pervasives.cmx nativeint.cmi -nativeint.cmi : -obj.cmo : marshal.cmi int32.cmi obj.cmi -obj.cmx : marshal.cmx int32.cmx obj.cmi -obj.cmi : int32.cmi -oo.cmo : camlinternalOO.cmi oo.cmi -oo.cmx : camlinternalOO.cmx oo.cmi -oo.cmi : camlinternalOO.cmi -parsing.cmo : obj.cmi lexing.cmi array.cmi parsing.cmi -parsing.cmx : obj.cmx lexing.cmx array.cmx parsing.cmi -parsing.cmi : obj.cmi lexing.cmi -pervasives.cmo : camlinternalFormatBasics.cmi pervasives.cmi -pervasives.cmx : camlinternalFormatBasics.cmx pervasives.cmi -pervasives.cmi : camlinternalFormatBasics.cmi -printexc.cmo : printf.cmi pervasives.cmi obj.cmi buffer.cmi array.cmi \ - printexc.cmi -printexc.cmx : printf.cmx pervasives.cmx obj.cmx buffer.cmx array.cmx \ - printexc.cmi -printexc.cmi : -printf.cmo : camlinternalFormatBasics.cmi camlinternalFormat.cmi buffer.cmi \ - printf.cmi -printf.cmx : camlinternalFormatBasics.cmx camlinternalFormat.cmx buffer.cmx \ - printf.cmi -printf.cmi : buffer.cmi -queue.cmo : queue.cmi -queue.cmx : queue.cmi -queue.cmi : -random.cmo : string.cmi pervasives.cmi nativeint.cmi int64.cmi int32.cmi \ - digest.cmi char.cmi array.cmi random.cmi -random.cmx : string.cmx pervasives.cmx nativeint.cmx int64.cmx int32.cmx \ - digest.cmx char.cmx array.cmx random.cmi -random.cmi : nativeint.cmi int64.cmi int32.cmi -scanf.cmo : string.cmi printf.cmi pervasives.cmi list.cmi \ - camlinternalFormatBasics.cmi camlinternalFormat.cmi bytes.cmi buffer.cmi \ - scanf.cmi -scanf.cmx : string.cmx printf.cmx pervasives.cmx list.cmx \ - camlinternalFormatBasics.cmx camlinternalFormat.cmx bytes.cmx buffer.cmx \ - scanf.cmi -scanf.cmi : pervasives.cmi -set.cmo : list.cmi set.cmi -set.cmx : list.cmx set.cmi -set.cmi : -sort.cmo : array.cmi sort.cmi -sort.cmx : array.cmx sort.cmi -sort.cmi : -spacetime.cmo : gc.cmi spacetime.cmi -spacetime.cmx : gc.cmx spacetime.cmi -spacetime.cmi : -stack.cmo : list.cmi stack.cmi -stack.cmx : list.cmx stack.cmi -stack.cmi : -stdLabels.cmo : stringLabels.cmi listLabels.cmi bytesLabels.cmi \ - arrayLabels.cmi stdLabels.cmi -stdLabels.cmx : stringLabels.cmx listLabels.cmx bytesLabels.cmx \ - arrayLabels.cmx stdLabels.cmi -stdLabels.cmi : stringLabels.cmi listLabels.cmi bytesLabels.cmi \ - arrayLabels.cmi +camlinternalMod.cmi : stdlib__obj.cmi +camlinternalOO.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__obj.cmi stdlib__map.cmi stdlib__list.cmi stdlib__char.cmi \ + stdlib__array.cmi camlinternalOO.cmi +camlinternalOO.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__obj.cmx stdlib__map.cmx stdlib__list.cmx stdlib__char.cmx \ + stdlib__array.cmx camlinternalOO.cmi +camlinternalOO.cmi : stdlib__obj.cmi +stdlib__char.cmo : stdlib__char.cmi +stdlib__char.cmx : stdlib__char.cmi +stdlib__char.cmi : +stdlib__complex.cmo : stdlib__complex.cmi +stdlib__complex.cmx : stdlib__complex.cmi +stdlib__complex.cmi : +stdlib__digest.cmo : stdlib__string.cmi stdlib__char.cmi stdlib__bytes.cmi stdlib__digest.cmi +stdlib__digest.cmx : stdlib__string.cmx stdlib__char.cmx stdlib__bytes.cmx stdlib__digest.cmi +stdlib__digest.cmi : +stdlib__ephemeron.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__random.cmi stdlib__obj.cmi stdlib__lazy.cmi stdlib__hashtbl.cmi \ + stdlib__array.cmi stdlib__ephemeron.cmi +stdlib__ephemeron.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__random.cmx stdlib__obj.cmx stdlib__lazy.cmx stdlib__hashtbl.cmx \ + stdlib__array.cmx stdlib__ephemeron.cmi +stdlib__ephemeron.cmi : stdlib__hashtbl.cmi +stdlib__filename.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__random.cmi stdlib__printf.cmi stdlib__lazy.cmi stdlib__buffer.cmi \ + stdlib__filename.cmi +stdlib__filename.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__random.cmx stdlib__printf.cmx stdlib__lazy.cmx stdlib__buffer.cmx \ + stdlib__filename.cmi +stdlib__filename.cmi : +stdlib__float.cmo : stdlib__float.cmi +stdlib__float.cmx : stdlib__float.cmi +stdlib__float.cmi : +stdlib__format.cmo : stdlib__string.cmi stdlib__list.cmi camlinternalFormatBasics.cmi \ + camlinternalFormat.cmi stdlib__buffer.cmi stdlib__format.cmi +stdlib__format.cmx : stdlib__string.cmx stdlib__list.cmx camlinternalFormatBasics.cmx \ + camlinternalFormat.cmx stdlib__buffer.cmx stdlib__format.cmi +stdlib__format.cmi : stdlib__buffer.cmi +stdlib__gc.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__printf.cmi stdlib__gc.cmi +stdlib__gc.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__printf.cmx stdlib__gc.cmi +stdlib__gc.cmi : +stdlib__genlex.cmo : stdlib__string.cmi stdlib__stream.cmi stdlib__list.cmi stdlib__hashtbl.cmi stdlib__char.cmi stdlib__bytes.cmi \ + stdlib__genlex.cmi +stdlib__genlex.cmx : stdlib__string.cmx stdlib__stream.cmx stdlib__list.cmx stdlib__hashtbl.cmx stdlib__char.cmx stdlib__bytes.cmx \ + stdlib__genlex.cmi +stdlib__genlex.cmi : stdlib__stream.cmi +stdlib__hashtbl.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__seq.cmi stdlib__random.cmi stdlib__obj.cmi stdlib__lazy.cmi \ + stdlib__array.cmi stdlib__hashtbl.cmi +stdlib__hashtbl.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__seq.cmx stdlib__random.cmx stdlib__obj.cmx stdlib__lazy.cmx \ + stdlib__array.cmx stdlib__hashtbl.cmi +stdlib__hashtbl.cmi : stdlib__seq.cmi +stdlib__int32.cmo : stdlib__int32.cmi +stdlib__int32.cmx : stdlib__int32.cmi +stdlib__int32.cmi : +stdlib__int64.cmo : stdlib__int64.cmi +stdlib__int64.cmx : stdlib__int64.cmi +stdlib__int64.cmi : +stdlib__lazy.cmo : stdlib__obj.cmi camlinternalLazy.cmi stdlib__lazy.cmi +stdlib__lazy.cmx : stdlib__obj.cmx camlinternalLazy.cmx stdlib__lazy.cmi +stdlib__lazy.cmi : +stdlib__lexing.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__bytes.cmi stdlib__array.cmi stdlib__lexing.cmi +stdlib__lexing.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__bytes.cmx stdlib__array.cmx stdlib__lexing.cmi +stdlib__lexing.cmi : +stdlib__list.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__list.cmi +stdlib__list.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__list.cmi +stdlib__list.cmi : stdlib__seq.cmi +stdlib__listLabels.cmo : stdlib__list.cmi stdlib__listLabels.cmi +stdlib__listLabels.cmx : stdlib__list.cmx stdlib__listLabels.cmi +stdlib__listLabels.cmi : stdlib__seq.cmi +stdlib__map.cmo : stdlib__seq.cmi stdlib__map.cmi +stdlib__map.cmx : stdlib__seq.cmx stdlib__map.cmi +stdlib__map.cmi : stdlib__seq.cmi +stdlib__marshal.cmo : stdlib__bytes.cmi stdlib__marshal.cmi +stdlib__marshal.cmx : stdlib__bytes.cmx stdlib__marshal.cmi +stdlib__marshal.cmi : +stdlib__moreLabels.cmo : stdlib__set.cmi stdlib__map.cmi stdlib__hashtbl.cmi stdlib__moreLabels.cmi +stdlib__moreLabels.cmx : stdlib__set.cmx stdlib__map.cmx stdlib__hashtbl.cmx stdlib__moreLabels.cmi +stdlib__moreLabels.cmi : stdlib__set.cmi stdlib__seq.cmi stdlib__map.cmi stdlib__hashtbl.cmi +stdlib__nativeint.cmo : stdlib__sys.cmi stdlib__nativeint.cmi +stdlib__nativeint.cmx : stdlib__sys.cmx stdlib__nativeint.cmi +stdlib__nativeint.cmi : +stdlib__obj.cmo : stdlib__marshal.cmi stdlib__int32.cmi stdlib__obj.cmi +stdlib__obj.cmx : stdlib__marshal.cmx stdlib__int32.cmx stdlib__obj.cmi +stdlib__obj.cmi : stdlib__int32.cmi +stdlib__oo.cmo : camlinternalOO.cmi stdlib__oo.cmi +stdlib__oo.cmx : camlinternalOO.cmx stdlib__oo.cmi +stdlib__oo.cmi : camlinternalOO.cmi +stdlib__parsing.cmo : stdlib__obj.cmi stdlib__lexing.cmi stdlib__array.cmi stdlib__parsing.cmi +stdlib__parsing.cmx : stdlib__obj.cmx stdlib__lexing.cmx stdlib__array.cmx stdlib__parsing.cmi +stdlib__parsing.cmi : stdlib__obj.cmi stdlib__lexing.cmi +stdlib__printexc.cmo : stdlib__printf.cmi stdlib__obj.cmi stdlib__buffer.cmi stdlib__array.cmi stdlib__printexc.cmi +stdlib__printexc.cmx : stdlib__printf.cmx stdlib__obj.cmx stdlib__buffer.cmx stdlib__array.cmx stdlib__printexc.cmi +stdlib__printexc.cmi : +stdlib__printf.cmo : camlinternalFormatBasics.cmi camlinternalFormat.cmi stdlib__buffer.cmi \ + stdlib__printf.cmi +stdlib__printf.cmx : camlinternalFormatBasics.cmx camlinternalFormat.cmx stdlib__buffer.cmx \ + stdlib__printf.cmi +stdlib__printf.cmi : stdlib__buffer.cmi +stdlib__queue.cmo : stdlib__seq.cmi stdlib__queue.cmi +stdlib__queue.cmx : stdlib__seq.cmx stdlib__queue.cmi +stdlib__queue.cmi : stdlib__seq.cmi +stdlib__random.cmo : stdlib__string.cmi stdlib__nativeint.cmi stdlib__int64.cmi stdlib__int32.cmi stdlib__digest.cmi \ + stdlib__char.cmi stdlib__array.cmi stdlib__random.cmi +stdlib__random.cmx : stdlib__string.cmx stdlib__nativeint.cmx stdlib__int64.cmx stdlib__int32.cmx stdlib__digest.cmx \ + stdlib__char.cmx stdlib__array.cmx stdlib__random.cmi +stdlib__random.cmi : stdlib__nativeint.cmi stdlib__int64.cmi stdlib__int32.cmi +stdlib__scanf.cmo : stdlib__string.cmi stdlib__printf.cmi stdlib__list.cmi camlinternalFormatBasics.cmi \ + camlinternalFormat.cmi stdlib__bytes.cmi stdlib__buffer.cmi stdlib__scanf.cmi +stdlib__scanf.cmx : stdlib__string.cmx stdlib__printf.cmx stdlib__list.cmx camlinternalFormatBasics.cmx \ + camlinternalFormat.cmx stdlib__bytes.cmx stdlib__buffer.cmx stdlib__scanf.cmi +stdlib__scanf.cmi : +stdlib__seq.cmo : stdlib__seq.cmi +stdlib__seq.cmx : stdlib__seq.cmi +stdlib__seq.cmi : +stdlib__set.cmo : stdlib__seq.cmi stdlib__list.cmi stdlib__set.cmi +stdlib__set.cmx : stdlib__seq.cmx stdlib__list.cmx stdlib__set.cmi +stdlib__set.cmi : stdlib__seq.cmi +stdlib__sort.cmo : stdlib__array.cmi stdlib__sort.cmi +stdlib__sort.cmx : stdlib__array.cmx stdlib__sort.cmi +stdlib__sort.cmi : +stdlib__spacetime.cmo : stdlib__gc.cmi stdlib__spacetime.cmi +stdlib__spacetime.cmx : stdlib__gc.cmx stdlib__spacetime.cmi +stdlib__spacetime.cmi : +stdlib__stack.cmo : stdlib__seq.cmi stdlib__list.cmi stdlib__stack.cmi +stdlib__stack.cmx : stdlib__seq.cmx stdlib__list.cmx stdlib__stack.cmi +stdlib__stack.cmi : stdlib__seq.cmi +stdlib__stdLabels.cmo : stdlib__stringLabels.cmi stdlib__listLabels.cmi stdlib__bytesLabels.cmi \ + stdlib__arrayLabels.cmi stdlib__stdLabels.cmi +stdlib__stdLabels.cmx : stdlib__stringLabels.cmx stdlib__listLabels.cmx stdlib__bytesLabels.cmx \ + stdlib__arrayLabels.cmx stdlib__stdLabels.cmi +stdlib__stdLabels.cmi : stdlib__stringLabels.cmi stdlib__listLabels.cmi stdlib__bytesLabels.cmi \ + stdlib__arrayLabels.cmi std_exit.cmo : std_exit.cmx : -stream.cmo : string.cmi list.cmi lazy.cmi bytes.cmi stream.cmi -stream.cmx : string.cmx list.cmx lazy.cmx bytes.cmx stream.cmi -stream.cmi : -string.cmo : pervasives.cmi bytes.cmi string.cmi -string.cmx : pervasives.cmx bytes.cmx string.cmi -string.cmi : -stringLabels.cmo : string.cmi stringLabels.cmi -stringLabels.cmx : string.cmx stringLabels.cmi -stringLabels.cmi : -sys.cmo : sys.cmi -sys.cmx : sys.cmi -sys.cmi : -uchar.cmo : pervasives.cmi char.cmi uchar.cmi -uchar.cmx : pervasives.cmx char.cmx uchar.cmi -uchar.cmi : -weak.cmo : sys.cmi obj.cmi hashtbl.cmi array.cmi weak.cmi -weak.cmx : sys.cmx obj.cmx hashtbl.cmx array.cmx weak.cmi -weak.cmi : hashtbl.cmi -arg.cmo : sys.cmi string.cmi printf.cmi list.cmi buffer.cmi array.cmi \ - arg.cmi -arg.p.cmx : sys.cmx string.cmx printf.cmx list.cmx buffer.cmx array.cmx \ - arg.cmi -array.cmo : array.cmi -array.p.cmx : array.cmi -arrayLabels.cmo : array.cmi arrayLabels.cmi -arrayLabels.p.cmx : array.cmx arrayLabels.cmi -buffer.cmo : uchar.cmi sys.cmi string.cmi char.cmi bytes.cmi buffer.cmi -buffer.p.cmx : uchar.cmx sys.cmx string.cmx char.cmx bytes.cmx buffer.cmi -bytes.cmo : pervasives.cmi char.cmi bytes.cmi -bytes.p.cmx : pervasives.cmx char.cmx bytes.cmi -bytesLabels.cmo : bytes.cmi bytesLabels.cmi -bytesLabels.p.cmx : bytes.cmx bytesLabels.cmi -callback.cmo : obj.cmi callback.cmi -callback.p.cmx : obj.cmx callback.cmi -camlinternalBigarray.cmo : complex.cmi -camlinternalBigarray.p.cmx : complex.cmx -camlinternalFormat.cmo : sys.cmi string.cmi char.cmi \ - camlinternalFormatBasics.cmi bytes.cmi buffer.cmi camlinternalFormat.cmi -camlinternalFormat.p.cmx : sys.cmx string.cmx char.cmx \ - camlinternalFormatBasics.cmx bytes.cmx buffer.cmx camlinternalFormat.cmi +stdlib__stream.cmo : stdlib__string.cmi stdlib__list.cmi stdlib__lazy.cmi stdlib__bytes.cmi stdlib__stream.cmi +stdlib__stream.cmx : stdlib__string.cmx stdlib__list.cmx stdlib__lazy.cmx stdlib__bytes.cmx stdlib__stream.cmi +stdlib__stream.cmi : +stdlib__string.cmo : stdlib__bytes.cmi stdlib__string.cmi +stdlib__string.cmx : stdlib__bytes.cmx stdlib__string.cmi +stdlib__string.cmi : stdlib__seq.cmi +stdlib__stringLabels.cmo : stdlib__string.cmi stdlib__stringLabels.cmi +stdlib__stringLabels.cmx : stdlib__string.cmx stdlib__stringLabels.cmi +stdlib__stringLabels.cmi : stdlib__seq.cmi +stdlib__sys.cmo : stdlib__sys.cmi +stdlib__sys.cmx : stdlib__sys.cmi +stdlib__sys.cmi : +stdlib__uchar.cmo : stdlib__char.cmi stdlib__uchar.cmi +stdlib__uchar.cmx : stdlib__char.cmx stdlib__uchar.cmi +stdlib__uchar.cmi : +stdlib__weak.cmo : stdlib__sys.cmi stdlib__obj.cmi stdlib__hashtbl.cmi stdlib__array.cmi stdlib__weak.cmi +stdlib__weak.cmx : stdlib__sys.cmx stdlib__obj.cmx stdlib__hashtbl.cmx stdlib__array.cmx stdlib__weak.cmi +stdlib__weak.cmi : stdlib__hashtbl.cmi +stdlib.cmo : camlinternalFormatBasics.cmi stdlib.cmi +stdlib.cmx : camlinternalFormatBasics.cmx stdlib.cmi +stdlib.cmi : camlinternalFormatBasics.cmi +stdlib__arg.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__printf.cmi stdlib__list.cmi stdlib__buffer.cmi stdlib__array.cmi \ + stdlib__arg.cmi +stdlib__arg.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__printf.cmx stdlib__list.cmx stdlib__buffer.cmx stdlib__array.cmx \ + stdlib__arg.cmi +stdlib__array.cmo : stdlib__seq.cmi stdlib__array.cmi +stdlib__array.p.cmx : stdlib__seq.cmx stdlib__array.cmi +stdlib__arrayLabels.cmo : stdlib__array.cmi stdlib__arrayLabels.cmi +stdlib__arrayLabels.p.cmx : stdlib__array.cmx stdlib__arrayLabels.cmi +stdlib__bigarray.cmo : stdlib__sys.cmi stdlib__complex.cmi stdlib__array.cmi stdlib__bigarray.cmi +stdlib__bigarray.p.cmx : stdlib__sys.cmx stdlib__complex.cmx stdlib__array.cmx stdlib__bigarray.cmi +stdlib__buffer.cmo : stdlib__uchar.cmi stdlib__sys.cmi stdlib__string.cmi stdlib__seq.cmi stdlib__char.cmi stdlib__bytes.cmi \ + stdlib__buffer.cmi +stdlib__buffer.p.cmx : stdlib__uchar.cmx stdlib__sys.cmx stdlib__string.cmx stdlib__seq.cmx stdlib__char.cmx stdlib__bytes.cmx \ + stdlib__buffer.cmi +stdlib__bytes.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__char.cmi stdlib__bytes.cmi +stdlib__bytes.p.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__char.cmx stdlib__bytes.cmi +stdlib__bytesLabels.cmo : stdlib__bytes.cmi stdlib__bytesLabels.cmi +stdlib__bytesLabels.p.cmx : stdlib__bytes.cmx stdlib__bytesLabels.cmi +stdlib__callback.cmo : stdlib__obj.cmi stdlib__callback.cmi +stdlib__callback.p.cmx : stdlib__obj.cmx stdlib__callback.cmi +camlinternalFormat.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__char.cmi \ + camlinternalFormatBasics.cmi stdlib__bytes.cmi stdlib__buffer.cmi camlinternalFormat.cmi +camlinternalFormat.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__char.cmx \ + camlinternalFormatBasics.cmx stdlib__bytes.cmx stdlib__buffer.cmx camlinternalFormat.cmi camlinternalFormatBasics.cmo : camlinternalFormatBasics.cmi camlinternalFormatBasics.p.cmx : camlinternalFormatBasics.cmi -camlinternalLazy.cmo : obj.cmi camlinternalLazy.cmi -camlinternalLazy.p.cmx : obj.cmx camlinternalLazy.cmi -camlinternalMod.cmo : obj.cmi camlinternalOO.cmi array.cmi \ +camlinternalLazy.cmo : stdlib__obj.cmi camlinternalLazy.cmi +camlinternalLazy.p.cmx : stdlib__obj.cmx camlinternalLazy.cmi +camlinternalMod.cmo : stdlib__obj.cmi camlinternalOO.cmi stdlib__array.cmi \ camlinternalMod.cmi -camlinternalMod.p.cmx : obj.cmx camlinternalOO.cmx array.cmx \ +camlinternalMod.p.cmx : stdlib__obj.cmx camlinternalOO.cmx stdlib__array.cmx \ camlinternalMod.cmi -camlinternalOO.cmo : sys.cmi string.cmi obj.cmi map.cmi list.cmi char.cmi \ - array.cmi camlinternalOO.cmi -camlinternalOO.p.cmx : sys.cmx string.cmx obj.cmx map.cmx list.cmx char.cmx \ - array.cmx camlinternalOO.cmi -char.cmo : char.cmi -char.p.cmx : char.cmi -complex.cmo : complex.cmi -complex.p.cmx : complex.cmi -digest.cmo : string.cmi char.cmi bytes.cmi digest.cmi -digest.p.cmx : string.cmx char.cmx bytes.cmx digest.cmi -ephemeron.cmo : sys.cmi random.cmi obj.cmi lazy.cmi hashtbl.cmi array.cmi \ - ephemeron.cmi -ephemeron.p.cmx : sys.cmx random.cmx obj.cmx lazy.cmx hashtbl.cmx array.cmx \ - ephemeron.cmi -filename.cmo : sys.cmi string.cmi random.cmi printf.cmi lazy.cmi buffer.cmi \ - filename.cmi -filename.p.cmx : sys.cmx string.cmx random.cmx printf.cmx lazy.cmx buffer.cmx \ - filename.cmi -format.cmo : string.cmi pervasives.cmi list.cmi camlinternalFormatBasics.cmi \ - camlinternalFormat.cmi buffer.cmi format.cmi -format.p.cmx : string.cmx pervasives.cmx list.cmx camlinternalFormatBasics.cmx \ - camlinternalFormat.cmx buffer.cmx format.cmi -gc.cmo : sys.cmi string.cmi printf.cmi gc.cmi -gc.p.cmx : sys.cmx string.cmx printf.cmx gc.cmi -genlex.cmo : string.cmi stream.cmi list.cmi hashtbl.cmi char.cmi bytes.cmi \ - genlex.cmi -genlex.p.cmx : string.cmx stream.cmx list.cmx hashtbl.cmx char.cmx bytes.cmx \ - genlex.cmi -hashtbl.cmo : sys.cmi string.cmi random.cmi obj.cmi lazy.cmi array.cmi \ - hashtbl.cmi -hashtbl.p.cmx : sys.cmx string.cmx random.cmx obj.cmx lazy.cmx array.cmx \ - hashtbl.cmi -int32.cmo : pervasives.cmi int32.cmi -int32.p.cmx : pervasives.cmx int32.cmi -int64.cmo : pervasives.cmi int64.cmi -int64.p.cmx : pervasives.cmx int64.cmi -lazy.cmo : obj.cmi camlinternalLazy.cmi lazy.cmi -lazy.p.cmx : obj.cmx camlinternalLazy.cmx lazy.cmi -lexing.cmo : sys.cmi string.cmi bytes.cmi array.cmi lexing.cmi -lexing.p.cmx : sys.cmx string.cmx bytes.cmx array.cmx lexing.cmi -list.cmo : list.cmi -list.p.cmx : list.cmi -listLabels.cmo : list.cmi listLabels.cmi -listLabels.p.cmx : list.cmx listLabels.cmi -map.cmo : map.cmi -map.p.cmx : map.cmi -marshal.cmo : bytes.cmi marshal.cmi -marshal.p.cmx : bytes.cmx marshal.cmi -moreLabels.cmo : set.cmi map.cmi hashtbl.cmi moreLabels.cmi -moreLabels.p.cmx : set.cmx map.cmx hashtbl.cmx moreLabels.cmi -nativeint.cmo : sys.cmi pervasives.cmi nativeint.cmi -nativeint.p.cmx : sys.cmx pervasives.cmx nativeint.cmi -obj.cmo : marshal.cmi int32.cmi obj.cmi -obj.p.cmx : marshal.cmx int32.cmx obj.cmi -oo.cmo : camlinternalOO.cmi oo.cmi -oo.p.cmx : camlinternalOO.cmx oo.cmi -parsing.cmo : obj.cmi lexing.cmi array.cmi parsing.cmi -parsing.p.cmx : obj.cmx lexing.cmx array.cmx parsing.cmi -pervasives.cmo : camlinternalFormatBasics.cmi pervasives.cmi -pervasives.p.cmx : camlinternalFormatBasics.cmx pervasives.cmi -printexc.cmo : printf.cmi pervasives.cmi obj.cmi buffer.cmi array.cmi \ - printexc.cmi -printexc.p.cmx : printf.cmx pervasives.cmx obj.cmx buffer.cmx array.cmx \ - printexc.cmi -printf.cmo : camlinternalFormatBasics.cmi camlinternalFormat.cmi buffer.cmi \ - printf.cmi -printf.p.cmx : camlinternalFormatBasics.cmx camlinternalFormat.cmx buffer.cmx \ - printf.cmi -queue.cmo : queue.cmi -queue.p.cmx : queue.cmi -random.cmo : string.cmi pervasives.cmi nativeint.cmi int64.cmi int32.cmi \ - digest.cmi char.cmi array.cmi random.cmi -random.p.cmx : string.cmx pervasives.cmx nativeint.cmx int64.cmx int32.cmx \ - digest.cmx char.cmx array.cmx random.cmi -scanf.cmo : string.cmi printf.cmi pervasives.cmi list.cmi \ - camlinternalFormatBasics.cmi camlinternalFormat.cmi bytes.cmi buffer.cmi \ - scanf.cmi -scanf.p.cmx : string.cmx printf.cmx pervasives.cmx list.cmx \ - camlinternalFormatBasics.cmx camlinternalFormat.cmx bytes.cmx buffer.cmx \ - scanf.cmi -set.cmo : list.cmi set.cmi -set.p.cmx : list.cmx set.cmi -sort.cmo : array.cmi sort.cmi -sort.p.cmx : array.cmx sort.cmi -spacetime.cmo : gc.cmi spacetime.cmi -spacetime.p.cmx : gc.cmx spacetime.cmi -stack.cmo : list.cmi stack.cmi -stack.p.cmx : list.cmx stack.cmi -stdLabels.cmo : stringLabels.cmi listLabels.cmi bytesLabels.cmi \ - arrayLabels.cmi stdLabels.cmi -stdLabels.p.cmx : stringLabels.cmx listLabels.cmx bytesLabels.cmx \ - arrayLabels.cmx stdLabels.cmi +camlinternalOO.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__obj.cmi stdlib__map.cmi stdlib__list.cmi stdlib__char.cmi \ + stdlib__array.cmi camlinternalOO.cmi +camlinternalOO.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__obj.cmx stdlib__map.cmx stdlib__list.cmx stdlib__char.cmx \ + stdlib__array.cmx camlinternalOO.cmi +stdlib__char.cmo : stdlib__char.cmi +stdlib__char.p.cmx : stdlib__char.cmi +stdlib__complex.cmo : stdlib__complex.cmi +stdlib__complex.p.cmx : stdlib__complex.cmi +stdlib__digest.cmo : stdlib__string.cmi stdlib__char.cmi stdlib__bytes.cmi stdlib__digest.cmi +stdlib__digest.p.cmx : stdlib__string.cmx stdlib__char.cmx stdlib__bytes.cmx stdlib__digest.cmi +stdlib__ephemeron.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__random.cmi stdlib__obj.cmi stdlib__lazy.cmi stdlib__hashtbl.cmi \ + stdlib__array.cmi stdlib__ephemeron.cmi +stdlib__ephemeron.p.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__random.cmx stdlib__obj.cmx stdlib__lazy.cmx stdlib__hashtbl.cmx \ + stdlib__array.cmx stdlib__ephemeron.cmi +stdlib__filename.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__random.cmi stdlib__printf.cmi stdlib__lazy.cmi stdlib__buffer.cmi \ + stdlib__filename.cmi +stdlib__filename.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__random.cmx stdlib__printf.cmx stdlib__lazy.cmx stdlib__buffer.cmx \ + stdlib__filename.cmi +stdlib__float.cmo : stdlib__float.cmi +stdlib__float.p.cmx : stdlib__float.cmi +stdlib__format.cmo : stdlib__string.cmi stdlib__list.cmi camlinternalFormatBasics.cmi \ + camlinternalFormat.cmi stdlib__buffer.cmi stdlib__format.cmi +stdlib__format.p.cmx : stdlib__string.cmx stdlib__list.cmx camlinternalFormatBasics.cmx \ + camlinternalFormat.cmx stdlib__buffer.cmx stdlib__format.cmi +stdlib__gc.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__printf.cmi stdlib__gc.cmi +stdlib__gc.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__printf.cmx stdlib__gc.cmi +stdlib__genlex.cmo : stdlib__string.cmi stdlib__stream.cmi stdlib__list.cmi stdlib__hashtbl.cmi stdlib__char.cmi stdlib__bytes.cmi \ + stdlib__genlex.cmi +stdlib__genlex.p.cmx : stdlib__string.cmx stdlib__stream.cmx stdlib__list.cmx stdlib__hashtbl.cmx stdlib__char.cmx stdlib__bytes.cmx \ + stdlib__genlex.cmi +stdlib__hashtbl.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__seq.cmi stdlib__random.cmi stdlib__obj.cmi stdlib__lazy.cmi \ + stdlib__array.cmi stdlib__hashtbl.cmi +stdlib__hashtbl.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__seq.cmx stdlib__random.cmx stdlib__obj.cmx stdlib__lazy.cmx \ + stdlib__array.cmx stdlib__hashtbl.cmi +stdlib__int32.cmo : stdlib__int32.cmi +stdlib__int32.p.cmx : stdlib__int32.cmi +stdlib__int64.cmo : stdlib__int64.cmi +stdlib__int64.p.cmx : stdlib__int64.cmi +stdlib__lazy.cmo : stdlib__obj.cmi camlinternalLazy.cmi stdlib__lazy.cmi +stdlib__lazy.p.cmx : stdlib__obj.cmx camlinternalLazy.cmx stdlib__lazy.cmi +stdlib__lexing.cmo : stdlib__sys.cmi stdlib__string.cmi stdlib__bytes.cmi stdlib__array.cmi stdlib__lexing.cmi +stdlib__lexing.p.cmx : stdlib__sys.cmx stdlib__string.cmx stdlib__bytes.cmx stdlib__array.cmx stdlib__lexing.cmi +stdlib__list.cmo : stdlib__sys.cmi stdlib__seq.cmi stdlib__list.cmi +stdlib__list.p.cmx : stdlib__sys.cmx stdlib__seq.cmx stdlib__list.cmi +stdlib__listLabels.cmo : stdlib__list.cmi stdlib__listLabels.cmi +stdlib__listLabels.p.cmx : stdlib__list.cmx stdlib__listLabels.cmi +stdlib__map.cmo : stdlib__seq.cmi stdlib__map.cmi +stdlib__map.p.cmx : stdlib__seq.cmx stdlib__map.cmi +stdlib__marshal.cmo : stdlib__bytes.cmi stdlib__marshal.cmi +stdlib__marshal.p.cmx : stdlib__bytes.cmx stdlib__marshal.cmi +stdlib__moreLabels.cmo : stdlib__set.cmi stdlib__map.cmi stdlib__hashtbl.cmi stdlib__moreLabels.cmi +stdlib__moreLabels.p.cmx : stdlib__set.cmx stdlib__map.cmx stdlib__hashtbl.cmx stdlib__moreLabels.cmi +stdlib__nativeint.cmo : stdlib__sys.cmi stdlib__nativeint.cmi +stdlib__nativeint.p.cmx : stdlib__sys.cmx stdlib__nativeint.cmi +stdlib__obj.cmo : stdlib__marshal.cmi stdlib__int32.cmi stdlib__obj.cmi +stdlib__obj.p.cmx : stdlib__marshal.cmx stdlib__int32.cmx stdlib__obj.cmi +stdlib__oo.cmo : camlinternalOO.cmi stdlib__oo.cmi +stdlib__oo.p.cmx : camlinternalOO.cmx stdlib__oo.cmi +stdlib__parsing.cmo : stdlib__obj.cmi stdlib__lexing.cmi stdlib__array.cmi stdlib__parsing.cmi +stdlib__parsing.p.cmx : stdlib__obj.cmx stdlib__lexing.cmx stdlib__array.cmx stdlib__parsing.cmi +stdlib__printexc.cmo : stdlib__printf.cmi stdlib__obj.cmi stdlib__buffer.cmi stdlib__array.cmi stdlib__printexc.cmi +stdlib__printexc.p.cmx : stdlib__printf.cmx stdlib__obj.cmx stdlib__buffer.cmx stdlib__array.cmx stdlib__printexc.cmi +stdlib__printf.cmo : camlinternalFormatBasics.cmi camlinternalFormat.cmi stdlib__buffer.cmi \ + stdlib__printf.cmi +stdlib__printf.p.cmx : camlinternalFormatBasics.cmx camlinternalFormat.cmx stdlib__buffer.cmx \ + stdlib__printf.cmi +stdlib__queue.cmo : stdlib__seq.cmi stdlib__queue.cmi +stdlib__queue.p.cmx : stdlib__seq.cmx stdlib__queue.cmi +stdlib__random.cmo : stdlib__string.cmi stdlib__nativeint.cmi stdlib__int64.cmi stdlib__int32.cmi stdlib__digest.cmi \ + stdlib__char.cmi stdlib__array.cmi stdlib__random.cmi +stdlib__random.p.cmx : stdlib__string.cmx stdlib__nativeint.cmx stdlib__int64.cmx stdlib__int32.cmx stdlib__digest.cmx \ + stdlib__char.cmx stdlib__array.cmx stdlib__random.cmi +stdlib__scanf.cmo : stdlib__string.cmi stdlib__printf.cmi stdlib__list.cmi camlinternalFormatBasics.cmi \ + camlinternalFormat.cmi stdlib__bytes.cmi stdlib__buffer.cmi stdlib__scanf.cmi +stdlib__scanf.p.cmx : stdlib__string.cmx stdlib__printf.cmx stdlib__list.cmx camlinternalFormatBasics.cmx \ + camlinternalFormat.cmx stdlib__bytes.cmx stdlib__buffer.cmx stdlib__scanf.cmi +stdlib__seq.cmo : stdlib__seq.cmi +stdlib__seq.p.cmx : stdlib__seq.cmi +stdlib__set.cmo : stdlib__seq.cmi stdlib__list.cmi stdlib__set.cmi +stdlib__set.p.cmx : stdlib__seq.cmx stdlib__list.cmx stdlib__set.cmi +stdlib__sort.cmo : stdlib__array.cmi stdlib__sort.cmi +stdlib__sort.p.cmx : stdlib__array.cmx stdlib__sort.cmi +stdlib__spacetime.cmo : stdlib__gc.cmi stdlib__spacetime.cmi +stdlib__spacetime.p.cmx : stdlib__gc.cmx stdlib__spacetime.cmi +stdlib__stack.cmo : stdlib__seq.cmi stdlib__list.cmi stdlib__stack.cmi +stdlib__stack.p.cmx : stdlib__seq.cmx stdlib__list.cmx stdlib__stack.cmi +stdlib__stdLabels.cmo : stdlib__stringLabels.cmi stdlib__listLabels.cmi stdlib__bytesLabels.cmi \ + stdlib__arrayLabels.cmi stdlib__stdLabels.cmi +stdlib__stdLabels.p.cmx : stdlib__stringLabels.cmx stdlib__listLabels.cmx stdlib__bytesLabels.cmx \ + stdlib__arrayLabels.cmx stdlib__stdLabels.cmi std_exit.cmo : std_exit.cmx : -stream.cmo : string.cmi list.cmi lazy.cmi bytes.cmi stream.cmi -stream.p.cmx : string.cmx list.cmx lazy.cmx bytes.cmx stream.cmi -string.cmo : pervasives.cmi bytes.cmi string.cmi -string.p.cmx : pervasives.cmx bytes.cmx string.cmi -stringLabels.cmo : string.cmi stringLabels.cmi -stringLabels.p.cmx : string.cmx stringLabels.cmi -sys.cmo : sys.cmi -sys.p.cmx : sys.cmi -uchar.cmo : pervasives.cmi char.cmi uchar.cmi -uchar.p.cmx : pervasives.cmx char.cmx uchar.cmi -weak.cmo : sys.cmi obj.cmi hashtbl.cmi array.cmi weak.cmi -weak.p.cmx : sys.cmx obj.cmx hashtbl.cmx array.cmx weak.cmi +stdlib__stream.cmo : stdlib__string.cmi stdlib__list.cmi stdlib__lazy.cmi stdlib__bytes.cmi stdlib__stream.cmi +stdlib__stream.p.cmx : stdlib__string.cmx stdlib__list.cmx stdlib__lazy.cmx stdlib__bytes.cmx stdlib__stream.cmi +stdlib__string.cmo : stdlib__bytes.cmi stdlib__string.cmi +stdlib__string.p.cmx : stdlib__bytes.cmx stdlib__string.cmi +stdlib__stringLabels.cmo : stdlib__string.cmi stdlib__stringLabels.cmi +stdlib__stringLabels.p.cmx : stdlib__string.cmx stdlib__stringLabels.cmi +stdlib__sys.cmo : stdlib__sys.cmi +stdlib__sys.p.cmx : stdlib__sys.cmi +stdlib__uchar.cmo : stdlib__char.cmi stdlib__uchar.cmi +stdlib__uchar.p.cmx : stdlib__char.cmx stdlib__uchar.cmi +stdlib__weak.cmo : stdlib__sys.cmi stdlib__obj.cmi stdlib__hashtbl.cmi stdlib__array.cmi stdlib__weak.cmi +stdlib__weak.p.cmx : stdlib__sys.cmx stdlib__obj.cmx stdlib__hashtbl.cmx stdlib__array.cmx stdlib__weak.cmi +stdlib.cmo : camlinternalFormatBasics.cmi stdlib.cmi +stdlib.p.cmx : camlinternalFormatBasics.cmx stdlib.cmi diff --git a/stdlib/Compflags b/stdlib/Compflags index 0f7b922a..0bffcebe 100755 --- a/stdlib/Compflags +++ b/stdlib/Compflags @@ -15,16 +15,20 @@ #************************************************************************** case $1 in - pervasives.cm[iox]|pervasives.p.cmx) echo ' -nopervasives';; - camlinternalOO.cmi) echo ' -nopervasives';; + stdlib.cm[iox]|stdlib.p.cmx) + echo ' -nopervasives -no-alias-deps -w -49' \ + ' -pp "$AWK -f expand_module_aliases.awk"';; + stdlib__pervasives.cm[iox]|stdlib__pervasives.p.cmx) echo ' -nopervasives';; camlinternalOO.cmx|camlinternalOO.p.cmx) echo ' -inline 0';; - buffer.cmx|buffer.p.cmx) echo ' -inline 3';; + stdlib__buffer.cmx|stdlib__buffer.p.cmx) echo ' -inline 3';; # make sure add_char is inlined (PR#5872) - buffer.cm[io]) echo ' -w A';; + stdlib__buffer.cm[io]) echo ' -w A';; camlinternalFormat.cm[io]) echo ' -w Ae';; camlinternalFormatBasics*.cm[iox]) echo ' -nopervasives';; - printf.cm[io]|format.cm[io]|scanf.cm[io]) echo ' -w Ae';; - scanf.cmx|scanf.p.cmx) echo ' -inline 9';; + stdlib__printf.cm[io]|stdlib__format.cm[io]|stdlib__scanf.cm[io]) + echo ' -w Ae';; + stdlib__scanf.cmx|stdlib__scanf.p.cmx) echo ' -inline 9';; *Labels.cm[ox]|*Labels.p.cmx) echo ' -nolabels -no-alias-deps';; + pervasives.cm[iox]|pervasives.p.cmx) echo ' -nopervasives -no-alias-deps -w -49';; *) echo ' ';; esac diff --git a/stdlib/Makefile b/stdlib/Makefile index 5f7bde13..4b044914 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -14,6 +14,8 @@ #************************************************************************** include ../config/Makefile +include ../Makefile.common + CAMLRUN ?= ../boot/ocamlrun CAMLYACC ?= ../boot/ocamlyacc TARGET_BINDIR ?= $(BINDIR) @@ -32,33 +34,39 @@ OPTCOMPILER=../ocamlopt CAMLOPT=$(CAMLRUN) $(OPTCOMPILER) CAMLDEP=$(CAMLRUN) ../tools/ocamldep -OBJS=camlinternalFormatBasics.cmo pervasives.cmo $(OTHERS) -OTHERS=list.cmo char.cmo uchar.cmo bytes.cmo string.cmo sys.cmo \ - sort.cmo marshal.cmo obj.cmo array.cmo \ - int32.cmo int64.cmo nativeint.cmo \ - lexing.cmo parsing.cmo \ - set.cmo map.cmo stack.cmo queue.cmo \ - camlinternalLazy.cmo lazy.cmo stream.cmo \ - buffer.cmo camlinternalFormat.cmo printf.cmo \ - arg.cmo printexc.cmo gc.cmo \ - digest.cmo random.cmo hashtbl.cmo weak.cmo \ - format.cmo scanf.cmo callback.cmo \ - camlinternalOO.cmo oo.cmo camlinternalMod.cmo \ - genlex.cmo ephemeron.cmo \ - filename.cmo complex.cmo \ - arrayLabels.cmo listLabels.cmo bytesLabels.cmo \ - stringLabels.cmo moreLabels.cmo stdLabels.cmo \ - spacetime.cmo camlinternalBigarray.cmo +# Object file prefix +P=stdlib__ + +OBJS=camlinternalFormatBasics.cmo stdlib.cmo $(OTHERS) +OTHERS=$(P)seq.cmo $(P)char.cmo $(P)uchar.cmo $(P)sys.cmo $(P)list.cmo \ + $(P)bytes.cmo $(P)string.cmo \ + $(P)sort.cmo $(P)marshal.cmo $(P)obj.cmo $(P)float.cmo $(P)array.cmo \ + $(P)int32.cmo $(P)int64.cmo $(P)nativeint.cmo \ + $(P)lexing.cmo $(P)parsing.cmo \ + $(P)set.cmo $(P)map.cmo $(P)stack.cmo $(P)queue.cmo \ + camlinternalLazy.cmo $(P)lazy.cmo $(P)stream.cmo \ + $(P)buffer.cmo camlinternalFormat.cmo $(P)printf.cmo \ + $(P)arg.cmo $(P)printexc.cmo $(P)gc.cmo \ + $(P)digest.cmo $(P)random.cmo $(P)hashtbl.cmo $(P)weak.cmo \ + $(P)format.cmo $(P)scanf.cmo $(P)callback.cmo \ + camlinternalOO.cmo $(P)oo.cmo camlinternalMod.cmo \ + $(P)genlex.cmo $(P)ephemeron.cmo \ + $(P)filename.cmo $(P)complex.cmo \ + $(P)arrayLabels.cmo $(P)listLabels.cmo $(P)bytesLabels.cmo \ + $(P)stringLabels.cmo $(P)moreLabels.cmo $(P)stdLabels.cmo \ + $(P)spacetime.cmo $(P)bigarray.cmo + +PREFIXED_OBJS=$(filter stdlib__%.cmo,$(OBJS)) .PHONY: all all: stdlib.cma std_exit.cmo camlheader target_camlheader camlheader_ur ifeq "$(RUNTIMED)" "true" -all: camlheaderd +all: camlheaderd target_camlheaderd endif ifeq "$(RUNTIMEI)" "true" -all: camlheaderi +all: camlheaderi target_camlheaderi endif ifeq "$(PROFILING)" "true" @@ -77,23 +85,28 @@ allopt-noprof: allopt-prof: stdlib.p.cmxa std_exit.p.cmx rm -f std_exit.p.cmi -INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR) - .PHONY: install install:: - cp stdlib.cma std_exit.cmo *.cmi *.cmt *.cmti *.mli *.ml \ - camlheader_ur \ +# Transitional: when upgrading from 4.06 -> 4.07, module M is in stdlib__m.cm*, +# while previously it was in m.cm*, which confuses the compiler. + rm -f $(patsubst stdlib__%,"$(INSTALL_LIBDIR)/%", $(filter stdlib__%,$(OBJS))) +# Remove "old" pervasives.* and bigarray.* to avoid getting confused with the +# Stdlib versions. + rm -f "$(INSTALL_LIBDIR)/pervasives.*" "$(INSTALL_LIBDIR)/bigarray.*" +# End transitional + $(INSTALL_DATA) \ + stdlib.cma std_exit.cmo *.cmi *.cmt *.cmti *.mli *.ml camlheader_ur \ "$(INSTALL_LIBDIR)" - cp target_camlheader "$(INSTALL_LIBDIR)/camlheader" + $(INSTALL_DATA) target_camlheader "$(INSTALL_LIBDIR)/camlheader" ifeq "$(RUNTIMED)" "true" install:: - cp target_camlheaderd $(INSTALL_LIBDIR) + $(INSTALL_DATA) target_camlheaderd $(INSTALL_LIBDIR) endif ifeq "$(RUNTIMEI)" "true" install:: - cp target_camlheaderi $(INSTALL_LIBDIR) + $(INSTALL_DATA) target_camlheaderi $(INSTALL_LIBDIR) endif .PHONY: installopt @@ -101,7 +114,9 @@ installopt: installopt-default installopt-$(PROFILINGTARGET) .PHONY: installopt-default installopt-default: - cp stdlib.cmxa stdlib.$(A) std_exit.$(O) *.cmx "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) \ + stdlib.cmxa stdlib.$(A) std_exit.$(O) *.cmx \ + "$(INSTALL_LIBDIR)" cd "$(INSTALL_LIBDIR)"; $(RANLIB) stdlib.$(A) .PHONY: installopt-noprof @@ -109,7 +124,8 @@ installopt-noprof: .PHONY: installopt-prof installopt-prof: - cp stdlib.p.cmxa stdlib.p.$(A) std_exit.p.cmx std_exit.p.$(O) \ + $(INSTALL_DATA) \ + stdlib.p.cmxa stdlib.p.$(A) std_exit.p.cmx std_exit.p.$(O) \ "$(INSTALL_LIBDIR)" cd "$(INSTALL_LIBDIR)"; $(RANLIB) stdlib.p.$(A) @@ -156,27 +172,36 @@ else # Windows # TODO: see whether there is a way to further merge the rules below # with those above -camlheader target_camlheader camlheader_ur: headernt.c +camlheader: headernt.c $(CC) -c $(CFLAGS) $(CPPFLAGS) -I../byterun \ -DRUNTIME_NAME='"ocamlrun"' $(OUTPUTOBJ)headernt.$(O) $< $(MKEXE) -o tmpheader.exe headernt.$(O) $(EXTRALIBS) rm -f camlheader.exe mv tmpheader.exe camlheader + +target_camlheader: camlheader cp camlheader target_camlheader + +camlheader_ur: camlheader cp camlheader camlheader_ur -camlheaderd target_camlheaderd: headernt.c +camlheaderd: headernt.c $(CC) -c $(CFLAGS) $(CPPFLAGS) -I../byterun \ - -DRUNTIME_NAME='"ocamlrund"' $(OUTPUTOBJ)headernt.$(O) $< - $(MKEXE) -o tmpheader.exe headernt.$(O) $(EXTRALIBS) - mv tmpheader.exe camlheaderd + -DRUNTIME_NAME='"ocamlrund"' $(OUTPUTOBJ)headerntd.$(O) $< + $(MKEXE) -o tmpheaderd.exe headerntd.$(O) $(EXTRALIBS) + mv tmpheaderd.exe camlheaderd + +target_camlheaderd: camlheaderd cp camlheaderd target_camlheaderd camlheaderi: headernt.c $(CC) -c $(CFLAGS) $(CPPFLAGS) -I../byterun \ - -DRUNTIME_NAME='"ocamlruni"' $(OUTPUTOBJ)headernt.$(O) - $(MKEXE) -o tmpheader.exe headernt.$(O) $(EXTRALIBS) - mv tmpheader.exe camlheaderi + -DRUNTIME_NAME='"ocamlruni"' $(OUTPUTOBJ)headernti.$(O) $< + $(MKEXE) -o tmpheaderi.exe headernti.$(O) $(EXTRALIBS) + mv tmpheaderi.exe camlheaderi + +target_camlheaderi: camlheaderi + cp camlheaderi target_camlheaderi # TODO: do not call flexlink to build tmpheader.exe (we don't need # the export table) @@ -206,18 +231,34 @@ clean:: .SUFFIXES: .mli .ml .cmi .cmo .cmx .p.cmx -.mli.cmi: - $(CAMLC) $(COMPFLAGS) `sh ./Compflags $@` -c $< +export AWK + +%.cmi: %.mli + $(CAMLC) $(COMPFLAGS) $(shell ./Compflags $@) -c $< + +stdlib__%.cmi: %.mli + $(CAMLC) $(COMPFLAGS) $(shell ./Compflags $@) -o $@ -c $< + +%.cmo: %.ml + $(CAMLC) $(COMPFLAGS) $(shell ./Compflags $@) -c $< -.ml.cmo: - $(CAMLC) $(COMPFLAGS) `sh ./Compflags $@` -c $< +stdlib__%.cmo: %.ml + $(CAMLC) $(COMPFLAGS) $(shell ./Compflags $@) -o $@ -c $< -.ml.cmx: - $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) `sh ./Compflags $@` -c $< +%.cmx: %.ml + $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) $(shell ./Compflags $@) -c $< -.ml.p.cmx: - $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) `sh ./Compflags $@` \ - -p -c -o $*.p.cmx $< +stdlib__%.cmx: %.ml + $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) $(shell ./Compflags $@) \ + -o $@ -c $< + +%.p.cmx: %.ml + $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) $(shell ./Compflags $@) \ + -p -c -o $@ $< + +stdlib__%.p.cmx: %.ml + $(CAMLOPT) $(COMPFLAGS) $(OPTCOMPFLAGS) $(shell ./Compflags $@) \ + -p -c -o $@ $< # Dependencies on the compiler COMPILER_DEPS=$(filter-out -use-prims, $(COMPILER)) @@ -226,25 +267,38 @@ $(OBJS:.cmo=.cmi) std_exit.cmi: $(COMPILER_DEPS) $(OBJS:.cmo=.cmx) std_exit.cmx: $(OPTCOMPILER) $(OBJS:.cmo=.p.cmx) std_exit.p.cmx: $(OPTCOMPILER) -# Dependencies on Pervasives (not tracked by ocamldep) -$(OTHERS) std_exit.cmo: pervasives.cmi -$(OTHERS:.cmo=.cmi) std_exit.cmi: pervasives.cmi -$(OBJS:.cmo=.cmx) std_exit.cmx: pervasives.cmi -$(OBJS:.cmo=.p.cmx) std_exit.p.cmx: pervasives.cmi -$(OTHERS:.cmo=.cmx) std_exit.cmx: pervasives.cmx -$(OTHERS:.cmo=.p.cmx) std_exit.p.cmx: pervasives.cmx +# Dependencies on Stdlib (not tracked by ocamldep) +$(OTHERS) std_exit.cmo: stdlib.cmi +$(OTHERS:.cmo=.cmi) std_exit.cmi: stdlib.cmi +$(OBJS:.cmo=.cmx) std_exit.cmx: stdlib.cmi +$(OBJS:.cmo=.p.cmx) std_exit.p.cmx: stdlib.cmi +$(OTHERS:.cmo=.cmx) std_exit.cmx: stdlib.cmx +$(OTHERS:.cmo=.p.cmx) std_exit.p.cmx: stdlib.cmx clean:: - rm -f *.cm* *.$(O) *.$(A) + rm -f *.cm* *.$(O) *.$(A) *.odoc rm -f *~ rm -f camlheader* include .depend +EMPTY := +SPACE := $(EMPTY) $(EMPTY) + # Note that .p.cmx targets do not depend (for compilation) upon other # .p.cmx files. When the compiler imports another compilation unit, # it looks for the .cmx file (not .p.cmx). .PHONY: depend depend: - $(CAMLDEP) -slash *.mli *.ml > .depend - $(CAMLDEP) -slash *.ml | sed -e 's/\.cmx : /.p.cmx : /g' >>.depend + $(CAMLDEP) -slash $(filter-out stdlib.%,$(wildcard *.mli *.ml)) \ + > .depend.tmp + $(CAMLDEP) -slash -pp "$(AWK) -f remove_module_aliases.awk" \ + stdlib.ml stdlib.mli >> .depend.tmp + $(CAMLDEP) -slash $(filter-out stdlib.%,$(wildcard *.ml)) \ + | sed -e 's/\.cmx : /.p.cmx : /g' >>.depend.tmp + $(CAMLDEP) -slash -pp "$(AWK) -f remove_module_aliases.awk" stdlib.ml \ + | sed -e 's/\.cmx : /.p.cmx : /g' >> .depend.tmp + sed -Ee \ + 's#(^| )(${subst ${SPACE},|,${PREFIXED_OBJS:stdlib__%.cmo=%}})[.]#\1stdlib__\2.#g' \ + .depend.tmp > .depend + rm -f .depend.tmp diff --git a/stdlib/StdlibModules b/stdlib/StdlibModules index 28207401..490c78cd 100644 --- a/stdlib/StdlibModules +++ b/stdlib/StdlibModules @@ -18,55 +18,60 @@ # This file lists all standard library modules. # It is used in particular to know what to expunge in toplevels. +P ?= stdlib__ + STDLIB_MODULES=\ - spacetime \ - arg \ - array \ - arrayLabels \ - buffer \ - bytes \ - bytesLabels \ - callback \ + $(P)spacetime \ + $(P)arg \ + $(P)array \ + $(P)arrayLabels \ + $(P)bigarray \ + $(P)buffer \ + $(P)bytes \ + $(P)bytesLabels \ + $(P)callback \ camlinternalFormat \ camlinternalFormatBasics \ camlinternalLazy \ camlinternalMod \ camlinternalOO \ - char \ - complex \ - digest \ - ephemeron \ - filename \ - format \ - gc \ - genlex \ - hashtbl \ - int32 \ - int64 \ - lazy \ - lexing \ - list \ - listLabels \ - map \ - marshal \ - moreLabels \ - nativeint \ - obj \ - oo \ - parsing \ - pervasives \ - printexc \ - printf \ - queue \ - random \ - scanf \ - set \ - sort \ - stack \ - stdLabels \ - stream \ - string \ - stringLabels \ - sys \ - uchar \ - weak + $(P)char \ + $(P)complex \ + $(P)digest \ + $(P)ephemeron \ + $(P)filename \ + $(P)float \ + $(P)format \ + $(P)gc \ + $(P)genlex \ + $(P)hashtbl \ + $(P)int32 \ + $(P)int64 \ + $(P)lazy \ + $(P)lexing \ + $(P)list \ + $(P)listLabels \ + $(P)map \ + $(P)marshal \ + $(P)moreLabels \ + $(P)nativeint \ + $(P)obj \ + $(P)oo \ + $(P)parsing \ + $(P)printexc \ + $(P)printf \ + $(P)queue \ + $(P)random \ + $(P)scanf \ + $(P)seq \ + $(P)set \ + $(P)sort \ + $(P)stack \ + $(P)stdLabels \ + stdlib \ + $(P)stream \ + $(P)string \ + $(P)stringLabels \ + $(P)sys \ + $(P)uchar \ + $(P)weak diff --git a/stdlib/arg.ml b/stdlib/arg.ml index e315e511..eb06f795 100644 --- a/stdlib/arg.ml +++ b/stdlib/arg.ml @@ -369,23 +369,19 @@ let read_aux trim sep file = let buf = Buffer.create 200 in let words = ref [] in let stash () = - let word = (Buffer.contents buf) in + let word = Buffer.contents buf in let word = if trim then trim_cr word else word in words := word :: !words; Buffer.clear buf in - let rec read () = - try - let c = input_char ic in - if c = sep then begin - stash (); read () - end else begin - Buffer.add_char buf c; read () - end - with End_of_file -> - if Buffer.length buf > 0 then - stash () in - read (); + begin + try while true do + let c = input_char ic in + if c = sep then stash () else Buffer.add_char buf c + done + with End_of_file -> () + end; + if Buffer.length buf > 0 then stash (); close_in ic; Array.of_list (List.rev !words) diff --git a/stdlib/array.ml b/stdlib/array.ml index 9b545878..d29a04fa 100644 --- a/stdlib/array.ml +++ b/stdlib/array.ml @@ -302,3 +302,40 @@ let stable_sort cmp a = let fast_sort = stable_sort + +(** {6 Iterators} *) + +let to_seq a = + let rec aux i () = + if i < length a + then + let x = unsafe_get a i in + Seq.Cons (x, aux (i+1)) + else Seq.Nil + in + aux 0 + +let to_seqi a = + let rec aux i () = + if i < length a + then + let x = unsafe_get a i in + Seq.Cons ((i,x), aux (i+1)) + else Seq.Nil + in + aux 0 + +let of_rev_list = function + [] -> [||] + | hd::tl as l -> + let len = list_length 0 l in + let a = create len hd in + let rec fill i = function + [] -> a + | hd::tl -> unsafe_set a i hd; fill (i-1) tl + in + fill (len-1) tl + +let of_seq i = + let l = Seq.fold_left (fun acc x -> x::acc) [] i in + of_rev_list l diff --git a/stdlib/array.mli b/stdlib/array.mli index bfad5317..0a9e7f3f 100644 --- a/stdlib/array.mli +++ b/stdlib/array.mli @@ -256,6 +256,23 @@ val fast_sort : ('a -> 'a -> int) -> 'a array -> unit *) +(** {6 Iterators} *) + +val to_seq : 'a array -> 'a Seq.t +(** Iterate on the array, in increasing order. Modifications of the + array during iteration will be reflected in the iterator. + @since 4.07 *) + +val to_seqi : 'a array -> (int * 'a) Seq.t +(** Iterate on the array, in increasing order, yielding indices along elements. + Modifications of the array during iteration will be reflected in the + iterator. + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a array +(** Create an array from the generator + @since 4.07 *) + (**/**) (** {1 Undocumented functions} *) diff --git a/stdlib/arrayLabels.mli b/stdlib/arrayLabels.mli index 0b9fe0c9..2ecf4dd2 100644 --- a/stdlib/arrayLabels.mli +++ b/stdlib/arrayLabels.mli @@ -256,6 +256,20 @@ val fast_sort : cmp:('a -> 'a -> int) -> 'a array -> unit *) +(** {6 Iterators} *) + +val to_seq : 'a array -> 'a Seq.t +(** Iterate on the array, in increasing order + @since 4.07 *) + +val to_seqi : 'a array -> (int * 'a) Seq.t +(** Iterate on the array, in increasing order, yielding indices along elements + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a array +(** Create an array from the generator + @since 4.07 *) + (**/**) (** {1 Undocumented functions} *) diff --git a/stdlib/bigarray.ml b/stdlib/bigarray.ml new file mode 100644 index 00000000..86c737ae --- /dev/null +++ b/stdlib/bigarray.ml @@ -0,0 +1,349 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Manuel Serrano et Xavier Leroy, INRIA Rocquencourt *) +(* *) +(* Copyright 2000 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Module [Bigarray]: large, multi-dimensional, numerical arrays *) + +(* These types in must be kept in sync with the tables in + ../typing/typeopt.ml *) + +type float32_elt = Float32_elt +type float64_elt = Float64_elt +type int8_signed_elt = Int8_signed_elt +type int8_unsigned_elt = Int8_unsigned_elt +type int16_signed_elt = Int16_signed_elt +type int16_unsigned_elt = Int16_unsigned_elt +type int32_elt = Int32_elt +type int64_elt = Int64_elt +type int_elt = Int_elt +type nativeint_elt = Nativeint_elt +type complex32_elt = Complex32_elt +type complex64_elt = Complex64_elt + +type ('a, 'b) kind = + Float32 : (float, float32_elt) kind + | Float64 : (float, float64_elt) kind + | Int8_signed : (int, int8_signed_elt) kind + | Int8_unsigned : (int, int8_unsigned_elt) kind + | Int16_signed : (int, int16_signed_elt) kind + | Int16_unsigned : (int, int16_unsigned_elt) kind + | Int32 : (int32, int32_elt) kind + | Int64 : (int64, int64_elt) kind + | Int : (int, int_elt) kind + | Nativeint : (nativeint, nativeint_elt) kind + | Complex32 : (Complex.t, complex32_elt) kind + | Complex64 : (Complex.t, complex64_elt) kind + | Char : (char, int8_unsigned_elt) kind + +type c_layout = C_layout_typ +type fortran_layout = Fortran_layout_typ (**) + +type 'a layout = + C_layout: c_layout layout + | Fortran_layout: fortran_layout layout + +(* Keep those constants in sync with the caml_ba_kind enumeration + in bigarray.h *) + +let float32 = Float32 +let float64 = Float64 +let int8_signed = Int8_signed +let int8_unsigned = Int8_unsigned +let int16_signed = Int16_signed +let int16_unsigned = Int16_unsigned +let int32 = Int32 +let int64 = Int64 +let int = Int +let nativeint = Nativeint +let complex32 = Complex32 +let complex64 = Complex64 +let char = Char + +let kind_size_in_bytes : type a b. (a, b) kind -> int = function + | Float32 -> 4 + | Float64 -> 8 + | Int8_signed -> 1 + | Int8_unsigned -> 1 + | Int16_signed -> 2 + | Int16_unsigned -> 2 + | Int32 -> 4 + | Int64 -> 8 + | Int -> Sys.word_size / 8 + | Nativeint -> Sys.word_size / 8 + | Complex32 -> 8 + | Complex64 -> 16 + | Char -> 1 + +(* Keep those constants in sync with the caml_ba_layout enumeration + in bigarray.h *) + +let c_layout = C_layout +let fortran_layout = Fortran_layout + +module Genarray = struct + type ('a, 'b, 'c) t + external create: ('a, 'b) kind -> 'c layout -> int array -> ('a, 'b, 'c) t + = "caml_ba_create" + external get: ('a, 'b, 'c) t -> int array -> 'a + = "caml_ba_get_generic" + external set: ('a, 'b, 'c) t -> int array -> 'a -> unit + = "caml_ba_set_generic" + external num_dims: ('a, 'b, 'c) t -> int = "caml_ba_num_dims" + external nth_dim: ('a, 'b, 'c) t -> int -> int = "caml_ba_dim" + let dims a = + let n = num_dims a in + let d = Array.make n 0 in + for i = 0 to n-1 do d.(i) <- nth_dim a i done; + d + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + + let size_in_bytes arr = + (kind_size_in_bytes (kind arr)) * (Array.fold_left ( * ) 1 (dims arr)) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + external sub_right: ('a, 'b, fortran_layout) t -> int -> int -> + ('a, 'b, fortran_layout) t + = "caml_ba_sub" + external slice_left: ('a, 'b, c_layout) t -> int array -> + ('a, 'b, c_layout) t + = "caml_ba_slice" + external slice_right: ('a, 'b, fortran_layout) t -> int array -> + ('a, 'b, fortran_layout) t + = "caml_ba_slice" + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit + = "caml_ba_blit" + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" +end + +module Array0 = struct + type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t + let create kind layout = + Genarray.create kind layout [||] + let get arr = Genarray.get arr [||] + let set arr = Genarray.set arr [||] + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + + let size_in_bytes arr = kind_size_in_bytes (kind arr) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + + let of_value kind layout v = + let a = create kind layout in + set a v; + a +end + +module Array1 = struct + type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t + let create kind layout dim = + Genarray.create kind layout [|dim|] + external get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_ref_1" + external set: ('a, 'b, 'c) t -> int -> 'a -> unit = "%caml_ba_set_1" + external unsafe_get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_unsafe_ref_1" + external unsafe_set: ('a, 'b, 'c) t -> int -> 'a -> unit + = "%caml_ba_unsafe_set_1" + external dim: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + + let size_in_bytes arr = + (kind_size_in_bytes (kind arr)) * (dim arr) + + external sub: ('a, 'b, 'c) t -> int -> int -> ('a, 'b, 'c) t = "caml_ba_sub" + let slice (type t) (a : (_, _, t) Genarray.t) n = + match layout a with + | C_layout -> (Genarray.slice_left a [|n|] : (_, _, t) Genarray.t) + | Fortran_layout -> (Genarray.slice_right a [|n|]: (_, _, t) Genarray.t) + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + let of_array (type t) kind (layout: t layout) data = + let ba = create kind layout (Array.length data) in + let ofs = + match layout with + C_layout -> 0 + | Fortran_layout -> 1 + in + for i = 0 to Array.length data - 1 do unsafe_set ba (i + ofs) data.(i) done; + ba +end + +module Array2 = struct + type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t + let create kind layout dim1 dim2 = + Genarray.create kind layout [|dim1; dim2|] + external get: ('a, 'b, 'c) t -> int -> int -> 'a = "%caml_ba_ref_2" + external set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit = "%caml_ba_set_2" + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> 'a + = "%caml_ba_unsafe_ref_2" + external unsafe_set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit + = "%caml_ba_unsafe_set_2" + external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + + let size_in_bytes arr = + (kind_size_in_bytes (kind arr)) * (dim1 arr) * (dim2 arr) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + external sub_right: + ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t + = "caml_ba_sub" + let slice_left a n = Genarray.slice_left a [|n|] + let slice_right a n = Genarray.slice_right a [|n|] + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + let of_array (type t) kind (layout: t layout) data = + let dim1 = Array.length data in + let dim2 = if dim1 = 0 then 0 else Array.length data.(0) in + let ba = create kind layout dim1 dim2 in + let ofs = + match layout with + C_layout -> 0 + | Fortran_layout -> 1 + in + for i = 0 to dim1 - 1 do + let row = data.(i) in + if Array.length row <> dim2 then + invalid_arg("Bigarray.Array2.of_array: non-rectangular data"); + for j = 0 to dim2 - 1 do + unsafe_set ba (i + ofs) (j + ofs) row.(j) + done + done; + ba +end + +module Array3 = struct + type ('a, 'b, 'c) t = ('a, 'b, 'c) Genarray.t + let create kind layout dim1 dim2 dim3 = + Genarray.create kind layout [|dim1; dim2; dim3|] + external get: ('a, 'b, 'c) t -> int -> int -> int -> 'a = "%caml_ba_ref_3" + external set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit + = "%caml_ba_set_3" + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> int -> 'a + = "%caml_ba_unsafe_ref_3" + external unsafe_set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit + = "%caml_ba_unsafe_set_3" + external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" + external dim3: ('a, 'b, 'c) t -> int = "%caml_ba_dim_3" + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + + let size_in_bytes arr = + (kind_size_in_bytes (kind arr)) * (dim1 arr) * (dim2 arr) * (dim3 arr) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + external sub_right: + ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t + = "caml_ba_sub" + let slice_left_1 a n m = Genarray.slice_left a [|n; m|] + let slice_right_1 a n m = Genarray.slice_right a [|n; m|] + let slice_left_2 a n = Genarray.slice_left a [|n|] + let slice_right_2 a n = Genarray.slice_right a [|n|] + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + let of_array (type t) kind (layout: t layout) data = + let dim1 = Array.length data in + let dim2 = if dim1 = 0 then 0 else Array.length data.(0) in + let dim3 = if dim2 = 0 then 0 else Array.length data.(0).(0) in + let ba = create kind layout dim1 dim2 dim3 in + let ofs = + match layout with + C_layout -> 0 + | Fortran_layout -> 1 + in + for i = 0 to dim1 - 1 do + let row = data.(i) in + if Array.length row <> dim2 then + invalid_arg("Bigarray.Array3.of_array: non-cubic data"); + for j = 0 to dim2 - 1 do + let col = row.(j) in + if Array.length col <> dim3 then + invalid_arg("Bigarray.Array3.of_array: non-cubic data"); + for k = 0 to dim3 - 1 do + unsafe_set ba (i + ofs) (j + ofs) (k + ofs) col.(k) + done + done + done; + ba +end + +external genarray_of_array0: ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t + = "%identity" +external genarray_of_array1: ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t + = "%identity" +external genarray_of_array2: ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t + = "%identity" +external genarray_of_array3: ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t + = "%identity" +let array0_of_genarray a = + if Genarray.num_dims a = 0 then a + else invalid_arg "Bigarray.array0_of_genarray" +let array1_of_genarray a = + if Genarray.num_dims a = 1 then a + else invalid_arg "Bigarray.array1_of_genarray" +let array2_of_genarray a = + if Genarray.num_dims a = 2 then a + else invalid_arg "Bigarray.array2_of_genarray" +let array3_of_genarray a = + if Genarray.num_dims a = 3 then a + else invalid_arg "Bigarray.array3_of_genarray" + +external reshape: + ('a, 'b, 'c) Genarray.t -> int array -> ('a, 'b, 'c) Genarray.t + = "caml_ba_reshape" +let reshape_0 a = reshape a [||] +let reshape_1 a dim1 = reshape a [|dim1|] +let reshape_2 a dim1 dim2 = reshape a [|dim1;dim2|] +let reshape_3 a dim1 dim2 dim3 = reshape a [|dim1;dim2;dim3|] + +(* Force caml_ba_get_{1,2,3,N} to be linked in, since we don't refer + to those primitives directly in this file *) + +let _ = + let _ = Genarray.get in + let _ = Array1.get in + let _ = Array2.get in + let _ = Array3.get in + () + +[@@@ocaml.warning "-32"] +external get1: unit -> unit = "caml_ba_get_1" +external get2: unit -> unit = "caml_ba_get_2" +external get3: unit -> unit = "caml_ba_get_3" +external set1: unit -> unit = "caml_ba_set_1" +external set2: unit -> unit = "caml_ba_set_2" +external set3: unit -> unit = "caml_ba_set_3" diff --git a/stdlib/bigarray.mli b/stdlib/bigarray.mli new file mode 100644 index 00000000..39433dde --- /dev/null +++ b/stdlib/bigarray.mli @@ -0,0 +1,961 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Manuel Serrano and Xavier Leroy, INRIA Rocquencourt *) +(* *) +(* Copyright 2000 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(** Large, multi-dimensional, numerical arrays. + + This module implements multi-dimensional arrays of integers and + floating-point numbers, thereafter referred to as 'big arrays', + to distinguish them from the standard OCaml arrays described in + {!module:Array}. + + The implementation allows efficient sharing of large numerical + arrays between OCaml code and C or Fortran numerical libraries. + + The main differences between 'big arrays' and standard OCaml + arrays are as follows: + - Big arrays are not limited in size, unlike OCaml arrays. + (Normal float arrays are limited to 2,097,151 elements on a 32-bit + platform, and normal arrays of other types to 4,194,303 elements.) + - Big arrays are multi-dimensional. Any number of dimensions + between 0 and 16 is supported. In contrast, OCaml arrays + are mono-dimensional and require encoding multi-dimensional + arrays as arrays of arrays. + - Big arrays can only contain integers and floating-point numbers, + while OCaml arrays can contain arbitrary OCaml data types. + - Big arrays provide more space-efficient storage of + integer and floating-point elements than normal OCaml arrays, in + particular because they support 'small' types such as + single-precision floats and 8 and 16-bit integers, in addition to + the standard OCaml types of double-precision floats and 32 and + 64-bit integers. + - The memory layout of big arrays is entirely compatible with that + of arrays in C and Fortran, allowing large arrays to be passed + back and forth between OCaml code and C / Fortran code with no + data copying at all. + - Big arrays support interesting high-level operations that normal + arrays do not provide efficiently, such as extracting sub-arrays + and 'slicing' a multi-dimensional array along certain dimensions, + all without any copying. + + Users of this module are encouraged to do [open Bigarray] in their + source, then refer to array types and operations via short dot + notation, e.g. [Array1.t] or [Array2.sub]. + + Big arrays support all the OCaml ad-hoc polymorphic operations: + - comparisons ([=], [<>], [<=], etc, as well as {!Pervasives.compare}); + - hashing (module [Hash]); + - and structured input-output (the functions from the + {!Marshal} module, as well as {!Pervasives.output_value} + and {!Pervasives.input_value}). +*) + +(** {1 Element kinds} *) + +(** Big arrays can contain elements of the following kinds: +- IEEE single precision (32 bits) floating-point numbers + ({!Bigarray.float32_elt}), +- IEEE double precision (64 bits) floating-point numbers + ({!Bigarray.float64_elt}), +- IEEE single precision (2 * 32 bits) floating-point complex numbers + ({!Bigarray.complex32_elt}), +- IEEE double precision (2 * 64 bits) floating-point complex numbers + ({!Bigarray.complex64_elt}), +- 8-bit integers (signed or unsigned) + ({!Bigarray.int8_signed_elt} or {!Bigarray.int8_unsigned_elt}), +- 16-bit integers (signed or unsigned) + ({!Bigarray.int16_signed_elt} or {!Bigarray.int16_unsigned_elt}), +- OCaml integers (signed, 31 bits on 32-bit architectures, + 63 bits on 64-bit architectures) ({!Bigarray.int_elt}), +- 32-bit signed integers ({!Bigarray.int32_elt}), +- 64-bit signed integers ({!Bigarray.int64_elt}), +- platform-native signed integers (32 bits on 32-bit architectures, + 64 bits on 64-bit architectures) ({!Bigarray.nativeint_elt}). + + Each element kind is represented at the type level by one of the + [*_elt] types defined below (defined with a single constructor instead + of abstract types for technical injectivity reasons). + + @since 4.07.0 Moved from otherlibs to stdlib. +*) + +type float32_elt = Float32_elt +type float64_elt = Float64_elt +type int8_signed_elt = Int8_signed_elt +type int8_unsigned_elt = Int8_unsigned_elt +type int16_signed_elt = Int16_signed_elt +type int16_unsigned_elt = Int16_unsigned_elt +type int32_elt = Int32_elt +type int64_elt = Int64_elt +type int_elt = Int_elt +type nativeint_elt = Nativeint_elt +type complex32_elt = Complex32_elt +type complex64_elt = Complex64_elt + +type ('a, 'b) kind = + Float32 : (float, float32_elt) kind + | Float64 : (float, float64_elt) kind + | Int8_signed : (int, int8_signed_elt) kind + | Int8_unsigned : (int, int8_unsigned_elt) kind + | Int16_signed : (int, int16_signed_elt) kind + | Int16_unsigned : (int, int16_unsigned_elt) kind + | Int32 : (int32, int32_elt) kind + | Int64 : (int64, int64_elt) kind + | Int : (int, int_elt) kind + | Nativeint : (nativeint, nativeint_elt) kind + | Complex32 : (Complex.t, complex32_elt) kind + | Complex64 : (Complex.t, complex64_elt) kind + | Char : (char, int8_unsigned_elt) kind (**) +(** To each element kind is associated an OCaml type, which is + the type of OCaml values that can be stored in the big array + or read back from it. This type is not necessarily the same + as the type of the array elements proper: for instance, + a big array whose elements are of kind [float32_elt] contains + 32-bit single precision floats, but reading or writing one of + its elements from OCaml uses the OCaml type [float], which is + 64-bit double precision floats. + + The GADT type [('a, 'b) kind] captures this association + of an OCaml type ['a] for values read or written in the big array, + and of an element kind ['b] which represents the actual contents + of the big array. Its constructors list all possible associations + of OCaml types with element kinds, and are re-exported below for + backward-compatibility reasons. + + Using a generalized algebraic datatype (GADT) here allows to write + well-typed polymorphic functions whose return type depend on the + argument type, such as: + +{[ + let zero : type a b. (a, b) kind -> a = function + | Float32 -> 0.0 | Complex32 -> Complex.zero + | Float64 -> 0.0 | Complex64 -> Complex.zero + | Int8_signed -> 0 | Int8_unsigned -> 0 + | Int16_signed -> 0 | Int16_unsigned -> 0 + | Int32 -> 0l | Int64 -> 0L + | Int -> 0 | Nativeint -> 0n + | Char -> '\000' +]} +*) + +val float32 : (float, float32_elt) kind +(** See {!Bigarray.char}. *) + +val float64 : (float, float64_elt) kind +(** See {!Bigarray.char}. *) + +val complex32 : (Complex.t, complex32_elt) kind +(** See {!Bigarray.char}. *) + +val complex64 : (Complex.t, complex64_elt) kind +(** See {!Bigarray.char}. *) + +val int8_signed : (int, int8_signed_elt) kind +(** See {!Bigarray.char}. *) + +val int8_unsigned : (int, int8_unsigned_elt) kind +(** See {!Bigarray.char}. *) + +val int16_signed : (int, int16_signed_elt) kind +(** See {!Bigarray.char}. *) + +val int16_unsigned : (int, int16_unsigned_elt) kind +(** See {!Bigarray.char}. *) + +val int : (int, int_elt) kind +(** See {!Bigarray.char}. *) + +val int32 : (int32, int32_elt) kind +(** See {!Bigarray.char}. *) + +val int64 : (int64, int64_elt) kind +(** See {!Bigarray.char}. *) + +val nativeint : (nativeint, nativeint_elt) kind +(** See {!Bigarray.char}. *) + +val char : (char, int8_unsigned_elt) kind +(** As shown by the types of the values above, + big arrays of kind [float32_elt] and [float64_elt] are + accessed using the OCaml type [float]. Big arrays of complex kinds + [complex32_elt], [complex64_elt] are accessed with the OCaml type + {!Complex.t}. Big arrays of + integer kinds are accessed using the smallest OCaml integer + type large enough to represent the array elements: + [int] for 8- and 16-bit integer bigarrays, as well as OCaml-integer + bigarrays; [int32] for 32-bit integer bigarrays; [int64] + for 64-bit integer bigarrays; and [nativeint] for + platform-native integer bigarrays. Finally, big arrays of + kind [int8_unsigned_elt] can also be accessed as arrays of + characters instead of arrays of small integers, by using + the kind value [char] instead of [int8_unsigned]. *) + +val kind_size_in_bytes : ('a, 'b) kind -> int +(** [kind_size_in_bytes k] is the number of bytes used to store + an element of type [k]. + + @since 4.03.0 *) + +(** {1 Array layouts} *) + +type c_layout = C_layout_typ (**) +(** See {!Bigarray.fortran_layout}.*) + +type fortran_layout = Fortran_layout_typ (**) +(** To facilitate interoperability with existing C and Fortran code, + this library supports two different memory layouts for big arrays, + one compatible with the C conventions, + the other compatible with the Fortran conventions. + + In the C-style layout, array indices start at 0, and + multi-dimensional arrays are laid out in row-major format. + That is, for a two-dimensional array, all elements of + row 0 are contiguous in memory, followed by all elements of + row 1, etc. In other terms, the array elements at [(x,y)] + and [(x, y+1)] are adjacent in memory. + + In the Fortran-style layout, array indices start at 1, and + multi-dimensional arrays are laid out in column-major format. + That is, for a two-dimensional array, all elements of + column 0 are contiguous in memory, followed by all elements of + column 1, etc. In other terms, the array elements at [(x,y)] + and [(x+1, y)] are adjacent in memory. + + Each layout style is identified at the type level by the + phantom types {!Bigarray.c_layout} and {!Bigarray.fortran_layout} + respectively. *) + +(** {7 Supported layouts} + + The GADT type ['a layout] represents one of the two supported + memory layouts: C-style or Fortran-style. Its constructors are + re-exported as values below for backward-compatibility reasons. +*) + +type 'a layout = + C_layout: c_layout layout + | Fortran_layout: fortran_layout layout + +val c_layout : c_layout layout +val fortran_layout : fortran_layout layout + + +(** {1 Generic arrays (of arbitrarily many dimensions)} *) + +module Genarray : + sig + type ('a, 'b, 'c) t + (** The type [Genarray.t] is the type of big arrays with variable + numbers of dimensions. Any number of dimensions between 0 and 16 + is supported. + + The three type parameters to [Genarray.t] identify the array element + kind and layout, as follows: + - the first parameter, ['a], is the OCaml type for accessing array + elements ([float], [int], [int32], [int64], [nativeint]); + - the second parameter, ['b], is the actual kind of array elements + ([float32_elt], [float64_elt], [int8_signed_elt], [int8_unsigned_elt], + etc); + - the third parameter, ['c], identifies the array layout + ([c_layout] or [fortran_layout]). + + For instance, [(float, float32_elt, fortran_layout) Genarray.t] + is the type of generic big arrays containing 32-bit floats + in Fortran layout; reads and writes in this array use the + OCaml type [float]. *) + + external create: ('a, 'b) kind -> 'c layout -> int array -> ('a, 'b, 'c) t + = "caml_ba_create" + (** [Genarray.create kind layout dimensions] returns a new big array + whose element kind is determined by the parameter [kind] (one of + [float32], [float64], [int8_signed], etc) and whose layout is + determined by the parameter [layout] (one of [c_layout] or + [fortran_layout]). The [dimensions] parameter is an array of + integers that indicate the size of the big array in each dimension. + The length of [dimensions] determines the number of dimensions + of the bigarray. + + For instance, [Genarray.create int32 c_layout [|4;6;8|]] + returns a fresh big array of 32-bit integers, in C layout, + having three dimensions, the three dimensions being 4, 6 and 8 + respectively. + + Big arrays returned by [Genarray.create] are not initialized: + the initial values of array elements is unspecified. + + [Genarray.create] raises [Invalid_argument] if the number of dimensions + is not in the range 0 to 16 inclusive, or if one of the dimensions + is negative. *) + + external num_dims: ('a, 'b, 'c) t -> int = "caml_ba_num_dims" + (** Return the number of dimensions of the given big array. *) + + val dims : ('a, 'b, 'c) t -> int array + (** [Genarray.dims a] returns all dimensions of the big array [a], + as an array of integers of length [Genarray.num_dims a]. *) + + external nth_dim: ('a, 'b, 'c) t -> int -> int = "caml_ba_dim" + (** [Genarray.nth_dim a n] returns the [n]-th dimension of the + big array [a]. The first dimension corresponds to [n = 0]; + the second dimension corresponds to [n = 1]; the last dimension, + to [n = Genarray.num_dims a - 1]. + Raise [Invalid_argument] if [n] is less than 0 or greater or equal than + [Genarray.num_dims a]. *) + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + (** Return the kind of the given big array. *) + + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + (** Return the layout of the given big array. *) + + external change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + = "caml_ba_change_layout" + (** [Genarray.change_layout a layout] returns a bigarray with the + specified [layout], sharing the data with [a] (and hence having + the same dimensions as [a]). No copying of elements is involved: the + new array and the original array share the same storage space. + The dimensions are reversed, such that [get v [| a; b |]] in + C layout becomes [get v [| b+1; a+1 |]] in Fortran layout. + + @since 4.04.0 + *) + + val size_in_bytes : ('a, 'b, 'c) t -> int + (** [size_in_bytes a] is the number of elements in [a] multiplied + by [a]'s {!kind_size_in_bytes}. + + @since 4.03.0 *) + + external get: ('a, 'b, 'c) t -> int array -> 'a = "caml_ba_get_generic" + (** Read an element of a generic big array. + [Genarray.get a [|i1; ...; iN|]] returns the element of [a] + whose coordinates are [i1] in the first dimension, [i2] in + the second dimension, ..., [iN] in the [N]-th dimension. + + If [a] has C layout, the coordinates must be greater or equal than 0 + and strictly less than the corresponding dimensions of [a]. + If [a] has Fortran layout, the coordinates must be greater or equal + than 1 and less or equal than the corresponding dimensions of [a]. + Raise [Invalid_argument] if the array [a] does not have exactly [N] + dimensions, or if the coordinates are outside the array bounds. + + If [N > 3], alternate syntax is provided: you can write + [a.{i1, i2, ..., iN}] instead of [Genarray.get a [|i1; ...; iN|]]. + (The syntax [a.{...}] with one, two or three coordinates is + reserved for accessing one-, two- and three-dimensional arrays + as described below.) *) + + external set: ('a, 'b, 'c) t -> int array -> 'a -> unit + = "caml_ba_set_generic" + (** Assign an element of a generic big array. + [Genarray.set a [|i1; ...; iN|] v] stores the value [v] in the + element of [a] whose coordinates are [i1] in the first dimension, + [i2] in the second dimension, ..., [iN] in the [N]-th dimension. + + The array [a] must have exactly [N] dimensions, and all coordinates + must lie inside the array bounds, as described for [Genarray.get]; + otherwise, [Invalid_argument] is raised. + + If [N > 3], alternate syntax is provided: you can write + [a.{i1, i2, ..., iN} <- v] instead of + [Genarray.set a [|i1; ...; iN|] v]. + (The syntax [a.{...} <- v] with one, two or three coordinates is + reserved for updating one-, two- and three-dimensional arrays + as described below.) *) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + (** Extract a sub-array of the given big array by restricting the + first (left-most) dimension. [Genarray.sub_left a ofs len] + returns a big array with the same number of dimensions as [a], + and the same dimensions as [a], except the first dimension, + which corresponds to the interval [[ofs ... ofs + len - 1]] + of the first dimension of [a]. No copying of elements is + involved: the sub-array and the original array share the same + storage space. In other terms, the element at coordinates + [[|i1; ...; iN|]] of the sub-array is identical to the + element at coordinates [[|i1+ofs; ...; iN|]] of the original + array [a]. + + [Genarray.sub_left] applies only to big arrays in C layout. + Raise [Invalid_argument] if [ofs] and [len] do not designate + a valid sub-array of [a], that is, if [ofs < 0], or [len < 0], + or [ofs + len > Genarray.nth_dim a 0]. *) + + external sub_right: + ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t + = "caml_ba_sub" + (** Extract a sub-array of the given big array by restricting the + last (right-most) dimension. [Genarray.sub_right a ofs len] + returns a big array with the same number of dimensions as [a], + and the same dimensions as [a], except the last dimension, + which corresponds to the interval [[ofs ... ofs + len - 1]] + of the last dimension of [a]. No copying of elements is + involved: the sub-array and the original array share the same + storage space. In other terms, the element at coordinates + [[|i1; ...; iN|]] of the sub-array is identical to the + element at coordinates [[|i1; ...; iN+ofs|]] of the original + array [a]. + + [Genarray.sub_right] applies only to big arrays in Fortran layout. + Raise [Invalid_argument] if [ofs] and [len] do not designate + a valid sub-array of [a], that is, if [ofs < 1], or [len < 0], + or [ofs + len > Genarray.nth_dim a (Genarray.num_dims a - 1)]. *) + + external slice_left: + ('a, 'b, c_layout) t -> int array -> ('a, 'b, c_layout) t + = "caml_ba_slice" + (** Extract a sub-array of lower dimension from the given big array + by fixing one or several of the first (left-most) coordinates. + [Genarray.slice_left a [|i1; ... ; iM|]] returns the 'slice' + of [a] obtained by setting the first [M] coordinates to + [i1], ..., [iM]. If [a] has [N] dimensions, the slice has + dimension [N - M], and the element at coordinates + [[|j1; ...; j(N-M)|]] in the slice is identical to the element + at coordinates [[|i1; ...; iM; j1; ...; j(N-M)|]] in the original + array [a]. No copying of elements is involved: the slice and + the original array share the same storage space. + + [Genarray.slice_left] applies only to big arrays in C layout. + Raise [Invalid_argument] if [M >= N], or if [[|i1; ... ; iM|]] + is outside the bounds of [a]. *) + + external slice_right: + ('a, 'b, fortran_layout) t -> int array -> ('a, 'b, fortran_layout) t + = "caml_ba_slice" + (** Extract a sub-array of lower dimension from the given big array + by fixing one or several of the last (right-most) coordinates. + [Genarray.slice_right a [|i1; ... ; iM|]] returns the 'slice' + of [a] obtained by setting the last [M] coordinates to + [i1], ..., [iM]. If [a] has [N] dimensions, the slice has + dimension [N - M], and the element at coordinates + [[|j1; ...; j(N-M)|]] in the slice is identical to the element + at coordinates [[|j1; ...; j(N-M); i1; ...; iM|]] in the original + array [a]. No copying of elements is involved: the slice and + the original array share the same storage space. + + [Genarray.slice_right] applies only to big arrays in Fortran layout. + Raise [Invalid_argument] if [M >= N], or if [[|i1; ... ; iM|]] + is outside the bounds of [a]. *) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit + = "caml_ba_blit" + (** Copy all elements of a big array in another big array. + [Genarray.blit src dst] copies all elements of [src] into + [dst]. Both arrays [src] and [dst] must have the same number of + dimensions and equal dimensions. Copying a sub-array of [src] + to a sub-array of [dst] can be achieved by applying [Genarray.blit] + to sub-array or slices of [src] and [dst]. *) + + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + (** Set all elements of a big array to a given value. + [Genarray.fill a v] stores the value [v] in all elements of + the big array [a]. Setting only some elements of [a] to [v] + can be achieved by applying [Genarray.fill] to a sub-array + or a slice of [a]. *) + end + +(** {1 Zero-dimensional arrays} *) + +(** Zero-dimensional arrays. The [Array0] structure provides operations + similar to those of {!Bigarray.Genarray}, but specialized to the case + of zero-dimensional arrays that only contain a single scalar value. + Statically knowing the number of dimensions of the array allows + faster operations, and more precise static type-checking. + @since 4.05.0 *) +module Array0 : sig + type ('a, 'b, 'c) t + (** The type of zero-dimensional big arrays whose elements have + OCaml type ['a], representation kind ['b], and memory layout ['c]. *) + + val create: ('a, 'b) kind -> 'c layout -> ('a, 'b, 'c) t + (** [Array0.create kind layout] returns a new bigarray of zero dimension. + [kind] and [layout] determine the array element kind and the array + layout as described for {!Genarray.create}. *) + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + (** Return the kind of the given big array. *) + + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + (** Return the layout of the given big array. *) + + val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + (** [Array0.change_layout a layout] returns a big array with the + specified [layout], sharing the data with [a]. No copying of elements + is involved: the new array and the original array share the same + storage space. + + @since 4.06.0 + *) + + val size_in_bytes : ('a, 'b, 'c) t -> int + (** [size_in_bytes a] is [a]'s {!kind_size_in_bytes}. *) + + val get: ('a, 'b, 'c) t -> 'a + (** [Array0.get a] returns the only element in [a]. *) + + val set: ('a, 'b, 'c) t -> 'a -> unit + (** [Array0.set a x v] stores the value [v] in [a]. *) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit = "caml_ba_blit" + (** Copy the first big array to the second big array. + See {!Genarray.blit} for more details. *) + + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + (** Fill the given big array with the given value. + See {!Genarray.fill} for more details. *) + + val of_value: ('a, 'b) kind -> 'c layout -> 'a -> ('a, 'b, 'c) t + (** Build a zero-dimensional big array initialized from the + given value. *) + +end + + +(** {1 One-dimensional arrays} *) + +(** One-dimensional arrays. The [Array1] structure provides operations + similar to those of + {!Bigarray.Genarray}, but specialized to the case of one-dimensional arrays. + (The {!Array2} and {!Array3} structures below provide operations + specialized for two- and three-dimensional arrays.) + Statically knowing the number of dimensions of the array allows + faster operations, and more precise static type-checking. *) +module Array1 : sig + type ('a, 'b, 'c) t + (** The type of one-dimensional big arrays whose elements have + OCaml type ['a], representation kind ['b], and memory layout ['c]. *) + + val create: ('a, 'b) kind -> 'c layout -> int -> ('a, 'b, 'c) t + (** [Array1.create kind layout dim] returns a new bigarray of + one dimension, whose size is [dim]. [kind] and [layout] + determine the array element kind and the array layout + as described for {!Genarray.create}. *) + + external dim: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + (** Return the size (dimension) of the given one-dimensional + big array. *) + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + (** Return the kind of the given big array. *) + + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + (** Return the layout of the given big array. *) + + val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + (** [Array1.change_layout a layout] returns a bigarray with the + specified [layout], sharing the data with [a] (and hence having + the same dimension as [a]). No copying of elements is involved: the + new array and the original array share the same storage space. + + @since 4.06.0 + *) + + + val size_in_bytes : ('a, 'b, 'c) t -> int + (** [size_in_bytes a] is the number of elements in [a] + multiplied by [a]'s {!kind_size_in_bytes}. + + @since 4.03.0 *) + + external get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_ref_1" + (** [Array1.get a x], or alternatively [a.{x}], + returns the element of [a] at index [x]. + [x] must be greater or equal than [0] and strictly less than + [Array1.dim a] if [a] has C layout. If [a] has Fortran layout, + [x] must be greater or equal than [1] and less or equal than + [Array1.dim a]. Otherwise, [Invalid_argument] is raised. *) + + external set: ('a, 'b, 'c) t -> int -> 'a -> unit = "%caml_ba_set_1" + (** [Array1.set a x v], also written [a.{x} <- v], + stores the value [v] at index [x] in [a]. + [x] must be inside the bounds of [a] as described in + {!Bigarray.Array1.get}; + otherwise, [Invalid_argument] is raised. *) + + external sub: ('a, 'b, 'c) t -> int -> int -> ('a, 'b, 'c) t + = "caml_ba_sub" + (** Extract a sub-array of the given one-dimensional big array. + See {!Genarray.sub_left} for more details. *) + + val slice: ('a, 'b, 'c) t -> int -> ('a, 'b, 'c) Array0.t + (** Extract a scalar (zero-dimensional slice) of the given one-dimensional + big array. The integer parameter is the index of the scalar to + extract. See {!Bigarray.Genarray.slice_left} and + {!Bigarray.Genarray.slice_right} for more details. + @since 4.05.0 *) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit + = "caml_ba_blit" + (** Copy the first big array to the second big array. + See {!Genarray.blit} for more details. *) + + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + (** Fill the given big array with the given value. + See {!Genarray.fill} for more details. *) + + val of_array: ('a, 'b) kind -> 'c layout -> 'a array -> ('a, 'b, 'c) t + (** Build a one-dimensional big array initialized from the + given array. *) + + external unsafe_get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_unsafe_ref_1" + (** Like {!Bigarray.Array1.get}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds. *) + + external unsafe_set: ('a, 'b, 'c) t -> int -> 'a -> unit + = "%caml_ba_unsafe_set_1" + (** Like {!Bigarray.Array1.set}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds. *) + +end + + +(** {1 Two-dimensional arrays} *) + +(** Two-dimensional arrays. The [Array2] structure provides operations + similar to those of {!Bigarray.Genarray}, but specialized to the + case of two-dimensional arrays. *) +module Array2 : + sig + type ('a, 'b, 'c) t + (** The type of two-dimensional big arrays whose elements have + OCaml type ['a], representation kind ['b], and memory layout ['c]. *) + + val create: ('a, 'b) kind -> 'c layout -> int -> int -> ('a, 'b, 'c) t + (** [Array2.create kind layout dim1 dim2] returns a new bigarray of + two dimension, whose size is [dim1] in the first dimension + and [dim2] in the second dimension. [kind] and [layout] + determine the array element kind and the array layout + as described for {!Bigarray.Genarray.create}. *) + + external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + (** Return the first dimension of the given two-dimensional big array. *) + + external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" + (** Return the second dimension of the given two-dimensional big array. *) + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + (** Return the kind of the given big array. *) + + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + (** Return the layout of the given big array. *) + + val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + (** [Array2.change_layout a layout] returns a bigarray with the + specified [layout], sharing the data with [a] (and hence having + the same dimensions as [a]). No copying of elements is involved: the + new array and the original array share the same storage space. + The dimensions are reversed, such that [get v [| a; b |]] in + C layout becomes [get v [| b+1; a+1 |]] in Fortran layout. + + @since 4.06.0 + *) + + + val size_in_bytes : ('a, 'b, 'c) t -> int + (** [size_in_bytes a] is the number of elements in [a] + multiplied by [a]'s {!kind_size_in_bytes}. + + @since 4.03.0 *) + + external get: ('a, 'b, 'c) t -> int -> int -> 'a = "%caml_ba_ref_2" + (** [Array2.get a x y], also written [a.{x,y}], + returns the element of [a] at coordinates ([x], [y]). + [x] and [y] must be within the bounds + of [a], as described for {!Bigarray.Genarray.get}; + otherwise, [Invalid_argument] is raised. *) + + external set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit = "%caml_ba_set_2" + (** [Array2.set a x y v], or alternatively [a.{x,y} <- v], + stores the value [v] at coordinates ([x], [y]) in [a]. + [x] and [y] must be within the bounds of [a], + as described for {!Bigarray.Genarray.set}; + otherwise, [Invalid_argument] is raised. *) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + (** Extract a two-dimensional sub-array of the given two-dimensional + big array by restricting the first dimension. + See {!Bigarray.Genarray.sub_left} for more details. + [Array2.sub_left] applies only to arrays with C layout. *) + + external sub_right: + ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t + = "caml_ba_sub" + (** Extract a two-dimensional sub-array of the given two-dimensional + big array by restricting the second dimension. + See {!Bigarray.Genarray.sub_right} for more details. + [Array2.sub_right] applies only to arrays with Fortran layout. *) + + val slice_left: ('a, 'b, c_layout) t -> int -> ('a, 'b, c_layout) Array1.t + (** Extract a row (one-dimensional slice) of the given two-dimensional + big array. The integer parameter is the index of the row to + extract. See {!Bigarray.Genarray.slice_left} for more details. + [Array2.slice_left] applies only to arrays with C layout. *) + + val slice_right: + ('a, 'b, fortran_layout) t -> int -> ('a, 'b, fortran_layout) Array1.t + (** Extract a column (one-dimensional slice) of the given + two-dimensional big array. The integer parameter is the + index of the column to extract. See {!Bigarray.Genarray.slice_right} + for more details. [Array2.slice_right] applies only to arrays + with Fortran layout. *) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit + = "caml_ba_blit" + (** Copy the first big array to the second big array. + See {!Bigarray.Genarray.blit} for more details. *) + + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + (** Fill the given big array with the given value. + See {!Bigarray.Genarray.fill} for more details. *) + + val of_array: ('a, 'b) kind -> 'c layout -> 'a array array -> ('a, 'b, 'c) t + (** Build a two-dimensional big array initialized from the + given array of arrays. *) + + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> 'a + = "%caml_ba_unsafe_ref_2" + (** Like {!Bigarray.Array2.get}, but bounds checking is not always + performed. *) + + external unsafe_set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit + = "%caml_ba_unsafe_set_2" + (** Like {!Bigarray.Array2.set}, but bounds checking is not always + performed. *) + +end + +(** {1 Three-dimensional arrays} *) + +(** Three-dimensional arrays. The [Array3] structure provides operations + similar to those of {!Bigarray.Genarray}, but specialized to the case + of three-dimensional arrays. *) +module Array3 : + sig + type ('a, 'b, 'c) t + (** The type of three-dimensional big arrays whose elements have + OCaml type ['a], representation kind ['b], and memory layout ['c]. *) + + val create: ('a, 'b) kind -> 'c layout -> int -> int -> int -> ('a, 'b, 'c) t + (** [Array3.create kind layout dim1 dim2 dim3] returns a new bigarray of + three dimension, whose size is [dim1] in the first dimension, + [dim2] in the second dimension, and [dim3] in the third. + [kind] and [layout] determine the array element kind and + the array layout as described for {!Bigarray.Genarray.create}. *) + + external dim1: ('a, 'b, 'c) t -> int = "%caml_ba_dim_1" + (** Return the first dimension of the given three-dimensional big array. *) + + external dim2: ('a, 'b, 'c) t -> int = "%caml_ba_dim_2" + (** Return the second dimension of the given three-dimensional big array. *) + + external dim3: ('a, 'b, 'c) t -> int = "%caml_ba_dim_3" + (** Return the third dimension of the given three-dimensional big array. *) + + external kind: ('a, 'b, 'c) t -> ('a, 'b) kind = "caml_ba_kind" + (** Return the kind of the given big array. *) + + external layout: ('a, 'b, 'c) t -> 'c layout = "caml_ba_layout" + (** Return the layout of the given big array. *) + + + val change_layout: ('a, 'b, 'c) t -> 'd layout -> ('a, 'b, 'd) t + (** [Array3.change_layout a layout] returns a bigarray with the + specified [layout], sharing the data with [a] (and hence having + the same dimensions as [a]). No copying of elements is involved: the + new array and the original array share the same storage space. + The dimensions are reversed, such that [get v [| a; b; c |]] in + C layout becomes [get v [| c+1; b+1; a+1 |]] in Fortran layout. + + @since 4.06.0 + *) + + val size_in_bytes : ('a, 'b, 'c) t -> int + (** [size_in_bytes a] is the number of elements in [a] + multiplied by [a]'s {!kind_size_in_bytes}. + + @since 4.03.0 *) + + external get: ('a, 'b, 'c) t -> int -> int -> int -> 'a = "%caml_ba_ref_3" + (** [Array3.get a x y z], also written [a.{x,y,z}], + returns the element of [a] at coordinates ([x], [y], [z]). + [x], [y] and [z] must be within the bounds of [a], + as described for {!Bigarray.Genarray.get}; + otherwise, [Invalid_argument] is raised. *) + + external set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit + = "%caml_ba_set_3" + (** [Array3.set a x y v], or alternatively [a.{x,y,z} <- v], + stores the value [v] at coordinates ([x], [y], [z]) in [a]. + [x], [y] and [z] must be within the bounds of [a], + as described for {!Bigarray.Genarray.set}; + otherwise, [Invalid_argument] is raised. *) + + external sub_left: ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) t + = "caml_ba_sub" + (** Extract a three-dimensional sub-array of the given + three-dimensional big array by restricting the first dimension. + See {!Bigarray.Genarray.sub_left} for more details. [Array3.sub_left] + applies only to arrays with C layout. *) + + external sub_right: + ('a, 'b, fortran_layout) t -> int -> int -> ('a, 'b, fortran_layout) t + = "caml_ba_sub" + (** Extract a three-dimensional sub-array of the given + three-dimensional big array by restricting the second dimension. + See {!Bigarray.Genarray.sub_right} for more details. [Array3.sub_right] + applies only to arrays with Fortran layout. *) + + val slice_left_1: + ('a, 'b, c_layout) t -> int -> int -> ('a, 'b, c_layout) Array1.t + (** Extract a one-dimensional slice of the given three-dimensional + big array by fixing the first two coordinates. + The integer parameters are the coordinates of the slice to + extract. See {!Bigarray.Genarray.slice_left} for more details. + [Array3.slice_left_1] applies only to arrays with C layout. *) + + val slice_right_1: + ('a, 'b, fortran_layout) t -> + int -> int -> ('a, 'b, fortran_layout) Array1.t + (** Extract a one-dimensional slice of the given three-dimensional + big array by fixing the last two coordinates. + The integer parameters are the coordinates of the slice to + extract. See {!Bigarray.Genarray.slice_right} for more details. + [Array3.slice_right_1] applies only to arrays with Fortran + layout. *) + + val slice_left_2: ('a, 'b, c_layout) t -> int -> ('a, 'b, c_layout) Array2.t + (** Extract a two-dimensional slice of the given three-dimensional + big array by fixing the first coordinate. + The integer parameter is the first coordinate of the slice to + extract. See {!Bigarray.Genarray.slice_left} for more details. + [Array3.slice_left_2] applies only to arrays with C layout. *) + + val slice_right_2: + ('a, 'b, fortran_layout) t -> int -> ('a, 'b, fortran_layout) Array2.t + (** Extract a two-dimensional slice of the given + three-dimensional big array by fixing the last coordinate. + The integer parameter is the coordinate of the slice + to extract. See {!Bigarray.Genarray.slice_right} for more details. + [Array3.slice_right_2] applies only to arrays with Fortran + layout. *) + + external blit: ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit + = "caml_ba_blit" + (** Copy the first big array to the second big array. + See {!Bigarray.Genarray.blit} for more details. *) + + external fill: ('a, 'b, 'c) t -> 'a -> unit = "caml_ba_fill" + (** Fill the given big array with the given value. + See {!Bigarray.Genarray.fill} for more details. *) + + val of_array: + ('a, 'b) kind -> 'c layout -> 'a array array array -> ('a, 'b, 'c) t + (** Build a three-dimensional big array initialized from the + given array of arrays of arrays. *) + + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> int -> 'a + = "%caml_ba_unsafe_ref_3" + (** Like {!Bigarray.Array3.get}, but bounds checking is not always + performed. *) + + external unsafe_set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit + = "%caml_ba_unsafe_set_3" + (** Like {!Bigarray.Array3.set}, but bounds checking is not always + performed. *) + +end + +(** {1 Coercions between generic big arrays and fixed-dimension big arrays} *) + +external genarray_of_array0 : + ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t = "%identity" +(** Return the generic big array corresponding to the given zero-dimensional + big array. @since 4.05.0 *) + +external genarray_of_array1 : + ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t = "%identity" +(** Return the generic big array corresponding to the given one-dimensional + big array. *) + +external genarray_of_array2 : + ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t = "%identity" +(** Return the generic big array corresponding to the given two-dimensional + big array. *) + +external genarray_of_array3 : + ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t = "%identity" +(** Return the generic big array corresponding to the given three-dimensional + big array. *) + +val array0_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t +(** Return the zero-dimensional big array corresponding to the given + generic big array. Raise [Invalid_argument] if the generic big array + does not have exactly zero dimension. + @since 4.05.0 *) + +val array1_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t +(** Return the one-dimensional big array corresponding to the given + generic big array. Raise [Invalid_argument] if the generic big array + does not have exactly one dimension. *) + +val array2_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t +(** Return the two-dimensional big array corresponding to the given + generic big array. Raise [Invalid_argument] if the generic big array + does not have exactly two dimensions. *) + +val array3_of_genarray : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t +(** Return the three-dimensional big array corresponding to the given + generic big array. Raise [Invalid_argument] if the generic big array + does not have exactly three dimensions. *) + + +(** {1 Re-shaping big arrays} *) + +val reshape : ('a, 'b, 'c) Genarray.t -> int array -> ('a, 'b, 'c) Genarray.t +(** [reshape b [|d1;...;dN|]] converts the big array [b] to a + [N]-dimensional array of dimensions [d1]...[dN]. The returned + array and the original array [b] share their data + and have the same layout. For instance, assuming that [b] + is a one-dimensional array of dimension 12, [reshape b [|3;4|]] + returns a two-dimensional array [b'] of dimensions 3 and 4. + If [b] has C layout, the element [(x,y)] of [b'] corresponds + to the element [x * 3 + y] of [b]. If [b] has Fortran layout, + the element [(x,y)] of [b'] corresponds to the element + [x + (y - 1) * 4] of [b]. + The returned big array must have exactly the same number of + elements as the original big array [b]. That is, the product + of the dimensions of [b] must be equal to [i1 * ... * iN]. + Otherwise, [Invalid_argument] is raised. *) + +val reshape_0 : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t +(** Specialized version of {!Bigarray.reshape} for reshaping to + zero-dimensional arrays. + @since 4.05.0 *) + +val reshape_1 : ('a, 'b, 'c) Genarray.t -> int -> ('a, 'b, 'c) Array1.t +(** Specialized version of {!Bigarray.reshape} for reshaping to + one-dimensional arrays. *) + +val reshape_2 : ('a, 'b, 'c) Genarray.t -> int -> int -> ('a, 'b, 'c) Array2.t +(** Specialized version of {!Bigarray.reshape} for reshaping to + two-dimensional arrays. *) + +val reshape_3 : + ('a, 'b, 'c) Genarray.t -> int -> int -> int -> ('a, 'b, 'c) Array3.t +(** Specialized version of {!Bigarray.reshape} for reshaping to + three-dimensional arrays. *) diff --git a/stdlib/buffer.ml b/stdlib/buffer.ml index 0b03b560..387b51a5 100644 --- a/stdlib/buffer.ml +++ b/stdlib/buffer.ml @@ -272,3 +272,31 @@ let truncate b len = invalid_arg "Buffer.truncate" else b.position <- len + +(** {6 Iterators} *) + +let to_seq b = + let rec aux i () = + if i >= b.position then Seq.Nil + else + let x = Bytes.get b.buffer i in + Seq.Cons (x, aux (i+1)) + in + aux 0 + +let to_seqi b = + let rec aux i () = + if i >= b.position then Seq.Nil + else + let x = Bytes.get b.buffer i in + Seq.Cons ((i,x), aux (i+1)) + in + aux 0 + +let add_seq b seq = Seq.iter (add_char b) seq + +let of_seq i = + let b = create 32 in + add_seq b i; + b + diff --git a/stdlib/buffer.mli b/stdlib/buffer.mli index 21baaad6..884973a2 100644 --- a/stdlib/buffer.mli +++ b/stdlib/buffer.mli @@ -157,3 +157,24 @@ val truncate : t -> int -> unit Note: the internal byte sequence is not shortened. Raise [Invalid_argument] if [len < 0] or [len > length b]. @since 4.05.0 *) + +(** {6 Iterators} *) + +val to_seq : t -> char Seq.t +(** Iterate on the buffer, in increasing order. + Modification of the buffer during iteration is undefined behavior. + @since 4.07 *) + +val to_seqi : t -> (int * char) Seq.t +(** Iterate on the buffer, in increasing order, yielding indices along chars. + Modification of the buffer during iteration is undefined behavior. + @since 4.07 *) + +val add_seq : t -> char Seq.t -> unit +(** Add chars to the buffer + @since 4.07 *) + +val of_seq : char Seq.t -> t +(** Create a buffer from the generator + @since 4.07 *) + diff --git a/stdlib/bytes.ml b/stdlib/bytes.ml index 0783babc..3532bc4b 100644 --- a/stdlib/bytes.ml +++ b/stdlib/bytes.ml @@ -327,3 +327,43 @@ let lowercase s = map Char.lowercase s let capitalize s = apply1 Char.uppercase s let uncapitalize s = apply1 Char.lowercase s + +(** {6 Iterators} *) + +let to_seq s = + let rec aux i () = + if i = length s then Seq.Nil + else + let x = get s i in + Seq.Cons (x, aux (i+1)) + in + aux 0 + +let to_seqi s = + let rec aux i () = + if i = length s then Seq.Nil + else + let x = get s i in + Seq.Cons ((i,x), aux (i+1)) + in + aux 0 + +let of_seq i = + let n = ref 0 in + let buf = ref (make 256 '\000') in + let resize () = + (* resize *) + let new_len = min (2 * length !buf) Sys.max_string_length in + if length !buf = new_len then failwith "Bytes.of_seq: cannot grow bytes"; + let new_buf = make new_len '\000' in + blit !buf 0 new_buf 0 !n; + buf := new_buf + in + Seq.iter + (fun c -> + if !n = length !buf then resize(); + set !buf !n c; + incr n) + i; + sub !buf 0 !n + diff --git a/stdlib/bytes.mli b/stdlib/bytes.mli index 3bef5b4a..6a889eca 100644 --- a/stdlib/bytes.mli +++ b/stdlib/bytes.mli @@ -447,6 +447,21 @@ let s = Bytes.of_string "hello" [string] type for this purpose. *) +(** {6 Iterators} *) + +val to_seq : t -> char Seq.t +(** Iterate on the string, in increasing index order. Modifications of the + string during iteration will be reflected in the iterator. + @since 4.07 *) + +val to_seqi : t -> (int * char) Seq.t +(** Iterate on the string, in increasing order, yielding indices along chars + @since 4.07 *) + +val of_seq : char Seq.t -> t +(** Create a string from the generator + @since 4.07 *) + (**/**) (* The following is for system use only. Do not call directly. *) diff --git a/stdlib/bytesLabels.mli b/stdlib/bytesLabels.mli index 35399832..dc710a9f 100644 --- a/stdlib/bytesLabels.mli +++ b/stdlib/bytesLabels.mli @@ -292,6 +292,21 @@ val equal: t -> t -> bool (** The equality function for byte sequences. @since 4.05.0 *) +(** {6 Iterators} *) + +val to_seq : t -> char Seq.t +(** Iterate on the string, in increasing index order. Modifications of the + string during iteration will be reflected in the iterator. + @since 4.07 *) + +val to_seqi : t -> (int * char) Seq.t +(** Iterate on the string, in increasing order, yielding indices along chars + @since 4.07 *) + +val of_seq : char Seq.t -> t +(** Create a string from the generator + @since 4.07 *) + (**/**) (* The following is for system use only. Do not call directly. *) diff --git a/stdlib/camlinternalBigarray.ml b/stdlib/camlinternalBigarray.ml deleted file mode 100644 index 04d908be..00000000 --- a/stdlib/camlinternalBigarray.ml +++ /dev/null @@ -1,54 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Manuel Serrano and Xavier Leroy, INRIA Rocquencourt *) -(* *) -(* Copyright 2000 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* Bigarray types. These must be kept in sync with the tables in - ../typing/typeopt.ml *) - -type float32_elt = Float32_elt -type float64_elt = Float64_elt -type int8_signed_elt = Int8_signed_elt -type int8_unsigned_elt = Int8_unsigned_elt -type int16_signed_elt = Int16_signed_elt -type int16_unsigned_elt = Int16_unsigned_elt -type int32_elt = Int32_elt -type int64_elt = Int64_elt -type int_elt = Int_elt -type nativeint_elt = Nativeint_elt -type complex32_elt = Complex32_elt -type complex64_elt = Complex64_elt - -type ('a, 'b) kind = - Float32 : (float, float32_elt) kind - | Float64 : (float, float64_elt) kind - | Int8_signed : (int, int8_signed_elt) kind - | Int8_unsigned : (int, int8_unsigned_elt) kind - | Int16_signed : (int, int16_signed_elt) kind - | Int16_unsigned : (int, int16_unsigned_elt) kind - | Int32 : (int32, int32_elt) kind - | Int64 : (int64, int64_elt) kind - | Int : (int, int_elt) kind - | Nativeint : (nativeint, nativeint_elt) kind - | Complex32 : (Complex.t, complex32_elt) kind - | Complex64 : (Complex.t, complex64_elt) kind - | Char : (char, int8_unsigned_elt) kind - -type c_layout = C_layout_typ -type fortran_layout = Fortran_layout_typ - -type 'a layout = - C_layout: c_layout layout - | Fortran_layout: fortran_layout layout - -type ('a, 'b, 'c) genarray diff --git a/stdlib/ephemeron.ml b/stdlib/ephemeron.ml index c2b3d05d..24bd1e70 100644 --- a/stdlib/ephemeron.ml +++ b/stdlib/ephemeron.ml @@ -379,6 +379,39 @@ module GenHashTable = struct max_bucket_length = mbl; bucket_histogram = histo } + let to_seq tbl = + (* capture current array, so that even if the table is resized we + keep iterating on the same array *) + let tbl_data = tbl.data in + (* state: index * next bucket to traverse *) + let rec aux i buck () = match buck with + | Empty -> + if i = Array.length tbl_data + then Seq.Nil + else aux(i+1) tbl_data.(i) () + | Cons (_, c, next) -> + begin match H.get_key c, H.get_data c with + | None, _ | _, None -> aux i next () + | Some key, Some data -> + Seq.Cons ((key, data), aux i next) + end + in + aux 0 Empty + + let to_seq_keys m = Seq.map fst (to_seq m) + + let to_seq_values m = Seq.map snd (to_seq m) + + let add_seq tbl i = + Seq.iter (fun (k,v) -> add tbl k v) i + + let replace_seq tbl i = + Seq.iter (fun (k,v) -> replace tbl k v) i + + let of_seq i = + let tbl = create 16 in + replace_seq tbl i; + tbl end end diff --git a/stdlib/expand_module_aliases.awk b/stdlib/expand_module_aliases.awk new file mode 100644 index 00000000..c373b351 --- /dev/null +++ b/stdlib/expand_module_aliases.awk @@ -0,0 +1,27 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Jeremie Dimino, Jane Street Europe * +#* * +#* Copyright 2017 Jane Street Group LLC * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# This script adds the Stdlib__ prefixes to the module aliases in +# stdlib.ml and stdlib.mli +BEGIN { state=0 } +NR == 1 { printf ("# 1 \"%s\"\n", FILENAME) } +/\(\*MODULE_ALIASES\*\)\r?/ { state=1 } +{ if (state==0) + print; + else if (state==1) + state=2; + else if ($1 == "module") + printf ("\n(** @canonical %s *)\nmodule %s = Stdlib__%s%s\n", + $2, $2, tolower(substr($4,1,1)), substr($4,2)); +} diff --git a/stdlib/float.ml b/stdlib/float.ml new file mode 100644 index 00000000..3cd01006 --- /dev/null +++ b/stdlib/float.ml @@ -0,0 +1,101 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* Nicolas Ojeda Bar, LexiFi *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +external neg : float -> float = "%negfloat" +external add : float -> float -> float = "%addfloat" +external sub : float -> float -> float = "%subfloat" +external mul : float -> float -> float = "%mulfloat" +external div : float -> float -> float = "%divfloat" +external rem : float -> float -> float = "caml_fmod_float" "fmod" + [@@unboxed] [@@noalloc] +external abs : float -> float = "%absfloat" +let infinity = Pervasives.infinity +let neg_infinity = Pervasives.neg_infinity +let nan = Pervasives.nan +let pi = 0x1.921fb54442d18p+1 +let max_float = Pervasives.max_float +let min_float = Pervasives.min_float +let epsilon = Pervasives.epsilon_float +external of_int : int -> float = "%floatofint" +external to_int : float -> int = "%intoffloat" +external of_string : string -> float = "caml_float_of_string" +let of_string_opt = Pervasives.float_of_string_opt +let to_string = Pervasives.string_of_float +type fpclass = Pervasives.fpclass = + FP_normal + | FP_subnormal + | FP_zero + | FP_infinite + | FP_nan +external classify_float : (float [@unboxed]) -> fpclass = + "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] +external pow : float -> float -> float = "caml_power_float" "pow" + [@@unboxed] [@@noalloc] +external sqrt : float -> float = "caml_sqrt_float" "sqrt" + [@@unboxed] [@@noalloc] +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +external log10 : float -> float = "caml_log10_float" "log10" + [@@unboxed] [@@noalloc] +external expm1 : float -> float = "caml_expm1_float" "caml_expm1" + [@@unboxed] [@@noalloc] +external log1p : float -> float = "caml_log1p_float" "caml_log1p" + [@@unboxed] [@@noalloc] +external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] +external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] +external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] +external acos : float -> float = "caml_acos_float" "acos" + [@@unboxed] [@@noalloc] +external asin : float -> float = "caml_asin_float" "asin" + [@@unboxed] [@@noalloc] +external atan : float -> float = "caml_atan_float" "atan" + [@@unboxed] [@@noalloc] +external atan2 : float -> float -> float = "caml_atan2_float" "atan2" + [@@unboxed] [@@noalloc] +external hypot : float -> float -> float + = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] +external cosh : float -> float = "caml_cosh_float" "cosh" + [@@unboxed] [@@noalloc] +external sinh : float -> float = "caml_sinh_float" "sinh" + [@@unboxed] [@@noalloc] +external tanh : float -> float = "caml_tanh_float" "tanh" + [@@unboxed] [@@noalloc] +external ceil : float -> float = "caml_ceil_float" "ceil" + [@@unboxed] [@@noalloc] +external floor : float -> float = "caml_floor_float" "floor" +[@@unboxed] [@@noalloc] +external copysign : float -> float -> float + = "caml_copysign_float" "caml_copysign" + [@@unboxed] [@@noalloc] +external frexp : float -> float * int = "caml_frexp_float" +external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = + "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] +external modf : float -> float * float = "caml_modf_float" +type t = float +external compare : float -> float -> int = "%compare" +let equal x y = compare x y = 0 +external seeded_hash_param : int -> int -> int -> float -> int = "caml_hash" [@@noalloc] +let hash x = seeded_hash_param 10 100 0 x + +module Array = struct + type t = floatarray + external create : int -> t = "caml_floatarray_create" + external length : t -> int = "%floatarray_length" + external get : t -> int -> float = "%floatarray_safe_get" + external set : t -> int -> float -> unit = "%floatarray_safe_set" + external unsafe_get : t -> int -> float = "%floatarray_unsafe_get" + external unsafe_set : t -> int -> float -> unit = "%floatarray_unsafe_set" +end diff --git a/stdlib/float.mli b/stdlib/float.mli new file mode 100644 index 00000000..f7b4cd8d --- /dev/null +++ b/stdlib/float.mli @@ -0,0 +1,267 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* Nicolas Ojeda Bar, LexiFi *) +(* *) +(* Copyright 2018 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(** {1 Floating-point arithmetic} + + OCaml's floating-point numbers follow the + IEEE 754 standard, using double precision (64 bits) numbers. + Floating-point operations never raise an exception on overflow, + underflow, division by zero, etc. Instead, special IEEE numbers + are returned as appropriate, such as [infinity] for [1.0 /. 0.0], + [neg_infinity] for [-1.0 /. 0.0], and [nan] ('not a number') + for [0.0 /. 0.0]. These special numbers then propagate through + floating-point computations as expected: for instance, + [1.0 /. infinity] is [0.0], and any arithmetic operation with [nan] + as argument returns [nan] as result. + + @since 4.07.0 +*) + +external neg : float -> float = "%negfloat" +(** Unary negation. *) + +external add : float -> float -> float = "%addfloat" +(** Floating-point addition. *) + +external sub : float -> float -> float = "%subfloat" +(** Floating-point subtraction. *) + +external mul : float -> float -> float = "%mulfloat" +(** Floating-point multiplication. *) + +external div : float -> float -> float = "%divfloat" +(** Floating-point division. *) + +external rem : float -> float -> float = "caml_fmod_float" "fmod" +[@@unboxed] [@@noalloc] +(** [rem a b] returns the remainder of [a] with respect to [b]. The returned + value is [a -. n *. b], where [n] is the quotient [a /. b] rounded towards + zero to an integer. *) + +external abs : float -> float = "%absfloat" +(** [abs f] returns the absolute value of [f]. *) + +val infinity : float +(** Positive infinity. *) + +val neg_infinity : float +(** Negative infinity. *) + +val nan : float +(** A special floating-point value denoting the result of an + undefined operation such as [0.0 /. 0.0]. Stands for + 'not a number'. Any floating-point operation with [nan] as + argument returns [nan] as result. As for floating-point comparisons, + [=], [<], [<=], [>] and [>=] return [false] and [<>] returns [true] + if one or both of their arguments is [nan]. *) + +val pi : float +(** The constant pi. *) + +val max_float : float +(** The largest positive finite value of type [float]. *) + +val min_float : float +(** The smallest positive, non-zero, non-denormalized value of type [float]. *) + +val epsilon : float +(** The difference between [1.0] and the smallest exactly representable + floating-point number greater than [1.0]. *) + +external of_int : int -> float = "%floatofint" +(** Convert an integer to floating-point. *) + +external to_int : float -> int = "%intoffloat" +(** Truncate the given floating-point number to an integer. + The result is unspecified if the argument is [nan] or falls outside the + range of representable integers. *) + +external of_string : string -> float = "caml_float_of_string" +(** Convert the given string to a float. The string is read in decimal + (by default) or in hexadecimal (marked by [0x] or [0X]). + The format of decimal floating-point numbers is + [ [-] dd.ddd (e|E) [+|-] dd ], where [d] stands for a decimal digit. + The format of hexadecimal floating-point numbers is + [ [-] 0(x|X) hh.hhh (p|P) [+|-] dd ], where [h] stands for an + hexadecimal digit and [d] for a decimal digit. + In both cases, at least one of the integer and fractional parts must be + given; the exponent part is optional. + The [_] (underscore) character can appear anywhere in the string + and is ignored. + Depending on the execution platforms, other representations of + floating-point numbers can be accepted, but should not be relied upon. + Raise [Failure "float_of_string"] if the given string is not a valid + representation of a float. *) + +val of_string_opt: string -> float option +(** Same as [of_string], but returns [None] instead of raising. *) + +val to_string : float -> string +(** Return the string representation of a floating-point number. *) + +type fpclass = Pervasives.fpclass = + FP_normal (** Normal number, none of the below *) + | FP_subnormal (** Number very close to 0.0, has reduced precision *) + | FP_zero (** Number is 0.0 or -0.0 *) + | FP_infinite (** Number is positive or negative infinity *) + | FP_nan (** Not a number: result of an undefined operation *) +(** The five classes of floating-point numbers, as determined by + the {!classify_float} function. *) + +external classify_float : (float [@unboxed]) -> fpclass = + "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] +(** Return the class of the given floating-point number: + normal, subnormal, zero, infinite, or not a number. *) + +external pow : float -> float -> float = "caml_power_float" "pow" +[@@unboxed] [@@noalloc] +(** Exponentiation. *) + +external sqrt : float -> float = "caml_sqrt_float" "sqrt" +[@@unboxed] [@@noalloc] +(** Square root. *) + +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +(** Exponential. *) + +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +(** Natural logarithm. *) + +external log10 : float -> float = "caml_log10_float" "log10" +[@@unboxed] [@@noalloc] +(** Base 10 logarithm. *) + +external expm1 : float -> float = "caml_expm1_float" "caml_expm1" +[@@unboxed] [@@noalloc] +(** [expm1 x] computes [exp x -. 1.0], giving numerically-accurate results + even if [x] is close to [0.0]. *) + +external log1p : float -> float = "caml_log1p_float" "caml_log1p" +[@@unboxed] [@@noalloc] +(** [log1p x] computes [log(1.0 +. x)] (natural logarithm), + giving numerically-accurate results even if [x] is close to [0.0]. *) + +external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] +(** Cosine. Argument is in radians. *) + +external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] +(** Sine. Argument is in radians. *) + +external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] +(** Tangent. Argument is in radians. *) + +external acos : float -> float = "caml_acos_float" "acos" +[@@unboxed] [@@noalloc] +(** Arc cosine. The argument must fall within the range [[-1.0, 1.0]]. + Result is in radians and is between [0.0] and [pi]. *) + +external asin : float -> float = "caml_asin_float" "asin" +[@@unboxed] [@@noalloc] +(** Arc sine. The argument must fall within the range [[-1.0, 1.0]]. + Result is in radians and is between [-pi/2] and [pi/2]. *) + +external atan : float -> float = "caml_atan_float" "atan" +[@@unboxed] [@@noalloc] +(** Arc tangent. + Result is in radians and is between [-pi/2] and [pi/2]. *) + +external atan2 : float -> float -> float = "caml_atan2_float" "atan2" +[@@unboxed] [@@noalloc] +(** [atan2 y x] returns the arc tangent of [y /. x]. The signs of [x] + and [y] are used to determine the quadrant of the result. + Result is in radians and is between [-pi] and [pi]. *) + +external hypot : float -> float -> float = "caml_hypot_float" "caml_hypot" +[@@unboxed] [@@noalloc] +(** [hypot x y] returns [sqrt(x *. x + y *. y)], that is, the length + of the hypotenuse of a right-angled triangle with sides of length + [x] and [y], or, equivalently, the distance of the point [(x,y)] + to origin. If one of [x] or [y] is infinite, returns [infinity] + even if the other is [nan]. *) + +external cosh : float -> float = "caml_cosh_float" "cosh" +[@@unboxed] [@@noalloc] +(** Hyperbolic cosine. Argument is in radians. *) + +external sinh : float -> float = "caml_sinh_float" "sinh" +[@@unboxed] [@@noalloc] +(** Hyperbolic sine. Argument is in radians. *) + +external tanh : float -> float = "caml_tanh_float" "tanh" +[@@unboxed] [@@noalloc] +(** Hyperbolic tangent. Argument is in radians. *) + +external ceil : float -> float = "caml_ceil_float" "ceil" +[@@unboxed] [@@noalloc] +(** Round above to an integer value. + [ceil f] returns the least integer value greater than or equal to [f]. + The result is returned as a float. *) + +external floor : float -> float = "caml_floor_float" "floor" +[@@unboxed] [@@noalloc] +(** Round below to an integer value. + [floor f] returns the greatest integer value less than or + equal to [f]. + The result is returned as a float. *) + +external copysign : float -> float -> float + = "caml_copysign_float" "caml_copysign" +[@@unboxed] [@@noalloc] +(** [copysign x y] returns a float whose absolute value is that of [x] + and whose sign is that of [y]. If [x] is [nan], returns [nan]. + If [y] is [nan], returns either [x] or [-. x], but it is not + specified which. *) + +external frexp : float -> float * int = "caml_frexp_float" +(** [frexp f] returns the pair of the significant + and the exponent of [f]. When [f] is zero, the + significant [x] and the exponent [n] of [f] are equal to + zero. When [f] is non-zero, they are defined by + [f = x *. 2 ** n] and [0.5 <= x < 1.0]. *) + +external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = + "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] +(** [ldexp x n] returns [x *. 2 ** n]. *) + +external modf : float -> float * float = "caml_modf_float" +(** [modf f] returns the pair of the fractional and integral + part of [f]. *) + +type t = float +(** An alias for the type of floating-point numbers. *) + +val compare: t -> t -> int +(** [compare x y] returns [0] if [x] is equal to [y], a negative integer if [x] + is less than [y], and a positive integer if [x] is greater than + [y]. [compare] treats [nan] as equal to itself and less than any other float + value. This treatment of [nan] ensures that [compare] defines a total + ordering relation. *) + +val equal: t -> t -> bool +(** The equal function for floating-point numbers, compared using {!compare}. *) + +val hash: t -> int +(** The hash function for floating-point numbers. *) + +module Array : sig + type t = floatarray + external create : int -> t = "caml_floatarray_create" + external length : t -> int = "%floatarray_length" + external get : t -> int -> float = "%floatarray_safe_get" + external set : t -> int -> float -> unit = "%floatarray_safe_set" + external unsafe_get : t -> int -> float = "%floatarray_unsafe_get" + external unsafe_set : t -> int -> float -> unit = "%floatarray_unsafe_set" +end diff --git a/stdlib/hashtbl.ml b/stdlib/hashtbl.ml index 77e8b907..99726341 100644 --- a/stdlib/hashtbl.ml +++ b/stdlib/hashtbl.ml @@ -354,6 +354,38 @@ let stats h = max_bucket_length = mbl; bucket_histogram = histo } +(** {6 Iterators} *) + +let to_seq tbl = + (* capture current array, so that even if the table is resized we + keep iterating on the same array *) + let tbl_data = tbl.data in + (* state: index * next bucket to traverse *) + let rec aux i buck () = match buck with + | Empty -> + if i = Array.length tbl_data + then Seq.Nil + else aux(i+1) tbl_data.(i) () + | Cons {key; data; next} -> + Seq.Cons ((key, data), aux i next) + in + aux 0 Empty + +let to_seq_keys m = Seq.map fst (to_seq m) + +let to_seq_values m = Seq.map snd (to_seq m) + +let add_seq tbl i = + Seq.iter (fun (k,v) -> add tbl k v) i + +let replace_seq tbl i = + Seq.iter (fun (k,v) -> replace tbl k v) i + +let of_seq i = + let tbl = create 16 in + replace_seq tbl i; + tbl + (* Functorial interface *) module type HashedType = @@ -390,6 +422,12 @@ module type S = val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b val length: 'a t -> int val stats: 'a t -> statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : _ t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t end module type SeededS = @@ -412,6 +450,12 @@ module type SeededS = val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b val length : 'a t -> int val stats: 'a t -> statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : _ t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t end module MakeSeeded(H: SeededHashedType): (SeededS with type key = H.t) = @@ -531,6 +575,12 @@ module MakeSeeded(H: SeededHashedType): (SeededS with type key = H.t) = let fold = fold let length = length let stats = stats + let to_seq = to_seq + let to_seq_keys = to_seq_keys + let to_seq_values = to_seq_values + let add_seq = add_seq + let replace_seq = replace_seq + let of_seq = of_seq end module Make(H: HashedType): (S with type key = H.t) = diff --git a/stdlib/hashtbl.mli b/stdlib/hashtbl.mli index 6449c055..a96c99c3 100644 --- a/stdlib/hashtbl.mli +++ b/stdlib/hashtbl.mli @@ -216,6 +216,39 @@ val stats : ('a, 'b) t -> statistics buckets by size. @since 4.00.0 *) +(** {6 Iterators} *) + +val to_seq : ('a,'b) t -> ('a * 'b) Seq.t +(** Iterate on the whole table, in unspecified order. + + The behavior is not defined if the hash table is modified + during the iteration. + + @since 4.07 *) + +val to_seq_keys : ('a,_) t -> 'a Seq.t +(** Iterate on 'as, in ascending order + @since 4.07 *) + +val to_seq_values : (_,'b) t -> 'b Seq.t +(** Iterate on values, in ascending order of their corresponding 'a + @since 4.07 *) + +val add_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit +(** Add the given bindings to the table, using {!add} + @since 4.07 *) + +val replace_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit +(** Add the given bindings to the table, using {!replace} + @since 4.07 *) + +val of_seq : ('a * 'b) Seq.t -> ('a, 'b) t +(** Build a table from the given bindings. The bindings are added + in the same order they appear in the sequence, using {!replace_seq}, + which means that if two pairs have the same key, only the latest one + will appear in the table. + @since 4.07 *) + (** {1 Functorial interface} *) (** The functorial interface allows the use of specific comparison @@ -296,6 +329,24 @@ module type S = val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b val length : 'a t -> int val stats: 'a t -> statistics (** @since 4.00.0 *) + + val to_seq : 'a t -> (key * 'a) Seq.t + (** @since 4.07 *) + + val to_seq_keys : _ t -> key Seq.t + (** @since 4.07 *) + + val to_seq_values : 'a t -> 'a Seq.t + (** @since 4.07 *) + + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** @since 4.07 *) end (** The output signature of the functor {!Hashtbl.Make}. *) @@ -352,6 +403,24 @@ module type SeededS = val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b val length : 'a t -> int val stats: 'a t -> statistics + + val to_seq : 'a t -> (key * 'a) Seq.t + (** @since 4.07 *) + + val to_seq_keys : _ t -> key Seq.t + (** @since 4.07 *) + + val to_seq_values : 'a t -> 'a Seq.t + (** @since 4.07 *) + + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** @since 4.07 *) end (** The output signature of the functor {!Hashtbl.MakeSeeded}. @since 4.00.0 *) diff --git a/stdlib/list.ml b/stdlib/list.ml index 5b7b679f..7cee6094 100644 --- a/stdlib/list.ml +++ b/stdlib/list.ml @@ -66,9 +66,15 @@ let rec init_aux i n f = let r = f i in r :: init_aux (i+1) n f +let rev_init_threshold = + match Sys.backend_type with + | Sys.Native | Sys.Bytecode -> 10_000 + (* We don't known the size of the stack, better be safe and assume it's small. *) + | Sys.Other _ -> 50 + let init len f = if len < 0 then invalid_arg "List.init" else - if len > 10_000 then rev (init_tailrec_aux [] 0 len f) + if len > rev_init_threshold then rev (init_tailrec_aux [] 0 len f) else init_aux 0 len f let rec flatten = function @@ -483,3 +489,24 @@ let rec compare_length_with l n = if n <= 0 then 1 else compare_length_with l (n-1) ;; + +(** {6 Iterators} *) + +let to_seq l = + let rec aux l () = match l with + | [] -> Seq.Nil + | x :: tail -> Seq.Cons (x, aux tail) + in + aux l + +let of_seq seq = + let rec direct depth seq : _ list = + if depth=0 + then + Seq.fold_left (fun acc x -> x::acc) [] seq + |> rev (* tailrec *) + else match seq() with + | Seq.Nil -> [] + | Seq.Cons (x, next) -> x :: direct (depth-1) next + in + direct 500 seq diff --git a/stdlib/list.mli b/stdlib/list.mli index cdcd23cd..e7a339b5 100644 --- a/stdlib/list.mli +++ b/stdlib/list.mli @@ -345,3 +345,13 @@ val merge : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list before the elements of [l2]. Not tail-recursive (sum of the lengths of the arguments). *) + +(** {6 Iterators} *) + +val to_seq : 'a list -> 'a Seq.t +(** Iterate on the list + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a list +(** Create a list from the iterator + @since 4.07 *) diff --git a/stdlib/listLabels.mli b/stdlib/listLabels.mli index d5d9cd40..ab6980c2 100644 --- a/stdlib/listLabels.mli +++ b/stdlib/listLabels.mli @@ -351,3 +351,13 @@ val merge : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list before the elements of [l2]. Not tail-recursive (sum of the lengths of the arguments). *) + +(** {6 Iterators} *) + +val to_seq : 'a list -> 'a Seq.t +(** Iterate on the list + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a list +(** Create a list from the iterator + @since 4.07 *) diff --git a/stdlib/map.ml b/stdlib/map.ml index 7d096dfb..28bb5bd0 100644 --- a/stdlib/map.ml +++ b/stdlib/map.ml @@ -58,6 +58,10 @@ module type S = val find_last_opt: (key -> bool) -> 'a t -> (key * 'a) option val map: ('a -> 'b) -> 'a t -> 'b t val mapi: (key -> 'a -> 'b) -> 'a t -> 'b t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t end module Make(Ord: OrderedType) = struct @@ -477,4 +481,27 @@ module Make(Ord: OrderedType) = struct let choose_opt = min_binding_opt + let add_seq i m = + Seq.fold_left (fun m (k,v) -> add k v m) m i + + let of_seq i = add_seq i empty + + let rec seq_of_enum_ c () = match c with + | End -> Seq.Nil + | More (k,v,t,rest) -> Seq.Cons ((k,v), seq_of_enum_ (cons_enum t rest)) + + let to_seq m = + seq_of_enum_ (cons_enum m End) + + let to_seq_from low m = + let rec aux low m c = match m with + | Empty -> c + | Node {l; v; d; r; _} -> + begin match Ord.compare v low with + | 0 -> More (v, d, r, c) + | n when n<0 -> aux low r c + | _ -> aux low l (More (v, d, r, c)) + end + in + seq_of_enum_ (aux low m End) end diff --git a/stdlib/map.mli b/stdlib/map.mli index 7552c480..531fb8fe 100644 --- a/stdlib/map.mli +++ b/stdlib/map.mli @@ -306,7 +306,24 @@ module type S = (** Same as {!Map.S.map}, but the function receives as arguments both the key and the associated value for each binding of the map. *) + (** {6 Iterators} *) + val to_seq : 'a t -> (key * 'a) Seq.t + (** Iterate on the whole map, in ascending order + @since 4.07 *) + + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + (** [to_seq_from k m] iterates on a subset of the bindings of [m], + in ascending order, from key [k] or above. + @since 4.07 *) + + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + (** Add the given bindings to the map, in order. + @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** Build a map from the given bindings + @since 4.07 *) end (** Output signature of the functor {!Map.Make}. *) diff --git a/stdlib/marshal.ml b/stdlib/marshal.ml index 458f003b..63133d7f 100644 --- a/stdlib/marshal.ml +++ b/stdlib/marshal.ml @@ -22,7 +22,7 @@ type extern_flags = external to_channel: out_channel -> 'a -> extern_flags list -> unit = "caml_output_value" external to_bytes: 'a -> extern_flags list -> bytes - = "caml_output_value_to_string" + = "caml_output_value_to_bytes" external to_string: 'a -> extern_flags list -> string = "caml_output_value_to_string" external to_buffer_unsafe: @@ -41,8 +41,7 @@ let to_buffer buff ofs len v flags = *) external from_channel: in_channel -> 'a = "caml_input_value" -external from_bytes_unsafe: bytes -> int -> 'a - = "caml_input_value_from_string" +external from_bytes_unsafe: bytes -> int -> 'a = "caml_input_value_from_bytes" external data_size_unsafe: bytes -> int -> int = "caml_marshal_data_size" let header_size = 20 diff --git a/stdlib/marshal.mli b/stdlib/marshal.mli index 28c22e90..53e3fb75 100644 --- a/stdlib/marshal.mli +++ b/stdlib/marshal.mli @@ -112,7 +112,7 @@ val to_channel : out_channel -> 'a -> extern_flags list -> unit *) external to_bytes : - 'a -> extern_flags list -> bytes = "caml_output_value_to_string" + 'a -> extern_flags list -> bytes = "caml_output_value_to_bytes" (** [Marshal.to_bytes v flags] returns a byte sequence containing the representation of [v]. The [flags] argument has the same meaning as for diff --git a/stdlib/moreLabels.mli b/stdlib/moreLabels.mli index 95efcf8c..7a57d5eb 100644 --- a/stdlib/moreLabels.mli +++ b/stdlib/moreLabels.mli @@ -47,6 +47,12 @@ module Hashtbl : sig val is_randomized : unit -> bool type statistics = Hashtbl.statistics val stats : ('a, 'b) t -> statistics + val to_seq : ('a,'b) t -> ('a * 'b) Seq.t + val to_seq_keys : ('a,_) t -> 'a Seq.t + val to_seq_values : (_,'b) t -> 'b Seq.t + val add_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit + val replace_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit + val of_seq : ('a * 'b) Seq.t -> ('a, 'b) t module type HashedType = Hashtbl.HashedType module type SeededHashedType = Hashtbl.SeededHashedType module type S = @@ -72,6 +78,12 @@ module Hashtbl : sig 'a t -> init:'b -> 'b val length : 'a t -> int val stats: 'a t -> statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : _ t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t end module type SeededS = sig @@ -96,9 +108,19 @@ module Hashtbl : sig 'a t -> init:'b -> 'b val length : 'a t -> int val stats: 'a t -> statistics + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_keys : _ t -> key Seq.t + val to_seq_values : 'a t -> 'a Seq.t + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + val of_seq : (key * 'a) Seq.t -> 'a t end - module Make : functor (H : HashedType) -> S with type key = H.t - module MakeSeeded (H : SeededHashedType) : SeededS with type key = H.t + module Make : functor (H : HashedType) -> S + with type key = H.t + and type 'a t = 'a Hashtbl.Make(H).t + module MakeSeeded (H : SeededHashedType) : SeededS + with type key = H.t + and type 'a t = 'a Hashtbl.MakeSeeded(H).t val hash : 'a -> int val seeded_hash : int -> 'a -> int val hash_param : int -> int -> 'a -> int @@ -148,8 +170,14 @@ module Map : sig val find_last_opt : f:(key -> bool) -> 'a t -> (key * 'a) option val map : f:('a -> 'b) -> 'a t -> 'b t val mapi : f:(key -> 'a -> 'b) -> 'a t -> 'b t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t end - module Make : functor (Ord : OrderedType) -> S with type key = Ord.t + module Make : functor (Ord : OrderedType) -> S + with type key = Ord.t + and type 'a t = 'a Map.Make(Ord).t end module Set : sig @@ -193,6 +221,12 @@ module Set : sig val find_last: f:(elt -> bool) -> t -> elt val find_last_opt: f:(elt -> bool) -> t -> elt option val of_list: elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end - module Make : functor (Ord : OrderedType) -> S with type elt = Ord.t + module Make : functor (Ord : OrderedType) -> S + with type elt = Ord.t + and type t = Set.Make(Ord).t end diff --git a/stdlib/pervasives.ml b/stdlib/pervasives.ml deleted file mode 100644 index faa42187..00000000 --- a/stdlib/pervasives.ml +++ /dev/null @@ -1,548 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) -(* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(* type 'a option = None | Some of 'a *) - -(* Exceptions *) - -external register_named_value : string -> 'a -> unit - = "caml_register_named_value" - -let () = - (* for asmrun/fail.c *) - register_named_value "Pervasives.array_bound_error" - (Invalid_argument "index out of bounds") - - -external raise : exn -> 'a = "%raise" -external raise_notrace : exn -> 'a = "%raise_notrace" - -let failwith s = raise(Failure s) -let invalid_arg s = raise(Invalid_argument s) - -exception Exit - -(* Composition operators *) - -external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" -external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" - -(* Debugging *) - -external __LOC__ : string = "%loc_LOC" -external __FILE__ : string = "%loc_FILE" -external __LINE__ : int = "%loc_LINE" -external __MODULE__ : string = "%loc_MODULE" -external __POS__ : string * int * int * int = "%loc_POS" - -external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" -external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" -external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" - -(* Comparisons *) - -external ( = ) : 'a -> 'a -> bool = "%equal" -external ( <> ) : 'a -> 'a -> bool = "%notequal" -external ( < ) : 'a -> 'a -> bool = "%lessthan" -external ( > ) : 'a -> 'a -> bool = "%greaterthan" -external ( <= ) : 'a -> 'a -> bool = "%lessequal" -external ( >= ) : 'a -> 'a -> bool = "%greaterequal" -external compare : 'a -> 'a -> int = "%compare" - -let min x y = if x <= y then x else y -let max x y = if x >= y then x else y - -external ( == ) : 'a -> 'a -> bool = "%eq" -external ( != ) : 'a -> 'a -> bool = "%noteq" - -(* Boolean operations *) - -external not : bool -> bool = "%boolnot" -external ( & ) : bool -> bool -> bool = "%sequand" -external ( && ) : bool -> bool -> bool = "%sequand" -external ( or ) : bool -> bool -> bool = "%sequor" -external ( || ) : bool -> bool -> bool = "%sequor" - -(* Integer operations *) - -external ( ~- ) : int -> int = "%negint" -external ( ~+ ) : int -> int = "%identity" -external succ : int -> int = "%succint" -external pred : int -> int = "%predint" -external ( + ) : int -> int -> int = "%addint" -external ( - ) : int -> int -> int = "%subint" -external ( * ) : int -> int -> int = "%mulint" -external ( / ) : int -> int -> int = "%divint" -external ( mod ) : int -> int -> int = "%modint" - -let abs x = if x >= 0 then x else -x - -external ( land ) : int -> int -> int = "%andint" -external ( lor ) : int -> int -> int = "%orint" -external ( lxor ) : int -> int -> int = "%xorint" - -let lnot x = x lxor (-1) - -external ( lsl ) : int -> int -> int = "%lslint" -external ( lsr ) : int -> int -> int = "%lsrint" -external ( asr ) : int -> int -> int = "%asrint" - -let max_int = (-1) lsr 1 -let min_int = max_int + 1 - -(* Floating-point operations *) - -external ( ~-. ) : float -> float = "%negfloat" -external ( ~+. ) : float -> float = "%identity" -external ( +. ) : float -> float -> float = "%addfloat" -external ( -. ) : float -> float -> float = "%subfloat" -external ( *. ) : float -> float -> float = "%mulfloat" -external ( /. ) : float -> float -> float = "%divfloat" -external ( ** ) : float -> float -> float = "caml_power_float" "pow" - [@@unboxed] [@@noalloc] -external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] -external expm1 : float -> float = "caml_expm1_float" "caml_expm1" - [@@unboxed] [@@noalloc] -external acos : float -> float = "caml_acos_float" "acos" - [@@unboxed] [@@noalloc] -external asin : float -> float = "caml_asin_float" "asin" - [@@unboxed] [@@noalloc] -external atan : float -> float = "caml_atan_float" "atan" - [@@unboxed] [@@noalloc] -external atan2 : float -> float -> float = "caml_atan2_float" "atan2" - [@@unboxed] [@@noalloc] -external hypot : float -> float -> float - = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] -external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] -external cosh : float -> float = "caml_cosh_float" "cosh" - [@@unboxed] [@@noalloc] -external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] -external log10 : float -> float = "caml_log10_float" "log10" - [@@unboxed] [@@noalloc] -external log1p : float -> float = "caml_log1p_float" "caml_log1p" - [@@unboxed] [@@noalloc] -external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] -external sinh : float -> float = "caml_sinh_float" "sinh" - [@@unboxed] [@@noalloc] -external sqrt : float -> float = "caml_sqrt_float" "sqrt" - [@@unboxed] [@@noalloc] -external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] -external tanh : float -> float = "caml_tanh_float" "tanh" - [@@unboxed] [@@noalloc] -external ceil : float -> float = "caml_ceil_float" "ceil" - [@@unboxed] [@@noalloc] -external floor : float -> float = "caml_floor_float" "floor" - [@@unboxed] [@@noalloc] -external abs_float : float -> float = "%absfloat" -external copysign : float -> float -> float - = "caml_copysign_float" "caml_copysign" - [@@unboxed] [@@noalloc] -external mod_float : float -> float -> float = "caml_fmod_float" "fmod" - [@@unboxed] [@@noalloc] -external frexp : float -> float * int = "caml_frexp_float" -external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = - "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] -external modf : float -> float * float = "caml_modf_float" -external float : int -> float = "%floatofint" -external float_of_int : int -> float = "%floatofint" -external truncate : float -> int = "%intoffloat" -external int_of_float : float -> int = "%intoffloat" -external float_of_bits : int64 -> float - = "caml_int64_float_of_bits" "caml_int64_float_of_bits_unboxed" - [@@unboxed] [@@noalloc] -let infinity = - float_of_bits 0x7F_F0_00_00_00_00_00_00L -let neg_infinity = - float_of_bits 0xFF_F0_00_00_00_00_00_00L -let nan = - float_of_bits 0x7F_F0_00_00_00_00_00_01L -let max_float = - float_of_bits 0x7F_EF_FF_FF_FF_FF_FF_FFL -let min_float = - float_of_bits 0x00_10_00_00_00_00_00_00L -let epsilon_float = - float_of_bits 0x3C_B0_00_00_00_00_00_00L - -type fpclass = - FP_normal - | FP_subnormal - | FP_zero - | FP_infinite - | FP_nan -external classify_float : (float [@unboxed]) -> fpclass = - "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] - -(* String and byte sequence operations -- more in modules String and Bytes *) - -external string_length : string -> int = "%string_length" -external bytes_length : bytes -> int = "%bytes_length" -external bytes_create : int -> bytes = "caml_create_bytes" -external string_blit : string -> int -> bytes -> int -> int -> unit - = "caml_blit_string" [@@noalloc] -external bytes_blit : bytes -> int -> bytes -> int -> int -> unit - = "caml_blit_bytes" [@@noalloc] -external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string" - -let ( ^ ) s1 s2 = - let l1 = string_length s1 and l2 = string_length s2 in - let s = bytes_create (l1 + l2) in - string_blit s1 0 s 0 l1; - string_blit s2 0 s l1 l2; - bytes_unsafe_to_string s - -(* Character operations -- more in module Char *) - -external int_of_char : char -> int = "%identity" -external unsafe_char_of_int : int -> char = "%identity" -let char_of_int n = - if n < 0 || n > 255 then invalid_arg "char_of_int" else unsafe_char_of_int n - -(* Unit operations *) - -external ignore : 'a -> unit = "%ignore" - -(* Pair operations *) - -external fst : 'a * 'b -> 'a = "%field0" -external snd : 'a * 'b -> 'b = "%field1" - -(* References *) - -type 'a ref = { mutable contents : 'a } -external ref : 'a -> 'a ref = "%makemutable" -external ( ! ) : 'a ref -> 'a = "%field0" -external ( := ) : 'a ref -> 'a -> unit = "%setfield0" -external incr : int ref -> unit = "%incr" -external decr : int ref -> unit = "%decr" - -(* Result type *) - -type ('a,'b) result = Ok of 'a | Error of 'b - -(* String conversion functions *) - -external format_int : string -> int -> string = "caml_format_int" -external format_float : string -> float -> string = "caml_format_float" - -let string_of_bool b = - if b then "true" else "false" -let bool_of_string = function - | "true" -> true - | "false" -> false - | _ -> invalid_arg "bool_of_string" - -let bool_of_string_opt = function - | "true" -> Some true - | "false" -> Some false - | _ -> None - -let string_of_int n = - format_int "%d" n - -external int_of_string : string -> int = "caml_int_of_string" - -let int_of_string_opt s = - (* TODO: provide this directly as a non-raising primitive. *) - try Some (int_of_string s) - with Failure _ -> None - -external string_get : string -> int -> char = "%string_safe_get" - -let valid_float_lexem s = - let l = string_length s in - let rec loop i = - if i >= l then s ^ "." else - match string_get s i with - | '0' .. '9' | '-' -> loop (i + 1) - | _ -> s - in - loop 0 - -let string_of_float f = valid_float_lexem (format_float "%.12g" f) - -external float_of_string : string -> float = "caml_float_of_string" - -let float_of_string_opt s = - (* TODO: provide this directly as a non-raising primitive. *) - try Some (float_of_string s) - with Failure _ -> None - -(* List operations -- more in module List *) - -let rec ( @ ) l1 l2 = - match l1 with - [] -> l2 - | hd :: tl -> hd :: (tl @ l2) - -(* I/O operations *) - -type in_channel -type out_channel - -external open_descriptor_out : int -> out_channel - = "caml_ml_open_descriptor_out" -external open_descriptor_in : int -> in_channel = "caml_ml_open_descriptor_in" - -let stdin = open_descriptor_in 0 -let stdout = open_descriptor_out 1 -let stderr = open_descriptor_out 2 - -(* General output functions *) - -type open_flag = - Open_rdonly | Open_wronly | Open_append - | Open_creat | Open_trunc | Open_excl - | Open_binary | Open_text | Open_nonblock - -external open_desc : string -> open_flag list -> int -> int = "caml_sys_open" - -external set_out_channel_name: out_channel -> string -> unit = - "caml_ml_set_channel_name" - -let open_out_gen mode perm name = - let c = open_descriptor_out(open_desc name mode perm) in - set_out_channel_name c name; - c - -let open_out name = - open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o666 name - -let open_out_bin name = - open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_binary] 0o666 name - -external flush : out_channel -> unit = "caml_ml_flush" - -external out_channels_list : unit -> out_channel list - = "caml_ml_out_channels_list" - -let flush_all () = - let rec iter = function - [] -> () - | a::l -> - begin try - flush a - with Sys_error _ -> - () (* ignore channels closed during a preceding flush. *) - end; - iter l - in iter (out_channels_list ()) - -external unsafe_output : out_channel -> bytes -> int -> int -> unit - = "caml_ml_output_bytes" -external unsafe_output_string : out_channel -> string -> int -> int -> unit - = "caml_ml_output" - -external output_char : out_channel -> char -> unit = "caml_ml_output_char" - -let output_bytes oc s = - unsafe_output oc s 0 (bytes_length s) - -let output_string oc s = - unsafe_output_string oc s 0 (string_length s) - -let output oc s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "output" - else unsafe_output oc s ofs len - -let output_substring oc s ofs len = - if ofs < 0 || len < 0 || ofs > string_length s - len - then invalid_arg "output_substring" - else unsafe_output_string oc s ofs len - -external output_byte : out_channel -> int -> unit = "caml_ml_output_char" -external output_binary_int : out_channel -> int -> unit = "caml_ml_output_int" - -external marshal_to_channel : out_channel -> 'a -> unit list -> unit - = "caml_output_value" -let output_value chan v = marshal_to_channel chan v [] - -external seek_out : out_channel -> int -> unit = "caml_ml_seek_out" -external pos_out : out_channel -> int = "caml_ml_pos_out" -external out_channel_length : out_channel -> int = "caml_ml_channel_size" -external close_out_channel : out_channel -> unit = "caml_ml_close_channel" -let close_out oc = flush oc; close_out_channel oc -let close_out_noerr oc = - (try flush oc with _ -> ()); - (try close_out_channel oc with _ -> ()) -external set_binary_mode_out : out_channel -> bool -> unit - = "caml_ml_set_binary_mode" - -(* General input functions *) - -external set_in_channel_name: in_channel -> string -> unit = - "caml_ml_set_channel_name" - -let open_in_gen mode perm name = - let c = open_descriptor_in(open_desc name mode perm) in - set_in_channel_name c name; - c - -let open_in name = - open_in_gen [Open_rdonly; Open_text] 0 name - -let open_in_bin name = - open_in_gen [Open_rdonly; Open_binary] 0 name - -external input_char : in_channel -> char = "caml_ml_input_char" - -external unsafe_input : in_channel -> bytes -> int -> int -> int - = "caml_ml_input" - -let input ic s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "input" - else unsafe_input ic s ofs len - -let rec unsafe_really_input ic s ofs len = - if len <= 0 then () else begin - let r = unsafe_input ic s ofs len in - if r = 0 - then raise End_of_file - else unsafe_really_input ic s (ofs + r) (len - r) - end - -let really_input ic s ofs len = - if ofs < 0 || len < 0 || ofs > bytes_length s - len - then invalid_arg "really_input" - else unsafe_really_input ic s ofs len - -let really_input_string ic len = - let s = bytes_create len in - really_input ic s 0 len; - bytes_unsafe_to_string s - -external input_scan_line : in_channel -> int = "caml_ml_input_scan_line" - -let input_line chan = - let rec build_result buf pos = function - [] -> buf - | hd :: tl -> - let len = bytes_length hd in - bytes_blit hd 0 buf (pos - len) len; - build_result buf (pos - len) tl in - let rec scan accu len = - let n = input_scan_line chan in - if n = 0 then begin (* n = 0: we are at EOF *) - match accu with - [] -> raise End_of_file - | _ -> build_result (bytes_create len) len accu - end else if n > 0 then begin (* n > 0: newline found in buffer *) - let res = bytes_create (n - 1) in - ignore (unsafe_input chan res 0 (n - 1)); - ignore (input_char chan); (* skip the newline *) - match accu with - [] -> res - | _ -> let len = len + n - 1 in - build_result (bytes_create len) len (res :: accu) - end else begin (* n < 0: newline not found *) - let beg = bytes_create (-n) in - ignore(unsafe_input chan beg 0 (-n)); - scan (beg :: accu) (len - n) - end - in bytes_unsafe_to_string (scan [] 0) - -external input_byte : in_channel -> int = "caml_ml_input_char" -external input_binary_int : in_channel -> int = "caml_ml_input_int" -external input_value : in_channel -> 'a = "caml_input_value" -external seek_in : in_channel -> int -> unit = "caml_ml_seek_in" -external pos_in : in_channel -> int = "caml_ml_pos_in" -external in_channel_length : in_channel -> int = "caml_ml_channel_size" -external close_in : in_channel -> unit = "caml_ml_close_channel" -let close_in_noerr ic = (try close_in ic with _ -> ()) -external set_binary_mode_in : in_channel -> bool -> unit - = "caml_ml_set_binary_mode" - -(* Output functions on standard output *) - -let print_char c = output_char stdout c -let print_string s = output_string stdout s -let print_bytes s = output_bytes stdout s -let print_int i = output_string stdout (string_of_int i) -let print_float f = output_string stdout (string_of_float f) -let print_endline s = - output_string stdout s; output_char stdout '\n'; flush stdout -let print_newline () = output_char stdout '\n'; flush stdout - -(* Output functions on standard error *) - -let prerr_char c = output_char stderr c -let prerr_string s = output_string stderr s -let prerr_bytes s = output_bytes stderr s -let prerr_int i = output_string stderr (string_of_int i) -let prerr_float f = output_string stderr (string_of_float f) -let prerr_endline s = - output_string stderr s; output_char stderr '\n'; flush stderr -let prerr_newline () = output_char stderr '\n'; flush stderr - -(* Input functions on standard input *) - -let read_line () = flush stdout; input_line stdin -let read_int () = int_of_string(read_line()) -let read_int_opt () = int_of_string_opt(read_line()) -let read_float () = float_of_string(read_line()) -let read_float_opt () = float_of_string_opt(read_line()) - -(* Operations on large files *) - -module LargeFile = - struct - external seek_out : out_channel -> int64 -> unit = "caml_ml_seek_out_64" - external pos_out : out_channel -> int64 = "caml_ml_pos_out_64" - external out_channel_length : out_channel -> int64 - = "caml_ml_channel_size_64" - external seek_in : in_channel -> int64 -> unit = "caml_ml_seek_in_64" - external pos_in : in_channel -> int64 = "caml_ml_pos_in_64" - external in_channel_length : in_channel -> int64 = "caml_ml_channel_size_64" - end - -(* Formats *) - -type ('a, 'b, 'c, 'd, 'e, 'f) format6 - = ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 - = Format of ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.fmt - * string - -type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 - -type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 - -let string_of_format (Format (_fmt, str)) = str - -external format_of_string : - ('a, 'b, 'c, 'd, 'e, 'f) format6 -> - ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" - -let ( ^^ ) (Format (fmt1, str1)) (Format (fmt2, str2)) = - Format (CamlinternalFormatBasics.concat_fmt fmt1 fmt2, - str1 ^ "%," ^ str2) - -(* Miscellaneous *) - -external sys_exit : int -> 'a = "caml_sys_exit" - -let exit_function = ref flush_all - -let at_exit f = - let g = !exit_function in - exit_function := (fun () -> f(); g()) - -let do_at_exit () = (!exit_function) () - -let exit retcode = - do_at_exit (); - sys_exit retcode - -let _ = register_named_value "Pervasives.do_at_exit" do_at_exit diff --git a/stdlib/pervasives.mli b/stdlib/pervasives.mli deleted file mode 100644 index af0cffee..00000000 --- a/stdlib/pervasives.mli +++ /dev/null @@ -1,1221 +0,0 @@ -(**************************************************************************) -(* *) -(* OCaml *) -(* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) -(* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) -(* en Automatique. *) -(* *) -(* All rights reserved. This file is distributed under the terms of *) -(* the GNU Lesser General Public License version 2.1, with the *) -(* special exception on linking described in the file LICENSE. *) -(* *) -(**************************************************************************) - -(** The initially opened module. - - This module provides the basic operations over the built-in types - (numbers, booleans, byte sequences, strings, exceptions, references, - lists, arrays, input-output channels, ...). - - This module is automatically opened at the beginning of each compilation. - All components of this module can therefore be referred by their short - name, without prefixing them by [Pervasives]. -*) - - -(** {1 Exceptions} *) - -external raise : exn -> 'a = "%raise" -(** Raise the given exception value *) - -external raise_notrace : exn -> 'a = "%raise_notrace" -(** A faster version [raise] which does not record the backtrace. - @since 4.02.0 -*) - -val invalid_arg : string -> 'a -(** Raise exception [Invalid_argument] with the given string. *) - -val failwith : string -> 'a -(** Raise exception [Failure] with the given string. *) - -exception Exit -(** The [Exit] exception is not raised by any library function. It is - provided for use in your programs. *) - - -(** {1 Comparisons} *) - -external ( = ) : 'a -> 'a -> bool = "%equal" -(** [e1 = e2] tests for structural equality of [e1] and [e2]. - Mutable structures (e.g. references and arrays) are equal - if and only if their current contents are structurally equal, - even if the two mutable objects are not the same physical object. - Equality between functional values raises [Invalid_argument]. - Equality between cyclic data structures may not terminate. - Left-associative operator at precedence level 4/11. *) - -external ( <> ) : 'a -> 'a -> bool = "%notequal" -(** Negation of {!Pervasives.( = )}. - Left-associative operator at precedence level 4/11. *) - -external ( < ) : 'a -> 'a -> bool = "%lessthan" -(** See {!Pervasives.( >= )}. - Left-associative operator at precedence level 4/11. *) - -external ( > ) : 'a -> 'a -> bool = "%greaterthan" -(** See {!Pervasives.( >= )}. - Left-associative operator at precedence level 4/11. *) - -external ( <= ) : 'a -> 'a -> bool = "%lessequal" -(** See {!Pervasives.( >= )}. - Left-associative operator at precedence level 4/11. *) - -external ( >= ) : 'a -> 'a -> bool = "%greaterequal" -(** Structural ordering functions. These functions coincide with - the usual orderings over integers, characters, strings, byte sequences - and floating-point numbers, and extend them to a - total ordering over all types. - The ordering is compatible with [( = )]. As in the case - of [( = )], mutable structures are compared by contents. - Comparison between functional values raises [Invalid_argument]. - Comparison between cyclic structures may not terminate. - Left-associative operator at precedence level 4/11. *) - -external compare : 'a -> 'a -> int = "%compare" -(** [compare x y] returns [0] if [x] is equal to [y], - a negative integer if [x] is less than [y], and a positive integer - if [x] is greater than [y]. The ordering implemented by [compare] - is compatible with the comparison predicates [=], [<] and [>] - defined above, with one difference on the treatment of the float value - {!Pervasives.nan}. Namely, the comparison predicates treat [nan] - as different from any other float value, including itself; - while [compare] treats [nan] as equal to itself and less than any - other float value. This treatment of [nan] ensures that [compare] - defines a total ordering relation. - - [compare] applied to functional values may raise [Invalid_argument]. - [compare] applied to cyclic structures may not terminate. - - The [compare] function can be used as the comparison function - required by the {!Set.Make} and {!Map.Make} functors, as well as - the {!List.sort} and {!Array.sort} functions. *) - -val min : 'a -> 'a -> 'a -(** Return the smaller of the two arguments. - The result is unspecified if one of the arguments contains - the float value [nan]. *) - -val max : 'a -> 'a -> 'a -(** Return the greater of the two arguments. - The result is unspecified if one of the arguments contains - the float value [nan]. *) - -external ( == ) : 'a -> 'a -> bool = "%eq" -(** [e1 == e2] tests for physical equality of [e1] and [e2]. - On mutable types such as references, arrays, byte sequences, records with - mutable fields and objects with mutable instance variables, - [e1 == e2] is true if and only if physical modification of [e1] - also affects [e2]. - On non-mutable types, the behavior of [( == )] is - implementation-dependent; however, it is guaranteed that - [e1 == e2] implies [compare e1 e2 = 0]. - Left-associative operator at precedence level 4/11. *) - -external ( != ) : 'a -> 'a -> bool = "%noteq" -(** Negation of {!Pervasives.( == )}. - Left-associative operator at precedence level 4/11. *) - - -(** {1 Boolean operations} *) - -external not : bool -> bool = "%boolnot" -(** The boolean negation. *) - -external ( && ) : bool -> bool -> bool = "%sequand" -(** The boolean 'and'. Evaluation is sequential, left-to-right: - in [e1 && e2], [e1] is evaluated first, and if it returns [false], - [e2] is not evaluated at all. - Right-associative operator at precedence level 3/11. *) - -external ( & ) : bool -> bool -> bool = "%sequand" - [@@ocaml.deprecated "Use (&&) instead."] -(** @deprecated {!Pervasives.( && )} should be used instead. - Right-associative operator at precedence level 3/11. *) - -external ( || ) : bool -> bool -> bool = "%sequor" -(** The boolean 'or'. Evaluation is sequential, left-to-right: - in [e1 || e2], [e1] is evaluated first, and if it returns [true], - [e2] is not evaluated at all. - Right-associative operator at precedence level 2/11. -*) - -external ( or ) : bool -> bool -> bool = "%sequor" - [@@ocaml.deprecated "Use (||) instead."] -(** @deprecated {!Pervasives.( || )} should be used instead. - Right-associative operator at precedence level 2/11. *) - -(** {1 Debugging} *) - -external __LOC__ : string = "%loc_LOC" -(** [__LOC__] returns the location at which this expression appears in - the file currently being parsed by the compiler, with the standard - error format of OCaml: "File %S, line %d, characters %d-%d". - @since 4.02.0 -*) - -external __FILE__ : string = "%loc_FILE" -(** [__FILE__] returns the name of the file currently being - parsed by the compiler. - @since 4.02.0 -*) - -external __LINE__ : int = "%loc_LINE" -(** [__LINE__] returns the line number at which this expression - appears in the file currently being parsed by the compiler. - @since 4.02.0 -*) - -external __MODULE__ : string = "%loc_MODULE" -(** [__MODULE__] returns the module name of the file being - parsed by the compiler. - @since 4.02.0 -*) - -external __POS__ : string * int * int * int = "%loc_POS" -(** [__POS__] returns a tuple [(file,lnum,cnum,enum)], corresponding - to the location at which this expression appears in the file - currently being parsed by the compiler. [file] is the current - filename, [lnum] the line number, [cnum] the character position in - the line and [enum] the last character position in the line. - @since 4.02.0 - *) - -external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" -(** [__LOC_OF__ expr] returns a pair [(loc, expr)] where [loc] is the - location of [expr] in the file currently being parsed by the - compiler, with the standard error format of OCaml: "File %S, line - %d, characters %d-%d". - @since 4.02.0 -*) - -external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" -(** [__LINE__ expr] returns a pair [(line, expr)], where [line] is the - line number at which the expression [expr] appears in the file - currently being parsed by the compiler. - @since 4.02.0 - *) - -external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" -(** [__POS_OF__ expr] returns a pair [(loc,expr)], where [loc] is a - tuple [(file,lnum,cnum,enum)] corresponding to the location at - which the expression [expr] appears in the file currently being - parsed by the compiler. [file] is the current filename, [lnum] the - line number, [cnum] the character position in the line and [enum] - the last character position in the line. - @since 4.02.0 - *) - -(** {1 Composition operators} *) - -external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" -(** Reverse-application operator: [x |> f |> g] is exactly equivalent - to [g (f (x))]. - Left-associative operator at precedence level 4/11. - @since 4.01 - *) - -external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" -(** Application operator: [g @@ f @@ x] is exactly equivalent to - [g (f (x))]. - Right-associative operator at precedence level 5/11. - @since 4.01 -*) - -(** {1 Integer arithmetic} *) - -(** Integers are 31 bits wide (or 63 bits on 64-bit processors). - All operations are taken modulo 2{^31} (or 2{^63}). - They do not fail on overflow. *) - -external ( ~- ) : int -> int = "%negint" -(** Unary negation. You can also write [- e] instead of [~- e]. - Unary operator at precedence level 9/11 for [- e] - and 11/11 for [~- e]. *) - -external ( ~+ ) : int -> int = "%identity" -(** Unary addition. You can also write [+ e] instead of [~+ e]. - Unary operator at precedence level 9/11 for [+ e] - and 11/11 for [~+ e]. - @since 3.12.0 -*) - -external succ : int -> int = "%succint" -(** [succ x] is [x + 1]. *) - -external pred : int -> int = "%predint" -(** [pred x] is [x - 1]. *) - -external ( + ) : int -> int -> int = "%addint" -(** Integer addition. - Left-associative operator at precedence level 6/11. *) - -external ( - ) : int -> int -> int = "%subint" -(** Integer subtraction. - Left-associative operator at precedence level 6/11. *) - -external ( * ) : int -> int -> int = "%mulint" -(** Integer multiplication. - Left-associative operator at precedence level 7/11. *) - -external ( / ) : int -> int -> int = "%divint" -(** Integer division. - Raise [Division_by_zero] if the second argument is 0. - Integer division rounds the real quotient of its arguments towards zero. - More precisely, if [x >= 0] and [y > 0], [x / y] is the greatest integer - less than or equal to the real quotient of [x] by [y]. Moreover, - [(- x) / y = x / (- y) = - (x / y)]. - Left-associative operator at precedence level 7/11. *) - -external ( mod ) : int -> int -> int = "%modint" -(** Integer remainder. If [y] is not zero, the result - of [x mod y] satisfies the following properties: - [x = (x / y) * y + x mod y] and - [abs(x mod y) <= abs(y) - 1]. - If [y = 0], [x mod y] raises [Division_by_zero]. - Note that [x mod y] is negative only if [x < 0]. - Raise [Division_by_zero] if [y] is zero. - Left-associative operator at precedence level 7/11. *) - -val abs : int -> int -(** Return the absolute value of the argument. Note that this may be - negative if the argument is [min_int]. *) - -val max_int : int -(** The greatest representable integer. *) - -val min_int : int -(** The smallest representable integer. *) - - -(** {2 Bitwise operations} *) - -external ( land ) : int -> int -> int = "%andint" -(** Bitwise logical and. - Left-associative operator at precedence level 7/11. *) - -external ( lor ) : int -> int -> int = "%orint" -(** Bitwise logical or. - Left-associative operator at precedence level 7/11. *) - -external ( lxor ) : int -> int -> int = "%xorint" -(** Bitwise logical exclusive or. - Left-associative operator at precedence level 7/11. *) - -val lnot : int -> int -(** Bitwise logical negation. *) - -external ( lsl ) : int -> int -> int = "%lslint" -(** [n lsl m] shifts [n] to the left by [m] bits. - The result is unspecified if [m < 0] or [m >= bitsize], - where [bitsize] is [32] on a 32-bit platform and - [64] on a 64-bit platform. - Right-associative operator at precedence level 8/11. *) - -external ( lsr ) : int -> int -> int = "%lsrint" -(** [n lsr m] shifts [n] to the right by [m] bits. - This is a logical shift: zeroes are inserted regardless of - the sign of [n]. - The result is unspecified if [m < 0] or [m >= bitsize]. - Right-associative operator at precedence level 8/11. *) - -external ( asr ) : int -> int -> int = "%asrint" -(** [n asr m] shifts [n] to the right by [m] bits. - This is an arithmetic shift: the sign bit of [n] is replicated. - The result is unspecified if [m < 0] or [m >= bitsize]. - Right-associative operator at precedence level 8/11. *) - - -(** {1 Floating-point arithmetic} - - OCaml's floating-point numbers follow the - IEEE 754 standard, using double precision (64 bits) numbers. - Floating-point operations never raise an exception on overflow, - underflow, division by zero, etc. Instead, special IEEE numbers - are returned as appropriate, such as [infinity] for [1.0 /. 0.0], - [neg_infinity] for [-1.0 /. 0.0], and [nan] ('not a number') - for [0.0 /. 0.0]. These special numbers then propagate through - floating-point computations as expected: for instance, - [1.0 /. infinity] is [0.0], and any arithmetic operation with [nan] - as argument returns [nan] as result. -*) - -external ( ~-. ) : float -> float = "%negfloat" -(** Unary negation. You can also write [-. e] instead of [~-. e]. - Unary operator at precedence level 9/11 for [-. e] - and 11/11 for [~-. e]. *) - -external ( ~+. ) : float -> float = "%identity" -(** Unary addition. You can also write [+. e] instead of [~+. e]. - Unary operator at precedence level 9/11 for [+. e] - and 11/11 for [~+. e]. - @since 3.12.0 -*) - -external ( +. ) : float -> float -> float = "%addfloat" -(** Floating-point addition. - Left-associative operator at precedence level 6/11. *) - -external ( -. ) : float -> float -> float = "%subfloat" -(** Floating-point subtraction. - Left-associative operator at precedence level 6/11. *) - -external ( *. ) : float -> float -> float = "%mulfloat" -(** Floating-point multiplication. - Left-associative operator at precedence level 7/11. *) - -external ( /. ) : float -> float -> float = "%divfloat" -(** Floating-point division. - Left-associative operator at precedence level 7/11. *) - -external ( ** ) : float -> float -> float = "caml_power_float" "pow" - [@@unboxed] [@@noalloc] -(** Exponentiation. - Right-associative operator at precedence level 8/11. *) - -external sqrt : float -> float = "caml_sqrt_float" "sqrt" - [@@unboxed] [@@noalloc] -(** Square root. *) - -external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] -(** Exponential. *) - -external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] -(** Natural logarithm. *) - -external log10 : float -> float = "caml_log10_float" "log10" - [@@unboxed] [@@noalloc] -(** Base 10 logarithm. *) - -external expm1 : float -> float = "caml_expm1_float" "caml_expm1" - [@@unboxed] [@@noalloc] -(** [expm1 x] computes [exp x -. 1.0], giving numerically-accurate results - even if [x] is close to [0.0]. - @since 3.12.0 -*) - -external log1p : float -> float = "caml_log1p_float" "caml_log1p" - [@@unboxed] [@@noalloc] -(** [log1p x] computes [log(1.0 +. x)] (natural logarithm), - giving numerically-accurate results even if [x] is close to [0.0]. - @since 3.12.0 -*) - -external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] -(** Cosine. Argument is in radians. *) - -external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] -(** Sine. Argument is in radians. *) - -external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] -(** Tangent. Argument is in radians. *) - -external acos : float -> float = "caml_acos_float" "acos" - [@@unboxed] [@@noalloc] -(** Arc cosine. The argument must fall within the range [[-1.0, 1.0]]. - Result is in radians and is between [0.0] and [pi]. *) - -external asin : float -> float = "caml_asin_float" "asin" - [@@unboxed] [@@noalloc] -(** Arc sine. The argument must fall within the range [[-1.0, 1.0]]. - Result is in radians and is between [-pi/2] and [pi/2]. *) - -external atan : float -> float = "caml_atan_float" "atan" - [@@unboxed] [@@noalloc] -(** Arc tangent. - Result is in radians and is between [-pi/2] and [pi/2]. *) - -external atan2 : float -> float -> float = "caml_atan2_float" "atan2" - [@@unboxed] [@@noalloc] -(** [atan2 y x] returns the arc tangent of [y /. x]. The signs of [x] - and [y] are used to determine the quadrant of the result. - Result is in radians and is between [-pi] and [pi]. *) - -external hypot : float -> float -> float = "caml_hypot_float" "caml_hypot" - [@@unboxed] [@@noalloc] -(** [hypot x y] returns [sqrt(x *. x + y *. y)], that is, the length - of the hypotenuse of a right-angled triangle with sides of length - [x] and [y], or, equivalently, the distance of the point [(x,y)] - to origin. If one of [x] or [y] is infinite, returns [infinity] - even if the other is [nan]. - @since 4.00.0 *) - -external cosh : float -> float = "caml_cosh_float" "cosh" - [@@unboxed] [@@noalloc] -(** Hyperbolic cosine. Argument is in radians. *) - -external sinh : float -> float = "caml_sinh_float" "sinh" - [@@unboxed] [@@noalloc] -(** Hyperbolic sine. Argument is in radians. *) - -external tanh : float -> float = "caml_tanh_float" "tanh" - [@@unboxed] [@@noalloc] -(** Hyperbolic tangent. Argument is in radians. *) - -external ceil : float -> float = "caml_ceil_float" "ceil" - [@@unboxed] [@@noalloc] -(** Round above to an integer value. - [ceil f] returns the least integer value greater than or equal to [f]. - The result is returned as a float. *) - -external floor : float -> float = "caml_floor_float" "floor" - [@@unboxed] [@@noalloc] -(** Round below to an integer value. - [floor f] returns the greatest integer value less than or - equal to [f]. - The result is returned as a float. *) - -external abs_float : float -> float = "%absfloat" -(** [abs_float f] returns the absolute value of [f]. *) - -external copysign : float -> float -> float - = "caml_copysign_float" "caml_copysign" - [@@unboxed] [@@noalloc] -(** [copysign x y] returns a float whose absolute value is that of [x] - and whose sign is that of [y]. If [x] is [nan], returns [nan]. - If [y] is [nan], returns either [x] or [-. x], but it is not - specified which. - @since 4.00.0 *) - -external mod_float : float -> float -> float = "caml_fmod_float" "fmod" - [@@unboxed] [@@noalloc] -(** [mod_float a b] returns the remainder of [a] with respect to - [b]. The returned value is [a -. n *. b], where [n] - is the quotient [a /. b] rounded towards zero to an integer. *) - -external frexp : float -> float * int = "caml_frexp_float" -(** [frexp f] returns the pair of the significant - and the exponent of [f]. When [f] is zero, the - significant [x] and the exponent [n] of [f] are equal to - zero. When [f] is non-zero, they are defined by - [f = x *. 2 ** n] and [0.5 <= x < 1.0]. *) - - -external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = - "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] -(** [ldexp x n] returns [x *. 2 ** n]. *) - -external modf : float -> float * float = "caml_modf_float" -(** [modf f] returns the pair of the fractional and integral - part of [f]. *) - -external float : int -> float = "%floatofint" -(** Same as {!Pervasives.float_of_int}. *) - -external float_of_int : int -> float = "%floatofint" -(** Convert an integer to floating-point. *) - -external truncate : float -> int = "%intoffloat" -(** Same as {!Pervasives.int_of_float}. *) - -external int_of_float : float -> int = "%intoffloat" -(** Truncate the given floating-point number to an integer. - The result is unspecified if the argument is [nan] or falls outside the - range of representable integers. *) - -val infinity : float -(** Positive infinity. *) - -val neg_infinity : float -(** Negative infinity. *) - -val nan : float -(** A special floating-point value denoting the result of an - undefined operation such as [0.0 /. 0.0]. Stands for - 'not a number'. Any floating-point operation with [nan] as - argument returns [nan] as result. As for floating-point comparisons, - [=], [<], [<=], [>] and [>=] return [false] and [<>] returns [true] - if one or both of their arguments is [nan]. *) - -val max_float : float -(** The largest positive finite value of type [float]. *) - -val min_float : float -(** The smallest positive, non-zero, non-denormalized value of type [float]. *) - -val epsilon_float : float -(** The difference between [1.0] and the smallest exactly representable - floating-point number greater than [1.0]. *) - -type fpclass = - FP_normal (** Normal number, none of the below *) - | FP_subnormal (** Number very close to 0.0, has reduced precision *) - | FP_zero (** Number is 0.0 or -0.0 *) - | FP_infinite (** Number is positive or negative infinity *) - | FP_nan (** Not a number: result of an undefined operation *) -(** The five classes of floating-point numbers, as determined by - the {!Pervasives.classify_float} function. *) - -external classify_float : (float [@unboxed]) -> fpclass = - "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] -(** Return the class of the given floating-point number: - normal, subnormal, zero, infinite, or not a number. *) - - -(** {1 String operations} - - More string operations are provided in module {!String}. -*) - -val ( ^ ) : string -> string -> string -(** String concatenation. - Right-associative operator at precedence level 5/11. *) - - -(** {1 Character operations} - - More character operations are provided in module {!Char}. -*) - -external int_of_char : char -> int = "%identity" -(** Return the ASCII code of the argument. *) - -val char_of_int : int -> char -(** Return the character with the given ASCII code. - Raise [Invalid_argument "char_of_int"] if the argument is - outside the range 0--255. *) - - -(** {1 Unit operations} *) - -external ignore : 'a -> unit = "%ignore" -(** Discard the value of its argument and return [()]. - For instance, [ignore(f x)] discards the result of - the side-effecting function [f]. It is equivalent to - [f x; ()], except that the latter may generate a - compiler warning; writing [ignore(f x)] instead - avoids the warning. *) - - -(** {1 String conversion functions} *) - -val string_of_bool : bool -> string -(** Return the string representation of a boolean. As the returned values - may be shared, the user should not modify them directly. -*) - -val bool_of_string : string -> bool -(** Convert the given string to a boolean. - Raise [Invalid_argument "bool_of_string"] if the string is not - ["true"] or ["false"]. *) - -val bool_of_string_opt: string -> bool option -(** Convert the given string to a boolean. - Return [None] if the string is not - ["true"] or ["false"]. - @since 4.05 -*) - -val string_of_int : int -> string -(** Return the string representation of an integer, in decimal. *) - -external int_of_string : string -> int = "caml_int_of_string" -(** Convert the given string to an integer. - The string is read in decimal (by default, or if the string - begins with [0u]), in hexadecimal (if it begins with [0x] or - [0X]), in octal (if it begins with [0o] or [0O]), or in binary - (if it begins with [0b] or [0B]). - - The [0u] prefix reads the input as an unsigned integer in the range - [[0, 2*max_int+1]]. If the input exceeds {!max_int} - it is converted to the signed integer - [min_int + input - max_int - 1]. - - The [_] (underscore) character can appear anywhere in the string - and is ignored. - Raise [Failure "int_of_string"] if the given string is not - a valid representation of an integer, or if the integer represented - exceeds the range of integers representable in type [int]. *) - - -val int_of_string_opt: string -> int option -(** Same as [int_of_string], but returns [None] instead of raising. - @since 4.05 -*) - -val string_of_float : float -> string -(** Return the string representation of a floating-point number. *) - -external float_of_string : string -> float = "caml_float_of_string" -(** Convert the given string to a float. The string is read in decimal - (by default) or in hexadecimal (marked by [0x] or [0X]). - The format of decimal floating-point numbers is - [ [-] dd.ddd (e|E) [+|-] dd ], where [d] stands for a decimal digit. - The format of hexadecimal floating-point numbers is - [ [-] 0(x|X) hh.hhh (p|P) [+|-] dd ], where [h] stands for an - hexadecimal digit and [d] for a decimal digit. - In both cases, at least one of the integer and fractional parts must be - given; the exponent part is optional. - The [_] (underscore) character can appear anywhere in the string - and is ignored. - Depending on the execution platforms, other representations of - floating-point numbers can be accepted, but should not be relied upon. - Raise [Failure "float_of_string"] if the given string is not a valid - representation of a float. *) - -val float_of_string_opt: string -> float option -(** Same as [float_of_string], but returns [None] instead of raising. - @since 4.05 -*) - -(** {1 Pair operations} *) - -external fst : 'a * 'b -> 'a = "%field0" -(** Return the first component of a pair. *) - -external snd : 'a * 'b -> 'b = "%field1" -(** Return the second component of a pair. *) - - -(** {1 List operations} - - More list operations are provided in module {!List}. -*) - -val ( @ ) : 'a list -> 'a list -> 'a list -(** List concatenation. Not tail-recursive (length of the first argument). - Right-associative operator at precedence level 5/11. *) - - -(** {1 Input/output} - Note: all input/output functions can raise [Sys_error] when the system - calls they invoke fail. *) - -type in_channel -(** The type of input channel. *) - -type out_channel -(** The type of output channel. *) - -val stdin : in_channel -(** The standard input for the process. *) - -val stdout : out_channel -(** The standard output for the process. *) - -val stderr : out_channel -(** The standard error output for the process. *) - - -(** {2 Output functions on standard output} *) - -val print_char : char -> unit -(** Print a character on standard output. *) - -val print_string : string -> unit -(** Print a string on standard output. *) - -val print_bytes : bytes -> unit -(** Print a byte sequence on standard output. - @since 4.02.0 *) - -val print_int : int -> unit -(** Print an integer, in decimal, on standard output. *) - -val print_float : float -> unit -(** Print a floating-point number, in decimal, on standard output. *) - -val print_endline : string -> unit -(** Print a string, followed by a newline character, on - standard output and flush standard output. *) - -val print_newline : unit -> unit -(** Print a newline character on standard output, and flush - standard output. This can be used to simulate line - buffering of standard output. *) - - -(** {2 Output functions on standard error} *) - -val prerr_char : char -> unit -(** Print a character on standard error. *) - -val prerr_string : string -> unit -(** Print a string on standard error. *) - -val prerr_bytes : bytes -> unit -(** Print a byte sequence on standard error. - @since 4.02.0 *) - -val prerr_int : int -> unit -(** Print an integer, in decimal, on standard error. *) - -val prerr_float : float -> unit -(** Print a floating-point number, in decimal, on standard error. *) - -val prerr_endline : string -> unit -(** Print a string, followed by a newline character on standard - error and flush standard error. *) - -val prerr_newline : unit -> unit -(** Print a newline character on standard error, and flush - standard error. *) - - -(** {2 Input functions on standard input} *) - -val read_line : unit -> string -(** Flush standard output, then read characters from standard input - until a newline character is encountered. Return the string of - all characters read, without the newline character at the end. *) - -val read_int : unit -> int -(** Flush standard output, then read one line from standard input - and convert it to an integer. Raise [Failure "int_of_string"] - if the line read is not a valid representation of an integer. *) - -val read_int_opt: unit -> int option -(** Same as [read_int_opt], but returns [None] instead of raising. - @since 4.05 -*) - -val read_float : unit -> float -(** Flush standard output, then read one line from standard input - and convert it to a floating-point number. - The result is unspecified if the line read is not a valid - representation of a floating-point number. *) - -val read_float_opt: unit -> float option -(** Flush standard output, then read one line from standard input - and convert it to a floating-point number. - Returns [None] if the line read is not a valid - representation of a floating-point number. - @since 4.05.0 *) - - -(** {2 General output functions} *) - -type open_flag = - Open_rdonly (** open for reading. *) - | Open_wronly (** open for writing. *) - | Open_append (** open for appending: always write at end of file. *) - | Open_creat (** create the file if it does not exist. *) - | Open_trunc (** empty the file if it already exists. *) - | Open_excl (** fail if Open_creat and the file already exists. *) - | Open_binary (** open in binary mode (no conversion). *) - | Open_text (** open in text mode (may perform conversions). *) - | Open_nonblock (** open in non-blocking mode. *) -(** Opening modes for {!Pervasives.open_out_gen} and - {!Pervasives.open_in_gen}. *) - -val open_out : string -> out_channel -(** Open the named file for writing, and return a new output channel - on that file, positioned at the beginning of the file. The - file is truncated to zero length if it already exists. It - is created if it does not already exists. *) - -val open_out_bin : string -> out_channel -(** Same as {!Pervasives.open_out}, but the file is opened in binary mode, - so that no translation takes place during writes. On operating - systems that do not distinguish between text mode and binary - mode, this function behaves like {!Pervasives.open_out}. *) - -val open_out_gen : open_flag list -> int -> string -> out_channel -(** [open_out_gen mode perm filename] opens the named file for writing, - as described above. The extra argument [mode] - specifies the opening mode. The extra argument [perm] specifies - the file permissions, in case the file must be created. - {!Pervasives.open_out} and {!Pervasives.open_out_bin} are special - cases of this function. *) - -val flush : out_channel -> unit -(** Flush the buffer associated with the given output channel, - performing all pending writes on that channel. - Interactive programs must be careful about flushing standard - output and standard error at the right time. *) - -val flush_all : unit -> unit -(** Flush all open output channels; ignore errors. *) - -val output_char : out_channel -> char -> unit -(** Write the character on the given output channel. *) - -val output_string : out_channel -> string -> unit -(** Write the string on the given output channel. *) - -val output_bytes : out_channel -> bytes -> unit -(** Write the byte sequence on the given output channel. - @since 4.02.0 *) - -val output : out_channel -> bytes -> int -> int -> unit -(** [output oc buf pos len] writes [len] characters from byte sequence [buf], - starting at offset [pos], to the given output channel [oc]. - Raise [Invalid_argument "output"] if [pos] and [len] do not - designate a valid range of [buf]. *) - -val output_substring : out_channel -> string -> int -> int -> unit -(** Same as [output] but take a string as argument instead of - a byte sequence. - @since 4.02.0 *) - -val output_byte : out_channel -> int -> unit -(** Write one 8-bit integer (as the single character with that code) - on the given output channel. The given integer is taken modulo - 256. *) - -val output_binary_int : out_channel -> int -> unit -(** Write one integer in binary format (4 bytes, big-endian) - on the given output channel. - The given integer is taken modulo 2{^32}. - The only reliable way to read it back is through the - {!Pervasives.input_binary_int} function. The format is compatible across - all machines for a given version of OCaml. *) - -val output_value : out_channel -> 'a -> unit -(** Write the representation of a structured value of any type - to a channel. Circularities and sharing inside the value - are detected and preserved. The object can be read back, - by the function {!Pervasives.input_value}. See the description of module - {!Marshal} for more information. {!Pervasives.output_value} is equivalent - to {!Marshal.to_channel} with an empty list of flags. *) - -val seek_out : out_channel -> int -> unit -(** [seek_out chan pos] sets the current writing position to [pos] - for channel [chan]. This works only for regular files. On - files of other kinds (such as terminals, pipes and sockets), - the behavior is unspecified. *) - -val pos_out : out_channel -> int -(** Return the current writing position for the given channel. Does - not work on channels opened with the [Open_append] flag (returns - unspecified results). *) - -val out_channel_length : out_channel -> int -(** Return the size (number of characters) of the regular file - on which the given channel is opened. If the channel is opened - on a file that is not a regular file, the result is meaningless. *) - -val close_out : out_channel -> unit -(** Close the given channel, flushing all buffered write operations. - Output functions raise a [Sys_error] exception when they are - applied to a closed output channel, except [close_out] and [flush], - which do nothing when applied to an already closed channel. - Note that [close_out] may raise [Sys_error] if the operating - system signals an error when flushing or closing. *) - -val close_out_noerr : out_channel -> unit -(** Same as [close_out], but ignore all errors. *) - -val set_binary_mode_out : out_channel -> bool -> unit -(** [set_binary_mode_out oc true] sets the channel [oc] to binary - mode: no translations take place during output. - [set_binary_mode_out oc false] sets the channel [oc] to text - mode: depending on the operating system, some translations - may take place during output. For instance, under Windows, - end-of-lines will be translated from [\n] to [\r\n]. - This function has no effect under operating systems that - do not distinguish between text mode and binary mode. *) - - -(** {2 General input functions} *) - -val open_in : string -> in_channel -(** Open the named file for reading, and return a new input channel - on that file, positioned at the beginning of the file. *) - -val open_in_bin : string -> in_channel -(** Same as {!Pervasives.open_in}, but the file is opened in binary mode, - so that no translation takes place during reads. On operating - systems that do not distinguish between text mode and binary - mode, this function behaves like {!Pervasives.open_in}. *) - -val open_in_gen : open_flag list -> int -> string -> in_channel -(** [open_in_gen mode perm filename] opens the named file for reading, - as described above. The extra arguments - [mode] and [perm] specify the opening mode and file permissions. - {!Pervasives.open_in} and {!Pervasives.open_in_bin} are special - cases of this function. *) - -val input_char : in_channel -> char -(** Read one character from the given input channel. - Raise [End_of_file] if there are no more characters to read. *) - -val input_line : in_channel -> string -(** Read characters from the given input channel, until a - newline character is encountered. Return the string of - all characters read, without the newline character at the end. - Raise [End_of_file] if the end of the file is reached - at the beginning of line. *) - -val input : in_channel -> bytes -> int -> int -> int -(** [input ic buf pos len] reads up to [len] characters from - the given channel [ic], storing them in byte sequence [buf], starting at - character number [pos]. - It returns the actual number of characters read, between 0 and - [len] (inclusive). - A return value of 0 means that the end of file was reached. - A return value between 0 and [len] exclusive means that - not all requested [len] characters were read, either because - no more characters were available at that time, or because - the implementation found it convenient to do a partial read; - [input] must be called again to read the remaining characters, - if desired. (See also {!Pervasives.really_input} for reading - exactly [len] characters.) - Exception [Invalid_argument "input"] is raised if [pos] and [len] - do not designate a valid range of [buf]. *) - -val really_input : in_channel -> bytes -> int -> int -> unit -(** [really_input ic buf pos len] reads [len] characters from channel [ic], - storing them in byte sequence [buf], starting at character number [pos]. - Raise [End_of_file] if the end of file is reached before [len] - characters have been read. - Raise [Invalid_argument "really_input"] if - [pos] and [len] do not designate a valid range of [buf]. *) - -val really_input_string : in_channel -> int -> string -(** [really_input_string ic len] reads [len] characters from channel [ic] - and returns them in a new string. - Raise [End_of_file] if the end of file is reached before [len] - characters have been read. - @since 4.02.0 *) - -val input_byte : in_channel -> int -(** Same as {!Pervasives.input_char}, but return the 8-bit integer representing - the character. - Raise [End_of_file] if an end of file was reached. *) - -val input_binary_int : in_channel -> int -(** Read an integer encoded in binary format (4 bytes, big-endian) - from the given input channel. See {!Pervasives.output_binary_int}. - Raise [End_of_file] if an end of file was reached while reading the - integer. *) - -val input_value : in_channel -> 'a -(** Read the representation of a structured value, as produced - by {!Pervasives.output_value}, and return the corresponding value. - This function is identical to {!Marshal.from_channel}; - see the description of module {!Marshal} for more information, - in particular concerning the lack of type safety. *) - -val seek_in : in_channel -> int -> unit -(** [seek_in chan pos] sets the current reading position to [pos] - for channel [chan]. This works only for regular files. On - files of other kinds, the behavior is unspecified. *) - -val pos_in : in_channel -> int -(** Return the current reading position for the given channel. *) - -val in_channel_length : in_channel -> int -(** Return the size (number of characters) of the regular file - on which the given channel is opened. If the channel is opened - on a file that is not a regular file, the result is meaningless. - The returned size does not take into account the end-of-line - translations that can be performed when reading from a channel - opened in text mode. *) - -val close_in : in_channel -> unit -(** Close the given channel. Input functions raise a [Sys_error] - exception when they are applied to a closed input channel, - except [close_in], which does nothing when applied to an already - closed channel. *) - -val close_in_noerr : in_channel -> unit -(** Same as [close_in], but ignore all errors. *) - -val set_binary_mode_in : in_channel -> bool -> unit -(** [set_binary_mode_in ic true] sets the channel [ic] to binary - mode: no translations take place during input. - [set_binary_mode_out ic false] sets the channel [ic] to text - mode: depending on the operating system, some translations - may take place during input. For instance, under Windows, - end-of-lines will be translated from [\r\n] to [\n]. - This function has no effect under operating systems that - do not distinguish between text mode and binary mode. *) - - -(** {2 Operations on large files} *) - -module LargeFile : - sig - val seek_out : out_channel -> int64 -> unit - val pos_out : out_channel -> int64 - val out_channel_length : out_channel -> int64 - val seek_in : in_channel -> int64 -> unit - val pos_in : in_channel -> int64 - val in_channel_length : in_channel -> int64 - end -(** Operations on large files. - This sub-module provides 64-bit variants of the channel functions - that manipulate file positions and file sizes. By representing - positions and sizes by 64-bit integers (type [int64]) instead of - regular integers (type [int]), these alternate functions allow - operating on files whose sizes are greater than [max_int]. *) - - -(** {1 References} *) - -type 'a ref = { mutable contents : 'a } -(** The type of references (mutable indirection cells) containing - a value of type ['a]. *) - -external ref : 'a -> 'a ref = "%makemutable" -(** Return a fresh reference containing the given value. *) - -external ( ! ) : 'a ref -> 'a = "%field0" -(** [!r] returns the current contents of reference [r]. - Equivalent to [fun r -> r.contents]. - Unary operator at precedence level 11/11.*) - -external ( := ) : 'a ref -> 'a -> unit = "%setfield0" -(** [r := a] stores the value of [a] in reference [r]. - Equivalent to [fun r v -> r.contents <- v]. - Right-associative operator at precedence level 1/11. *) - -external incr : int ref -> unit = "%incr" -(** Increment the integer contained in the given reference. - Equivalent to [fun r -> r := succ !r]. *) - -external decr : int ref -> unit = "%decr" -(** Decrement the integer contained in the given reference. - Equivalent to [fun r -> r := pred !r]. *) - -(** {1 Result type} *) - -(** @since 4.03.0 *) -type ('a,'b) result = Ok of 'a | Error of 'b - -(** {1 Operations on format strings} *) - -(** Format strings are character strings with special lexical conventions - that defines the functionality of formatted input/output functions. Format - strings are used to read data with formatted input functions from module - {!Scanf} and to print data with formatted output functions from modules - {!Printf} and {!Format}. - - Format strings are made of three kinds of entities: - - {e conversions specifications}, introduced by the special character ['%'] - followed by one or more characters specifying what kind of argument to - read or print, - - {e formatting indications}, introduced by the special character ['@'] - followed by one or more characters specifying how to read or print the - argument, - - {e plain characters} that are regular characters with usual lexical - conventions. Plain characters specify string literals to be read in the - input or printed in the output. - - There is an additional lexical rule to escape the special characters ['%'] - and ['@'] in format strings: if a special character follows a ['%'] - character, it is treated as a plain character. In other words, ["%%"] is - considered as a plain ['%'] and ["%@"] as a plain ['@']. - - For more information about conversion specifications and formatting - indications available, read the documentation of modules {!Scanf}, - {!Printf} and {!Format}. -*) - -(** Format strings have a general and highly polymorphic type - [('a, 'b, 'c, 'd, 'e, 'f) format6]. - The two simplified types, [format] and [format4] below are - included for backward compatibility with earlier releases of - OCaml. - - The meaning of format string type parameters is as follows: - - - ['a] is the type of the parameters of the format for formatted output - functions ([printf]-style functions); - ['a] is the type of the values read by the format for formatted input - functions ([scanf]-style functions). - - - ['b] is the type of input source for formatted input functions and the - type of output target for formatted output functions. - For [printf]-style functions from module {!Printf}, ['b] is typically - [out_channel]; - for [printf]-style functions from module {!Format}, ['b] is typically - {!Format.formatter}; - for [scanf]-style functions from module {!Scanf}, ['b] is typically - {!Scanf.Scanning.in_channel}. - - Type argument ['b] is also the type of the first argument given to - user's defined printing functions for [%a] and [%t] conversions, - and user's defined reading functions for [%r] conversion. - - - ['c] is the type of the result of the [%a] and [%t] printing - functions, and also the type of the argument transmitted to the - first argument of [kprintf]-style functions or to the - [kscanf]-style functions. - - - ['d] is the type of parameters for the [scanf]-style functions. - - - ['e] is the type of the receiver function for the [scanf]-style functions. - - - ['f] is the final result type of a formatted input/output function - invocation: for the [printf]-style functions, it is typically [unit]; - for the [scanf]-style functions, it is typically the result type of the - receiver function. -*) - -type ('a, 'b, 'c, 'd, 'e, 'f) format6 = - ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 - -type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 - -type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 - -val string_of_format : ('a, 'b, 'c, 'd, 'e, 'f) format6 -> string -(** Converts a format string into a string. *) - -external format_of_string : - ('a, 'b, 'c, 'd, 'e, 'f) format6 -> - ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" -(** [format_of_string s] returns a format string read from the string - literal [s]. - Note: [format_of_string] can not convert a string argument that is not a - literal. If you need this functionality, use the more general - {!Scanf.format_from_string} function. -*) - -val ( ^^ ) : - ('a, 'b, 'c, 'd, 'e, 'f) format6 -> - ('f, 'b, 'c, 'e, 'g, 'h) format6 -> - ('a, 'b, 'c, 'd, 'g, 'h) format6 -(** [f1 ^^ f2] catenates format strings [f1] and [f2]. The result is a - format string that behaves as the concatenation of format strings [f1] and - [f2]: in case of formatted output, it accepts arguments from [f1], then - arguments from [f2]; in case of formatted input, it returns results from - [f1], then results from [f2]. - Right-associative operator at precedence level 5/11. *) - - -(** {1 Program termination} *) - -val exit : int -> 'a -(** Terminate the process, returning the given status code - to the operating system: usually 0 to indicate no errors, - and a small positive integer to indicate failure. - All open output channels are flushed with [flush_all]. - An implicit [exit 0] is performed each time a program - terminates normally. An implicit [exit 2] is performed if the program - terminates early because of an uncaught exception. *) - -val at_exit : (unit -> unit) -> unit -(** Register the given function to be called at program termination - time. The functions registered with [at_exit] will be called when - the program does any of the following: - - executes {!Pervasives.exit} - - terminates, either normally or because of an uncaught - exception - - executes the C function [caml_shutdown]. - The functions are called in 'last in, first out' order: the - function most recently added with [at_exit] is called first. *) - -(**/**) - -(* The following is for system use only. Do not call directly. *) - -val valid_float_lexem : string -> string - -val unsafe_really_input : in_channel -> bytes -> int -> int -> unit - -val do_at_exit : unit -> unit diff --git a/stdlib/queue.ml b/stdlib/queue.ml index ffda7a46..72c134b3 100644 --- a/stdlib/queue.ml +++ b/stdlib/queue.ml @@ -130,3 +130,20 @@ let transfer q1 q2 = last.next <- q1.first; q2.last <- q1.last; clear q1 + +(** {6 Iterators} *) + +let to_seq q = + let rec aux c () = match c with + | Nil -> Seq.Nil + | Cons { content=x; next; } -> Seq.Cons (x, aux next) + in + aux q.first + +let add_seq q i = Seq.iter (fun x -> push x q) i + +let of_seq g = + let q = create() in + add_seq q g; + q + diff --git a/stdlib/queue.mli b/stdlib/queue.mli index 46e48fd0..afff9209 100644 --- a/stdlib/queue.mli +++ b/stdlib/queue.mli @@ -80,3 +80,20 @@ val transfer : 'a t -> 'a t -> unit the queue [q2], then clears [q1]. It is equivalent to the sequence [iter (fun x -> add x q2) q1; clear q1], but runs in constant time. *) + +(** {6 Iterators} *) + +val to_seq : 'a t -> 'a Seq.t +(** Iterate on the queue, in front-to-back order. + The behavior is not defined if the queue is modified + during the iteration. + @since 4.07 *) + +val add_seq : 'a t -> 'a Seq.t -> unit +(** Add the elements from the generator to the end of the queue + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a t +(** Create an array from the generator + @since 4.07 *) + diff --git a/stdlib/remove_module_aliases.awk b/stdlib/remove_module_aliases.awk new file mode 100644 index 00000000..1551cb10 --- /dev/null +++ b/stdlib/remove_module_aliases.awk @@ -0,0 +1,21 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Jeremie Dimino, Jane Street Europe * +#* * +#* Copyright 2017 Jane Street Group LLC * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# This script remove the module aliases from stdlib.ml and stdlib.mli +# so that ocamldep doesn't register dependencies from stdlib to all +# other modules +BEGIN { in_aliases=0 } +NR == 1 { printf ("# 1 \"%s\"\n", FILENAME) } +/^\(\*MODULE_ALIASES\*\)\r?$/ { in_aliases=1 } +!in_aliases { print } diff --git a/stdlib/seq.ml b/stdlib/seq.ml new file mode 100644 index 00000000..ccdbfde4 --- /dev/null +++ b/stdlib/seq.ml @@ -0,0 +1,73 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Simon Cruanes *) +(* *) +(* Copyright 2017 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Module [Seq]: functional iterators *) + +type +'a node = + | Nil + | Cons of 'a * 'a t + +and 'a t = unit -> 'a node + +let empty () = Nil + +let return x () = Cons (x, empty) + +let rec map f seq () = match seq() with + | Nil -> Nil + | Cons (x, next) -> Cons (f x, map f next) + +let rec filter_map f seq () = match seq() with + | Nil -> Nil + | Cons (x, next) -> + match f x with + | None -> filter_map f next () + | Some y -> Cons (y, filter_map f next) + +let rec filter f seq () = match seq() with + | Nil -> Nil + | Cons (x, next) -> + if f x + then Cons (x, filter f next) + else filter f next () + +let rec flat_map f seq () = match seq () with + | Nil -> Nil + | Cons (x, next) -> + flat_map_app f (f x) next () + +(* this is [append seq (flat_map f tail)] *) +and flat_map_app f seq tail () = match seq () with + | Nil -> flat_map f tail () + | Cons (x, next) -> + Cons (x, flat_map_app f next tail) + +let fold_left f acc seq = + let rec aux f acc seq = match seq () with + | Nil -> acc + | Cons (x, next) -> + let acc = f acc x in + aux f acc next + in + aux f acc seq + +let iter f seq = + let rec aux seq = match seq () with + | Nil -> () + | Cons (x, next) -> + f x; + aux next + in + aux seq diff --git a/stdlib/seq.mli b/stdlib/seq.mli new file mode 100644 index 00000000..f33c19ac --- /dev/null +++ b/stdlib/seq.mli @@ -0,0 +1,77 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Simon Cruanes *) +(* *) +(* Copyright 2017 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Module [Seq]: functional iterators *) + +(** {1 Functional Iterators} *) + +(** The type ['a t] is a {b delayed list}, i.e. a list where some evaluation + is needed to access the next element. This makes it possible to build + infinite sequences, to build sequences as we traverse them, and to transform + them in a lazy fashion rather than upfront. +*) + +(** @since 4.07 *) + +type 'a t = unit -> 'a node +(** The type of delayed lists containing elements of type ['a]. + Note that the concrete list node ['a node] is delayed under a closure, + not a [lazy] block, which means it might be recomputed every time + we access it. *) + +and +'a node = + | Nil + | Cons of 'a * 'a t +(** A fully-evaluated list node, either empty or containing an element + and a delayed tail. *) + +val empty : 'a t +(** The empty sequence, containing no elements. *) + +val return : 'a -> 'a t +(** The singleton sequence containing only the given element. *) + +val map : ('a -> 'b) -> 'a t -> 'b t +(** [map f seq] returns a new sequence whose elements are the elements of + [seq], transformed by [f]. + This transformation is lazy, it only applies when the result is traversed. + + If [seq = [1;2;3]], then [map f seq = [f 1; f 2; f 3]]. *) + +val filter : ('a -> bool) -> 'a t -> 'a t +(** Remove from the sequence the elements that do not satisfy the + given predicate. + This transformation is lazy, it only applies when the result is traversed. *) + +val filter_map : ('a -> 'b option) -> 'a t -> 'b t +(** Apply the function to every element; if [f x = None] then [x] is dropped; + if [f x = Some y] then [y] is returned. + This transformation is lazy, it only applies when the result is traversed. *) + +val flat_map : ('a -> 'b t) -> 'a t -> 'b t +(** Map each element to a subsequence, then return each element of this + sub-sequence in turn. + This transformation is lazy, it only applies when the result is traversed. *) + +val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a +(** Traverse the sequence from left to right, combining each element with the + accumulator using the given function. + The traversal happens immediately and will not terminate on infinite sequences. + + Also see {!List.fold_left} *) + +val iter : ('a -> unit) -> 'a t -> unit +(** Iterate on the sequence, calling the (imperative) function on every element. + The traversal happens immediately and will not terminate on infinite sequences. *) diff --git a/stdlib/set.ml b/stdlib/set.ml index b3cbda47..2793de0f 100644 --- a/stdlib/set.ml +++ b/stdlib/set.ml @@ -60,6 +60,10 @@ module type S = val find_last: (elt -> bool) -> t -> elt val find_last_opt: (elt -> bool) -> t -> elt option val of_list: elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end module Make(Ord: OrderedType) = @@ -523,4 +527,27 @@ module Make(Ord: OrderedType) = | [x0; x1; x2; x3] -> add x3 (add x2 (add x1 (singleton x0))) | [x0; x1; x2; x3; x4] -> add x4 (add x3 (add x2 (add x1 (singleton x0)))) | _ -> of_sorted_list (List.sort_uniq Ord.compare l) + + let add_seq i m = + Seq.fold_left (fun s x -> add x s) m i + + let of_seq i = add_seq i empty + + let rec seq_of_enum_ c () = match c with + | End -> Seq.Nil + | More (x, t, rest) -> Seq.Cons (x, seq_of_enum_ (cons_enum t rest)) + + let to_seq c = seq_of_enum_ (cons_enum c End) + + let to_seq_from low s = + let rec aux low s c = match s with + | Empty -> c + | Node {l; r; v; _} -> + begin match Ord.compare v low with + | 0 -> More (v, r, c) + | n when n<0 -> aux low r c + | _ -> aux low l (More (v, r, c)) + end + in + seq_of_enum_ (aux low s End) end diff --git a/stdlib/set.mli b/stdlib/set.mli index ef61e1a7..ba8343c9 100644 --- a/stdlib/set.mli +++ b/stdlib/set.mli @@ -258,6 +258,25 @@ module type S = This is usually more efficient than folding [add] over the list, except perhaps for lists with many duplicated elements. @since 4.02.0 *) + + (** {6 Iterators} *) + + val to_seq_from : elt -> t -> elt Seq.t + (** [to_seq_from x s] iterates on a subset of the elements of [s] + in ascending order, from [x] or above. + @since 4.07 *) + + val to_seq : t -> elt Seq.t + (** Iterate on the whole set, in ascending order + @since 4.07 *) + + val add_seq : elt Seq.t -> t -> t + (** Add the given elements to the set, in order. + @since 4.07 *) + + val of_seq : elt Seq.t -> t + (** Build a set from the given bindings + @since 4.07 *) end (** Output signature of the functor {!Set.Make}. *) diff --git a/stdlib/stack.ml b/stdlib/stack.ml index 21dad3e8..1b48c0e0 100644 --- a/stdlib/stack.ml +++ b/stdlib/stack.ml @@ -42,3 +42,15 @@ let length s = s.len let iter f s = List.iter f s.c let fold f acc s = List.fold_left f acc s.c + +(** {6 Iterators} *) + +let to_seq s = List.to_seq s.c + +let add_seq q i = Seq.iter (fun x -> push x q) i + +let of_seq g = + let s = create() in + add_seq s g; + s + diff --git a/stdlib/stack.mli b/stdlib/stack.mli index 4ce89953..9fa6ed07 100644 --- a/stdlib/stack.mli +++ b/stdlib/stack.mli @@ -61,3 +61,19 @@ val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b where [x1] is the top of the stack, [x2] the second element, and [xn] the bottom element. The stack is unchanged. @since 4.03 *) + +(** {6 Iterators} *) + +val to_seq : 'a t -> 'a Seq.t +(** Iterate on the stack, top to bottom. + It is safe to modify the stack during iteration. + @since 4.07 *) + +val add_seq : 'a t -> 'a Seq.t -> unit +(** Add the elements from the iterator on the top of the stack. + @since 4.07 *) + +val of_seq : 'a Seq.t -> 'a t +(** Create a stack from the iterator + @since 4.07 *) + diff --git a/stdlib/stdlib.ml b/stdlib/stdlib.ml new file mode 100644 index 00000000..05dfe9e8 --- /dev/null +++ b/stdlib/stdlib.ml @@ -0,0 +1,607 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +module Pervasives = struct +(* type 'a option = None | Some of 'a *) + +(* Exceptions *) + +external register_named_value : string -> 'a -> unit + = "caml_register_named_value" + +let () = + (* for asmrun/fail.c *) + register_named_value "Pervasives.array_bound_error" + (Invalid_argument "index out of bounds") + + +external raise : exn -> 'a = "%raise" +external raise_notrace : exn -> 'a = "%raise_notrace" + +let failwith s = raise(Failure s) +let invalid_arg s = raise(Invalid_argument s) + +exception Exit + +(* Composition operators *) + +external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" +external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" + +(* Debugging *) + +external __LOC__ : string = "%loc_LOC" +external __FILE__ : string = "%loc_FILE" +external __LINE__ : int = "%loc_LINE" +external __MODULE__ : string = "%loc_MODULE" +external __POS__ : string * int * int * int = "%loc_POS" + +external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" +external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" +external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" + +(* Comparisons *) + +external ( = ) : 'a -> 'a -> bool = "%equal" +external ( <> ) : 'a -> 'a -> bool = "%notequal" +external ( < ) : 'a -> 'a -> bool = "%lessthan" +external ( > ) : 'a -> 'a -> bool = "%greaterthan" +external ( <= ) : 'a -> 'a -> bool = "%lessequal" +external ( >= ) : 'a -> 'a -> bool = "%greaterequal" +external compare : 'a -> 'a -> int = "%compare" + +let min x y = if x <= y then x else y +let max x y = if x >= y then x else y + +external ( == ) : 'a -> 'a -> bool = "%eq" +external ( != ) : 'a -> 'a -> bool = "%noteq" + +(* Boolean operations *) + +external not : bool -> bool = "%boolnot" +external ( & ) : bool -> bool -> bool = "%sequand" +external ( && ) : bool -> bool -> bool = "%sequand" +external ( or ) : bool -> bool -> bool = "%sequor" +external ( || ) : bool -> bool -> bool = "%sequor" + +(* Integer operations *) + +external ( ~- ) : int -> int = "%negint" +external ( ~+ ) : int -> int = "%identity" +external succ : int -> int = "%succint" +external pred : int -> int = "%predint" +external ( + ) : int -> int -> int = "%addint" +external ( - ) : int -> int -> int = "%subint" +external ( * ) : int -> int -> int = "%mulint" +external ( / ) : int -> int -> int = "%divint" +external ( mod ) : int -> int -> int = "%modint" + +let abs x = if x >= 0 then x else -x + +external ( land ) : int -> int -> int = "%andint" +external ( lor ) : int -> int -> int = "%orint" +external ( lxor ) : int -> int -> int = "%xorint" + +let lnot x = x lxor (-1) + +external ( lsl ) : int -> int -> int = "%lslint" +external ( lsr ) : int -> int -> int = "%lsrint" +external ( asr ) : int -> int -> int = "%asrint" + +let max_int = (-1) lsr 1 +let min_int = max_int + 1 + +(* Floating-point operations *) + +external ( ~-. ) : float -> float = "%negfloat" +external ( ~+. ) : float -> float = "%identity" +external ( +. ) : float -> float -> float = "%addfloat" +external ( -. ) : float -> float -> float = "%subfloat" +external ( *. ) : float -> float -> float = "%mulfloat" +external ( /. ) : float -> float -> float = "%divfloat" +external ( ** ) : float -> float -> float = "caml_power_float" "pow" + [@@unboxed] [@@noalloc] +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +external expm1 : float -> float = "caml_expm1_float" "caml_expm1" + [@@unboxed] [@@noalloc] +external acos : float -> float = "caml_acos_float" "acos" + [@@unboxed] [@@noalloc] +external asin : float -> float = "caml_asin_float" "asin" + [@@unboxed] [@@noalloc] +external atan : float -> float = "caml_atan_float" "atan" + [@@unboxed] [@@noalloc] +external atan2 : float -> float -> float = "caml_atan2_float" "atan2" + [@@unboxed] [@@noalloc] +external hypot : float -> float -> float + = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] +external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] +external cosh : float -> float = "caml_cosh_float" "cosh" + [@@unboxed] [@@noalloc] +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +external log10 : float -> float = "caml_log10_float" "log10" + [@@unboxed] [@@noalloc] +external log1p : float -> float = "caml_log1p_float" "caml_log1p" + [@@unboxed] [@@noalloc] +external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] +external sinh : float -> float = "caml_sinh_float" "sinh" + [@@unboxed] [@@noalloc] +external sqrt : float -> float = "caml_sqrt_float" "sqrt" + [@@unboxed] [@@noalloc] +external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] +external tanh : float -> float = "caml_tanh_float" "tanh" + [@@unboxed] [@@noalloc] +external ceil : float -> float = "caml_ceil_float" "ceil" + [@@unboxed] [@@noalloc] +external floor : float -> float = "caml_floor_float" "floor" + [@@unboxed] [@@noalloc] +external abs_float : float -> float = "%absfloat" +external copysign : float -> float -> float + = "caml_copysign_float" "caml_copysign" + [@@unboxed] [@@noalloc] +external mod_float : float -> float -> float = "caml_fmod_float" "fmod" + [@@unboxed] [@@noalloc] +external frexp : float -> float * int = "caml_frexp_float" +external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = + "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] +external modf : float -> float * float = "caml_modf_float" +external float : int -> float = "%floatofint" +external float_of_int : int -> float = "%floatofint" +external truncate : float -> int = "%intoffloat" +external int_of_float : float -> int = "%intoffloat" +external float_of_bits : int64 -> float + = "caml_int64_float_of_bits" "caml_int64_float_of_bits_unboxed" + [@@unboxed] [@@noalloc] +let infinity = + float_of_bits 0x7F_F0_00_00_00_00_00_00L +let neg_infinity = + float_of_bits 0xFF_F0_00_00_00_00_00_00L +let nan = + float_of_bits 0x7F_F0_00_00_00_00_00_01L +let max_float = + float_of_bits 0x7F_EF_FF_FF_FF_FF_FF_FFL +let min_float = + float_of_bits 0x00_10_00_00_00_00_00_00L +let epsilon_float = + float_of_bits 0x3C_B0_00_00_00_00_00_00L + +type fpclass = + FP_normal + | FP_subnormal + | FP_zero + | FP_infinite + | FP_nan +external classify_float : (float [@unboxed]) -> fpclass = + "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] + +(* String and byte sequence operations -- more in modules String and Bytes *) + +external string_length : string -> int = "%string_length" +external bytes_length : bytes -> int = "%bytes_length" +external bytes_create : int -> bytes = "caml_create_bytes" +external string_blit : string -> int -> bytes -> int -> int -> unit + = "caml_blit_string" [@@noalloc] +external bytes_blit : bytes -> int -> bytes -> int -> int -> unit + = "caml_blit_bytes" [@@noalloc] +external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string" + +let ( ^ ) s1 s2 = + let l1 = string_length s1 and l2 = string_length s2 in + let s = bytes_create (l1 + l2) in + string_blit s1 0 s 0 l1; + string_blit s2 0 s l1 l2; + bytes_unsafe_to_string s + +(* Character operations -- more in module Char *) + +external int_of_char : char -> int = "%identity" +external unsafe_char_of_int : int -> char = "%identity" +let char_of_int n = + if n < 0 || n > 255 then invalid_arg "char_of_int" else unsafe_char_of_int n + +(* Unit operations *) + +external ignore : 'a -> unit = "%ignore" + +(* Pair operations *) + +external fst : 'a * 'b -> 'a = "%field0" +external snd : 'a * 'b -> 'b = "%field1" + +(* References *) + +type 'a ref = { mutable contents : 'a } +external ref : 'a -> 'a ref = "%makemutable" +external ( ! ) : 'a ref -> 'a = "%field0" +external ( := ) : 'a ref -> 'a -> unit = "%setfield0" +external incr : int ref -> unit = "%incr" +external decr : int ref -> unit = "%decr" + +(* Result type *) + +type ('a,'b) result = Ok of 'a | Error of 'b + +(* String conversion functions *) + +external format_int : string -> int -> string = "caml_format_int" +external format_float : string -> float -> string = "caml_format_float" + +let string_of_bool b = + if b then "true" else "false" +let bool_of_string = function + | "true" -> true + | "false" -> false + | _ -> invalid_arg "bool_of_string" + +let bool_of_string_opt = function + | "true" -> Some true + | "false" -> Some false + | _ -> None + +let string_of_int n = + format_int "%d" n + +external int_of_string : string -> int = "caml_int_of_string" + +let int_of_string_opt s = + (* TODO: provide this directly as a non-raising primitive. *) + try Some (int_of_string s) + with Failure _ -> None + +external string_get : string -> int -> char = "%string_safe_get" + +let valid_float_lexem s = + let l = string_length s in + let rec loop i = + if i >= l then s ^ "." else + match string_get s i with + | '0' .. '9' | '-' -> loop (i + 1) + | _ -> s + in + loop 0 + +let string_of_float f = valid_float_lexem (format_float "%.12g" f) + +external float_of_string : string -> float = "caml_float_of_string" + +let float_of_string_opt s = + (* TODO: provide this directly as a non-raising primitive. *) + try Some (float_of_string s) + with Failure _ -> None + +(* List operations -- more in module List *) + +let rec ( @ ) l1 l2 = + match l1 with + [] -> l2 + | hd :: tl -> hd :: (tl @ l2) + +(* I/O operations *) + +type in_channel +type out_channel + +external open_descriptor_out : int -> out_channel + = "caml_ml_open_descriptor_out" +external open_descriptor_in : int -> in_channel = "caml_ml_open_descriptor_in" + +let stdin = open_descriptor_in 0 +let stdout = open_descriptor_out 1 +let stderr = open_descriptor_out 2 + +(* General output functions *) + +type open_flag = + Open_rdonly | Open_wronly | Open_append + | Open_creat | Open_trunc | Open_excl + | Open_binary | Open_text | Open_nonblock + +external open_desc : string -> open_flag list -> int -> int = "caml_sys_open" + +external set_out_channel_name: out_channel -> string -> unit = + "caml_ml_set_channel_name" + +let open_out_gen mode perm name = + let c = open_descriptor_out(open_desc name mode perm) in + set_out_channel_name c name; + c + +let open_out name = + open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o666 name + +let open_out_bin name = + open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_binary] 0o666 name + +external flush : out_channel -> unit = "caml_ml_flush" + +external out_channels_list : unit -> out_channel list + = "caml_ml_out_channels_list" + +let flush_all () = + let rec iter = function + [] -> () + | a::l -> + begin try + flush a + with Sys_error _ -> + () (* ignore channels closed during a preceding flush. *) + end; + iter l + in iter (out_channels_list ()) + +external unsafe_output : out_channel -> bytes -> int -> int -> unit + = "caml_ml_output_bytes" +external unsafe_output_string : out_channel -> string -> int -> int -> unit + = "caml_ml_output" + +external output_char : out_channel -> char -> unit = "caml_ml_output_char" + +let output_bytes oc s = + unsafe_output oc s 0 (bytes_length s) + +let output_string oc s = + unsafe_output_string oc s 0 (string_length s) + +let output oc s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "output" + else unsafe_output oc s ofs len + +let output_substring oc s ofs len = + if ofs < 0 || len < 0 || ofs > string_length s - len + then invalid_arg "output_substring" + else unsafe_output_string oc s ofs len + +external output_byte : out_channel -> int -> unit = "caml_ml_output_char" +external output_binary_int : out_channel -> int -> unit = "caml_ml_output_int" + +external marshal_to_channel : out_channel -> 'a -> unit list -> unit + = "caml_output_value" +let output_value chan v = marshal_to_channel chan v [] + +external seek_out : out_channel -> int -> unit = "caml_ml_seek_out" +external pos_out : out_channel -> int = "caml_ml_pos_out" +external out_channel_length : out_channel -> int = "caml_ml_channel_size" +external close_out_channel : out_channel -> unit = "caml_ml_close_channel" +let close_out oc = flush oc; close_out_channel oc +let close_out_noerr oc = + (try flush oc with _ -> ()); + (try close_out_channel oc with _ -> ()) +external set_binary_mode_out : out_channel -> bool -> unit + = "caml_ml_set_binary_mode" + +(* General input functions *) + +external set_in_channel_name: in_channel -> string -> unit = + "caml_ml_set_channel_name" + +let open_in_gen mode perm name = + let c = open_descriptor_in(open_desc name mode perm) in + set_in_channel_name c name; + c + +let open_in name = + open_in_gen [Open_rdonly; Open_text] 0 name + +let open_in_bin name = + open_in_gen [Open_rdonly; Open_binary] 0 name + +external input_char : in_channel -> char = "caml_ml_input_char" + +external unsafe_input : in_channel -> bytes -> int -> int -> int + = "caml_ml_input" + +let input ic s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "input" + else unsafe_input ic s ofs len + +let rec unsafe_really_input ic s ofs len = + if len <= 0 then () else begin + let r = unsafe_input ic s ofs len in + if r = 0 + then raise End_of_file + else unsafe_really_input ic s (ofs + r) (len - r) + end + +let really_input ic s ofs len = + if ofs < 0 || len < 0 || ofs > bytes_length s - len + then invalid_arg "really_input" + else unsafe_really_input ic s ofs len + +let really_input_string ic len = + let s = bytes_create len in + really_input ic s 0 len; + bytes_unsafe_to_string s + +external input_scan_line : in_channel -> int = "caml_ml_input_scan_line" + +let input_line chan = + let rec build_result buf pos = function + [] -> buf + | hd :: tl -> + let len = bytes_length hd in + bytes_blit hd 0 buf (pos - len) len; + build_result buf (pos - len) tl in + let rec scan accu len = + let n = input_scan_line chan in + if n = 0 then begin (* n = 0: we are at EOF *) + match accu with + [] -> raise End_of_file + | _ -> build_result (bytes_create len) len accu + end else if n > 0 then begin (* n > 0: newline found in buffer *) + let res = bytes_create (n - 1) in + ignore (unsafe_input chan res 0 (n - 1)); + ignore (input_char chan); (* skip the newline *) + match accu with + [] -> res + | _ -> let len = len + n - 1 in + build_result (bytes_create len) len (res :: accu) + end else begin (* n < 0: newline not found *) + let beg = bytes_create (-n) in + ignore(unsafe_input chan beg 0 (-n)); + scan (beg :: accu) (len - n) + end + in bytes_unsafe_to_string (scan [] 0) + +external input_byte : in_channel -> int = "caml_ml_input_char" +external input_binary_int : in_channel -> int = "caml_ml_input_int" +external input_value : in_channel -> 'a = "caml_input_value" +external seek_in : in_channel -> int -> unit = "caml_ml_seek_in" +external pos_in : in_channel -> int = "caml_ml_pos_in" +external in_channel_length : in_channel -> int = "caml_ml_channel_size" +external close_in : in_channel -> unit = "caml_ml_close_channel" +let close_in_noerr ic = (try close_in ic with _ -> ()) +external set_binary_mode_in : in_channel -> bool -> unit + = "caml_ml_set_binary_mode" + +(* Output functions on standard output *) + +let print_char c = output_char stdout c +let print_string s = output_string stdout s +let print_bytes s = output_bytes stdout s +let print_int i = output_string stdout (string_of_int i) +let print_float f = output_string stdout (string_of_float f) +let print_endline s = + output_string stdout s; output_char stdout '\n'; flush stdout +let print_newline () = output_char stdout '\n'; flush stdout + +(* Output functions on standard error *) + +let prerr_char c = output_char stderr c +let prerr_string s = output_string stderr s +let prerr_bytes s = output_bytes stderr s +let prerr_int i = output_string stderr (string_of_int i) +let prerr_float f = output_string stderr (string_of_float f) +let prerr_endline s = + output_string stderr s; output_char stderr '\n'; flush stderr +let prerr_newline () = output_char stderr '\n'; flush stderr + +(* Input functions on standard input *) + +let read_line () = flush stdout; input_line stdin +let read_int () = int_of_string(read_line()) +let read_int_opt () = int_of_string_opt(read_line()) +let read_float () = float_of_string(read_line()) +let read_float_opt () = float_of_string_opt(read_line()) + +(* Operations on large files *) + +module LargeFile = + struct + external seek_out : out_channel -> int64 -> unit = "caml_ml_seek_out_64" + external pos_out : out_channel -> int64 = "caml_ml_pos_out_64" + external out_channel_length : out_channel -> int64 + = "caml_ml_channel_size_64" + external seek_in : in_channel -> int64 -> unit = "caml_ml_seek_in_64" + external pos_in : in_channel -> int64 = "caml_ml_pos_in_64" + external in_channel_length : in_channel -> int64 = "caml_ml_channel_size_64" + end + +(* Formats *) + +type ('a, 'b, 'c, 'd, 'e, 'f) format6 + = ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 + = Format of ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.fmt + * string + +type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 + +type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 + +let string_of_format (Format (_fmt, str)) = str + +external format_of_string : + ('a, 'b, 'c, 'd, 'e, 'f) format6 -> + ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" + +let ( ^^ ) (Format (fmt1, str1)) (Format (fmt2, str2)) = + Format (CamlinternalFormatBasics.concat_fmt fmt1 fmt2, + str1 ^ "%," ^ str2) + +(* Miscellaneous *) + +external sys_exit : int -> 'a = "caml_sys_exit" + +let exit_function = ref flush_all + +let at_exit f = + let g = !exit_function in + (* MPR#7253, MPR#7796: make sure "f" is executed only once *) + let f_already_ran = ref false in + exit_function := + (fun () -> + if not !f_already_ran then begin f_already_ran := true; f() end; + g()) + +let do_at_exit () = (!exit_function) () + +let exit retcode = + do_at_exit (); + sys_exit retcode + +let _ = register_named_value "Pervasives.do_at_exit" do_at_exit +end + +include Pervasives + +(*MODULE_ALIASES*) +module Arg = Arg +module Array = Array +module ArrayLabels = ArrayLabels +module Bigarray = Bigarray +module Buffer = Buffer +module Bytes = Bytes +module BytesLabels = BytesLabels +module Callback = Callback +module Char = Char +module Complex = Complex +module Digest = Digest +module Ephemeron = Ephemeron +module Filename = Filename +module Float = Float +module Format = Format +module Gc = Gc +module Genlex = Genlex +module Hashtbl = Hashtbl +module Int32 = Int32 +module Int64 = Int64 +module Lazy = Lazy +module Lexing = Lexing +module List = List +module ListLabels = ListLabels +module Map = Map +module Marshal = Marshal +module MoreLabels = MoreLabels +module Nativeint = Nativeint +module Obj = Obj +module Oo = Oo +module Parsing = Parsing +module Printexc = Printexc +module Printf = Printf +module Queue = Queue +module Random = Random +module Scanf = Scanf +module Seq = Seq +module Set = Set +module Sort = Sort +module Spacetime = Spacetime +module Stack = Stack +module StdLabels = StdLabels +module Stream = Stream +module String = String +module StringLabels = StringLabels +module Sys = Sys +module Uchar = Uchar +module Weak = Weak diff --git a/stdlib/stdlib.mli b/stdlib/stdlib.mli new file mode 100644 index 00000000..99eca4b8 --- /dev/null +++ b/stdlib/stdlib.mli @@ -0,0 +1,1278 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(** The OCaml Standard library. + + This module is automatically opened at the beginning of each + compilation. All components of this module can therefore be + referred by their short name, without prefixing them by [Stdlib]. +*) + +module Pervasives : sig +(** Pervasive operations. + + This module provides the basic operations over the built-in types + (numbers, booleans, byte sequences, strings, exceptions, references, + lists, arrays, input-output channels, ...). + + This module is included in the toplevel [Stdlib] module. +*) + + +(** {1 Exceptions} *) + +external raise : exn -> 'a = "%raise" +(** Raise the given exception value *) + +external raise_notrace : exn -> 'a = "%raise_notrace" +(** A faster version [raise] which does not record the backtrace. + @since 4.02.0 +*) + +val invalid_arg : string -> 'a +(** Raise exception [Invalid_argument] with the given string. *) + +val failwith : string -> 'a +(** Raise exception [Failure] with the given string. *) + +exception Exit +(** The [Exit] exception is not raised by any library function. It is + provided for use in your programs. *) + + +(** {1 Comparisons} *) + +external ( = ) : 'a -> 'a -> bool = "%equal" +(** [e1 = e2] tests for structural equality of [e1] and [e2]. + Mutable structures (e.g. references and arrays) are equal + if and only if their current contents are structurally equal, + even if the two mutable objects are not the same physical object. + Equality between functional values raises [Invalid_argument]. + Equality between cyclic data structures may not terminate. + Left-associative operator at precedence level 4/11. *) + +external ( <> ) : 'a -> 'a -> bool = "%notequal" +(** Negation of {!Pervasives.( = )}. + Left-associative operator at precedence level 4/11. *) + +external ( < ) : 'a -> 'a -> bool = "%lessthan" +(** See {!Pervasives.( >= )}. + Left-associative operator at precedence level 4/11. *) + +external ( > ) : 'a -> 'a -> bool = "%greaterthan" +(** See {!Pervasives.( >= )}. + Left-associative operator at precedence level 4/11. *) + +external ( <= ) : 'a -> 'a -> bool = "%lessequal" +(** See {!Pervasives.( >= )}. + Left-associative operator at precedence level 4/11. *) + +external ( >= ) : 'a -> 'a -> bool = "%greaterequal" +(** Structural ordering functions. These functions coincide with + the usual orderings over integers, characters, strings, byte sequences + and floating-point numbers, and extend them to a + total ordering over all types. + The ordering is compatible with [( = )]. As in the case + of [( = )], mutable structures are compared by contents. + Comparison between functional values raises [Invalid_argument]. + Comparison between cyclic structures may not terminate. + Left-associative operator at precedence level 4/11. *) + +external compare : 'a -> 'a -> int = "%compare" +(** [compare x y] returns [0] if [x] is equal to [y], + a negative integer if [x] is less than [y], and a positive integer + if [x] is greater than [y]. The ordering implemented by [compare] + is compatible with the comparison predicates [=], [<] and [>] + defined above, with one difference on the treatment of the float value + {!Pervasives.nan}. Namely, the comparison predicates treat [nan] + as different from any other float value, including itself; + while [compare] treats [nan] as equal to itself and less than any + other float value. This treatment of [nan] ensures that [compare] + defines a total ordering relation. + + [compare] applied to functional values may raise [Invalid_argument]. + [compare] applied to cyclic structures may not terminate. + + The [compare] function can be used as the comparison function + required by the {!Set.Make} and {!Map.Make} functors, as well as + the {!List.sort} and {!Array.sort} functions. *) + +val min : 'a -> 'a -> 'a +(** Return the smaller of the two arguments. + The result is unspecified if one of the arguments contains + the float value [nan]. *) + +val max : 'a -> 'a -> 'a +(** Return the greater of the two arguments. + The result is unspecified if one of the arguments contains + the float value [nan]. *) + +external ( == ) : 'a -> 'a -> bool = "%eq" +(** [e1 == e2] tests for physical equality of [e1] and [e2]. + On mutable types such as references, arrays, byte sequences, records with + mutable fields and objects with mutable instance variables, + [e1 == e2] is true if and only if physical modification of [e1] + also affects [e2]. + On non-mutable types, the behavior of [( == )] is + implementation-dependent; however, it is guaranteed that + [e1 == e2] implies [compare e1 e2 = 0]. + Left-associative operator at precedence level 4/11. *) + +external ( != ) : 'a -> 'a -> bool = "%noteq" +(** Negation of {!Pervasives.( == )}. + Left-associative operator at precedence level 4/11. *) + + +(** {1 Boolean operations} *) + +external not : bool -> bool = "%boolnot" +(** The boolean negation. *) + +external ( && ) : bool -> bool -> bool = "%sequand" +(** The boolean 'and'. Evaluation is sequential, left-to-right: + in [e1 && e2], [e1] is evaluated first, and if it returns [false], + [e2] is not evaluated at all. + Right-associative operator at precedence level 3/11. *) + +external ( & ) : bool -> bool -> bool = "%sequand" + [@@ocaml.deprecated "Use (&&) instead."] +(** @deprecated {!Pervasives.( && )} should be used instead. + Right-associative operator at precedence level 3/11. *) + +external ( || ) : bool -> bool -> bool = "%sequor" +(** The boolean 'or'. Evaluation is sequential, left-to-right: + in [e1 || e2], [e1] is evaluated first, and if it returns [true], + [e2] is not evaluated at all. + Right-associative operator at precedence level 2/11. +*) + +external ( or ) : bool -> bool -> bool = "%sequor" + [@@ocaml.deprecated "Use (||) instead."] +(** @deprecated {!Pervasives.( || )} should be used instead. + Right-associative operator at precedence level 2/11. *) + +(** {1 Debugging} *) + +external __LOC__ : string = "%loc_LOC" +(** [__LOC__] returns the location at which this expression appears in + the file currently being parsed by the compiler, with the standard + error format of OCaml: "File %S, line %d, characters %d-%d". + @since 4.02.0 +*) + +external __FILE__ : string = "%loc_FILE" +(** [__FILE__] returns the name of the file currently being + parsed by the compiler. + @since 4.02.0 +*) + +external __LINE__ : int = "%loc_LINE" +(** [__LINE__] returns the line number at which this expression + appears in the file currently being parsed by the compiler. + @since 4.02.0 +*) + +external __MODULE__ : string = "%loc_MODULE" +(** [__MODULE__] returns the module name of the file being + parsed by the compiler. + @since 4.02.0 +*) + +external __POS__ : string * int * int * int = "%loc_POS" +(** [__POS__] returns a tuple [(file,lnum,cnum,enum)], corresponding + to the location at which this expression appears in the file + currently being parsed by the compiler. [file] is the current + filename, [lnum] the line number, [cnum] the character position in + the line and [enum] the last character position in the line. + @since 4.02.0 + *) + +external __LOC_OF__ : 'a -> string * 'a = "%loc_LOC" +(** [__LOC_OF__ expr] returns a pair [(loc, expr)] where [loc] is the + location of [expr] in the file currently being parsed by the + compiler, with the standard error format of OCaml: "File %S, line + %d, characters %d-%d". + @since 4.02.0 +*) + +external __LINE_OF__ : 'a -> int * 'a = "%loc_LINE" +(** [__LINE_OF__ expr] returns a pair [(line, expr)], where [line] is the + line number at which the expression [expr] appears in the file + currently being parsed by the compiler. + @since 4.02.0 + *) + +external __POS_OF__ : 'a -> (string * int * int * int) * 'a = "%loc_POS" +(** [__POS_OF__ expr] returns a pair [(loc,expr)], where [loc] is a + tuple [(file,lnum,cnum,enum)] corresponding to the location at + which the expression [expr] appears in the file currently being + parsed by the compiler. [file] is the current filename, [lnum] the + line number, [cnum] the character position in the line and [enum] + the last character position in the line. + @since 4.02.0 + *) + +(** {1 Composition operators} *) + +external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" +(** Reverse-application operator: [x |> f |> g] is exactly equivalent + to [g (f (x))]. + Left-associative operator at precedence level 4/11. + @since 4.01 + *) + +external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" +(** Application operator: [g @@ f @@ x] is exactly equivalent to + [g (f (x))]. + Right-associative operator at precedence level 5/11. + @since 4.01 +*) + +(** {1 Integer arithmetic} *) + +(** Integers are [Sys.int_size] bits wide. + All operations are taken modulo 2{^[Sys.int_size]}. + They do not fail on overflow. *) + +external ( ~- ) : int -> int = "%negint" +(** Unary negation. You can also write [- e] instead of [~- e]. + Unary operator at precedence level 9/11 for [- e] + and 11/11 for [~- e]. *) + +external ( ~+ ) : int -> int = "%identity" +(** Unary addition. You can also write [+ e] instead of [~+ e]. + Unary operator at precedence level 9/11 for [+ e] + and 11/11 for [~+ e]. + @since 3.12.0 +*) + +external succ : int -> int = "%succint" +(** [succ x] is [x + 1]. *) + +external pred : int -> int = "%predint" +(** [pred x] is [x - 1]. *) + +external ( + ) : int -> int -> int = "%addint" +(** Integer addition. + Left-associative operator at precedence level 6/11. *) + +external ( - ) : int -> int -> int = "%subint" +(** Integer subtraction. + Left-associative operator at precedence level 6/11. *) + +external ( * ) : int -> int -> int = "%mulint" +(** Integer multiplication. + Left-associative operator at precedence level 7/11. *) + +external ( / ) : int -> int -> int = "%divint" +(** Integer division. + Raise [Division_by_zero] if the second argument is 0. + Integer division rounds the real quotient of its arguments towards zero. + More precisely, if [x >= 0] and [y > 0], [x / y] is the greatest integer + less than or equal to the real quotient of [x] by [y]. Moreover, + [(- x) / y = x / (- y) = - (x / y)]. + Left-associative operator at precedence level 7/11. *) + +external ( mod ) : int -> int -> int = "%modint" +(** Integer remainder. If [y] is not zero, the result + of [x mod y] satisfies the following properties: + [x = (x / y) * y + x mod y] and + [abs(x mod y) <= abs(y) - 1]. + If [y = 0], [x mod y] raises [Division_by_zero]. + Note that [x mod y] is negative only if [x < 0]. + Raise [Division_by_zero] if [y] is zero. + Left-associative operator at precedence level 7/11. *) + +val abs : int -> int +(** Return the absolute value of the argument. Note that this may be + negative if the argument is [min_int]. *) + +val max_int : int +(** The greatest representable integer. *) + +val min_int : int +(** The smallest representable integer. *) + + +(** {2 Bitwise operations} *) + +external ( land ) : int -> int -> int = "%andint" +(** Bitwise logical and. + Left-associative operator at precedence level 7/11. *) + +external ( lor ) : int -> int -> int = "%orint" +(** Bitwise logical or. + Left-associative operator at precedence level 7/11. *) + +external ( lxor ) : int -> int -> int = "%xorint" +(** Bitwise logical exclusive or. + Left-associative operator at precedence level 7/11. *) + +val lnot : int -> int +(** Bitwise logical negation. *) + +external ( lsl ) : int -> int -> int = "%lslint" +(** [n lsl m] shifts [n] to the left by [m] bits. + The result is unspecified if [m < 0] or [m > Sys.int_size]. + Right-associative operator at precedence level 8/11. *) + +external ( lsr ) : int -> int -> int = "%lsrint" +(** [n lsr m] shifts [n] to the right by [m] bits. + This is a logical shift: zeroes are inserted regardless of + the sign of [n]. + The result is unspecified if [m < 0] or [m > Sys.int_size]. + Right-associative operator at precedence level 8/11. *) + +external ( asr ) : int -> int -> int = "%asrint" +(** [n asr m] shifts [n] to the right by [m] bits. + This is an arithmetic shift: the sign bit of [n] is replicated. + The result is unspecified if [m < 0] or [m > Sys.int_size]. + Right-associative operator at precedence level 8/11. *) + + +(** {1 Floating-point arithmetic} + + OCaml's floating-point numbers follow the + IEEE 754 standard, using double precision (64 bits) numbers. + Floating-point operations never raise an exception on overflow, + underflow, division by zero, etc. Instead, special IEEE numbers + are returned as appropriate, such as [infinity] for [1.0 /. 0.0], + [neg_infinity] for [-1.0 /. 0.0], and [nan] ('not a number') + for [0.0 /. 0.0]. These special numbers then propagate through + floating-point computations as expected: for instance, + [1.0 /. infinity] is [0.0], and any arithmetic operation with [nan] + as argument returns [nan] as result. +*) + +external ( ~-. ) : float -> float = "%negfloat" +(** Unary negation. You can also write [-. e] instead of [~-. e]. + Unary operator at precedence level 9/11 for [-. e] + and 11/11 for [~-. e]. *) + +external ( ~+. ) : float -> float = "%identity" +(** Unary addition. You can also write [+. e] instead of [~+. e]. + Unary operator at precedence level 9/11 for [+. e] + and 11/11 for [~+. e]. + @since 3.12.0 +*) + +external ( +. ) : float -> float -> float = "%addfloat" +(** Floating-point addition. + Left-associative operator at precedence level 6/11. *) + +external ( -. ) : float -> float -> float = "%subfloat" +(** Floating-point subtraction. + Left-associative operator at precedence level 6/11. *) + +external ( *. ) : float -> float -> float = "%mulfloat" +(** Floating-point multiplication. + Left-associative operator at precedence level 7/11. *) + +external ( /. ) : float -> float -> float = "%divfloat" +(** Floating-point division. + Left-associative operator at precedence level 7/11. *) + +external ( ** ) : float -> float -> float = "caml_power_float" "pow" + [@@unboxed] [@@noalloc] +(** Exponentiation. + Right-associative operator at precedence level 8/11. *) + +external sqrt : float -> float = "caml_sqrt_float" "sqrt" + [@@unboxed] [@@noalloc] +(** Square root. *) + +external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] +(** Exponential. *) + +external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] +(** Natural logarithm. *) + +external log10 : float -> float = "caml_log10_float" "log10" + [@@unboxed] [@@noalloc] +(** Base 10 logarithm. *) + +external expm1 : float -> float = "caml_expm1_float" "caml_expm1" + [@@unboxed] [@@noalloc] +(** [expm1 x] computes [exp x -. 1.0], giving numerically-accurate results + even if [x] is close to [0.0]. + @since 3.12.0 +*) + +external log1p : float -> float = "caml_log1p_float" "caml_log1p" + [@@unboxed] [@@noalloc] +(** [log1p x] computes [log(1.0 +. x)] (natural logarithm), + giving numerically-accurate results even if [x] is close to [0.0]. + @since 3.12.0 +*) + +external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] +(** Cosine. Argument is in radians. *) + +external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] +(** Sine. Argument is in radians. *) + +external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] +(** Tangent. Argument is in radians. *) + +external acos : float -> float = "caml_acos_float" "acos" + [@@unboxed] [@@noalloc] +(** Arc cosine. The argument must fall within the range [[-1.0, 1.0]]. + Result is in radians and is between [0.0] and [pi]. *) + +external asin : float -> float = "caml_asin_float" "asin" + [@@unboxed] [@@noalloc] +(** Arc sine. The argument must fall within the range [[-1.0, 1.0]]. + Result is in radians and is between [-pi/2] and [pi/2]. *) + +external atan : float -> float = "caml_atan_float" "atan" + [@@unboxed] [@@noalloc] +(** Arc tangent. + Result is in radians and is between [-pi/2] and [pi/2]. *) + +external atan2 : float -> float -> float = "caml_atan2_float" "atan2" + [@@unboxed] [@@noalloc] +(** [atan2 y x] returns the arc tangent of [y /. x]. The signs of [x] + and [y] are used to determine the quadrant of the result. + Result is in radians and is between [-pi] and [pi]. *) + +external hypot : float -> float -> float = "caml_hypot_float" "caml_hypot" + [@@unboxed] [@@noalloc] +(** [hypot x y] returns [sqrt(x *. x + y *. y)], that is, the length + of the hypotenuse of a right-angled triangle with sides of length + [x] and [y], or, equivalently, the distance of the point [(x,y)] + to origin. If one of [x] or [y] is infinite, returns [infinity] + even if the other is [nan]. + @since 4.00.0 *) + +external cosh : float -> float = "caml_cosh_float" "cosh" + [@@unboxed] [@@noalloc] +(** Hyperbolic cosine. Argument is in radians. *) + +external sinh : float -> float = "caml_sinh_float" "sinh" + [@@unboxed] [@@noalloc] +(** Hyperbolic sine. Argument is in radians. *) + +external tanh : float -> float = "caml_tanh_float" "tanh" + [@@unboxed] [@@noalloc] +(** Hyperbolic tangent. Argument is in radians. *) + +external ceil : float -> float = "caml_ceil_float" "ceil" + [@@unboxed] [@@noalloc] +(** Round above to an integer value. + [ceil f] returns the least integer value greater than or equal to [f]. + The result is returned as a float. *) + +external floor : float -> float = "caml_floor_float" "floor" + [@@unboxed] [@@noalloc] +(** Round below to an integer value. + [floor f] returns the greatest integer value less than or + equal to [f]. + The result is returned as a float. *) + +external abs_float : float -> float = "%absfloat" +(** [abs_float f] returns the absolute value of [f]. *) + +external copysign : float -> float -> float + = "caml_copysign_float" "caml_copysign" + [@@unboxed] [@@noalloc] +(** [copysign x y] returns a float whose absolute value is that of [x] + and whose sign is that of [y]. If [x] is [nan], returns [nan]. + If [y] is [nan], returns either [x] or [-. x], but it is not + specified which. + @since 4.00.0 *) + +external mod_float : float -> float -> float = "caml_fmod_float" "fmod" + [@@unboxed] [@@noalloc] +(** [mod_float a b] returns the remainder of [a] with respect to + [b]. The returned value is [a -. n *. b], where [n] + is the quotient [a /. b] rounded towards zero to an integer. *) + +external frexp : float -> float * int = "caml_frexp_float" +(** [frexp f] returns the pair of the significant + and the exponent of [f]. When [f] is zero, the + significant [x] and the exponent [n] of [f] are equal to + zero. When [f] is non-zero, they are defined by + [f = x *. 2 ** n] and [0.5 <= x < 1.0]. *) + + +external ldexp : (float [@unboxed]) -> (int [@untagged]) -> (float [@unboxed]) = + "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] +(** [ldexp x n] returns [x *. 2 ** n]. *) + +external modf : float -> float * float = "caml_modf_float" +(** [modf f] returns the pair of the fractional and integral + part of [f]. *) + +external float : int -> float = "%floatofint" +(** Same as {!Pervasives.float_of_int}. *) + +external float_of_int : int -> float = "%floatofint" +(** Convert an integer to floating-point. *) + +external truncate : float -> int = "%intoffloat" +(** Same as {!Pervasives.int_of_float}. *) + +external int_of_float : float -> int = "%intoffloat" +(** Truncate the given floating-point number to an integer. + The result is unspecified if the argument is [nan] or falls outside the + range of representable integers. *) + +val infinity : float +(** Positive infinity. *) + +val neg_infinity : float +(** Negative infinity. *) + +val nan : float +(** A special floating-point value denoting the result of an + undefined operation such as [0.0 /. 0.0]. Stands for + 'not a number'. Any floating-point operation with [nan] as + argument returns [nan] as result. As for floating-point comparisons, + [=], [<], [<=], [>] and [>=] return [false] and [<>] returns [true] + if one or both of their arguments is [nan]. *) + +val max_float : float +(** The largest positive finite value of type [float]. *) + +val min_float : float +(** The smallest positive, non-zero, non-denormalized value of type [float]. *) + +val epsilon_float : float +(** The difference between [1.0] and the smallest exactly representable + floating-point number greater than [1.0]. *) + +type fpclass = + FP_normal (** Normal number, none of the below *) + | FP_subnormal (** Number very close to 0.0, has reduced precision *) + | FP_zero (** Number is 0.0 or -0.0 *) + | FP_infinite (** Number is positive or negative infinity *) + | FP_nan (** Not a number: result of an undefined operation *) +(** The five classes of floating-point numbers, as determined by + the {!Pervasives.classify_float} function. *) + +external classify_float : (float [@unboxed]) -> fpclass = + "caml_classify_float" "caml_classify_float_unboxed" [@@noalloc] +(** Return the class of the given floating-point number: + normal, subnormal, zero, infinite, or not a number. *) + + +(** {1 String operations} + + More string operations are provided in module {!String}. +*) + +val ( ^ ) : string -> string -> string +(** String concatenation. + Right-associative operator at precedence level 5/11. *) + + +(** {1 Character operations} + + More character operations are provided in module {!Char}. +*) + +external int_of_char : char -> int = "%identity" +(** Return the ASCII code of the argument. *) + +val char_of_int : int -> char +(** Return the character with the given ASCII code. + Raise [Invalid_argument "char_of_int"] if the argument is + outside the range 0--255. *) + + +(** {1 Unit operations} *) + +external ignore : 'a -> unit = "%ignore" +(** Discard the value of its argument and return [()]. + For instance, [ignore(f x)] discards the result of + the side-effecting function [f]. It is equivalent to + [f x; ()], except that the latter may generate a + compiler warning; writing [ignore(f x)] instead + avoids the warning. *) + + +(** {1 String conversion functions} *) + +val string_of_bool : bool -> string +(** Return the string representation of a boolean. As the returned values + may be shared, the user should not modify them directly. +*) + +val bool_of_string : string -> bool +(** Convert the given string to a boolean. + Raise [Invalid_argument "bool_of_string"] if the string is not + ["true"] or ["false"]. *) + +val bool_of_string_opt: string -> bool option +(** Convert the given string to a boolean. + Return [None] if the string is not + ["true"] or ["false"]. + @since 4.05 +*) + +val string_of_int : int -> string +(** Return the string representation of an integer, in decimal. *) + +external int_of_string : string -> int = "caml_int_of_string" +(** Convert the given string to an integer. + The string is read in decimal (by default, or if the string + begins with [0u]), in hexadecimal (if it begins with [0x] or + [0X]), in octal (if it begins with [0o] or [0O]), or in binary + (if it begins with [0b] or [0B]). + + The [0u] prefix reads the input as an unsigned integer in the range + [[0, 2*max_int+1]]. If the input exceeds {!max_int} + it is converted to the signed integer + [min_int + input - max_int - 1]. + + The [_] (underscore) character can appear anywhere in the string + and is ignored. + Raise [Failure "int_of_string"] if the given string is not + a valid representation of an integer, or if the integer represented + exceeds the range of integers representable in type [int]. *) + + +val int_of_string_opt: string -> int option +(** Same as [int_of_string], but returns [None] instead of raising. + @since 4.05 +*) + +val string_of_float : float -> string +(** Return the string representation of a floating-point number. *) + +external float_of_string : string -> float = "caml_float_of_string" +(** Convert the given string to a float. The string is read in decimal + (by default) or in hexadecimal (marked by [0x] or [0X]). + The format of decimal floating-point numbers is + [ [-] dd.ddd (e|E) [+|-] dd ], where [d] stands for a decimal digit. + The format of hexadecimal floating-point numbers is + [ [-] 0(x|X) hh.hhh (p|P) [+|-] dd ], where [h] stands for an + hexadecimal digit and [d] for a decimal digit. + In both cases, at least one of the integer and fractional parts must be + given; the exponent part is optional. + The [_] (underscore) character can appear anywhere in the string + and is ignored. + Depending on the execution platforms, other representations of + floating-point numbers can be accepted, but should not be relied upon. + Raise [Failure "float_of_string"] if the given string is not a valid + representation of a float. *) + +val float_of_string_opt: string -> float option +(** Same as [float_of_string], but returns [None] instead of raising. + @since 4.05 +*) + +(** {1 Pair operations} *) + +external fst : 'a * 'b -> 'a = "%field0" +(** Return the first component of a pair. *) + +external snd : 'a * 'b -> 'b = "%field1" +(** Return the second component of a pair. *) + + +(** {1 List operations} + + More list operations are provided in module {!List}. +*) + +val ( @ ) : 'a list -> 'a list -> 'a list +(** List concatenation. Not tail-recursive (length of the first argument). + Right-associative operator at precedence level 5/11. *) + + +(** {1 Input/output} + Note: all input/output functions can raise [Sys_error] when the system + calls they invoke fail. *) + +type in_channel +(** The type of input channel. *) + +type out_channel +(** The type of output channel. *) + +val stdin : in_channel +(** The standard input for the process. *) + +val stdout : out_channel +(** The standard output for the process. *) + +val stderr : out_channel +(** The standard error output for the process. *) + + +(** {2 Output functions on standard output} *) + +val print_char : char -> unit +(** Print a character on standard output. *) + +val print_string : string -> unit +(** Print a string on standard output. *) + +val print_bytes : bytes -> unit +(** Print a byte sequence on standard output. + @since 4.02.0 *) + +val print_int : int -> unit +(** Print an integer, in decimal, on standard output. *) + +val print_float : float -> unit +(** Print a floating-point number, in decimal, on standard output. *) + +val print_endline : string -> unit +(** Print a string, followed by a newline character, on + standard output and flush standard output. *) + +val print_newline : unit -> unit +(** Print a newline character on standard output, and flush + standard output. This can be used to simulate line + buffering of standard output. *) + + +(** {2 Output functions on standard error} *) + +val prerr_char : char -> unit +(** Print a character on standard error. *) + +val prerr_string : string -> unit +(** Print a string on standard error. *) + +val prerr_bytes : bytes -> unit +(** Print a byte sequence on standard error. + @since 4.02.0 *) + +val prerr_int : int -> unit +(** Print an integer, in decimal, on standard error. *) + +val prerr_float : float -> unit +(** Print a floating-point number, in decimal, on standard error. *) + +val prerr_endline : string -> unit +(** Print a string, followed by a newline character on standard + error and flush standard error. *) + +val prerr_newline : unit -> unit +(** Print a newline character on standard error, and flush + standard error. *) + + +(** {2 Input functions on standard input} *) + +val read_line : unit -> string +(** Flush standard output, then read characters from standard input + until a newline character is encountered. Return the string of + all characters read, without the newline character at the end. *) + +val read_int : unit -> int +(** Flush standard output, then read one line from standard input + and convert it to an integer. Raise [Failure "int_of_string"] + if the line read is not a valid representation of an integer. *) + +val read_int_opt: unit -> int option +(** Same as [read_int_opt], but returns [None] instead of raising. + @since 4.05 +*) + +val read_float : unit -> float +(** Flush standard output, then read one line from standard input + and convert it to a floating-point number. + The result is unspecified if the line read is not a valid + representation of a floating-point number. *) + +val read_float_opt: unit -> float option +(** Flush standard output, then read one line from standard input + and convert it to a floating-point number. + Returns [None] if the line read is not a valid + representation of a floating-point number. + @since 4.05.0 *) + + +(** {2 General output functions} *) + +type open_flag = + Open_rdonly (** open for reading. *) + | Open_wronly (** open for writing. *) + | Open_append (** open for appending: always write at end of file. *) + | Open_creat (** create the file if it does not exist. *) + | Open_trunc (** empty the file if it already exists. *) + | Open_excl (** fail if Open_creat and the file already exists. *) + | Open_binary (** open in binary mode (no conversion). *) + | Open_text (** open in text mode (may perform conversions). *) + | Open_nonblock (** open in non-blocking mode. *) +(** Opening modes for {!Pervasives.open_out_gen} and + {!Pervasives.open_in_gen}. *) + +val open_out : string -> out_channel +(** Open the named file for writing, and return a new output channel + on that file, positioned at the beginning of the file. The + file is truncated to zero length if it already exists. It + is created if it does not already exists. *) + +val open_out_bin : string -> out_channel +(** Same as {!Pervasives.open_out}, but the file is opened in binary mode, + so that no translation takes place during writes. On operating + systems that do not distinguish between text mode and binary + mode, this function behaves like {!Pervasives.open_out}. *) + +val open_out_gen : open_flag list -> int -> string -> out_channel +(** [open_out_gen mode perm filename] opens the named file for writing, + as described above. The extra argument [mode] + specifies the opening mode. The extra argument [perm] specifies + the file permissions, in case the file must be created. + {!Pervasives.open_out} and {!Pervasives.open_out_bin} are special + cases of this function. *) + +val flush : out_channel -> unit +(** Flush the buffer associated with the given output channel, + performing all pending writes on that channel. + Interactive programs must be careful about flushing standard + output and standard error at the right time. *) + +val flush_all : unit -> unit +(** Flush all open output channels; ignore errors. *) + +val output_char : out_channel -> char -> unit +(** Write the character on the given output channel. *) + +val output_string : out_channel -> string -> unit +(** Write the string on the given output channel. *) + +val output_bytes : out_channel -> bytes -> unit +(** Write the byte sequence on the given output channel. + @since 4.02.0 *) + +val output : out_channel -> bytes -> int -> int -> unit +(** [output oc buf pos len] writes [len] characters from byte sequence [buf], + starting at offset [pos], to the given output channel [oc]. + Raise [Invalid_argument "output"] if [pos] and [len] do not + designate a valid range of [buf]. *) + +val output_substring : out_channel -> string -> int -> int -> unit +(** Same as [output] but take a string as argument instead of + a byte sequence. + @since 4.02.0 *) + +val output_byte : out_channel -> int -> unit +(** Write one 8-bit integer (as the single character with that code) + on the given output channel. The given integer is taken modulo + 256. *) + +val output_binary_int : out_channel -> int -> unit +(** Write one integer in binary format (4 bytes, big-endian) + on the given output channel. + The given integer is taken modulo 2{^32}. + The only reliable way to read it back is through the + {!Pervasives.input_binary_int} function. The format is compatible across + all machines for a given version of OCaml. *) + +val output_value : out_channel -> 'a -> unit +(** Write the representation of a structured value of any type + to a channel. Circularities and sharing inside the value + are detected and preserved. The object can be read back, + by the function {!Pervasives.input_value}. See the description of module + {!Marshal} for more information. {!Pervasives.output_value} is equivalent + to {!Marshal.to_channel} with an empty list of flags. *) + +val seek_out : out_channel -> int -> unit +(** [seek_out chan pos] sets the current writing position to [pos] + for channel [chan]. This works only for regular files. On + files of other kinds (such as terminals, pipes and sockets), + the behavior is unspecified. *) + +val pos_out : out_channel -> int +(** Return the current writing position for the given channel. Does + not work on channels opened with the [Open_append] flag (returns + unspecified results). *) + +val out_channel_length : out_channel -> int +(** Return the size (number of characters) of the regular file + on which the given channel is opened. If the channel is opened + on a file that is not a regular file, the result is meaningless. *) + +val close_out : out_channel -> unit +(** Close the given channel, flushing all buffered write operations. + Output functions raise a [Sys_error] exception when they are + applied to a closed output channel, except [close_out] and [flush], + which do nothing when applied to an already closed channel. + Note that [close_out] may raise [Sys_error] if the operating + system signals an error when flushing or closing. *) + +val close_out_noerr : out_channel -> unit +(** Same as [close_out], but ignore all errors. *) + +val set_binary_mode_out : out_channel -> bool -> unit +(** [set_binary_mode_out oc true] sets the channel [oc] to binary + mode: no translations take place during output. + [set_binary_mode_out oc false] sets the channel [oc] to text + mode: depending on the operating system, some translations + may take place during output. For instance, under Windows, + end-of-lines will be translated from [\n] to [\r\n]. + This function has no effect under operating systems that + do not distinguish between text mode and binary mode. *) + + +(** {2 General input functions} *) + +val open_in : string -> in_channel +(** Open the named file for reading, and return a new input channel + on that file, positioned at the beginning of the file. *) + +val open_in_bin : string -> in_channel +(** Same as {!Pervasives.open_in}, but the file is opened in binary mode, + so that no translation takes place during reads. On operating + systems that do not distinguish between text mode and binary + mode, this function behaves like {!Pervasives.open_in}. *) + +val open_in_gen : open_flag list -> int -> string -> in_channel +(** [open_in_gen mode perm filename] opens the named file for reading, + as described above. The extra arguments + [mode] and [perm] specify the opening mode and file permissions. + {!Pervasives.open_in} and {!Pervasives.open_in_bin} are special + cases of this function. *) + +val input_char : in_channel -> char +(** Read one character from the given input channel. + Raise [End_of_file] if there are no more characters to read. *) + +val input_line : in_channel -> string +(** Read characters from the given input channel, until a + newline character is encountered. Return the string of + all characters read, without the newline character at the end. + Raise [End_of_file] if the end of the file is reached + at the beginning of line. *) + +val input : in_channel -> bytes -> int -> int -> int +(** [input ic buf pos len] reads up to [len] characters from + the given channel [ic], storing them in byte sequence [buf], starting at + character number [pos]. + It returns the actual number of characters read, between 0 and + [len] (inclusive). + A return value of 0 means that the end of file was reached. + A return value between 0 and [len] exclusive means that + not all requested [len] characters were read, either because + no more characters were available at that time, or because + the implementation found it convenient to do a partial read; + [input] must be called again to read the remaining characters, + if desired. (See also {!Pervasives.really_input} for reading + exactly [len] characters.) + Exception [Invalid_argument "input"] is raised if [pos] and [len] + do not designate a valid range of [buf]. *) + +val really_input : in_channel -> bytes -> int -> int -> unit +(** [really_input ic buf pos len] reads [len] characters from channel [ic], + storing them in byte sequence [buf], starting at character number [pos]. + Raise [End_of_file] if the end of file is reached before [len] + characters have been read. + Raise [Invalid_argument "really_input"] if + [pos] and [len] do not designate a valid range of [buf]. *) + +val really_input_string : in_channel -> int -> string +(** [really_input_string ic len] reads [len] characters from channel [ic] + and returns them in a new string. + Raise [End_of_file] if the end of file is reached before [len] + characters have been read. + @since 4.02.0 *) + +val input_byte : in_channel -> int +(** Same as {!Pervasives.input_char}, but return the 8-bit integer representing + the character. + Raise [End_of_file] if an end of file was reached. *) + +val input_binary_int : in_channel -> int +(** Read an integer encoded in binary format (4 bytes, big-endian) + from the given input channel. See {!Pervasives.output_binary_int}. + Raise [End_of_file] if an end of file was reached while reading the + integer. *) + +val input_value : in_channel -> 'a +(** Read the representation of a structured value, as produced + by {!Pervasives.output_value}, and return the corresponding value. + This function is identical to {!Marshal.from_channel}; + see the description of module {!Marshal} for more information, + in particular concerning the lack of type safety. *) + +val seek_in : in_channel -> int -> unit +(** [seek_in chan pos] sets the current reading position to [pos] + for channel [chan]. This works only for regular files. On + files of other kinds, the behavior is unspecified. *) + +val pos_in : in_channel -> int +(** Return the current reading position for the given channel. *) + +val in_channel_length : in_channel -> int +(** Return the size (number of characters) of the regular file + on which the given channel is opened. If the channel is opened + on a file that is not a regular file, the result is meaningless. + The returned size does not take into account the end-of-line + translations that can be performed when reading from a channel + opened in text mode. *) + +val close_in : in_channel -> unit +(** Close the given channel. Input functions raise a [Sys_error] + exception when they are applied to a closed input channel, + except [close_in], which does nothing when applied to an already + closed channel. *) + +val close_in_noerr : in_channel -> unit +(** Same as [close_in], but ignore all errors. *) + +val set_binary_mode_in : in_channel -> bool -> unit +(** [set_binary_mode_in ic true] sets the channel [ic] to binary + mode: no translations take place during input. + [set_binary_mode_out ic false] sets the channel [ic] to text + mode: depending on the operating system, some translations + may take place during input. For instance, under Windows, + end-of-lines will be translated from [\r\n] to [\n]. + This function has no effect under operating systems that + do not distinguish between text mode and binary mode. *) + + +(** {2 Operations on large files} *) + +module LargeFile : + sig + val seek_out : out_channel -> int64 -> unit + val pos_out : out_channel -> int64 + val out_channel_length : out_channel -> int64 + val seek_in : in_channel -> int64 -> unit + val pos_in : in_channel -> int64 + val in_channel_length : in_channel -> int64 + end +(** Operations on large files. + This sub-module provides 64-bit variants of the channel functions + that manipulate file positions and file sizes. By representing + positions and sizes by 64-bit integers (type [int64]) instead of + regular integers (type [int]), these alternate functions allow + operating on files whose sizes are greater than [max_int]. *) + + +(** {1 References} *) + +type 'a ref = { mutable contents : 'a } +(** The type of references (mutable indirection cells) containing + a value of type ['a]. *) + +external ref : 'a -> 'a ref = "%makemutable" +(** Return a fresh reference containing the given value. *) + +external ( ! ) : 'a ref -> 'a = "%field0" +(** [!r] returns the current contents of reference [r]. + Equivalent to [fun r -> r.contents]. + Unary operator at precedence level 11/11.*) + +external ( := ) : 'a ref -> 'a -> unit = "%setfield0" +(** [r := a] stores the value of [a] in reference [r]. + Equivalent to [fun r v -> r.contents <- v]. + Right-associative operator at precedence level 1/11. *) + +external incr : int ref -> unit = "%incr" +(** Increment the integer contained in the given reference. + Equivalent to [fun r -> r := succ !r]. *) + +external decr : int ref -> unit = "%decr" +(** Decrement the integer contained in the given reference. + Equivalent to [fun r -> r := pred !r]. *) + +(** {1 Result type} *) + +(** @since 4.03.0 *) +type ('a,'b) result = Ok of 'a | Error of 'b + +(** {1 Operations on format strings} *) + +(** Format strings are character strings with special lexical conventions + that defines the functionality of formatted input/output functions. Format + strings are used to read data with formatted input functions from module + {!Scanf} and to print data with formatted output functions from modules + {!Printf} and {!Format}. + + Format strings are made of three kinds of entities: + - {e conversions specifications}, introduced by the special character ['%'] + followed by one or more characters specifying what kind of argument to + read or print, + - {e formatting indications}, introduced by the special character ['@'] + followed by one or more characters specifying how to read or print the + argument, + - {e plain characters} that are regular characters with usual lexical + conventions. Plain characters specify string literals to be read in the + input or printed in the output. + + There is an additional lexical rule to escape the special characters ['%'] + and ['@'] in format strings: if a special character follows a ['%'] + character, it is treated as a plain character. In other words, ["%%"] is + considered as a plain ['%'] and ["%@"] as a plain ['@']. + + For more information about conversion specifications and formatting + indications available, read the documentation of modules {!Scanf}, + {!Printf} and {!Format}. +*) + +(** Format strings have a general and highly polymorphic type + [('a, 'b, 'c, 'd, 'e, 'f) format6]. + The two simplified types, [format] and [format4] below are + included for backward compatibility with earlier releases of + OCaml. + + The meaning of format string type parameters is as follows: + + - ['a] is the type of the parameters of the format for formatted output + functions ([printf]-style functions); + ['a] is the type of the values read by the format for formatted input + functions ([scanf]-style functions). + + - ['b] is the type of input source for formatted input functions and the + type of output target for formatted output functions. + For [printf]-style functions from module {!Printf}, ['b] is typically + [out_channel]; + for [printf]-style functions from module {!Format}, ['b] is typically + {!Format.formatter}; + for [scanf]-style functions from module {!Scanf}, ['b] is typically + {!Scanf.Scanning.in_channel}. + + Type argument ['b] is also the type of the first argument given to + user's defined printing functions for [%a] and [%t] conversions, + and user's defined reading functions for [%r] conversion. + + - ['c] is the type of the result of the [%a] and [%t] printing + functions, and also the type of the argument transmitted to the + first argument of [kprintf]-style functions or to the + [kscanf]-style functions. + + - ['d] is the type of parameters for the [scanf]-style functions. + + - ['e] is the type of the receiver function for the [scanf]-style functions. + + - ['f] is the final result type of a formatted input/output function + invocation: for the [printf]-style functions, it is typically [unit]; + for the [scanf]-style functions, it is typically the result type of the + receiver function. +*) + +type ('a, 'b, 'c, 'd, 'e, 'f) format6 = + ('a, 'b, 'c, 'd, 'e, 'f) CamlinternalFormatBasics.format6 + +type ('a, 'b, 'c, 'd) format4 = ('a, 'b, 'c, 'c, 'c, 'd) format6 + +type ('a, 'b, 'c) format = ('a, 'b, 'c, 'c) format4 + +val string_of_format : ('a, 'b, 'c, 'd, 'e, 'f) format6 -> string +(** Converts a format string into a string. *) + +external format_of_string : + ('a, 'b, 'c, 'd, 'e, 'f) format6 -> + ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity" +(** [format_of_string s] returns a format string read from the string + literal [s]. + Note: [format_of_string] can not convert a string argument that is not a + literal. If you need this functionality, use the more general + {!Scanf.format_from_string} function. +*) + +val ( ^^ ) : + ('a, 'b, 'c, 'd, 'e, 'f) format6 -> + ('f, 'b, 'c, 'e, 'g, 'h) format6 -> + ('a, 'b, 'c, 'd, 'g, 'h) format6 +(** [f1 ^^ f2] catenates format strings [f1] and [f2]. The result is a + format string that behaves as the concatenation of format strings [f1] and + [f2]: in case of formatted output, it accepts arguments from [f1], then + arguments from [f2]; in case of formatted input, it returns results from + [f1], then results from [f2]. + Right-associative operator at precedence level 5/11. *) + + +(** {1 Program termination} *) + +val exit : int -> 'a +(** Terminate the process, returning the given status code + to the operating system: usually 0 to indicate no errors, + and a small positive integer to indicate failure. + All open output channels are flushed with [flush_all]. + An implicit [exit 0] is performed each time a program + terminates normally. An implicit [exit 2] is performed if the program + terminates early because of an uncaught exception. *) + +val at_exit : (unit -> unit) -> unit +(** Register the given function to be called at program termination + time. The functions registered with [at_exit] will be called when + the program does any of the following: + - executes {!Pervasives.exit} + - terminates, either normally or because of an uncaught + exception + - executes the C function [caml_shutdown]. + The functions are called in 'last in, first out' order: the + function most recently added with [at_exit] is called first. *) + +(**/**) + +(* The following is for system use only. Do not call directly. *) + +val valid_float_lexem : string -> string + +val unsafe_really_input : in_channel -> bytes -> int -> int -> unit + +val do_at_exit : unit -> unit +end + +include module type of struct include Pervasives end + +(*MODULE_ALIASES*) +module Arg = Arg +module Array = Array +module ArrayLabels = ArrayLabels +module Bigarray = Bigarray +module Buffer = Buffer +module Bytes = Bytes +module BytesLabels = BytesLabels +module Callback = Callback +module Char = Char +module Complex = Complex +module Digest = Digest +module Ephemeron = Ephemeron +module Filename = Filename +module Float = Float +module Format = Format +module Gc = Gc +module Genlex = Genlex +module Hashtbl = Hashtbl +module Int32 = Int32 +module Int64 = Int64 +module Lazy = Lazy +module Lexing = Lexing +module List = List +module ListLabels = ListLabels +module Map = Map +module Marshal = Marshal +module MoreLabels = MoreLabels +module Nativeint = Nativeint +module Obj = Obj +module Oo = Oo +module Parsing = Parsing +module Printexc = Printexc +module Printf = Printf +module Queue = Queue +module Random = Random +module Scanf = Scanf +module Seq = Seq +module Set = Set +module Sort = Sort +module Spacetime = Spacetime +module Stack = Stack +module StdLabels = StdLabels +module Stream = Stream +module String = String +module StringLabels = StringLabels +module Sys = Sys +module Uchar = Uchar +module Weak = Weak diff --git a/stdlib/stream.ml b/stdlib/stream.ml index e9b5e611..2bfef709 100644 --- a/stdlib/stream.ml +++ b/stdlib/stream.ml @@ -99,7 +99,10 @@ let rec junk_data : type v. v cell -> unit = fun s -> match s.data with Scons (_, d) -> s.count <- (succ s.count); s.data <- d | Sgen ({curr = Some _} as g) -> s.count <- (succ s.count); g.curr <- None - | Sbuffio b -> s.count <- (succ s.count); b.ind <- succ b.ind + | Sbuffio b -> + if b.ind >= b.len then fill_buff b; + if b.len == 0 then s.data <- Sempty + else (s.count <- (succ s.count); b.ind <- succ b.ind) | _ -> match peek_data s with None -> () diff --git a/stdlib/string.ml b/stdlib/string.ml index 9a4b533f..82c4af36 100644 --- a/stdlib/string.ml +++ b/stdlib/string.ml @@ -101,17 +101,13 @@ let trim s = else s let escaped s = - let rec needs_escape i = - if i >= length s then false else + let rec escape_if_needed s n i = + if i >= n then s else match unsafe_get s i with - | '\"' | '\\' | '\n' | '\t' | '\r' | '\b' -> true - | ' ' .. '~' -> needs_escape (i+1) - | _ -> true + | '\"' | '\\' | '\000'..'\031' | '\127'.. '\255' -> bts (B.escaped (bos s)) + | _ -> escape_if_needed s n (i+1) in - if needs_escape 0 then - bts (B.escaped (bos s)) - else - s + escape_if_needed s (length s) 0 (* duplicated in bytes.ml *) let rec index_rec s lim i c = @@ -224,3 +220,12 @@ let capitalize s = B.capitalize (bos s) |> bts let uncapitalize s = B.uncapitalize (bos s) |> bts + +(** {6 Iterators} *) + +let to_seq s = bos s |> B.to_seq + +let to_seqi s = bos s |> B.to_seqi + +let of_seq g = B.of_seq g |> bts + diff --git a/stdlib/string.mli b/stdlib/string.mli index 6c250ef7..8ec3fff8 100644 --- a/stdlib/string.mli +++ b/stdlib/string.mli @@ -333,6 +333,21 @@ val split_on_char: char -> string -> string list @since 4.04.0 *) +(** {6 Iterators} *) + +val to_seq : t -> char Seq.t +(** Iterate on the string, in increasing index order. Modifications of the + string during iteration will be reflected in the iterator. + @since 4.07 *) + +val to_seqi : t -> (int * char) Seq.t +(** Iterate on the string, in increasing order, yielding indices along chars + @since 4.07 *) + +val of_seq : char Seq.t -> t +(** Create a string from the generator + @since 4.07 *) + (**/**) (* The following is for system use only. Do not call directly. *) diff --git a/stdlib/stringLabels.mli b/stdlib/stringLabels.mli index f249d439..dac714cb 100644 --- a/stdlib/stringLabels.mli +++ b/stdlib/stringLabels.mli @@ -288,6 +288,21 @@ val split_on_char: sep:char -> string -> string list @since 4.05.0 *) +(** {6 Iterators} *) + +val to_seq : t -> char Seq.t +(** Iterate on the string, in increasing index order. Modifications of the + string during iteration will be reflected in the iterator. + @since 4.07 *) + +val to_seqi : t -> (int * char) Seq.t +(** Iterate on the string, in increasing order, yielding indices along chars + @since 4.07 *) + +val of_seq : char Seq.t -> t +(** Create a string from the generator + @since 4.07 *) + (**/**) (* The following is for system use only. Do not call directly. *) diff --git a/stdlib/sys.mli b/stdlib/sys.mli index 3c86a144..22884950 100644 --- a/stdlib/sys.mli +++ b/stdlib/sys.mli @@ -27,7 +27,10 @@ val argv : string array given to the program. *) val executable_name : string -(** The name of the file containing the executable currently running. *) +(** The name of the file containing the executable currently running. + This name may be absolute or relative to the current directory, depending + on the platform and whether the program was compiled to bytecode or a native + executable. *) external file_exists : string -> bool = "caml_sys_file_exists" (** Test if a file with the given name exists. *) @@ -126,13 +129,12 @@ val cygwin : bool val word_size : int (** Size of one word on the machine currently executing the OCaml - program, in bits: 32 or 64. *) + program, in bits: 32 or 64. *) val int_size : int -(** Size of an int. It is 31 bits (resp. 63 bits) when using the - OCaml compiler on a 32 bits (resp. 64 bits) platform. It may - differ for other compilers, e.g. it is 32 bits when compiling to - JavaScript. +(** Size of [int], in bits. It is 31 (resp. 63) when using OCaml on a + 32-bit (resp. 64-bit) platform. It may differ for other implementations, + e.g. it can be 32 bits when compiling to JavaScript. @since 4.03.0 *) val big_endian : bool diff --git a/stdlib/uchar.mli b/stdlib/uchar.mli index c8b63bdb..afab670f 100644 --- a/stdlib/uchar.mli +++ b/stdlib/uchar.mli @@ -20,7 +20,7 @@ type t (** The type for Unicode characters. - A value of this type represents an Unicode + A value of this type represents a Unicode {{:http://unicode.org/glossary/#unicode_scalar_value}scalar value} which is an integer in the ranges [0x0000]...[0xD7FF] or [0xE000]...[0x10FFFF]. *) @@ -58,11 +58,11 @@ val pred : t -> t @raise Invalid_argument if [u] is {!min}. *) val is_valid : int -> bool -(** [is_valid n] is [true] iff [n] is an Unicode scalar value +(** [is_valid n] is [true] iff [n] is a Unicode scalar value (i.e. in the ranges [0x0000]...[0xD7FF] or [0xE000]...[0x10FFFF]).*) val of_int : int -> t -(** [of_int i] is [i] as an Unicode character. +(** [of_int i] is [i] as a Unicode character. @raise Invalid_argument if [i] does not satisfy {!is_valid}. *) @@ -77,7 +77,7 @@ val is_char : t -> bool (** [is_char u] is [true] iff [u] is a latin1 OCaml character. *) val of_char : char -> t -(** [of_char c] is [c] as an Unicode character. *) +(** [of_char c] is [c] as a Unicode character. *) val to_char : t -> char (** [to_char u] is [u] as an OCaml latin1 character. diff --git a/testsuite/Makefile b/testsuite/Makefile index 0a7325bc..7375c467 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -18,7 +18,8 @@ NO_PRINT=`$(MAKE) empty --no-print-directory >/dev/null 2>&1 \ && echo --no-print-directory` FIND=find -include ../config/Makefile +TOPDIR := .. +include $(TOPDIR)/Makefile.tools ifeq "$(UNIX_OR_WIN32)" "unix" ifeq "$(SYSTEM)" "cygwin" @@ -41,13 +42,15 @@ endif failstamp := failure.stamp +TESTLOG ?= _log + ocamltest_directory := ../ocamltest ocamltest_program := $(or \ $(wildcard $(ocamltest_directory)/ocamltest.opt$(EXE)),\ $(wildcard $(ocamltest_directory)/ocamltest$(EXE))) -ocamltest := $(FLEXLINK_PREFIX) $(ocamltest_program) +ocamltest := $(FLEXLINK_PREFIX) SORT=$(SORT) $(ocamltest_program) .PHONY: default default: @@ -73,27 +76,27 @@ default: .PHONY: all all: - @rm -f _log + @rm -f $(TESTLOG) @$(MAKE) $(NO_PRINT) legacy-without-report @$(MAKE) $(NO_PRINT) new-without-report @$(MAKE) $(NO_PRINT) report .PHONY: legacy legacy: - @rm -f _log + @rm -f $(TESTLOG) @$(MAKE) $(NO_PRINT) legacy-without-report @$(MAKE) $(NO_PRINT) report .PHONY: legacy-without-report legacy-without-report: lib tools @for dir in tests/*; do \ - $(MAKE) $(NO_PRINT) exec-one DIR=$$dir; \ - done 2>&1 | tee -a _log + $(MAKE) $(NO_PRINT) exec-one DIR=$$dir LEGACY=y; \ + done 2>&1 | tee -a $(TESTLOG) @$(MAKE) $(NO_PRINT) retries .PHONY: new new: - @rm -f _log + @rm -f $(TESTLOG) @$(MAKE) $(NO_PRINT) new-without-report @$(MAKE) $(NO_PRINT) report @@ -103,19 +106,16 @@ new-without-report: lib tools @(for file in `$(find) tests -name ocamltests`; do \ dir=`dirname $$file`; \ echo Running tests from \'$$dir\' ... ; \ - (IFS=$$(printf "\r\n"); while read testfile; do \ - TERM=dumb OCAMLRUNPARAM= \ - $(ocamltest) $$dir/$$testfile || \ - touch $(failstamp); \ - done < $$file) || touch $(failstamp); \ - done || touch $(failstamp)) 2>&1 | tee -a _log + $(MAKE) exec-ocamltest DIR=$$dir \ + OCAMLTESTENV="" OCAMLTESTFLAGS=""; \ + done || touch $(failstamp)) 2>&1 | tee -a $(TESTLOG) @if [ -f $(failstamp) ]; then rm $(failstamp); exit 1; fi .PHONY: all-% all-%: lib tools @for dir in tests/$**; do \ $(MAKE) $(NO_PRINT) exec-one DIR=$$dir; \ - done 2>&1 | tee _log + done 2>&1 | tee $(TESTLOG) @$(MAKE) $(NO_PRINT) retries @$(MAKE) report @@ -156,7 +156,7 @@ parallel-%: lib tools @for dir in tests/$**; do echo $$dir; done \ | parallel --gnu --no-notice --keep-order \ "$(MAKE) $(NO_PRINT) exec-one DIR={} 2>&1" \ - | tee _log + | tee $(TESTLOG) @$(MAKE) $(NO_PRINT) retries @$(MAKE) report @@ -171,7 +171,7 @@ list: lib tools fi @while read LINE; do \ $(MAKE) $(NO_PRINT) exec-one DIR=$$LINE; \ - done <$(FILE) 2>&1 | tee _log + done <$(FILE) 2>&1 | tee $(TESTLOG) @$(MAKE) $(NO_PRINT) retries @$(MAKE) report @@ -186,6 +186,7 @@ one: lib tools exit 1; \ fi @$(MAKE) $(NO_PRINT) exec-one DIR=$(DIR) + @if [ -f $(failstamp) ]; then rm $(failstamp); exit 1; fi .PHONY: exec-one exec-one: @@ -199,8 +200,24 @@ exec-one: echo "Running tests from '$$DIR' ..."; \ cd $(DIR) && \ $(MAKE) TERM=dumb BASEDIR=$(BASEDIR) || echo '=> unexpected error'; \ + elif [ -f $(DIR)/ocamltests ] && [ -z $(LEGACY) ] ; then \ + echo "Running tests from '$$DIR' ..."; \ + $(MAKE) exec-ocamltest DIR=$(DIR) \ + OCAMLTESTENV="OCAMLTESTDIR=$(shell $(CYGPATH) $(BASEDIR)/$(DIR)/_ocamltest)" \ + OCAMLTESTFLAGS=""; \ fi +.PHONY: exec-ocamltest +exec-ocamltest: + @if [ -z "$(DIR)" ]; then exit 1; fi + @if [ ! -d "$(DIR)" ]; then exit 1; fi + @file=$(DIR)/ocamltests; \ + (IFS=$$(printf "\r\n"); while read testfile; do \ + TERM=dumb $(OCAMLTESTENV) \ + $(ocamltest) $(OCAMLTESTFLAGS) $(DIR)/$$testfile || \ + touch $(failstamp); \ + done < $$file) || touch $(failstamp) + .PHONY: clean-one clean-one: @if [ ! -f $(DIR)/Makefile ]; then \ @@ -223,7 +240,13 @@ promote: echo "Directory '$(DIR)' does not exist."; \ exit 1; \ fi - @cd $(DIR) && $(MAKE) TERM=dumb BASEDIR=$(BASEDIR) promote + @if [ -f $(DIR)/ocamltests ]; then \ + $(MAKE) exec-ocamltest DIR=$(DIR) \ + OCAMLTESTENV="OCAMLTESTDIR=$(shell $(CYGPATH) $(BASEDIR)/$(DIR)/_ocamltest)" \ + OCAMLTESTFLAGS="-promote"; \ + else \ + cd $(DIR) && $(MAKE) TERM=dumb BASEDIR=$(BASEDIR) promote; \ + fi .PHONY: lib lib: @@ -245,16 +268,16 @@ clean: .PHONY: report report: - @if [ ! -f _log ]; then echo "No '_log' file."; exit 1; fi - @awk -f makefiles/summarize.awk <_log + @if [ ! -f $(TESTLOG) ]; then echo "No $(TESTLOG) file."; exit 1; fi + @awk -f makefiles/summarize.awk < $(TESTLOG) .PHONY: retry-list retry-list: @while read LINE; do \ if [ -n "$$LINE" ] ; then \ - echo re-ran $$LINE>>_log; \ + echo re-ran $$LINE>> $(TESTLOG); \ $(MAKE) $(NO_PRINT) clean-one DIR=$$LINE; \ - $(MAKE) $(NO_PRINT) exec-one DIR=$$LINE 2>&1 | tee -a _log ; \ + $(MAKE) $(NO_PRINT) exec-one DIR=$$LINE 2>&1 | tee -a $(TESTLOG) ; \ fi \ done <_retries; @$(MAKE) $(NO_PRINT) retries @@ -262,7 +285,7 @@ retry-list: .PHONY: retries retries: @awk -v retries=1 -v max_retries=$(MAX_TESTSUITE_DIR_RETRIES) \ - -f makefiles/summarize.awk <_log >_retries + -f makefiles/summarize.awk < $(TESTLOG) > _retries @test `cat _retries | wc -l` -eq 0 || $(MAKE) $(NO_PRINT) retry-list @rm -f _retries diff --git a/testsuite/interactive/lib-graph-3/Makefile b/testsuite/interactive/lib-graph-3/Makefile index 8e9e7f1a..7ac0c869 100644 --- a/testsuite/interactive/lib-graph-3/Makefile +++ b/testsuite/interactive/lib-graph-3/Makefile @@ -16,7 +16,7 @@ BASEDIR=../.. #MODULES= MAIN_MODULE=sorts -ADD_COMPFLAGS=-thread +ADD_COMPFLAGS=-I +threads LIBRARIES=unix threads graphics include $(BASEDIR)/makefiles/Makefile.one diff --git a/testsuite/lib/Makefile b/testsuite/lib/Makefile index 7efde5c2..8373eef9 100644 --- a/testsuite/lib/Makefile +++ b/testsuite/lib/Makefile @@ -25,7 +25,7 @@ clean: defaultclean include ../makefiles/Makefile.common .PHONY: compile-targets -compile-targets: testing.cmi testing.cma +compile-targets: testing.cmi testing.cma lib.cmo @if $(BYTECODE_ONLY); then : ; else \ $(MAKE) testing.cmxa; \ fi diff --git a/testsuite/tests/tool-ocaml/lib.ml b/testsuite/lib/lib.ml similarity index 100% rename from testsuite/tests/tool-ocaml/lib.ml rename to testsuite/lib/lib.ml diff --git a/testsuite/makefiles/Makefile.expect b/testsuite/makefiles/Makefile.expect index d1395a48..99e24014 100644 --- a/testsuite/makefiles/Makefile.expect +++ b/testsuite/makefiles/Makefile.expect @@ -16,14 +16,20 @@ default: @for file in *.ml; do \ printf " ... testing '$$file':"; \ - TERM=dumb $(EXPECT_TEST) -repo-root $(OTOPDIR) $$file && \ - TERM=dumb $(EXPECT_TEST) -repo-root $(OTOPDIR) -principal \ + TERM=dumb $(EXPECT_TEST) $(EXPECT_FLAGS) -repo-root $(OTOPDIR) $$file && \ + TERM=dumb $(EXPECT_TEST) $(EXPECT_FLAGS) -repo-root $(OTOPDIR) -principal \ $$file.corrected && \ mv $$file.corrected.corrected $$file.corrected && \ $(DIFF) $$file $$file.corrected && \ echo " => passed" || echo " => failed"; \ done +# Builds everything needed to run an expect test +.PHONY: deps +deps: + @$(MAKE) -C $(OTOPDIR) coldstart ocaml ocamlc + @$(MAKE) -C $(OTOPDIR)/testsuite/tools expect_test$(EXE) + .PHONY: promote promote: @for file in *.corrected; do \ diff --git a/testsuite/tests/afl-instrumentation/Makefile b/testsuite/tests/afl-instrumentation/Makefile deleted file mode 100644 index c32365e7..00000000 --- a/testsuite/tests/afl-instrumentation/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -BASEDIR=../.. - -default: - @printf " ... testing 'afl_instrumentation':" - @if ! which afl-showmap > /dev/null; then \ - echo " => skipped (afl-showmap unavailable)"; \ - else \ - if OCAMLOPT='$(OCAMLOPT)' ./test.sh > /dev/null; then \ - echo " => passed"; \ - else \ - echo " => failed"; \ - fi \ - fi - -include $(BASEDIR)/makefiles/Makefile.common - -clean: defaultclean diff --git a/testsuite/tests/afl-instrumentation/afltest.ml b/testsuite/tests/afl-instrumentation/afltest.ml new file mode 100644 index 00000000..b8a67b34 --- /dev/null +++ b/testsuite/tests/afl-instrumentation/afltest.ml @@ -0,0 +1,17 @@ +(* TEST (* Just a test-driver *) + * native-compiler + ** no-afl-instrument + *** script + script = "sh ${test_source_directory}/has-afl-showmap.sh" + files = "harness.ml test.ml" + **** setup-ocamlopt.byte-build-env + ***** ocamlopt.byte + module = "test.ml" + flags = "-afl-instrument" + ****** ocamlopt.byte + module = "" + program = "${test_build_directory}/test" + flags = "-afl-inst-ratio 0" + all_modules = "test.cmx harness.ml" + ******* run +*) diff --git a/testsuite/tests/afl-instrumentation/afltest.run b/testsuite/tests/afl-instrumentation/afltest.run new file mode 100755 index 00000000..eb495145 --- /dev/null +++ b/testsuite/tests/afl-instrumentation/afltest.run @@ -0,0 +1,36 @@ +#!/bin/bash + +set -e + +output="${program}".output +exec > ${output} 2>&1 + +NTESTS=`./test len` +failures='' +echo "running $NTESTS tests..." +for t in `seq 1 $NTESTS`; do + printf "%14s: " `./test name $t` + # when run twice, the instrumentation output should double + afl-showmap -q -o output-1 -- ./test 1 $t + afl-showmap -q -o output-2 -- ./test 2 $t + # see afl-showmap.c for what the numbers mean + cat output-1 | sed ' + s/:6/:7/; s/:5/:6/; + s/:4/:5/; s/:3/:4/; + s/:2/:4/; s/:1/:2/; + ' > output-2-predicted + if cmp -s output-2-predicted output-2; then + echo "passed." + else + echo "failed:" + paste output-2 output-1 + failures=1 + fi +done + +if [ -z "$failures" ]; then + echo "all tests passed"; + exit ${TEST_PASS} +else + exit ${TEST_FAIL}; +fi diff --git a/testsuite/tests/afl-instrumentation/has-afl-showmap.sh b/testsuite/tests/afl-instrumentation/has-afl-showmap.sh new file mode 100644 index 00000000..27396415 --- /dev/null +++ b/testsuite/tests/afl-instrumentation/has-afl-showmap.sh @@ -0,0 +1,7 @@ +#!/bin/sh +if ! which afl-showmap > /dev/null 2>&1; then + echo "afl-showmap not available" > ${ocamltest_response} + exit ${TEST_SKIP} +else + exit ${TEST_PASS} +fi diff --git a/testsuite/tests/afl-instrumentation/ocamltests b/testsuite/tests/afl-instrumentation/ocamltests new file mode 100644 index 00000000..99ac64b6 --- /dev/null +++ b/testsuite/tests/afl-instrumentation/ocamltests @@ -0,0 +1 @@ +afltest.ml diff --git a/testsuite/tests/afl-instrumentation/test.sh b/testsuite/tests/afl-instrumentation/test.sh deleted file mode 100755 index 804db5f2..00000000 --- a/testsuite/tests/afl-instrumentation/test.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -e - -$OCAMLOPT -c -afl-instrument test.ml -$OCAMLOPT -afl-inst-ratio 0 test.cmx harness.ml -o test - -NTESTS=`./test len` -failures='' -echo "running $NTESTS tests..." -for t in `seq 1 $NTESTS`; do - printf "%14s: " `./test name $t` - # when run twice, the instrumentation output should double - afl-showmap -q -o output-1 -- ./test 1 $t - afl-showmap -q -o output-2 -- ./test 2 $t - # see afl-showmap.c for what the numbers mean - cat output-1 | sed ' - s/:6/:7/; s/:5/:6/; - s/:4/:5/; s/:3/:4/; - s/:2/:4/; s/:1/:2/; - ' > output-2-predicted - if cmp -s output-2-predicted output-2; then - echo "passed." - else - echo "failed:" - paste output-2 output-1 - failures=1 - fi -done - -if [ -z "$failures" ]; then echo "all tests passed"; else exit 1; fi - -rm -f {test,harness}.{cmi,cmx,o} test output-{1,2,2-predicted} diff --git a/testsuite/tests/asmcomp/Makefile b/testsuite/tests/asmcomp/Makefile deleted file mode 100644 index 08921d12..00000000 --- a/testsuite/tests/asmcomp/Makefile +++ /dev/null @@ -1,163 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -include $(BASEDIR)/../config/Makefile - -INCLUDES=\ - -I $(OTOPDIR)/parsing \ - -I $(OTOPDIR)/utils \ - -I $(OTOPDIR)/typing \ - -I $(OTOPDIR)/middle_end \ - -I $(OTOPDIR)/bytecomp \ - -I $(OTOPDIR)/asmcomp - -OTHEROBJS=\ - $(OTOPDIR)/compilerlibs/ocamlcommon.cma \ - $(OTOPDIR)/compilerlibs/ocamloptcomp.cma - -OBJS=parsecmmaux.cmo parsecmm.cmo lexcmm.cmo - -ADD_COMPFLAGS=$(INCLUDES) -w -40 -g - -default: - @if $(BYTECODE_ONLY) || $(SKIP) ; then $(MAKE) skips ; else \ - $(MAKE) all; \ - fi - -all: - @$(MAKE) arch codegen - @$(MAKE) tests - -main.cmo: parsecmm.cmo - -codegen: parsecmm.ml lexcmm.ml $(OBJS:.cmo=.cmi) $(OBJS) main.cmo - @$(OCAMLC) $(LINKFLAGS) -o codegen $(OTHEROBJS) $(OBJS) main.cmo - -parsecmm.mli parsecmm.ml: parsecmm.mly - @$(OCAMLYACC) -q parsecmm.mly - -lexcmm.ml: lexcmm.mll - @$(OCAMLLEX) -q lexcmm.mll - -MLCASES=optargs staticalloc bind_tuples is_static register_typing \ - register_typing_switch -ARGS_optargs=-g -ARGS_is_static=-I $(OTOPDIR)/byterun is_in_static_data.c -MLCASES_FLAMBDA=is_static_flambda unrolling_flambda unrolling_flambda2 -MLCASES_FLAMBDA_FLOAT=static_float_array_flambda \ - static_float_array_flambda_opaque -ARGS_is_static_flambda=\ - -I $(OTOPDIR)/byterun is_in_static_data.c is_static_flambda_dep.ml -ARGS_static_float_array_flambda=\ - -I $(OTOPDIR)/byterun is_in_static_data.c simple_float_const.ml -ARGS_static_float_array_flambda_opaque=\ - -I $(OTOPDIR)/byterun is_in_static_data.c -opaque simple_float_const_opaque.ml - -CASES=fib tak quicksort quicksort2 soli \ - arith checkbound tagged-fib tagged-integr tagged-quicksort tagged-tak \ - catch-try catch-rec even-odd even-odd-spill pgcd -ARGS_fib=-DINT_INT -DFUN=fib main.c -ARGS_tak=-DUNIT_INT -DFUN=takmain main.c -ARGS_quicksort=-DSORT -DFUN=quicksort main.c -ARGS_quicksort2=-DSORT -DFUN=quicksort main.c -ARGS_soli=-DUNIT_INT -DFUN=solitaire main.c -ARGS_integr=-DINT_FLOAT -DFUN=test main.c -ARGS_arith=mainarith.c -ARGS_checkbound=-DCHECKBOUND main.c -ARGS_tagged-fib=-DINT_INT -DFUN=fib main.c -ARGS_tagged-integr=-DINT_FLOAT -DFUN=test main.c -ARGS_tagged-quicksort=-DSORT -DFUN=quicksort main.c -ARGS_tagged-tak=-DUNIT_INT -DFUN=takmain main.c -ARGS_staticalloc=-I $(OTOPDIR)/utils config.cmx -ARGS_catch-try=-DINT_INT -DFUN=catch_exit main.c -ARGS_catch-rec=-DINT_INT -DFUN=catch_fact main.c -ARGS_even-odd=-DINT_INT -DFUN=is_even main.c -ARGS_even-odd-spill=-DINT_INT -DFUN=is_even main.c -ARGS_pgcd=-DINT_INT -DFUN=pgcd_30030 main.c - -skips: - @for c in $(CASES) $(MLCASES) $(MLCASES_FLAMBDA) \ - $(MLCASES_FLAMBDA_FLOAT); do \ - echo " ... testing '$$c': => skipped"; \ - done - -one_ml: - @$(OCAMLOPT) $(ARGS_$(NAME)) -o $(NAME).exe $(NAME).ml && \ - ./$(NAME).exe && echo " => passed" || echo " => failed" - -one_ml_cond: - @if $(COND); then \ - $(OCAMLOPT) $(ARGS_$(NAME)) -o $(NAME).exe $(NAME).ml && \ - ./$(NAME).exe && echo " => passed" || echo " => failed"; \ - else \ - echo " => skipped"; \ - fi - -one: - @$(call CCOMP,$(NAME).out $(ARGS_$(NAME)) $(NAME).$(O) $(ARCH).$(O)) \ - && echo " => passed" || echo " => failed" - -clean: defaultclean - @rm -f ./codegen *.out *.out.manifest *.$(O) *.exe - @rm -f parsecmm.ml parsecmm.mli lexcmm.ml - @rm -f $(CASES:=.s) - -include $(BASEDIR)/makefiles/Makefile.common - -ifeq "$(CCOMPTYPE)-$(ARCH)" "msvc-amd64" -# these tests are not ported to MSVC64 yet -SKIP=true -else -SKIP=false -endif - -ifeq "$(WITH_SPACETIME)" "true" -# These tests have not been ported for Spacetime -SKIP=true -endif - -ifeq ($(CCOMPTYPE),msvc) -CCOMP=set -o pipefail ; $(CC) $(CFLAGS) /Fe$(1) | tail -n +2 -else -CCOMP=$(CC) $(CFLAGS) -o $(1) -endif -tests: $(CASES:=.$(O)) - @for c in $(CASES); do \ - printf " ... testing '$$c':"; \ - $(MAKE) one NAME=$$c; \ - done - @for c in $(MLCASES); do \ - printf " ... testing '$$c':"; \ - $(MAKE) one_ml NAME=$$c; \ - done - @for c in $(MLCASES_FLAMBDA); do \ - printf " ... testing '$$c':"; \ - $(MAKE) one_ml_cond NAME=$$c COND=$(FLAMBDA); \ - done - @for c in $(MLCASES_FLAMBDA_FLOAT); do \ - printf " ... testing '$$c':"; \ - $(MAKE) one_ml_cond NAME=$$c \ - COND='$(FLAMBDA) && $(FLAT_FLOAT_ARRAY)'; \ - done - -promote: - -arch: $(ARCH).$(O) - -i386.obj: i386nt.asm - @set -o pipefail ; \ - $(ASM) $@ $^ | tail -n +2 diff --git a/testsuite/tests/asmcomp/alpha.S b/testsuite/tests/asmcomp/alpha.S deleted file mode 100644 index 44528769..00000000 --- a/testsuite/tests/asmcomp/alpha.S +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - - .globl call_gen_code - .ent call_gen_code - -call_gen_code: - lda $sp, -80($sp) - stq $26, 0($sp) - stq $9, 8($sp) - stq $10, 16($sp) - stq $11, 24($sp) - stq $12, 32($sp) - stt $f2, 40($sp) - stt $f3, 48($sp) - stt $f4, 56($sp) - stt $f5, 64($sp) - mov $16, $27 - mov $17, $16 - mov $18, $17 - mov $19, $18 - mov $20, $19 - jsr ($27) - ldq $26, 0($sp) - ldq $9, 8($sp) - ldq $10, 16($sp) - ldq $11, 24($sp) - ldq $12, 32($sp) - ldt $f2, 40($sp) - ldt $f3, 48($sp) - ldt $f4, 56($sp) - ldt $f5, 64($sp) - lda $sp, 80($sp) - ret ($26) - - .end call_gen_code - - .globl caml_c_call - .ent caml_c_call -caml_c_call: - lda $sp, -16($sp) - stq $26, 0($sp) - stq $gp, 8($sp) - mov $25, $27 - jsr ($25) - ldq $26, 0($sp) - ldq $gp, 8($sp) - lda $sp, 16($sp) - ret ($26) - - .end caml_c_call diff --git a/testsuite/tests/asmcomp/amd64.S b/testsuite/tests/asmcomp/amd64.S deleted file mode 100644 index bb4f9b5c..00000000 --- a/testsuite/tests/asmcomp/amd64.S +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 2000 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -#ifdef SYS_macosx -#define ALIGN 4 -#else -#define ALIGN 16 -#endif - -#ifdef SYS_macosx -#define CALL_GEN_CODE _call_gen_code -#define CAML_C_CALL _caml_c_call -#define CAML_NEGF_MASK _caml_negf_mask -#define CAML_ABSF_MASK _caml_absf_mask -#else -#define CALL_GEN_CODE call_gen_code -#define CAML_C_CALL caml_c_call -#define CAML_NEGF_MASK caml_negf_mask -#define CAML_ABSF_MASK caml_absf_mask -#endif - - .globl CALL_GEN_CODE - .align ALIGN -CALL_GEN_CODE: - pushq %rbx - pushq %rbp - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - movq %rdi, %r10 - movq %rsi, %rax - movq %rdx, %rbx - movq %rcx, %rdi - movq %r8, %rsi - call *%r10 - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %rbp - popq %rbx - ret - - .globl CAML_C_CALL - .align ALIGN -CAML_C_CALL: - jmp *%rax - -#ifdef SYS_macosx - .literal16 -#elif defined(SYS_mingw64) || defined(SYS_cygwin) - .section .rodata.cst8 -#else - .section .rodata.cst8,"aM",@progbits,8 -#endif - .globl CAML_NEGF_MASK - .align ALIGN -CAML_NEGF_MASK: - .quad 0x8000000000000000, 0 - .globl CAML_ABSF_MASK - .align ALIGN -CAML_ABSF_MASK: - .quad 0x7FFFFFFFFFFFFFFF, 0 - - .comm young_limit, 8 diff --git a/testsuite/tests/asmcomp/arm.S b/testsuite/tests/asmcomp/arm.S deleted file mode 100644 index fbbe2763..00000000 --- a/testsuite/tests/asmcomp/arm.S +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1998 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - - .text - - .global call_gen_code - .type call_gen_code, %function - .align 0 -call_gen_code: - mov ip, sp - stmfd sp!, {r4, r5, r6, r7, r8, r9, fp, ip, lr, pc} - sub fp, ip, #4 - @ r0 is function to call - @ r1, r2, r3 are arguments 1, 2, 3 - mov r4, r0 - mov r0, r1 - mov r1, r2 - mov r2, r3 - mov lr, pc - mov pc, r4 - ldmea fp, {r4, r5, r6, r7, r8, r9, fp, sp, pc} - - .global caml_c_call - .type caml_c_call, %function - .align 0 -caml_c_call: - @ function to call is in r10 - mov pc, r10 diff --git a/testsuite/tests/asmcomp/arm64.S b/testsuite/tests/asmcomp/arm64.S deleted file mode 100644 index fa49f1ae..00000000 --- a/testsuite/tests/asmcomp/arm64.S +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Gallium, INRIA Rocquencourt */ -/* */ -/* Copyright 2013 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - - .globl call_gen_code - .align 2 -call_gen_code: - /* Set up stack frame and save callee-save registers */ - stp x29, x30, [sp, -160]! - add x29, sp, #0 - stp x19, x20, [sp, 16] - stp x21, x22, [sp, 32] - stp x23, x24, [sp, 48] - stp x25, x26, [sp, 64] - stp x27, x28, [sp, 80] - stp d8, d9, [sp, 96] - stp d10, d11, [sp, 112] - stp d12, d13, [sp, 128] - stp d14, d15, [sp, 144] - /* Shuffle arguments */ - mov x8, x0 - mov x0, x1 - mov x1, x2 - mov x2, x3 - mov x3, x4 - /* Call generated asm */ - blr x8 - /* Reload callee-save registers and return address */ - ldp x19, x20, [sp, 16] - ldp x21, x22, [sp, 32] - ldp x23, x24, [sp, 48] - ldp x25, x26, [sp, 64] - ldp x27, x28, [sp, 80] - ldp d8, d9, [sp, 96] - ldp d10, d11, [sp, 112] - ldp d12, d13, [sp, 128] - ldp d14, d15, [sp, 144] - ldp x29, x30, [sp], 160 - ret - - .globl caml_c_call - .align 2 -caml_c_call: - br x15 diff --git a/testsuite/tests/asmcomp/bind_tuples.ml b/testsuite/tests/asmcomp/bind_tuples.ml old mode 100755 new mode 100644 index a6dd2947..156b0872 --- a/testsuite/tests/asmcomp/bind_tuples.ml +++ b/testsuite/tests/asmcomp/bind_tuples.ml @@ -1,3 +1,7 @@ +(* TEST + * native +*) + (* Check the effectiveness of optimized compilation of tuple binding Ref: http://caml.inria.fr/mantis/view.php?id=4800 @@ -20,9 +24,21 @@ let f () = r := !r * x + y done; let x2 = Gc.allocated_bytes () in - print_int !r; assert (!r = 82); assert(x1 -. x0 = x2 -. x1) (* check no allocation between x1 and x2 *) [@@inline never] let () = f () + + + +(* MPR#7680 *) + +let f () = + let (a,b) = + try (1,2) + with _ -> assert false + in + if a + b = 3 then raise Not_found + +let () = try f (); assert false with Not_found -> () diff --git a/testsuite/tests/asmcomp/hppa.S b/testsuite/tests/asmcomp/hppa.S deleted file mode 100644 index 5f7455b7..00000000 --- a/testsuite/tests/asmcomp/hppa.S +++ /dev/null @@ -1,161 +0,0 @@ -;********************************************************************* -;* * -;* OCaml * -;* * -;* Xavier Leroy, projet Cristal, INRIA Rocquencourt * -;* * -;* Copyright 1996 Institut National de Recherche en Informatique et * -;* en Automatique. All rights reserved. This file is distributed * -;* under the terms of the Q Public License version 1.0. * -;* * -;********************************************************************* - -; Must be preprocessed by cpp - -#ifdef SYS_hpux -#define G(x) x -#define CODESPACE .code -#define CODE_ALIGN 4 -#define EXPORT_CODE(x) .export x, entry, priv_lev=3 -#define STARTPROC .proc ! .callinfo frame=0, no_calls ! .entry -#define ENDPROC .exit ! .procend -#endif - -#ifdef SYS_nextstep -#define G(x) _##x -#define CODESPACE .text -#define CODE_ALIGN 2 -#define EXPORT_CODE(x) .globl x -#define STARTPROC -#define ENDPROC -#endif - -#ifdef SYS_hpux - .space $PRIVATE$ - .subspa $DATA$,quad=1,align=8,access=31 - .subspa $BSS$,quad=1,align=8,access=31,zero,sort=82 - .space $TEXT$ - .subspa $LIT$,quad=0,align=8,access=44 - .subspa $CODE$,quad=0,align=8,access=44,code_only - .import $global$, data - .import $$dyncall, millicode -#endif - - CODESPACE - .align CODE_ALIGN - EXPORT_CODE(G(call_gen_code)) -G(call_gen_code): - STARTPROC - stw %r2,-20(%r30) - ldo 256(%r30), %r30 -; Save the callee-save registers - ldo -32(%r30), %r1 - stws,ma %r3, -4(%r1) - stws,ma %r4, -4(%r1) - stws,ma %r5, -4(%r1) - stws,ma %r6, -4(%r1) - stws,ma %r7, -4(%r1) - stws,ma %r8, -4(%r1) - stws,ma %r9, -4(%r1) - stws,ma %r10, -4(%r1) - stws,ma %r11, -4(%r1) - stws,ma %r12, -4(%r1) - stws,ma %r13, -4(%r1) - stws,ma %r14, -4(%r1) - stws,ma %r15, -4(%r1) - stws,ma %r16, -4(%r1) - stws,ma %r17, -4(%r1) - stws,ma %r18, -4(%r1) - fstds,ma %fr12, -8(%r1) - fstds,ma %fr13, -8(%r1) - fstds,ma %fr14, -8(%r1) - fstds,ma %fr15, -8(%r1) - fstds,ma %fr16, -8(%r1) - fstds,ma %fr17, -8(%r1) - fstds,ma %fr18, -8(%r1) - fstds,ma %fr19, -8(%r1) - fstds,ma %fr20, -8(%r1) - fstds,ma %fr21, -8(%r1) - fstds,ma %fr22, -8(%r1) - fstds,ma %fr23, -8(%r1) - fstds,ma %fr24, -8(%r1) - fstds,ma %fr25, -8(%r1) - fstds,ma %fr26, -8(%r1) - fstds,ma %fr27, -8(%r1) - fstds,ma %fr28, -8(%r1) - fstds,ma %fr29, -8(%r1) - fstds,ma %fr30, -8(%r1) - fstds,ma %fr31, -8(%r1) - -; Shuffle the arguments and call - copy %r26, %r22 - copy %r25, %r26 - copy %r24, %r25 - copy %r23, %r24 - fcpy,dbl %fr5, %fr4 -#ifdef SYS_hpux - bl $$dyncall, %r2 - nop -#else - ble 0(4, %r22) - copy %r31, %r2 -#endif -; Shuffle the results - copy %r26, %r28 -; Restore the callee-save registers - ldo -32(%r30), %r1 - ldws,ma -4(%r1), %r3 - ldws,ma -4(%r1), %r4 - ldws,ma -4(%r1), %r5 - ldws,ma -4(%r1), %r6 - ldws,ma -4(%r1), %r7 - ldws,ma -4(%r1), %r8 - ldws,ma -4(%r1), %r9 - ldws,ma -4(%r1), %r10 - ldws,ma -4(%r1), %r11 - ldws,ma -4(%r1), %r12 - ldws,ma -4(%r1), %r13 - ldws,ma -4(%r1), %r14 - ldws,ma -4(%r1), %r15 - ldws,ma -4(%r1), %r16 - ldws,ma -4(%r1), %r17 - ldws,ma -4(%r1), %r18 - fldds,ma -8(%r1), %fr12 - fldds,ma -8(%r1), %fr13 - fldds,ma -8(%r1), %fr14 - fldds,ma -8(%r1), %fr15 - fldds,ma -8(%r1), %fr16 - fldds,ma -8(%r1), %fr17 - fldds,ma -8(%r1), %fr18 - fldds,ma -8(%r1), %fr19 - fldds,ma -8(%r1), %fr20 - fldds,ma -8(%r1), %fr21 - fldds,ma -8(%r1), %fr22 - fldds,ma -8(%r1), %fr23 - fldds,ma -8(%r1), %fr24 - fldds,ma -8(%r1), %fr25 - fldds,ma -8(%r1), %fr26 - fldds,ma -8(%r1), %fr27 - fldds,ma -8(%r1), %fr28 - fldds,ma -8(%r1), %fr29 - fldds,ma -8(%r1), %fr30 - fldds,ma -8(%r1), %fr31 - - ldo -256(%r30), %r30 - ldw -20(%r30), %r2 - bv 0(%r2) - nop - ENDPROC - - .align CODE_ALIGN - EXPORT_CODE(caml_c_call) -G(caml_c_call): - STARTPROC -#ifdef SYS_hpux - bl $$dyncall, %r0 - nop -#else - bv 0(%r22) - nop -#endif - ENDPROC diff --git a/testsuite/tests/asmcomp/i386.S b/testsuite/tests/asmcomp/i386.S deleted file mode 100644 index 6da92f2a..00000000 --- a/testsuite/tests/asmcomp/i386.S +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -/* Linux with ELF binaries does not prefix identifiers with _. - Linux with a.out binaries, FreeBSD, and NextStep do. */ - -#if defined(SYS_linux_elf) || defined(SYS_bsd_elf) \ - || defined(SYS_solaris) || defined(SYS_beos) || defined(SYS_gnu) -#define G(x) x -#define FUNCTION_ALIGN 16 -#else -#define G(x) _##x -#define FUNCTION_ALIGN 4 -#endif - - .globl G(call_gen_code) - .align FUNCTION_ALIGN -G(call_gen_code): - pushl %ebp - movl %esp,%ebp - pushl %ebx - pushl %esi - pushl %edi - movl 12(%ebp),%eax - movl 16(%ebp),%ebx - movl 20(%ebp),%ecx - movl 24(%ebp),%edx - call *8(%ebp) - popl %edi - popl %esi - popl %ebx - popl %ebp - ret - - .globl G(caml_c_call) - .align FUNCTION_ALIGN -G(caml_c_call): - ffree %st(0) - ffree %st(1) - ffree %st(2) - ffree %st(3) - jmp *%eax - - .comm G(caml_exception_pointer), 4 - .comm G(young_ptr), 4 - .comm G(young_start), 4 diff --git a/testsuite/tests/asmcomp/ia64.S b/testsuite/tests/asmcomp/ia64.S deleted file mode 100644 index 5c325942..00000000 --- a/testsuite/tests/asmcomp/ia64.S +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -#define ST8OFF(a,b,d) st8 [a] = b, d -#define LD8OFF(a,b,d) ld8 a = [b], d -#define STFDOFF(a,b,d) stfd [a] = b, d -#define LDFDOFF(a,b,d) ldfd a = [b], d -#define STFSPILLOFF(a,b,d) stf.spill [a] = b, d -#define LDFFILLOFF(a,b,d) ldf.fill a = [b], d - - .text - .align 16 - - .global call_gen_code# - .proc call_gen_code# - -call_gen_code: - /* Allocate 64 "out" registers (for the OCaml code) and no locals */ - alloc r3 = ar.pfs, 0, 0, 64, 0 - - /* Save PFS, return address and GP on stack */ - add sp = -368, sp ;; - add r2 = 16, sp ;; - ST8OFF(r2,r3,8) ;; - mov r3 = b0 ;; - ST8OFF(r2,r3,8) ;; - ST8OFF(r2,gp,8) ;; - - /* Save predicates on stack */ - mov r3 = pr ;; - st8 [r2] = r3 - - /* Save callee-save floating-point registers on stack */ - add r2 = 48, sp - add r3 = 64, sp ;; - STFSPILLOFF(r2,f2,16) ;; - STFSPILLOFF(r3,f3,16) ;; - STFSPILLOFF(r2,f4,16) ;; - STFSPILLOFF(r3,f5,16) ;; - STFSPILLOFF(r2,f16,16) ;; - STFSPILLOFF(r3,f17,16) ;; - STFSPILLOFF(r2,f18,16) ;; - STFSPILLOFF(r3,f19,16) ;; - STFSPILLOFF(r2,f20,16) ;; - STFSPILLOFF(r3,f21,16) ;; - STFSPILLOFF(r2,f22,16) ;; - STFSPILLOFF(r3,f23,16) ;; - STFSPILLOFF(r2,f24,16) ;; - STFSPILLOFF(r3,f25,16) ;; - STFSPILLOFF(r2,f26,16) ;; - STFSPILLOFF(r3,f27,16) ;; - STFSPILLOFF(r2,f28,16) ;; - STFSPILLOFF(r3,f29,16) ;; - STFSPILLOFF(r2,f30,16) ;; - STFSPILLOFF(r3,f31,16) ;; - - /* Recover entry point and gp from the function pointer in in0 */ - LD8OFF(r2,r32,8) ;; - ld8 r3 = [r32] ;; - mov b6 = r2 - mov gp = r3 ;; - - /* Shift arguments r33 ... r35 to r32 ... r34 */ - mov r32 = r33 - mov r33 = r34 - mov r34 = r35 - - /* Do the call */ - br.call.sptk b0 = b6 ;; - - /* Restore the saved floating-point registers */ - add r2 = 48, sp - add r3 = 64, sp ;; - LDFFILLOFF(f2,r2,16) ;; - LDFFILLOFF(f3,r3,16) ;; - LDFFILLOFF(f4,r2,16) ;; - LDFFILLOFF(f5,r3,16) ;; - LDFFILLOFF(f16,r2,16) ;; - LDFFILLOFF(f17,r3,16) ;; - LDFFILLOFF(f18,r2,16) ;; - LDFFILLOFF(f19,r3,16) ;; - LDFFILLOFF(f20,r2,16) ;; - LDFFILLOFF(f21,r3,16) ;; - LDFFILLOFF(f22,r2,16) ;; - LDFFILLOFF(f23,r3,16) ;; - LDFFILLOFF(f24,r2,16) ;; - LDFFILLOFF(f25,r3,16) ;; - LDFFILLOFF(f26,r2,16) ;; - LDFFILLOFF(f27,r3,16) ;; - LDFFILLOFF(f28,r2,16) ;; - LDFFILLOFF(f29,r3,16) ;; - LDFFILLOFF(f30,r2,16) ;; - LDFFILLOFF(f31,r3,16) ;; - - /* Restore gp, predicates and return */ - add r2 = 16, sp ;; - LD8OFF(r3,r2,8) ;; - mov ar.pfs = r3 - LD8OFF(r3,r2,8) ;; - mov b0 = r3 - LD8OFF(gp,r2,8) ;; - LD8OFF(r3,r2,8) ;; - mov pr = r3, -1 - - br.ret.sptk.many b0 ;; - - .endp call_gen_code# diff --git a/testsuite/tests/asmcomp/is_static.ml b/testsuite/tests/asmcomp/is_static.ml index bedc033d..60263692 100644 --- a/testsuite/tests/asmcomp/is_static.ml +++ b/testsuite/tests/asmcomp/is_static.ml @@ -1,3 +1,8 @@ +(* TEST + modules = "is_in_static_data.c" + * native +*) + (* Data that should be statically allocated by the compiler (all versions) *) external is_in_static_data : 'a -> bool = "caml_is_in_static_data" diff --git a/testsuite/tests/asmcomp/is_static_flambda.ml b/testsuite/tests/asmcomp/is_static_flambda.ml index 94e0519b..de395c69 100644 --- a/testsuite/tests/asmcomp/is_static_flambda.ml +++ b/testsuite/tests/asmcomp/is_static_flambda.ml @@ -1,3 +1,9 @@ +(* TEST + modules = "is_in_static_data.c is_static_flambda_dep.ml" + * flambda + ** native +*) + (* Data that should be statically allocated by the compiler (flambda only) *) external is_in_static_data : 'a -> bool = "caml_is_in_static_data" @@ -185,7 +191,7 @@ module Int = struct type t = int let compare (a:int) b = compare a b end -module IntMap = (Map.Make [@inlined])(Int) +module IntMap = Map.Make (Int) let () = let f () = diff --git a/testsuite/tests/asmcomp/lexcmm.mll b/testsuite/tests/asmcomp/lexcmm.mll deleted file mode 100644 index a946f6aa..00000000 --- a/testsuite/tests/asmcomp/lexcmm.mll +++ /dev/null @@ -1,241 +0,0 @@ -{ -open Parsecmm - -type error = - Illegal_character - | Unterminated_comment - | Unterminated_string - -exception Error of error - -(* For nested comments *) - -let comment_depth = ref 0 - -(* The table of keywords *) - -let keyword_table = - Misc.create_hashtable 149 [ - "absf", ABSF; - "addr", ADDR; - "align", ALIGN; - "alloc", ALLOC; - "and", AND; - "app", APPLY; - "assign", ASSIGN; - "byte", BYTE; - "case", CASE; - "catch", CATCH; - "checkbound", CHECKBOUND; - "data", DATA; - "exit", EXIT; - "extcall", EXTCALL; - "float", FLOAT; - "float32", FLOAT32; - "float64", FLOAT64; - "floatofint", FLOATOFINT; - "function", FUNCTION; - "global", GLOBAL; - "half", HALF; - "if", IF; - "int", INT; - "int32", INT32; - "intoffloat", INTOFFLOAT; - "string", KSTRING; - "let", LET; - "load", LOAD; - "mod", MODI; - "mulh", MULH; - "or", OR; - "proj", PROJ; - "raise_withtrace", RAISE Cmm.Raise_withtrace; - "raise_notrace", RAISE Cmm.Raise_notrace; - "seq", SEQ; - "signed", SIGNED; - "skip", SKIP; - "store", STORE; - "switch", SWITCH; - "try", TRY; - "unit", UNIT; - "unsigned", UNSIGNED; - "val", VAL; - "while", WHILE; - "with", WITH; - "xor", XOR; - "addraref", ADDRAREF; - "intaref", INTAREF; - "floataref", FLOATAREF; - "addraset", ADDRASET; - "intaset", INTASET; - "floataset", FLOATASET -] - -(* To buffer string literals *) - -let initial_string_buffer = Bytes.create 256 -let string_buff = ref initial_string_buffer -let string_index = ref 0 - -let reset_string_buffer () = - string_buff := initial_string_buffer; - string_index := 0 - -let store_string_char c = - if !string_index >= Bytes.length (!string_buff) then begin - let new_buff = Bytes.create (Bytes.length (!string_buff) * 2) in - Bytes.blit (!string_buff) 0 new_buff 0 (Bytes.length (!string_buff)); - string_buff := new_buff - end; - Bytes.unsafe_set (!string_buff) (!string_index) c; - incr string_index - -let get_stored_string () = - let s = Bytes.sub_string (!string_buff) 0 (!string_index) in - string_buff := initial_string_buffer; - s - -(* To translate escape sequences *) - -let char_for_backslash = function - 'n' -> '\010' - | 'r' -> '\013' - | 'b' -> '\008' - | 't' -> '\009' - | c -> c - -let char_for_decimal_code lexbuf i = - Char.chr(100 * (Char.code(Lexing.lexeme_char lexbuf i) - 48) + - 10 * (Char.code(Lexing.lexeme_char lexbuf (i+1)) - 48) + - (Char.code(Lexing.lexeme_char lexbuf (i+2)) - 48)) - -(* Error report *) - -let report_error lexbuf msg = - prerr_string "Lexical error around character "; - prerr_int (Lexing.lexeme_start lexbuf); - match msg with - Illegal_character -> - prerr_string ": illegal character" - | Unterminated_comment -> - prerr_string ": unterminated comment" - | Unterminated_string -> - prerr_string ": unterminated string" - -} - -let newline = ('\013'* '\010') - -rule token = parse - newline - { Lexing.new_line lexbuf; token lexbuf } - | [' ' '\009' '\012'] + - { token lexbuf } - | "+a" { ADDA } - | "+v" { ADDV } - | "+f" { ADDF } - | "+" { ADDI } - | ">>s" { ASR } - | ":" { COLON } - | "/f" { DIVF } - | "/" { DIVI } - | eof { EOF } - | "==a" { EQA } - | "==f" { EQF } - | "==" { EQI } - | ">=a" { GEA } - | ">=f" { GEF } - | ">=" { GEI } - | ">a" { GTA } - | ">f" { GTF } - | ">" { GTI } - | "[" { LBRACKET } - | "<=a" { LEA } - | "<=f" { LEF } - | "<=" { LEI } - | "(" { LPAREN } - | "<<" { LSL } - | ">>u" { LSR } - | " - IDENT s } - | "\"" - { reset_string_buffer(); - string lexbuf; - STRING (get_stored_string()) } - | "(*" - { comment_depth := 1; - comment lexbuf; - token lexbuf } - | '{' ['A' - 'Z' 'a'-'z' '/' ',' '.' '-' '_' ' ''0'-'9']+ - ':' [ '0'-'9' ]+ ',' ['0'-'9' ]+ '-' ['0'-'9' ]+ '}' - { - let loc_s = Lexing.lexeme lexbuf in - let pos_fname, pos_lnum, start, end_ = - Scanf.sscanf loc_s "{%s@:%i,%i-%i}" (fun file line start end_ -> - (file, line, start, end_)) - in - let loc_start = - Lexing.{ pos_fname; pos_lnum; pos_bol = 0; pos_cnum = start } - in - let loc_end = - Lexing.{ pos_fname; pos_lnum; pos_bol = 0; pos_cnum = end_ } - in - let location = Location.{ loc_start; loc_end; loc_ghost = false } in - LOCATION location } - | _ { raise(Error(Illegal_character)) } - -and comment = parse - "(*" - { comment_depth := succ !comment_depth; comment lexbuf } - | "*)" - { comment_depth := pred !comment_depth; - if !comment_depth > 0 then comment lexbuf } - | eof - { raise (Error(Unterminated_comment)) } - | newline - { Lexing.new_line lexbuf; comment lexbuf } - | _ - { comment lexbuf } - -and string = parse - '"' - { () } - | '\\' [' ' '\010' '\013' '\009' '\026' '\012'] + - { string lexbuf } - | '\\' ['\\' '"' 'n' 't' 'b' 'r'] - { store_string_char(char_for_backslash(Lexing.lexeme_char lexbuf 1)); - string lexbuf } - | '\\' ['0'-'9'] ['0'-'9'] ['0'-'9'] - { store_string_char(char_for_decimal_code lexbuf 1); - string lexbuf } - | eof - { raise (Error(Unterminated_string)) } - | _ - { store_string_char(Lexing.lexeme_char lexbuf 0); - string lexbuf } - diff --git a/testsuite/tests/asmcomp/m68k.S b/testsuite/tests/asmcomp/m68k.S deleted file mode 100644 index 4d0f6a3a..00000000 --- a/testsuite/tests/asmcomp/m68k.S +++ /dev/null @@ -1,57 +0,0 @@ -|*********************************************************************** -|* * -|* OCaml * -|* * -|* Xavier Leroy, projet Cristal, INRIA Rocquencourt * -|* * -|* Copyright 1996 Institut National de Recherche en Informatique et * -|* en Automatique. All rights reserved. This file is distributed * -|* under the terms of the Q Public License version 1.0. * -|* * -|*********************************************************************** - -| call_gen_code is used with the following types: -| unit -> int -| int -> int -| int -> double -| int * int * address -> void -| int * int -> void -| unit -> unit -| Hence arg1 -> d0, arg2 -> d1, arg3 -> a0, -| and we need a special case for int -> double - - .text - .globl _call_gen_code -_call_gen_code: - link a6, #0 - movem d2-d7/a2-a6, a7@- - fmovem fp2-fp7, a7@- - movel a6@(8), a1 - movel a6@(12), d0 - movel a6@(16), d1 - movel a6@(20), a0 - jsr a1@ - fmovem a7@+, fp2-fp7 - movem a7@+, d2-d7/a2-a6 - unlk a6 - rts - - .globl _call_gen_code_float -_call_gen_code_float: - link a6, #0 - moveml d2-d7/a2-a6, a7@- - fmovem fp2-fp7, a7@- - movel a6@(8), a1 - movel a6@(12), d0 - jsr a1@ - fmoved fp0, a7@- - movel a7@+, d0 - movel a7@+, d1 - fmovem a7@+, fp2-fp7 - moveml a7@+, d2-d7/a2-a6 - unlk a6 - rts - - .globl _caml_c_call -_caml_c_call: - jmp a0@ diff --git a/testsuite/tests/asmcomp/mips.s b/testsuite/tests/asmcomp/mips.s deleted file mode 100644 index 1549dc0a..00000000 --- a/testsuite/tests/asmcomp/mips.s +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - - .globl call_gen_code - .ent call_gen_code -call_gen_code: - subu $sp, $sp, 0x90 - sd $31, 0x88($sp) - /* Save all callee-save registers */ - sd $16, 0x0($sp) - sd $17, 0x8($sp) - sd $18, 0x10($sp) - sd $19, 0x18($sp) - sd $20, 0x20($sp) - sd $21, 0x28($sp) - sd $22, 0x30($sp) - sd $23, 0x38($sp) - sd $30, 0x40($sp) - s.d $f20, 0x48($sp) - s.d $f22, 0x50($sp) - s.d $f24, 0x58($sp) - s.d $f26, 0x60($sp) - s.d $f28, 0x68($sp) - s.d $f30, 0x70($sp) - /* Shuffle arguments */ - move $8, $5 - move $9, $6 - move $10, $7 - move $25, $4 - jal $4 - /* Restore registers */ - ld $31, 0x88($sp) - ld $16, 0x0($sp) - ld $17, 0x8($sp) - ld $18, 0x10($sp) - ld $19, 0x18($sp) - ld $20, 0x20($sp) - ld $21, 0x28($sp) - ld $22, 0x30($sp) - ld $23, 0x38($sp) - ld $30, 0x40($sp) - l.d $f20, 0x48($sp) - l.d $f22, 0x50($sp) - l.d $f24, 0x58($sp) - l.d $f26, 0x60($sp) - l.d $f28, 0x68($sp) - l.d $f30, 0x70($sp) - addu $sp, $sp, 0x90 - j $31 - - .end call_gen_code - -/* Call a C function */ - - .globl caml_c_call - .ent caml_c_call -caml_c_call: - move $25, $24 - j $24 - .end caml_c_call diff --git a/testsuite/tests/asmcomp/ocamltests b/testsuite/tests/asmcomp/ocamltests new file mode 100644 index 00000000..bcd126df --- /dev/null +++ b/testsuite/tests/asmcomp/ocamltests @@ -0,0 +1,11 @@ +bind_tuples.ml +is_static_flambda.ml +is_static.ml +optargs.ml +register_typing.ml +register_typing_switch.ml +staticalloc.ml +static_float_array_flambda.ml +static_float_array_flambda_opaque.ml +unrolling_flambda2.ml +unrolling_flambda.ml diff --git a/testsuite/tests/asmcomp/optargs.ml b/testsuite/tests/asmcomp/optargs.ml index a4f40407..ccc27dcb 100644 --- a/testsuite/tests/asmcomp/optargs.ml +++ b/testsuite/tests/asmcomp/optargs.ml @@ -1,3 +1,9 @@ +(* TEST + flags = "-g" + compare_programs = "false" + * native +*) + (* Check the effectiveness of inlining the wrapper which fills in default values for optional arguments. diff --git a/testsuite/tests/asmcomp/parsecmm.mly b/testsuite/tests/asmcomp/parsecmm.mly deleted file mode 100644 index 52a6dfad..00000000 --- a/testsuite/tests/asmcomp/parsecmm.mly +++ /dev/null @@ -1,359 +0,0 @@ -/* A simple parser for C-- */ - -%{ -open Cmm -open Parsecmmaux - -let rec make_letdef def body = - match def with - [] -> body - | (id, def) :: rem -> - unbind_ident id; - Clet(id, def, make_letdef rem body) - -let make_switch n selector caselist = - let index = Array.make n 0 in - let casev = Array.of_list caselist in - let actv = Array.make (Array.length casev) (Cexit(0,[])) in - for i = 0 to Array.length casev - 1 do - let (posl, e) = casev.(i) in - List.iter (fun pos -> index.(pos) <- i) posl; - actv.(i) <- e - done; - Cswitch(selector, index, actv, Debuginfo.none) - -let access_array base numelt size = - match numelt with - Cconst_int 0 -> base - | Cconst_int n -> Cop(Cadda, [base; Cconst_int(n * size)], Debuginfo.none) - | _ -> Cop(Cadda, [base; - Cop(Clsl, [numelt; Cconst_int(Misc.log2 size)], - Debuginfo.none)], - Debuginfo.none) - -%} - -%token ABSF -%token ADDA -%token ADDF -%token ADDI -%token ADDV -%token ADDR -%token ALIGN -%token ALLOC -%token AND -%token APPLY -%token ASR -%token ASSIGN -%token BYTE -%token CASE -%token CATCH -%token CHECKBOUND -%token COLON -%token DATA -%token DIVF -%token DIVI -%token EOF -%token EQA -%token EQF -%token EQI -%token EXIT -%token EXTCALL -%token FLOAT -%token FLOAT32 -%token FLOAT64 -%token FLOATCONST -%token FLOATOFINT -%token FUNCTION -%token GEA -%token GEF -%token GEI -%token GLOBAL -%token GTA -%token GTF -%token GTI -%token HALF -%token IDENT -%token IF -%token INT -%token INT32 -%token INTCONST -%token INTOFFLOAT -%token KSTRING -%token LBRACKET -%token LEA -%token LEF -%token LEI -%token LET -%token LOAD -%token LOCATION -%token LPAREN -%token LSL -%token LSR -%token LTA -%token LTF -%token LTI -%token MODI -%token MULF -%token MULH -%token MULI -%token NEA -%token NEF -%token NEI -%token OR -%token POINTER -%token PROJ -%token RAISE -%token RBRACKET -%token RPAREN -%token SEQ -%token SIGNED -%token SKIP -%token STAR -%token STORE -%token STRING -%token SUBF -%token SUBI -%token SWITCH -%token TRY -%token UNIT -%token UNSIGNED -%token VAL -%token WHILE -%token WITH -%token XOR -%token ADDRAREF -%token INTAREF -%token FLOATAREF -%token ADDRASET -%token INTASET -%token FLOATASET - -%start phrase -%type phrase - -%% - -phrase: - fundecl { Cfunction $1 } - | datadecl { Cdata $1 } - | EOF { raise End_of_file } -; -fundecl: - LPAREN FUNCTION fun_name LPAREN params RPAREN sequence RPAREN - { List.iter (fun (id, ty) -> unbind_ident id) $5; - {fun_name = $3; fun_args = $5; fun_body = $7; fun_fast = true; - fun_dbg = debuginfo ()} } -; -fun_name: - STRING { $1 } - | IDENT { $1 } -params: - oneparam params { $1 :: $2 } - | /**/ { [] } -; -oneparam: - IDENT COLON machtype { (bind_ident $1, $3) } -; -machtype: - UNIT { [||] } - | componentlist { Array.of_list(List.rev $1) } -; -component: - VAL { Val } - | ADDR { Addr } - | INT { Int } - | FLOAT { Float } -; -componentlist: - component { [$1] } - | componentlist STAR component { $3 :: $1 } -; -expr: - INTCONST { Cconst_int $1 } - | FLOATCONST { Cconst_float (float_of_string $1) } - | STRING { Cconst_symbol $1 } - | POINTER { Cconst_pointer $1 } - | IDENT { Cvar(find_ident $1) } - | LBRACKET RBRACKET { Ctuple [] } - | LPAREN LET letdef sequence RPAREN { make_letdef $3 $4 } - | LPAREN ASSIGN IDENT expr RPAREN { Cassign(find_ident $3, $4) } - | LPAREN APPLY location expr exprlist machtype RPAREN - { Cop(Capply $6, $4 :: List.rev $5, debuginfo ?loc:$3 ()) } - | LPAREN EXTCALL STRING exprlist machtype RPAREN - {Cop(Cextcall($3, $5, false, None), List.rev $4, debuginfo ())} - | LPAREN ALLOC exprlist RPAREN { Cop(Calloc, List.rev $3, debuginfo ()) } - | LPAREN SUBF expr RPAREN { Cop(Cnegf, [$3], debuginfo ()) } - | LPAREN SUBF expr expr RPAREN { Cop(Csubf, [$3; $4], debuginfo ()) } - | LPAREN unaryop expr RPAREN { Cop($2, [$3], debuginfo ()) } - | LPAREN binaryop expr expr RPAREN { Cop($2, [$3; $4], debuginfo ()) } - | LPAREN SEQ sequence RPAREN { $3 } - | LPAREN IF expr expr expr RPAREN { Cifthenelse($3, $4, $5) } - | LPAREN SWITCH INTCONST expr caselist RPAREN { make_switch $3 $4 $5 } - | LPAREN WHILE expr sequence RPAREN - { let body = - match $3 with - Cconst_int x when x <> 0 -> $4 - | _ -> Cifthenelse($3, $4, (Cexit(0,[]))) in - Ccatch(Recursive, [0, [], Cloop body], Ctuple []) } - | LPAREN EXIT IDENT exprlist RPAREN - { Cexit(find_label $3, List.rev $4) } - | LPAREN CATCH sequence WITH catch_handlers RPAREN - { let handlers = $5 in - List.iter (fun (_, l, _) -> List.iter unbind_ident l) handlers; - Ccatch(Recursive, handlers, $3) } - | EXIT { Cexit(0,[]) } - | LPAREN TRY sequence WITH bind_ident sequence RPAREN - { unbind_ident $5; Ctrywith($3, $5, $6) } - | LPAREN VAL expr expr RPAREN - { Cop(Cload (Word_val, Mutable), [access_array $3 $4 Arch.size_addr], - debuginfo ()) } - | LPAREN ADDRAREF expr expr RPAREN - { Cop(Cload (Word_val, Mutable), [access_array $3 $4 Arch.size_addr], - Debuginfo.none) } - | LPAREN INTAREF expr expr RPAREN - { Cop(Cload (Word_int, Mutable), [access_array $3 $4 Arch.size_int], - Debuginfo.none) } - | LPAREN FLOATAREF expr expr RPAREN - { Cop(Cload (Double_u, Mutable), [access_array $3 $4 Arch.size_float], - Debuginfo.none) } - | LPAREN ADDRASET expr expr expr RPAREN - { Cop(Cstore (Word_val, Assignment), - [access_array $3 $4 Arch.size_addr; $5], Debuginfo.none) } - | LPAREN INTASET expr expr expr RPAREN - { Cop(Cstore (Word_int, Assignment), - [access_array $3 $4 Arch.size_int; $5], Debuginfo.none) } - | LPAREN FLOATASET expr expr expr RPAREN - { Cop(Cstore (Double_u, Assignment), - [access_array $3 $4 Arch.size_float; $5], Debuginfo.none) } -; -exprlist: - exprlist expr { $2 :: $1 } - | /**/ { [] } -; -letdef: - oneletdef { [$1] } - | LPAREN letdefmult RPAREN { $2 } -; -letdefmult: - /**/ { [] } - | oneletdef letdefmult { $1 :: $2 } -; -oneletdef: - IDENT expr { (bind_ident $1, $2) } -; -chunk: - UNSIGNED BYTE { Byte_unsigned } - | SIGNED BYTE { Byte_signed } - | UNSIGNED HALF { Sixteen_unsigned } - | SIGNED HALF { Sixteen_signed } - | UNSIGNED INT32 { Thirtytwo_unsigned } - | SIGNED INT32 { Thirtytwo_signed } - | INT { Word_int } - | ADDR { Word_val } - | FLOAT32 { Single } - | FLOAT64 { Double } - | FLOAT { Double_u } - | VAL { Word_val } -; -unaryop: - LOAD chunk { Cload ($2, Mutable) } - | FLOATOFINT { Cfloatofint } - | INTOFFLOAT { Cintoffloat } - | RAISE { Craise $1 } - | ABSF { Cabsf } -; -binaryop: - STORE chunk { Cstore ($2, Assignment) } - | ADDI { Caddi } - | SUBI { Csubi } - | STAR { Cmuli } - | DIVI { Cdivi } - | MODI { Cmodi } - | AND { Cand } - | OR { Cor } - | XOR { Cxor } - | LSL { Clsl } - | LSR { Clsr } - | ASR { Casr } - | EQI { Ccmpi Ceq } - | NEI { Ccmpi Cne } - | LTI { Ccmpi Clt } - | LEI { Ccmpi Cle } - | GTI { Ccmpi Cgt } - | GEI { Ccmpi Cge } - | ADDA { Cadda } - | ADDV { Caddv } - | EQA { Ccmpa Ceq } - | NEA { Ccmpa Cne } - | LTA { Ccmpa Clt } - | LEA { Ccmpa Cle } - | GTA { Ccmpa Cgt } - | GEA { Ccmpa Cge } - | ADDF { Caddf } - | MULF { Cmulf } - | DIVF { Cdivf } - | EQF { Ccmpf Ceq } - | NEF { Ccmpf Cne } - | LTF { Ccmpf Clt } - | LEF { Ccmpf Cle } - | GTF { Ccmpf Cgt } - | GEF { Ccmpf Cge } - | CHECKBOUND { Ccheckbound } - | MULH { Cmulhi } -; -sequence: - expr sequence { Csequence($1, $2) } - | expr { $1 } -; -caselist: - onecase sequence caselist { ($1, $2) :: $3 } - | /**/ { [] } -; -onecase: - CASE INTCONST COLON onecase { $2 :: $4 } - | CASE INTCONST COLON { [$2] } -; -bind_ident: - IDENT { bind_ident $1 } -; -datadecl: - LPAREN datalist RPAREN { List.rev $2 } - | LPAREN DATA datalist RPAREN { List.rev $3 } -; -datalist: - datalist dataitem { $2 :: $1 } - | /**/ { [] } -; -dataitem: - STRING COLON { Cdefine_symbol $1 } - | BYTE INTCONST { Cint8 $2 } - | HALF INTCONST { Cint16 $2 } - | INT INTCONST { Cint(Nativeint.of_int $2) } - | FLOAT FLOATCONST { Cdouble (float_of_string $2) } - | ADDR STRING { Csymbol_address $2 } - | VAL STRING { Csymbol_address $2 } - | KSTRING STRING { Cstring $2 } - | SKIP INTCONST { Cskip $2 } - | ALIGN INTCONST { Calign $2 } - | GLOBAL STRING { Cglobal_symbol $2 } -; -catch_handlers: - | catch_handler - { [$1] } - | catch_handler AND catch_handlers - { $1 :: $3 } - -catch_handler: - | sequence - { 0, [], $1 } - | LPAREN IDENT bind_identlist RPAREN sequence - { find_label $2, $3, $5 } - -bind_identlist: - /**/ { [] } - | bind_ident bind_identlist { $1 :: $2 } - -location: - /**/ { None } - | LOCATION { Some $1 } diff --git a/testsuite/tests/asmcomp/power.S b/testsuite/tests/asmcomp/power.S deleted file mode 100644 index d13035a4..00000000 --- a/testsuite/tests/asmcomp/power.S +++ /dev/null @@ -1,197 +0,0 @@ -/*********************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. All rights reserved. This file is distributed */ -/* under the terms of the Q Public License version 1.0. */ -/* */ -/*********************************************************************/ - -#if defined(MODEL_ppc64) || defined(MODEL_ppc64le) -#define EITHER(a,b) b -#else -#define EITHER(a,b) a -#endif - -#define WORD EITHER(4,8) -#define lg EITHER(lwz,ld) -#define lgu EITHER(lwzu,ldu) -#define stg EITHER(stw,std) -#define stgu EITHER(stwu,stdu) - -#if defined(MODEL_ppc) -#define RESERVED_STACK 16 -#define LR_SAVE_AREA 4 -#endif -#if defined(MODEL_ppc64) -#define RESERVED_STACK 48 -#define LR_SAVE_AREA 16 -#endif -#if defined(MODEL_ppc64le) -#define RESERVED_STACK 32 -#define LR_SAVE_AREA 16 -#endif - -/* Function definitions */ - -#if defined(MODEL_ppc) -#define FUNCTION(name) \ - .section ".text"; \ - .globl name; \ - .type name, @function; \ - .align 2; \ - name: -#endif - -#if defined(MODEL_ppc64) -#define FUNCTION(name) \ - .section ".opd","aw"; \ - .align 3; \ - .globl name; \ - .type name, @function; \ - name: .quad .L.name,.TOC.@tocbase; \ - .text; \ - .align 2; \ - .L.name: -#endif - -#if defined(MODEL_ppc64le) -#define FUNCTION(name) \ - .section ".text"; \ - .globl name; \ - .type name, @function; \ - .align 2; \ - name: ; \ - 0: addis 2, 12, (.TOC. - 0b)@ha; \ - addi 2, 2, (.TOC. - 0b)@l; \ - .localentry name, . - 0b -#endif - -FUNCTION(call_gen_code) - /* Allocate and link stack frame */ - stgu 1, -(WORD*18 + 8*18 + RESERVED_STACK)(1) - /* 18 saved GPRs, 18 saved FPRs */ - /* Save return address */ - mflr 0 - stg 0, (WORD*18 + 8*18 + RESERVED_STACK + LR_SAVE_AREA)(1) - /* Save all callee-save registers, starting at RESERVED_STACK */ - addi 11, 1, RESERVED_STACK - WORD - stgu 14, WORD(11) - stgu 15, WORD(11) - stgu 16, WORD(11) - stgu 17, WORD(11) - stgu 18, WORD(11) - stgu 19, WORD(11) - stgu 20, WORD(11) - stgu 21, WORD(11) - stgu 22, WORD(11) - stgu 23, WORD(11) - stgu 24, WORD(11) - stgu 25, WORD(11) - stgu 26, WORD(11) - stgu 27, WORD(11) - stgu 28, WORD(11) - stgu 29, WORD(11) - stgu 30, WORD(11) - stgu 31, WORD(11) - stfdu 14, 8(11) - stfdu 15, 8(11) - stfdu 16, 8(11) - stfdu 17, 8(11) - stfdu 18, 8(11) - stfdu 19, 8(11) - stfdu 20, 8(11) - stfdu 21, 8(11) - stfdu 22, 8(11) - stfdu 23, 8(11) - stfdu 24, 8(11) - stfdu 25, 8(11) - stfdu 26, 8(11) - stfdu 27, 8(11) - stfdu 28, 8(11) - stfdu 29, 8(11) - stfdu 30, 8(11) - stfdu 31, 8(11) - /* Get function pointer in CTR */ -#if defined(MODEL_ppc) - mtctr 3 -#elif defined(MODEL_ppc64) - ld 0, 0(3) - mtctr 0 - ld 2, 8(3) -#elif defined(MODEL_ppc64le) - mtctr 3 - mr 12, 3 -#else -#error "wrong MODEL" -#endif - /* Shuffle arguments */ - mr 3, 4 - mr 4, 5 - mr 5, 6 - mr 6, 7 - /* Call the function */ - bctrl - /* Restore callee-save registers */ - addi 11, 1, RESERVED_STACK - WORD - lgu 14, WORD(11) - lgu 15, WORD(11) - lgu 16, WORD(11) - lgu 17, WORD(11) - lgu 18, WORD(11) - lgu 19, WORD(11) - lgu 20, WORD(11) - lgu 21, WORD(11) - lgu 22, WORD(11) - lgu 23, WORD(11) - lgu 24, WORD(11) - lgu 25, WORD(11) - lgu 26, WORD(11) - lgu 27, WORD(11) - lgu 28, WORD(11) - lgu 29, WORD(11) - lgu 30, WORD(11) - lgu 31, WORD(11) - lfdu 14, 8(11) - lfdu 15, 8(11) - lfdu 16, 8(11) - lfdu 17, 8(11) - lfdu 18, 8(11) - lfdu 19, 8(11) - lfdu 20, 8(11) - lfdu 21, 8(11) - lfdu 22, 8(11) - lfdu 23, 8(11) - lfdu 24, 8(11) - lfdu 25, 8(11) - lfdu 26, 8(11) - lfdu 27, 8(11) - lfdu 28, 8(11) - lfdu 29, 8(11) - lfdu 30, 8(11) - lfdu 31, 8(11) - /* Reload return address */ - lg 0, (WORD*18 + 8*18 + RESERVED_STACK + LR_SAVE_AREA)(1) - mtlr 0 - /* Return */ - addi 1, 1, (WORD*18 + 8*18 + RESERVED_STACK) - blr - -FUNCTION(caml_c_call) - /* Jump to C function (address in r28) */ -#if defined(MODEL_ppc) - mtctr 28 -#elif defined(MODEL_ppc64) - ld 0, 0(28) - mtctr 0 - ld 2, 8(28) -#elif defined(MODEL_ppc64le) - mtctr 28 - mr 12, 28 -#else -#error "wrong MODEL" -#endif - bctr diff --git a/testsuite/tests/asmcomp/register_typing.ml b/testsuite/tests/asmcomp/register_typing.ml index 9d55d29b..af8501c1 100644 --- a/testsuite/tests/asmcomp/register_typing.ml +++ b/testsuite/tests/asmcomp/register_typing.ml @@ -1,3 +1,7 @@ +(* TEST + * native +*) + type 'a typ = Int : int typ | Ptr : int list typ let f (type a) (t : a typ) (p : int list) : a = diff --git a/testsuite/tests/asmcomp/register_typing_switch.ml b/testsuite/tests/asmcomp/register_typing_switch.ml index 18c4416d..a5cfe3f8 100644 --- a/testsuite/tests/asmcomp/register_typing_switch.ml +++ b/testsuite/tests/asmcomp/register_typing_switch.ml @@ -1,3 +1,7 @@ +(* TEST + * native +*) + type 'a typ = Int : int typ | Ptr : int list typ | Int2 : int typ let f (type a) (t : a typ) (p : int list) : a = diff --git a/testsuite/tests/asmcomp/s390x.S b/testsuite/tests/asmcomp/s390x.S deleted file mode 100644 index d0b4b3c8..00000000 --- a/testsuite/tests/asmcomp/s390x.S +++ /dev/null @@ -1,64 +0,0 @@ -#define ALIGN 8 - -#define CALL_GEN_CODE call_gen_code -#define CAML_C_CALL caml_c_call -#define CAML_NEGF_MASK caml_negf_mask -#define CAML_ABSF_MASK caml_absf_mask - - .section ".text" - - .globl CALL_GEN_CODE - .type CALL_GEN_CODE, @function - .align ALIGN -CALL_GEN_CODE: - /* Stack space */ - lay %r15, -144(%r15) - /* Save registers */ - stmg %r6,%r14, 0(%r15) - std %f8, 72(%r15) - std %f9, 80(%r15) - std %f10, 88(%r15) - std %f11, 96(%r15) - std %f12, 104(%r15) - std %f13, 112(%r15) - std %f14, 120(%r15) - std %f15, 128(%r15) - /* Shuffle args */ - lgr %r1, %r2 - lgr %r2, %r3 - lgr %r3, %r4 - lgr %r4, %r5 - /* Function call */ - basr %r14, %r1 - /* Restore registers */ - lmg %r6,%r14, 0(%r15) - ld %f8, 72(%r15) - ld %f9, 80(%r15) - ld %f10, 88(%r15) - ld %f11, 96(%r15) - ld %f12, 104(%r15) - ld %f13, 112(%r15) - ld %f14, 120(%r15) - ld %f15, 128(%r15) - /* Return */ - lay %r15, 144(%r15) - br %r14 - - .globl CAML_C_CALL - .type CAML_C_CALL, @function - .align ALIGN -CAML_C_CALL: - br %r7 - - .section ".rodata" - - .global CAML_NEGF_MASK - .align ALIGN -CAML_NEGF_MASK: - .quad 0x8000000000000000, 0 - .global CAML_ABSF_MASK - .align ALIGN -CAML_ABSF_MASK: - .quad 0x7FFFFFFFFFFFFFFF, 0 - - .comm young_limit, 8 diff --git a/testsuite/tests/asmcomp/sparc.S b/testsuite/tests/asmcomp/sparc.S deleted file mode 100644 index 5fd797b3..00000000 --- a/testsuite/tests/asmcomp/sparc.S +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************/ -/* */ -/* OCaml */ -/* */ -/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ -/* */ -/* Copyright 1996 Institut National de Recherche en Informatique et */ -/* en Automatique. */ -/* */ -/* All rights reserved. This file is distributed under the terms of */ -/* the GNU Lesser General Public License version 2.1, with the */ -/* special exception on linking described in the file LICENSE. */ -/* */ -/**************************************************************************/ - -#if defined(SYS_solaris) || defined(SYS_linux) -#define Call_gen_code call_gen_code -#define Caml_c_call caml_c_call -#else -#define Call_gen_code _call_gen_code -#define Caml_c_call _caml_c_call -#endif - - .global Call_gen_code -Call_gen_code: - save %sp, -96, %sp - mov %i0, %l0 - mov %i1, %i0 - mov %i2, %i1 - mov %i3, %i2 - mov %i4, %i3 - mov %i5, %i4 - call %l0 - nop - mov %o0, %i0 - ret - restore - - .global Caml_c_call -Caml_c_call: - jmp %g4 - nop diff --git a/testsuite/tests/asmcomp/static_float_array_flambda.ml b/testsuite/tests/asmcomp/static_float_array_flambda.ml index f60e530a..8401ca1e 100644 --- a/testsuite/tests/asmcomp/static_float_array_flambda.ml +++ b/testsuite/tests/asmcomp/static_float_array_flambda.ml @@ -1,3 +1,10 @@ +(* TEST + modules = "is_in_static_data.c simple_float_const.ml" + * flambda + ** flat-float-array + *** native +*) + external is_in_static_data : 'a -> bool = "caml_is_in_static_data" let a = [|0.; 1.|] diff --git a/testsuite/tests/asmcomp/static_float_array_flambda_opaque.ml b/testsuite/tests/asmcomp/static_float_array_flambda_opaque.ml index 518f48bc..63c08c1b 100644 --- a/testsuite/tests/asmcomp/static_float_array_flambda_opaque.ml +++ b/testsuite/tests/asmcomp/static_float_array_flambda_opaque.ml @@ -1,3 +1,11 @@ +(* TEST + modules = "is_in_static_data.c simple_float_const_opaque.ml" + flags = "-opaque" + * flambda + ** flat-float-array + *** native +*) + external is_in_static_data : 'a -> bool = "caml_is_in_static_data" let a = [|0.; 1.|] diff --git a/testsuite/tests/asmcomp/staticalloc.ml b/testsuite/tests/asmcomp/staticalloc.ml index 2e7c9a16..2092ecc6 100644 --- a/testsuite/tests/asmcomp/staticalloc.ml +++ b/testsuite/tests/asmcomp/staticalloc.ml @@ -1,3 +1,9 @@ +(* TEST + include config + * native + flags = "config.cmx" +*) + (* Check the effectiveness of structured constant propagation and static allocation. diff --git a/testsuite/tests/asmcomp/unrolling_flambda.ml b/testsuite/tests/asmcomp/unrolling_flambda.ml index 59dfa2a9..dcfcb033 100644 --- a/testsuite/tests/asmcomp/unrolling_flambda.ml +++ b/testsuite/tests/asmcomp/unrolling_flambda.ml @@ -1,3 +1,7 @@ +(* TEST + * flambda + ** native +*) let rec f x = if x > 0 then f (x - 1) diff --git a/testsuite/tests/asmcomp/unrolling_flambda2.ml b/testsuite/tests/asmcomp/unrolling_flambda2.ml index cccda47d..3079b732 100644 --- a/testsuite/tests/asmcomp/unrolling_flambda2.ml +++ b/testsuite/tests/asmcomp/unrolling_flambda2.ml @@ -1,3 +1,7 @@ +(* TEST + * flambda + ** native +*) type t = { fn : t -> t -> int -> unit -> unit } diff --git a/testsuite/tests/asmgen/Makefile b/testsuite/tests/asmgen/Makefile new file mode 100644 index 00000000..f6d0c238 --- /dev/null +++ b/testsuite/tests/asmgen/Makefile @@ -0,0 +1,122 @@ +#************************************************************************** +#* * +#* OCaml * +#* * +#* Xavier Clerc, SED, INRIA Rocquencourt * +#* * +#* Copyright 2010 Institut National de Recherche en Informatique et * +#* en Automatique. * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +BASEDIR=../.. + +include $(BASEDIR)/../config/Makefile + +INCLUDES=\ + -I $(OTOPDIR)/parsing \ + -I $(OTOPDIR)/utils \ + -I $(OTOPDIR)/typing \ + -I $(OTOPDIR)/middle_end \ + -I $(OTOPDIR)/bytecomp \ + -I $(OTOPDIR)/asmcomp + +OTHEROBJS=\ + $(OTOPDIR)/compilerlibs/ocamlcommon.cma \ + $(OTOPDIR)/compilerlibs/ocamloptcomp.cma + +OBJS=parsecmmaux.cmo parsecmm.cmo lexcmm.cmo + +ADD_COMPFLAGS=$(INCLUDES) -w -40 -g + +default: + @if $(BYTECODE_ONLY) || $(SKIP) ; then $(MAKE) skips ; else \ + $(MAKE) all; \ + fi + +all: + @$(MAKE) arch codegen + @$(MAKE) tests + +main.cmo: parsecmm.cmo + +codegen: parsecmm.ml lexcmm.ml $(OBJS:.cmo=.cmi) $(OBJS) main.cmo + @$(OCAMLC) $(LINKFLAGS) -o codegen $(OTHEROBJS) $(OBJS) main.cmo + +parsecmm.mli parsecmm.ml: parsecmm.mly + @$(OCAMLYACC) -q parsecmm.mly + +lexcmm.ml: lexcmm.mll + @$(OCAMLLEX) -q lexcmm.mll + +CASES=fib tak quicksort quicksort2 soli \ + arith checkbound tagged-fib tagged-integr tagged-quicksort tagged-tak \ + catch-try catch-rec even-odd even-odd-spill pgcd +ARGS_fib=-DINT_INT -DFUN=fib main.c +ARGS_tak=-DUNIT_INT -DFUN=takmain main.c +ARGS_quicksort=-DSORT -DFUN=quicksort main.c +ARGS_quicksort2=-DSORT -DFUN=quicksort main.c +ARGS_soli=-DUNIT_INT -DFUN=solitaire main.c +ARGS_integr=-DINT_FLOAT -DFUN=test main.c +ARGS_arith=mainarith.c +ARGS_checkbound=-DCHECKBOUND main.c +ARGS_tagged-fib=-DINT_INT -DFUN=fib main.c +ARGS_tagged-integr=-DINT_FLOAT -DFUN=test main.c +ARGS_tagged-quicksort=-DSORT -DFUN=quicksort main.c +ARGS_tagged-tak=-DUNIT_INT -DFUN=takmain main.c +ARGS_catch-try=-DINT_INT -DFUN=catch_exit main.c +ARGS_catch-rec=-DINT_INT -DFUN=catch_fact main.c +ARGS_even-odd=-DINT_INT -DFUN=is_even main.c +ARGS_even-odd-spill=-DINT_INT -DFUN=is_even main.c +ARGS_pgcd=-DINT_INT -DFUN=pgcd_30030 main.c + +skips: + @for c in $(CASES); do \ + echo " ... testing '$$c': => skipped"; \ + done + +one: + @$(call CCOMP,$(NAME).out $(ARGS_$(NAME)) $(NAME).$(O) $(ARCH).$(O)) \ + && echo " => passed" || echo " => failed" + +clean: defaultclean + @rm -f ./codegen *.out *.out.manifest *.$(O) *.exe + @rm -f parsecmm.ml parsecmm.mli lexcmm.ml + @rm -f $(CASES:=.s) + +include $(BASEDIR)/makefiles/Makefile.common + +ifeq "$(CCOMPTYPE)-$(ARCH)" "msvc-amd64" +# these tests are not ported to MSVC64 yet +SKIP=true +else +SKIP=false +endif + +ifeq "$(WITH_SPACETIME)" "true" +# These tests have not been ported for Spacetime +SKIP=true +endif + +ifeq ($(CCOMPTYPE),msvc) +CCOMP=set -o pipefail ; $(CC) $(CFLAGS) /Fe$(1) | tail -n +2 +else +CCOMP=$(CC) $(CFLAGS) -o $(1) +endif +tests: $(CASES:=.$(O)) + @for c in $(CASES); do \ + printf " ... testing '$$c':"; \ + $(MAKE) one NAME=$$c; \ + done + +promote: + +arch: $(ARCH).$(O) + +i386.obj: i386nt.asm + @set -o pipefail ; \ + $(ASM) $@ $^ | tail -n +2 diff --git a/testsuite/tests/asmgen/amd64.S b/testsuite/tests/asmgen/amd64.S new file mode 100644 index 00000000..fb87307d --- /dev/null +++ b/testsuite/tests/asmgen/amd64.S @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ +/* */ +/* Copyright 2000 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef SYS_macosx +#define ALIGN 4 +#else +#define ALIGN 16 +#endif + +#ifdef SYS_macosx +#define CALL_GEN_CODE _call_gen_code +#define CAML_C_CALL _caml_c_call +#define CAML_NEGF_MASK _caml_negf_mask +#define CAML_ABSF_MASK _caml_absf_mask +#else +#define CALL_GEN_CODE call_gen_code +#define CAML_C_CALL caml_c_call +#define CAML_NEGF_MASK caml_negf_mask +#define CAML_ABSF_MASK caml_absf_mask +#endif + + .globl CALL_GEN_CODE + .align ALIGN +CALL_GEN_CODE: + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + movq %rdi, %r10 + movq %rsi, %rax + movq %rdx, %rbx + movq %rcx, %rdi + movq %r8, %rsi + call *%r10 + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + ret + + .globl CAML_C_CALL + .align ALIGN +CAML_C_CALL: + jmp *%rax + +#ifdef SYS_macosx + .literal16 +#elif defined(SYS_mingw64) || defined(SYS_cygwin) + .section .rodata.cst8 +#else + .section .rodata.cst8,"aM",@progbits,8 +#endif + .globl CAML_NEGF_MASK + .align ALIGN +CAML_NEGF_MASK: + .quad 0x8000000000000000, 0 + .globl CAML_ABSF_MASK + .align ALIGN +CAML_ABSF_MASK: + .quad 0x7FFFFFFFFFFFFFFF, 0 + + .comm young_limit, 8 + +#if defined(SYS_linux) + /* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/testsuite/tests/asmcomp/arith.cmm b/testsuite/tests/asmgen/arith.cmm similarity index 100% rename from testsuite/tests/asmcomp/arith.cmm rename to testsuite/tests/asmgen/arith.cmm diff --git a/testsuite/tests/asmgen/arm.S b/testsuite/tests/asmgen/arm.S new file mode 100644 index 00000000..da6d9ee7 --- /dev/null +++ b/testsuite/tests/asmgen/arm.S @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ +/* */ +/* Copyright 1998 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + + .text + + .global call_gen_code + .type call_gen_code, %function + .align 0 +call_gen_code: + mov ip, sp + stmfd sp!, {r4, r5, r6, r7, r8, r9, fp, ip, lr, pc} + sub fp, ip, #4 + @ r0 is function to call + @ r1, r2, r3 are arguments 1, 2, 3 + mov r4, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + blx r4 + ldmea fp, {r4, r5, r6, r7, r8, r9, fp, sp, pc} + + .global caml_c_call + .type caml_c_call, %function + .align 0 +caml_c_call: + @ function to call is in r10 + bx r10 + +/* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits diff --git a/testsuite/tests/asmgen/arm64.S b/testsuite/tests/asmgen/arm64.S new file mode 100644 index 00000000..4b803d20 --- /dev/null +++ b/testsuite/tests/asmgen/arm64.S @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Gallium, INRIA Rocquencourt */ +/* */ +/* Copyright 2013 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + + .globl call_gen_code + .align 2 +call_gen_code: + /* Set up stack frame and save callee-save registers */ + stp x29, x30, [sp, -160]! + add x29, sp, #0 + stp x19, x20, [sp, 16] + stp x21, x22, [sp, 32] + stp x23, x24, [sp, 48] + stp x25, x26, [sp, 64] + stp x27, x28, [sp, 80] + stp d8, d9, [sp, 96] + stp d10, d11, [sp, 112] + stp d12, d13, [sp, 128] + stp d14, d15, [sp, 144] + /* Shuffle arguments */ + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + /* Call generated asm */ + blr x8 + /* Reload callee-save registers and return address */ + ldp x19, x20, [sp, 16] + ldp x21, x22, [sp, 32] + ldp x23, x24, [sp, 48] + ldp x25, x26, [sp, 64] + ldp x27, x28, [sp, 80] + ldp d8, d9, [sp, 96] + ldp d10, d11, [sp, 112] + ldp d12, d13, [sp, 128] + ldp d14, d15, [sp, 144] + ldp x29, x30, [sp], 160 + ret + + .globl caml_c_call + .align 2 +caml_c_call: + br x15 + +/* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits diff --git a/testsuite/tests/asmcomp/catch-rec.cmm b/testsuite/tests/asmgen/catch-rec.cmm similarity index 100% rename from testsuite/tests/asmcomp/catch-rec.cmm rename to testsuite/tests/asmgen/catch-rec.cmm diff --git a/testsuite/tests/asmcomp/catch-try.cmm b/testsuite/tests/asmgen/catch-try.cmm similarity index 100% rename from testsuite/tests/asmcomp/catch-try.cmm rename to testsuite/tests/asmgen/catch-try.cmm diff --git a/testsuite/tests/asmcomp/checkbound.cmm b/testsuite/tests/asmgen/checkbound.cmm similarity index 100% rename from testsuite/tests/asmcomp/checkbound.cmm rename to testsuite/tests/asmgen/checkbound.cmm diff --git a/testsuite/tests/asmcomp/even-odd-spill.cmm b/testsuite/tests/asmgen/even-odd-spill.cmm similarity index 100% rename from testsuite/tests/asmcomp/even-odd-spill.cmm rename to testsuite/tests/asmgen/even-odd-spill.cmm diff --git a/testsuite/tests/asmcomp/even-odd.cmm b/testsuite/tests/asmgen/even-odd.cmm similarity index 100% rename from testsuite/tests/asmcomp/even-odd.cmm rename to testsuite/tests/asmgen/even-odd.cmm diff --git a/testsuite/tests/asmcomp/fib.cmm b/testsuite/tests/asmgen/fib.cmm similarity index 100% rename from testsuite/tests/asmcomp/fib.cmm rename to testsuite/tests/asmgen/fib.cmm diff --git a/testsuite/tests/asmgen/i386.S b/testsuite/tests/asmgen/i386.S new file mode 100644 index 00000000..26dc83fc --- /dev/null +++ b/testsuite/tests/asmgen/i386.S @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ +/* */ +/* Copyright 1996 Institut National de Recherche en Informatique et */ +/* en Automatique. */ +/* */ +/* All rights reserved. This file is distributed under the terms of */ +/* the GNU Lesser General Public License version 2.1, with the */ +/* special exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +/* Linux with ELF binaries does not prefix identifiers with _. + Linux with a.out binaries, FreeBSD, and NextStep do. */ + +#if defined(SYS_linux_elf) || defined(SYS_bsd_elf) \ + || defined(SYS_solaris) || defined(SYS_beos) || defined(SYS_gnu) +#define G(x) x +#define FUNCTION_ALIGN 16 +#else +#define G(x) _##x +#define FUNCTION_ALIGN 4 +#endif + + .globl G(call_gen_code) + .align FUNCTION_ALIGN +G(call_gen_code): + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + pushl %edi + movl 12(%ebp),%eax + movl 16(%ebp),%ebx + movl 20(%ebp),%ecx + movl 24(%ebp),%edx + call *8(%ebp) + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + .globl G(caml_c_call) + .align FUNCTION_ALIGN +G(caml_c_call): + jmp *%eax + + .comm G(caml_exception_pointer), 4 + .comm G(young_ptr), 4 + .comm G(young_start), 4 + +#if defined(SYS_linux_elf) + /* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/testsuite/tests/asmcomp/i386nt.asm b/testsuite/tests/asmgen/i386nt.asm similarity index 100% rename from testsuite/tests/asmcomp/i386nt.asm rename to testsuite/tests/asmgen/i386nt.asm diff --git a/testsuite/tests/asmcomp/integr.cmm b/testsuite/tests/asmgen/integr.cmm similarity index 100% rename from testsuite/tests/asmcomp/integr.cmm rename to testsuite/tests/asmgen/integr.cmm diff --git a/testsuite/tests/asmcomp/lexcmm.mli b/testsuite/tests/asmgen/lexcmm.mli similarity index 100% rename from testsuite/tests/asmcomp/lexcmm.mli rename to testsuite/tests/asmgen/lexcmm.mli diff --git a/testsuite/tests/asmgen/lexcmm.mll b/testsuite/tests/asmgen/lexcmm.mll new file mode 100644 index 00000000..81eab9d0 --- /dev/null +++ b/testsuite/tests/asmgen/lexcmm.mll @@ -0,0 +1,245 @@ +{ +open Parsecmm + +type error = + Illegal_character + | Unterminated_comment + | Unterminated_string + +exception Error of error + +(* For nested comments *) + +let comment_depth = ref 0 + +(* The table of keywords *) + +let keyword_table = + Misc.create_hashtable 149 [ + "absf", ABSF; + "addr", ADDR; + "align", ALIGN; + "alloc", ALLOC; + "and", AND; + "app", APPLY; + "assign", ASSIGN; + "byte", BYTE; + "case", CASE; + "catch", CATCH; + "checkbound", CHECKBOUND; + "data", DATA; + "exit", EXIT; + "extcall", EXTCALL; + "float", FLOAT; + "float32", FLOAT32; + "float64", FLOAT64; + "floatofint", FLOATOFINT; + "function", FUNCTION; + "global", GLOBAL; + "half", HALF; + "if", IF; + "int", INT; + "int32", INT32; + "intoffloat", INTOFFLOAT; + "string", KSTRING; + "let", LET; + "load", LOAD; + "mod", MODI; + "mulh", MULH; + "or", OR; + "proj", PROJ; + "raise_withtrace", RAISE Cmm.Raise_withtrace; + "raise_notrace", RAISE Cmm.Raise_notrace; + "seq", SEQ; + "signed", SIGNED; + "skip", SKIP; + "store", STORE; + "switch", SWITCH; + "try", TRY; + "unit", UNIT; + "unsigned", UNSIGNED; + "val", VAL; + "while", WHILE; + "with", WITH; + "xor", XOR; + "addraref", ADDRAREF; + "intaref", INTAREF; + "floataref", FLOATAREF; + "addraset", ADDRASET; + "intaset", INTASET; + "floataset", FLOATASET +] + +(* To buffer string literals *) + +let initial_string_buffer = Bytes.create 256 +let string_buff = ref initial_string_buffer +let string_index = ref 0 + +let reset_string_buffer () = + string_buff := initial_string_buffer; + string_index := 0 + +let store_string_char c = + if !string_index >= Bytes.length (!string_buff) then begin + let new_buff = Bytes.create (Bytes.length (!string_buff) * 2) in + Bytes.blit (!string_buff) 0 new_buff 0 (Bytes.length (!string_buff)); + string_buff := new_buff + end; + Bytes.unsafe_set (!string_buff) (!string_index) c; + incr string_index + +let get_stored_string () = + let s = Bytes.sub_string (!string_buff) 0 (!string_index) in + string_buff := initial_string_buffer; + s + +(* To translate escape sequences *) + +let char_for_backslash = function + 'n' -> '\010' + | 'r' -> '\013' + | 'b' -> '\008' + | 't' -> '\009' + | c -> c + +let char_for_decimal_code lexbuf i = + Char.chr(100 * (Char.code(Lexing.lexeme_char lexbuf i) - 48) + + 10 * (Char.code(Lexing.lexeme_char lexbuf (i+1)) - 48) + + (Char.code(Lexing.lexeme_char lexbuf (i+2)) - 48)) + +(* Error report *) + +let report_error lexbuf msg = + prerr_string "Lexical error around character "; + prerr_int (Lexing.lexeme_start lexbuf); + match msg with + Illegal_character -> + prerr_string ": illegal character" + | Unterminated_comment -> + prerr_string ": unterminated comment" + | Unterminated_string -> + prerr_string ": unterminated string" + +} + +let newline = ('\013'* '\010') + +rule token = parse + newline + { Lexing.new_line lexbuf; token lexbuf } + | [' ' '\009' '\012'] + + { token lexbuf } + | "+a" { ADDA } + | "+v" { ADDV } + | "+f" { ADDF } + | "+" { ADDI } + | ">>s" { ASR } + | ":" { COLON } + | "/f" { DIVF } + | "/" { DIVI } + | eof { EOF } + | "==a" { EQA } + | "==f" { EQF } + | "==" { EQI } + | ">=a" { GEA } + | ">=f" { GEF } + | ">=" { GEI } + | ">a" { GTA } + | ">f" { GTF } + | ">" { GTI } + | "[" { LBRACKET } + | "<=a" { LEA } + | "<=f" { LEF } + | "<=" { LEI } + | "(" { LPAREN } + | "<<" { LSL } + | ">>u" { LSR } + | "=f" { NGEF } + | "!>f" { NGTF } + | "!<=f" { NLEF } + | "! + IDENT s } + | "\"" + { reset_string_buffer(); + string lexbuf; + STRING (get_stored_string()) } + | "(*" + { comment_depth := 1; + comment lexbuf; + token lexbuf } + | '{' ['A' - 'Z' 'a'-'z' '/' ',' '.' '-' '_' ' ''0'-'9']+ + ':' [ '0'-'9' ]+ ',' ['0'-'9' ]+ '-' ['0'-'9' ]+ '}' + { + let loc_s = Lexing.lexeme lexbuf in + let pos_fname, pos_lnum, start, end_ = + Scanf.sscanf loc_s "{%s@:%i,%i-%i}" (fun file line start end_ -> + (file, line, start, end_)) + in + let loc_start = + Lexing.{ pos_fname; pos_lnum; pos_bol = 0; pos_cnum = start } + in + let loc_end = + Lexing.{ pos_fname; pos_lnum; pos_bol = 0; pos_cnum = end_ } + in + let location = Location.{ loc_start; loc_end; loc_ghost = false } in + LOCATION location } + | _ { raise(Error(Illegal_character)) } + +and comment = parse + "(*" + { comment_depth := succ !comment_depth; comment lexbuf } + | "*)" + { comment_depth := pred !comment_depth; + if !comment_depth > 0 then comment lexbuf } + | eof + { raise (Error(Unterminated_comment)) } + | newline + { Lexing.new_line lexbuf; comment lexbuf } + | _ + { comment lexbuf } + +and string = parse + '"' + { () } + | '\\' [' ' '\010' '\013' '\009' '\026' '\012'] + + { string lexbuf } + | '\\' ['\\' '"' 'n' 't' 'b' 'r'] + { store_string_char(char_for_backslash(Lexing.lexeme_char lexbuf 1)); + string lexbuf } + | '\\' ['0'-'9'] ['0'-'9'] ['0'-'9'] + { store_string_char(char_for_decimal_code lexbuf 1); + string lexbuf } + | eof + { raise (Error(Unterminated_string)) } + | _ + { store_string_char(Lexing.lexeme_char lexbuf 0); + string lexbuf } + diff --git a/testsuite/tests/asmcomp/main.c b/testsuite/tests/asmgen/main.c similarity index 100% rename from testsuite/tests/asmcomp/main.c rename to testsuite/tests/asmgen/main.c diff --git a/testsuite/tests/asmcomp/main.ml b/testsuite/tests/asmgen/main.ml similarity index 100% rename from testsuite/tests/asmcomp/main.ml rename to testsuite/tests/asmgen/main.ml diff --git a/testsuite/tests/asmcomp/mainarith.c b/testsuite/tests/asmgen/mainarith.c similarity index 100% rename from testsuite/tests/asmcomp/mainarith.c rename to testsuite/tests/asmgen/mainarith.c diff --git a/testsuite/tests/asmgen/parsecmm.mly b/testsuite/tests/asmgen/parsecmm.mly new file mode 100644 index 00000000..b597a015 --- /dev/null +++ b/testsuite/tests/asmgen/parsecmm.mly @@ -0,0 +1,373 @@ +/* A simple parser for C-- */ + +%{ +open Cmm +open Parsecmmaux + +let rec make_letdef def body = + match def with + [] -> body + | (id, def) :: rem -> + unbind_ident id; + Clet(id, def, make_letdef rem body) + +let make_switch n selector caselist = + let index = Array.make n 0 in + let casev = Array.of_list caselist in + let actv = Array.make (Array.length casev) (Cexit(0,[])) in + for i = 0 to Array.length casev - 1 do + let (posl, e) = casev.(i) in + List.iter (fun pos -> index.(pos) <- i) posl; + actv.(i) <- e + done; + Cswitch(selector, index, actv, Debuginfo.none) + +let access_array base numelt size = + match numelt with + Cconst_int 0 -> base + | Cconst_int n -> Cop(Cadda, [base; Cconst_int(n * size)], Debuginfo.none) + | _ -> Cop(Cadda, [base; + Cop(Clsl, [numelt; Cconst_int(Misc.log2 size)], + Debuginfo.none)], + Debuginfo.none) + +%} + +%token ABSF +%token ADDA +%token ADDF +%token ADDI +%token ADDV +%token ADDR +%token ALIGN +%token ALLOC +%token AND +%token APPLY +%token ASR +%token ASSIGN +%token BYTE +%token CASE +%token CATCH +%token CHECKBOUND +%token COLON +%token DATA +%token DIVF +%token DIVI +%token EOF +%token EQA +%token EQF +%token EQI +%token EXIT +%token EXTCALL +%token FLOAT +%token FLOAT32 +%token FLOAT64 +%token FLOATCONST +%token FLOATOFINT +%token FUNCTION +%token GEA +%token GEF +%token GEI +%token GLOBAL +%token GTA +%token GTF +%token GTI +%token HALF +%token IDENT +%token IF +%token INT +%token INT32 +%token INTCONST +%token INTOFFLOAT +%token KSTRING +%token LBRACKET +%token LEA +%token LEF +%token LEI +%token LET +%token LOAD +%token LOCATION +%token LPAREN +%token LSL +%token LSR +%token LTA +%token LTF +%token LTI +%token MODI +%token MULF +%token MULH +%token MULI +%token NEA +%token NEF +%token NEI +%token NGEF +%token NGTF +%token NLEF +%token NLTF +%token OR +%token POINTER +%token PROJ +%token RAISE +%token RBRACKET +%token RPAREN +%token SEQ +%token SIGNED +%token SKIP +%token STAR +%token STORE +%token STRING +%token SUBF +%token SUBI +%token SWITCH +%token TRY +%token UNIT +%token UNSIGNED +%token VAL +%token WHILE +%token WITH +%token XOR +%token ADDRAREF +%token INTAREF +%token FLOATAREF +%token ADDRASET +%token INTASET +%token FLOATASET + +%start phrase +%type phrase + +%% + +phrase: + fundecl { Cfunction $1 } + | datadecl { Cdata $1 } + | EOF { raise End_of_file } +; +fundecl: + LPAREN FUNCTION fun_name LPAREN params RPAREN sequence RPAREN + { List.iter (fun (id, ty) -> unbind_ident id) $5; + {fun_name = $3; fun_args = $5; fun_body = $7; + fun_codegen_options = + if Config.flambda then [ + Reduce_code_size; + No_CSE; + ] + else [ Reduce_code_size ]; + fun_dbg = debuginfo ()} } +; +fun_name: + STRING { $1 } + | IDENT { $1 } +params: + oneparam params { $1 :: $2 } + | /**/ { [] } +; +oneparam: + IDENT COLON machtype { (bind_ident $1, $3) } +; +machtype: + UNIT { [||] } + | componentlist { Array.of_list(List.rev $1) } +; +component: + VAL { Val } + | ADDR { Addr } + | INT { Int } + | FLOAT { Float } +; +componentlist: + component { [$1] } + | componentlist STAR component { $3 :: $1 } +; +expr: + INTCONST { Cconst_int $1 } + | FLOATCONST { Cconst_float (float_of_string $1) } + | STRING { Cconst_symbol $1 } + | POINTER { Cconst_pointer $1 } + | IDENT { Cvar(find_ident $1) } + | LBRACKET RBRACKET { Ctuple [] } + | LPAREN LET letdef sequence RPAREN { make_letdef $3 $4 } + | LPAREN ASSIGN IDENT expr RPAREN { Cassign(find_ident $3, $4) } + | LPAREN APPLY location expr exprlist machtype RPAREN + { Cop(Capply $6, $4 :: List.rev $5, debuginfo ?loc:$3 ()) } + | LPAREN EXTCALL STRING exprlist machtype RPAREN + {Cop(Cextcall($3, $5, false, None), List.rev $4, debuginfo ())} + | LPAREN ALLOC exprlist RPAREN { Cop(Calloc, List.rev $3, debuginfo ()) } + | LPAREN SUBF expr RPAREN { Cop(Cnegf, [$3], debuginfo ()) } + | LPAREN SUBF expr expr RPAREN { Cop(Csubf, [$3; $4], debuginfo ()) } + | LPAREN unaryop expr RPAREN { Cop($2, [$3], debuginfo ()) } + | LPAREN binaryop expr expr RPAREN { Cop($2, [$3; $4], debuginfo ()) } + | LPAREN SEQ sequence RPAREN { $3 } + | LPAREN IF expr expr expr RPAREN { Cifthenelse($3, $4, $5) } + | LPAREN SWITCH INTCONST expr caselist RPAREN { make_switch $3 $4 $5 } + | LPAREN WHILE expr sequence RPAREN + { let body = + match $3 with + Cconst_int x when x <> 0 -> $4 + | _ -> Cifthenelse($3, $4, (Cexit(0,[]))) in + Ccatch(Recursive, [0, [], Cloop body], Ctuple []) } + | LPAREN EXIT IDENT exprlist RPAREN + { Cexit(find_label $3, List.rev $4) } + | LPAREN CATCH sequence WITH catch_handlers RPAREN + { let handlers = $5 in + List.iter (fun (_, l, _) -> List.iter unbind_ident l) handlers; + Ccatch(Recursive, handlers, $3) } + | EXIT { Cexit(0,[]) } + | LPAREN TRY sequence WITH bind_ident sequence RPAREN + { unbind_ident $5; Ctrywith($3, $5, $6) } + | LPAREN VAL expr expr RPAREN + { Cop(Cload (Word_val, Mutable), [access_array $3 $4 Arch.size_addr], + debuginfo ()) } + | LPAREN ADDRAREF expr expr RPAREN + { Cop(Cload (Word_val, Mutable), [access_array $3 $4 Arch.size_addr], + Debuginfo.none) } + | LPAREN INTAREF expr expr RPAREN + { Cop(Cload (Word_int, Mutable), [access_array $3 $4 Arch.size_int], + Debuginfo.none) } + | LPAREN FLOATAREF expr expr RPAREN + { Cop(Cload (Double_u, Mutable), [access_array $3 $4 Arch.size_float], + Debuginfo.none) } + | LPAREN ADDRASET expr expr expr RPAREN + { Cop(Cstore (Word_val, Assignment), + [access_array $3 $4 Arch.size_addr; $5], Debuginfo.none) } + | LPAREN INTASET expr expr expr RPAREN + { Cop(Cstore (Word_int, Assignment), + [access_array $3 $4 Arch.size_int; $5], Debuginfo.none) } + | LPAREN FLOATASET expr expr expr RPAREN + { Cop(Cstore (Double_u, Assignment), + [access_array $3 $4 Arch.size_float; $5], Debuginfo.none) } +; +exprlist: + exprlist expr { $2 :: $1 } + | /**/ { [] } +; +letdef: + oneletdef { [$1] } + | LPAREN letdefmult RPAREN { $2 } +; +letdefmult: + /**/ { [] } + | oneletdef letdefmult { $1 :: $2 } +; +oneletdef: + IDENT expr { (bind_ident $1, $2) } +; +chunk: + UNSIGNED BYTE { Byte_unsigned } + | SIGNED BYTE { Byte_signed } + | UNSIGNED HALF { Sixteen_unsigned } + | SIGNED HALF { Sixteen_signed } + | UNSIGNED INT32 { Thirtytwo_unsigned } + | SIGNED INT32 { Thirtytwo_signed } + | INT { Word_int } + | ADDR { Word_val } + | FLOAT32 { Single } + | FLOAT64 { Double } + | FLOAT { Double_u } + | VAL { Word_val } +; +unaryop: + LOAD chunk { Cload ($2, Mutable) } + | FLOATOFINT { Cfloatofint } + | INTOFFLOAT { Cintoffloat } + | RAISE { Craise $1 } + | ABSF { Cabsf } +; +binaryop: + STORE chunk { Cstore ($2, Assignment) } + | ADDI { Caddi } + | SUBI { Csubi } + | STAR { Cmuli } + | DIVI { Cdivi } + | MODI { Cmodi } + | AND { Cand } + | OR { Cor } + | XOR { Cxor } + | LSL { Clsl } + | LSR { Clsr } + | ASR { Casr } + | EQI { Ccmpi Ceq } + | NEI { Ccmpi Cne } + | LTI { Ccmpi Clt } + | LEI { Ccmpi Cle } + | GTI { Ccmpi Cgt } + | GEI { Ccmpi Cge } + | ADDA { Cadda } + | ADDV { Caddv } + | EQA { Ccmpa Ceq } + | NEA { Ccmpa Cne } + | LTA { Ccmpa Clt } + | LEA { Ccmpa Cle } + | GTA { Ccmpa Cgt } + | GEA { Ccmpa Cge } + | ADDF { Caddf } + | MULF { Cmulf } + | DIVF { Cdivf } + | EQF { Ccmpf CFeq } + | NEF { Ccmpf CFneq } + | LTF { Ccmpf CFlt } + | NLTF { Ccmpf CFnlt } + | LEF { Ccmpf CFle } + | NLEF { Ccmpf CFnle } + | GTF { Ccmpf CFgt } + | NGTF { Ccmpf CFngt } + | GEF { Ccmpf CFge } + | NGEF { Ccmpf CFnge } + | CHECKBOUND { Ccheckbound } + | MULH { Cmulhi } +; +sequence: + expr sequence { Csequence($1, $2) } + | expr { $1 } +; +caselist: + onecase sequence caselist { ($1, $2) :: $3 } + | /**/ { [] } +; +onecase: + CASE INTCONST COLON onecase { $2 :: $4 } + | CASE INTCONST COLON { [$2] } +; +bind_ident: + IDENT { bind_ident $1 } +; +datadecl: + LPAREN datalist RPAREN { List.rev $2 } + | LPAREN DATA datalist RPAREN { List.rev $3 } +; +datalist: + datalist dataitem { $2 :: $1 } + | /**/ { [] } +; +dataitem: + STRING COLON { Cdefine_symbol $1 } + | BYTE INTCONST { Cint8 $2 } + | HALF INTCONST { Cint16 $2 } + | INT INTCONST { Cint(Nativeint.of_int $2) } + | FLOAT FLOATCONST { Cdouble (float_of_string $2) } + | ADDR STRING { Csymbol_address $2 } + | VAL STRING { Csymbol_address $2 } + | KSTRING STRING { Cstring $2 } + | SKIP INTCONST { Cskip $2 } + | ALIGN INTCONST { Calign $2 } + | GLOBAL STRING { Cglobal_symbol $2 } +; +catch_handlers: + | catch_handler + { [$1] } + | catch_handler AND catch_handlers + { $1 :: $3 } + +catch_handler: + | sequence + { 0, [], $1 } + | LPAREN IDENT bind_identlist RPAREN sequence + { find_label $2, $3, $5 } + +bind_identlist: + /**/ { [] } + | bind_ident bind_identlist { $1 :: $2 } + +location: + /**/ { None } + | LOCATION { Some $1 } diff --git a/testsuite/tests/asmcomp/parsecmmaux.ml b/testsuite/tests/asmgen/parsecmmaux.ml similarity index 100% rename from testsuite/tests/asmcomp/parsecmmaux.ml rename to testsuite/tests/asmgen/parsecmmaux.ml diff --git a/testsuite/tests/asmcomp/parsecmmaux.mli b/testsuite/tests/asmgen/parsecmmaux.mli similarity index 100% rename from testsuite/tests/asmcomp/parsecmmaux.mli rename to testsuite/tests/asmgen/parsecmmaux.mli diff --git a/testsuite/tests/asmcomp/pgcd.cmm b/testsuite/tests/asmgen/pgcd.cmm similarity index 100% rename from testsuite/tests/asmcomp/pgcd.cmm rename to testsuite/tests/asmgen/pgcd.cmm diff --git a/testsuite/tests/asmgen/power.S b/testsuite/tests/asmgen/power.S new file mode 100644 index 00000000..71c692f9 --- /dev/null +++ b/testsuite/tests/asmgen/power.S @@ -0,0 +1,200 @@ +/*********************************************************************/ +/* */ +/* OCaml */ +/* */ +/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ +/* */ +/* Copyright 1996 Institut National de Recherche en Informatique et */ +/* en Automatique. All rights reserved. This file is distributed */ +/* under the terms of the Q Public License version 1.0. */ +/* */ +/*********************************************************************/ + +#if defined(MODEL_ppc64) || defined(MODEL_ppc64le) +#define EITHER(a,b) b +#else +#define EITHER(a,b) a +#endif + +#define WORD EITHER(4,8) +#define lg EITHER(lwz,ld) +#define lgu EITHER(lwzu,ldu) +#define stg EITHER(stw,std) +#define stgu EITHER(stwu,stdu) + +#if defined(MODEL_ppc) +#define RESERVED_STACK 16 +#define LR_SAVE_AREA 4 +#endif +#if defined(MODEL_ppc64) +#define RESERVED_STACK 48 +#define LR_SAVE_AREA 16 +#endif +#if defined(MODEL_ppc64le) +#define RESERVED_STACK 32 +#define LR_SAVE_AREA 16 +#endif + +/* Function definitions */ + +#if defined(MODEL_ppc) +#define FUNCTION(name) \ + .section ".text"; \ + .globl name; \ + .type name, @function; \ + .align 2; \ + name: +#endif + +#if defined(MODEL_ppc64) +#define FUNCTION(name) \ + .section ".opd","aw"; \ + .align 3; \ + .globl name; \ + .type name, @function; \ + name: .quad .L.name,.TOC.@tocbase; \ + .text; \ + .align 2; \ + .L.name: +#endif + +#if defined(MODEL_ppc64le) +#define FUNCTION(name) \ + .section ".text"; \ + .globl name; \ + .type name, @function; \ + .align 2; \ + name: ; \ + 0: addis 2, 12, (.TOC. - 0b)@ha; \ + addi 2, 2, (.TOC. - 0b)@l; \ + .localentry name, . - 0b +#endif + +FUNCTION(call_gen_code) + /* Allocate and link stack frame */ + stgu 1, -(WORD*18 + 8*18 + RESERVED_STACK)(1) + /* 18 saved GPRs, 18 saved FPRs */ + /* Save return address */ + mflr 0 + stg 0, (WORD*18 + 8*18 + RESERVED_STACK + LR_SAVE_AREA)(1) + /* Save all callee-save registers, starting at RESERVED_STACK */ + addi 11, 1, RESERVED_STACK - WORD + stgu 14, WORD(11) + stgu 15, WORD(11) + stgu 16, WORD(11) + stgu 17, WORD(11) + stgu 18, WORD(11) + stgu 19, WORD(11) + stgu 20, WORD(11) + stgu 21, WORD(11) + stgu 22, WORD(11) + stgu 23, WORD(11) + stgu 24, WORD(11) + stgu 25, WORD(11) + stgu 26, WORD(11) + stgu 27, WORD(11) + stgu 28, WORD(11) + stgu 29, WORD(11) + stgu 30, WORD(11) + stgu 31, WORD(11) + stfdu 14, 8(11) + stfdu 15, 8(11) + stfdu 16, 8(11) + stfdu 17, 8(11) + stfdu 18, 8(11) + stfdu 19, 8(11) + stfdu 20, 8(11) + stfdu 21, 8(11) + stfdu 22, 8(11) + stfdu 23, 8(11) + stfdu 24, 8(11) + stfdu 25, 8(11) + stfdu 26, 8(11) + stfdu 27, 8(11) + stfdu 28, 8(11) + stfdu 29, 8(11) + stfdu 30, 8(11) + stfdu 31, 8(11) + /* Get function pointer in CTR */ +#if defined(MODEL_ppc) + mtctr 3 +#elif defined(MODEL_ppc64) + ld 0, 0(3) + mtctr 0 + ld 2, 8(3) +#elif defined(MODEL_ppc64le) + mtctr 3 + mr 12, 3 +#else +#error "wrong MODEL" +#endif + /* Shuffle arguments */ + mr 3, 4 + mr 4, 5 + mr 5, 6 + mr 6, 7 + /* Call the function */ + bctrl + /* Restore callee-save registers */ + addi 11, 1, RESERVED_STACK - WORD + lgu 14, WORD(11) + lgu 15, WORD(11) + lgu 16, WORD(11) + lgu 17, WORD(11) + lgu 18, WORD(11) + lgu 19, WORD(11) + lgu 20, WORD(11) + lgu 21, WORD(11) + lgu 22, WORD(11) + lgu 23, WORD(11) + lgu 24, WORD(11) + lgu 25, WORD(11) + lgu 26, WORD(11) + lgu 27, WORD(11) + lgu 28, WORD(11) + lgu 29, WORD(11) + lgu 30, WORD(11) + lgu 31, WORD(11) + lfdu 14, 8(11) + lfdu 15, 8(11) + lfdu 16, 8(11) + lfdu 17, 8(11) + lfdu 18, 8(11) + lfdu 19, 8(11) + lfdu 20, 8(11) + lfdu 21, 8(11) + lfdu 22, 8(11) + lfdu 23, 8(11) + lfdu 24, 8(11) + lfdu 25, 8(11) + lfdu 26, 8(11) + lfdu 27, 8(11) + lfdu 28, 8(11) + lfdu 29, 8(11) + lfdu 30, 8(11) + lfdu 31, 8(11) + /* Reload return address */ + lg 0, (WORD*18 + 8*18 + RESERVED_STACK + LR_SAVE_AREA)(1) + mtlr 0 + /* Return */ + addi 1, 1, (WORD*18 + 8*18 + RESERVED_STACK) + blr + +FUNCTION(caml_c_call) + /* Jump to C function (address in r28) */ +#if defined(MODEL_ppc) + mtctr 28 +#elif defined(MODEL_ppc64) + ld 0, 0(28) + mtctr 0 + ld 2, 8(28) +#elif defined(MODEL_ppc64le) + mtctr 28 + mr 12, 28 +#else +#error "wrong MODEL" +#endif + bctr + +/* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits diff --git a/testsuite/tests/asmcomp/quicksort.cmm b/testsuite/tests/asmgen/quicksort.cmm similarity index 100% rename from testsuite/tests/asmcomp/quicksort.cmm rename to testsuite/tests/asmgen/quicksort.cmm diff --git a/testsuite/tests/asmcomp/quicksort2.cmm b/testsuite/tests/asmgen/quicksort2.cmm similarity index 100% rename from testsuite/tests/asmcomp/quicksort2.cmm rename to testsuite/tests/asmgen/quicksort2.cmm diff --git a/testsuite/tests/asmgen/s390x.S b/testsuite/tests/asmgen/s390x.S new file mode 100644 index 00000000..99eeca27 --- /dev/null +++ b/testsuite/tests/asmgen/s390x.S @@ -0,0 +1,67 @@ +#define ALIGN 8 + +#define CALL_GEN_CODE call_gen_code +#define CAML_C_CALL caml_c_call +#define CAML_NEGF_MASK caml_negf_mask +#define CAML_ABSF_MASK caml_absf_mask + + .section ".text" + + .globl CALL_GEN_CODE + .type CALL_GEN_CODE, @function + .align ALIGN +CALL_GEN_CODE: + /* Stack space */ + lay %r15, -144(%r15) + /* Save registers */ + stmg %r6,%r14, 0(%r15) + std %f8, 72(%r15) + std %f9, 80(%r15) + std %f10, 88(%r15) + std %f11, 96(%r15) + std %f12, 104(%r15) + std %f13, 112(%r15) + std %f14, 120(%r15) + std %f15, 128(%r15) + /* Shuffle args */ + lgr %r1, %r2 + lgr %r2, %r3 + lgr %r3, %r4 + lgr %r4, %r5 + /* Function call */ + basr %r14, %r1 + /* Restore registers */ + lmg %r6,%r14, 0(%r15) + ld %f8, 72(%r15) + ld %f9, 80(%r15) + ld %f10, 88(%r15) + ld %f11, 96(%r15) + ld %f12, 104(%r15) + ld %f13, 112(%r15) + ld %f14, 120(%r15) + ld %f15, 128(%r15) + /* Return */ + lay %r15, 144(%r15) + br %r14 + + .globl CAML_C_CALL + .type CAML_C_CALL, @function + .align ALIGN +CAML_C_CALL: + br %r7 + + .section ".rodata" + + .global CAML_NEGF_MASK + .align ALIGN +CAML_NEGF_MASK: + .quad 0x8000000000000000, 0 + .global CAML_ABSF_MASK + .align ALIGN +CAML_ABSF_MASK: + .quad 0x7FFFFFFFFFFFFFFF, 0 + + .comm young_limit, 8 + +/* Mark stack as non-executable */ + .section .note.GNU-stack,"",%progbits diff --git a/testsuite/tests/asmcomp/soli.cmm b/testsuite/tests/asmgen/soli.cmm similarity index 100% rename from testsuite/tests/asmcomp/soli.cmm rename to testsuite/tests/asmgen/soli.cmm diff --git a/testsuite/tests/asmcomp/tagged-fib.cmm b/testsuite/tests/asmgen/tagged-fib.cmm similarity index 100% rename from testsuite/tests/asmcomp/tagged-fib.cmm rename to testsuite/tests/asmgen/tagged-fib.cmm diff --git a/testsuite/tests/asmcomp/tagged-integr.cmm b/testsuite/tests/asmgen/tagged-integr.cmm similarity index 100% rename from testsuite/tests/asmcomp/tagged-integr.cmm rename to testsuite/tests/asmgen/tagged-integr.cmm diff --git a/testsuite/tests/asmcomp/tagged-quicksort.cmm b/testsuite/tests/asmgen/tagged-quicksort.cmm similarity index 100% rename from testsuite/tests/asmcomp/tagged-quicksort.cmm rename to testsuite/tests/asmgen/tagged-quicksort.cmm diff --git a/testsuite/tests/asmcomp/tagged-tak.cmm b/testsuite/tests/asmgen/tagged-tak.cmm similarity index 100% rename from testsuite/tests/asmcomp/tagged-tak.cmm rename to testsuite/tests/asmgen/tagged-tak.cmm diff --git a/testsuite/tests/asmcomp/tak.cmm b/testsuite/tests/asmgen/tak.cmm similarity index 100% rename from testsuite/tests/asmcomp/tak.cmm rename to testsuite/tests/asmgen/tak.cmm diff --git a/testsuite/tests/ast-invariants/Makefile b/testsuite/tests/ast-invariants/Makefile deleted file mode 100644 index ecea4d4e..00000000 --- a/testsuite/tests/ast-invariants/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -######################################################################### -# # -# OCaml # -# # -# Jeremie Dimino, Jane Street Europe # -# # -# Copyright 2015 Jane Street Group LLC # -# # -# All rights reserved. This file is distributed under the terms of # -# the GNU Lesser General Public License version 2.1, with the # -# special exception on linking described in the file ../LICENSE. # -# # -######################################################################### - -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/parsing -I $(OTOPDIR)/utils \ - -I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LIBRARIES=../../../compilerlibs/ocamlcommon unix -MODULES= -MAIN_MODULE=test - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common - -# This test is a bit slow and there is little value in testing both -# versions so we run only the native code one: -NATIVECODE_ONLY=true diff --git a/testsuite/tests/ast-invariants/ocamltests b/testsuite/tests/ast-invariants/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/ast-invariants/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/ast-invariants/test.ml b/testsuite/tests/ast-invariants/test.ml index 21e5e8c4..1e0074b1 100644 --- a/testsuite/tests/ast-invariants/test.ml +++ b/testsuite/tests/ast-invariants/test.ml @@ -1,3 +1,10 @@ +(* TEST + include ocamlcommon + include unix + arguments = "${ocamlsrcdir}" + * native +*) + (* This test checks all ml files in the ocaml repository that are accepted by the parser satisfy [Ast_invariants]. @@ -5,7 +12,8 @@ is to ensure that the parser doesn't accept more than [Ast_invariants]. *) -let root = "../../.." +let root = Sys.argv.(1) + let () = assert (Sys.file_exists (Filename.concat root "VERSION")) type _ kind = diff --git a/testsuite/tests/backtrace/Makefile b/testsuite/tests/backtrace/Makefile deleted file mode 100644 index 5df19fc6..00000000 --- a/testsuite/tests/backtrace/Makefile +++ /dev/null @@ -1,155 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -EXECNAME=program$(EXE) - -ABCDFILES=backtrace.ml -OTHERFILES=backtrace2.ml backtrace3.ml raw_backtrace.ml \ - backtrace_deprecated.ml backtrace_slots.ml -INLININGFILES=inline_test.ml inline_traversal_test.ml -OTHERFILESNOINLINING=pr6920_why_at.ml pr6920_why_swallow.ml -OTHERFILESNOINLINING_NATIVE=backtraces_and_finalizers.ml - -# Keep only filenames, lines and character ranges -LOCATIONFILTER=grep -oE \ - '[a-zA-Z_]+\.ml(:[0-9]+)?|(line|characters) [0-9-]+' - -default: - @$(MAKE) byte - @if $(BYTECODE_ONLY); then $(MAKE) skip ; else $(MAKE) native; fi - -.PHONY: byte -byte: - @for file in $(ABCDFILES); do \ - rm -f program program.exe; \ - $(OCAMLC) -g -o $(EXECNAME) $$file; \ - for arg in a b c d ''; do \ - printf " ... testing '$$file' with ocamlc and argument '$$arg':"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - $(OCAMLRUN) $(EXECNAME) $$arg || true) \ - >$$F.$$arg.byte.result 2>&1; \ - $(DIFF) $$F.$$arg.byte.reference $$F.$$arg.byte.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; \ - done - @for file in $(OTHERFILES) $(OTHERFILESNOINLINING); do \ - rm -f program program.exe; \ - $(OCAMLC) -g -o $(EXECNAME) $$file; \ - printf " ... testing '$$file' with ocamlc:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - $(OCAMLRUN) $(EXECNAME) $$arg || true) \ - >$$F.byte.result 2>&1; \ - $(DIFF) $$F.byte.reference $$F.byte.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; - @for file in $(INLININGFILES); \ - do \ - rm -f program program.exe; \ - $(OCAMLC) -g -o $(EXECNAME) $$file; \ - printf " ... testing '$$file' with ocamlc:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - $(OCAMLRUN) $(EXECNAME) $$arg 2>&1 || true) \ - | $(LOCATIONFILTER) >$$F.byte.result 2>&1; \ - $(DIFF) $$F.byte.reference $$F.byte.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -.PHONY: skip -skip: - @for file in $(ABCDFILES); do \ - for arg in a b c d ''; do \ - echo " ... testing '$$file' with ocamlopt and argument '$$arg': \ - => skipped"; \ - done; \ - done - @for file in $(OTHERFILES) $(OTHERFILESNOINLINING) \ - $(OTHERFILESNOINLINING_NATIVE) $(INLININGFILES); do \ - echo " ... testing '$$file' with ocamlopt: => skipped"; \ - done - -.PHONY: native -native: - @for file in $(ABCDFILES); do \ - rm -f program program.exe; \ - $(OCAMLOPT) -g -o $(EXECNAME) $$file; \ - for arg in a b c d ''; do \ - printf " ... testing '$$file' with ocamlopt and argument '$$arg':";\ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - ./$(EXECNAME) $$arg || true) \ - >$$F.$$arg.native.result 2>&1; \ - $(DIFF) $$F.$$arg.native.reference $$F.$$arg.native.result \ - >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; \ - done - @for file in $(OTHERFILES); do \ - rm -f program program.exe; \ - $(OCAMLOPT) -g -o $(EXECNAME) $$file; \ - printf " ... testing '$$file' with ocamlopt:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - ./$(EXECNAME) $$arg || true) \ - >$$F.native.result 2>&1; \ - $(DIFF) $$F.native.reference $$F.native.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; - @for file in $(OTHERFILESNOINLINING) $(OTHERFILESNOINLINING_NATIVE); \ - do \ - rm -f program program.exe; \ - $(OCAMLOPT) -inline 0 -g -o $(EXECNAME) $$file; \ - printf " ... testing '$$file' with ocamlopt:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - ./$(EXECNAME) $$arg || true) \ - >$$F.native.result 2>&1; \ - $(DIFF) $$F.native.reference $$F.native.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; - @for file in $(INLININGFILES); \ - do \ - rm -f program program.exe; \ - $(OCAMLOPT) -g -o $(EXECNAME) $$file; \ - printf " ... testing '$$file' with ocamlopt:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - ./$(EXECNAME) $$arg 2>&1 || true) \ - | $(LOCATIONFILTER) >$$F.native.result; \ - $(DIFF) $$F.native.reference $$F.native.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - rm -f program program.exe; \ - $(OCAMLOPT) -g -o $(EXECNAME) -O3 $$file; \ - printf " ... testing '$$file' with ocamlopt -O3:"; \ - F="`basename $$file .ml`"; \ - (OCAMLRUNPARAM=$$OCAMLRUNPARAM,b=1 \ - ./$(EXECNAME) $$arg 2>&1 || true) \ - | $(LOCATIONFILTER) >$$F.O3.result; \ - $(DIFF) $$F.native.reference $$F.O3.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result program program.exe - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/backtrace/backtrace..byte.reference b/testsuite/tests/backtrace/backtrace..byte.reference deleted file mode 100644 index d2d69337..00000000 --- a/testsuite/tests/backtrace/backtrace..byte.reference +++ /dev/null @@ -1,2 +0,0 @@ -Fatal error: exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace.ml", line 18, characters 12-24 diff --git a/testsuite/tests/backtrace/backtrace..native.reference b/testsuite/tests/backtrace/backtrace..native.reference deleted file mode 100644 index d2d69337..00000000 --- a/testsuite/tests/backtrace/backtrace..native.reference +++ /dev/null @@ -1,2 +0,0 @@ -Fatal error: exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace.ml", line 18, characters 12-24 diff --git a/testsuite/tests/backtrace/backtrace.a.byte.reference b/testsuite/tests/backtrace/backtrace.a.byte.reference deleted file mode 100644 index 78981922..00000000 --- a/testsuite/tests/backtrace/backtrace.a.byte.reference +++ /dev/null @@ -1 +0,0 @@ -a diff --git a/testsuite/tests/backtrace/backtrace.a.native.reference b/testsuite/tests/backtrace/backtrace.a.native.reference deleted file mode 100644 index 78981922..00000000 --- a/testsuite/tests/backtrace/backtrace.a.native.reference +++ /dev/null @@ -1 +0,0 @@ -a diff --git a/testsuite/tests/backtrace/backtrace.b.byte.reference b/testsuite/tests/backtrace/backtrace.b.byte.reference deleted file mode 100644 index 47375896..00000000 --- a/testsuite/tests/backtrace/backtrace.b.byte.reference +++ /dev/null @@ -1,11 +0,0 @@ -b -Fatal error: exception Backtrace.Error("b") -Raised at file "backtrace.ml", line 7, characters 21-32 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 11, characters 4-11 -Re-raised at file "backtrace.ml", line 13, characters 68-71 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.b.native.reference b/testsuite/tests/backtrace/backtrace.b.native.reference deleted file mode 100644 index f1e8da87..00000000 --- a/testsuite/tests/backtrace/backtrace.b.native.reference +++ /dev/null @@ -1,11 +0,0 @@ -b -Fatal error: exception Backtrace.Error("b") -Raised at file "backtrace.ml", line 7, characters 16-32 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 11, characters 4-11 -Re-raised at file "backtrace.ml", line 13, characters 62-71 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.byte.reference b/testsuite/tests/backtrace/backtrace.byte.reference new file mode 100644 index 00000000..224f5fd9 --- /dev/null +++ b/testsuite/tests/backtrace/backtrace.byte.reference @@ -0,0 +1,26 @@ +a +b +Fatal error: exception Backtrace.Error("b") +Raised at file "backtrace.ml", line 16, characters 21-32 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 20, characters 4-11 +Re-raised at file "backtrace.ml", line 22, characters 68-71 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Backtrace.Error("c") +Raised at file "backtrace.ml", line 23, characters 26-37 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Backtrace.Error("d") +Raised at file "backtrace.ml", line 16, characters 21-32 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 20, characters 4-11 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace.ml", line 27, characters 12-24 diff --git a/testsuite/tests/backtrace/backtrace.c.byte.reference b/testsuite/tests/backtrace/backtrace.c.byte.reference deleted file mode 100644 index 33cac474..00000000 --- a/testsuite/tests/backtrace/backtrace.c.byte.reference +++ /dev/null @@ -1,3 +0,0 @@ -Fatal error: exception Backtrace.Error("c") -Raised at file "backtrace.ml", line 14, characters 26-37 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.c.native.reference b/testsuite/tests/backtrace/backtrace.c.native.reference deleted file mode 100644 index 431cd546..00000000 --- a/testsuite/tests/backtrace/backtrace.c.native.reference +++ /dev/null @@ -1,3 +0,0 @@ -Fatal error: exception Backtrace.Error("c") -Raised at file "backtrace.ml", line 14, characters 20-37 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.d.byte.reference b/testsuite/tests/backtrace/backtrace.d.byte.reference deleted file mode 100644 index 9ba46824..00000000 --- a/testsuite/tests/backtrace/backtrace.d.byte.reference +++ /dev/null @@ -1,9 +0,0 @@ -Fatal error: exception Backtrace.Error("d") -Raised at file "backtrace.ml", line 7, characters 21-32 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 11, characters 4-11 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.d.native.reference b/testsuite/tests/backtrace/backtrace.d.native.reference deleted file mode 100644 index d074040c..00000000 --- a/testsuite/tests/backtrace/backtrace.d.native.reference +++ /dev/null @@ -1,9 +0,0 @@ -Fatal error: exception Backtrace.Error("d") -Raised at file "backtrace.ml", line 7, characters 16-32 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 7, characters 42-53 -Called from file "backtrace.ml", line 11, characters 4-11 -Called from file "backtrace.ml", line 18, characters 9-25 diff --git a/testsuite/tests/backtrace/backtrace.ml b/testsuite/tests/backtrace/backtrace.ml index ca4423e9..6ef8b37c 100644 --- a/testsuite/tests/backtrace/backtrace.ml +++ b/testsuite/tests/backtrace/backtrace.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/backtrace.byte.reference" + * native + reference = "${test_source_directory}/backtrace.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) diff --git a/testsuite/tests/backtrace/backtrace.opt.reference b/testsuite/tests/backtrace/backtrace.opt.reference new file mode 100644 index 00000000..42ed7662 --- /dev/null +++ b/testsuite/tests/backtrace/backtrace.opt.reference @@ -0,0 +1,26 @@ +a +b +Fatal error: exception Backtrace.Error("b") +Raised at file "backtrace.ml", line 16, characters 16-32 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 20, characters 4-11 +Re-raised at file "backtrace.ml", line 22, characters 62-71 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Backtrace.Error("c") +Raised at file "backtrace.ml", line 23, characters 20-37 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Backtrace.Error("d") +Raised at file "backtrace.ml", line 16, characters 16-32 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 16, characters 42-53 +Called from file "backtrace.ml", line 20, characters 4-11 +Called from file "backtrace.ml", line 27, characters 9-25 +Fatal error: exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace.ml", line 27, characters 12-24 diff --git a/testsuite/tests/backtrace/backtrace.run b/testsuite/tests/backtrace/backtrace.run new file mode 100644 index 00000000..a1bbd91c --- /dev/null +++ b/testsuite/tests/backtrace/backtrace.run @@ -0,0 +1,8 @@ +#!/bin/sh +# Run the backtrace test + +exec > "${output}" 2>&1 + +for arg in a b c d ''; do + "${program}" ${arg} || true +done diff --git a/testsuite/tests/backtrace/backtrace2.byte.reference b/testsuite/tests/backtrace/backtrace2.byte.reference index aef38381..231e7e60 100644 --- a/testsuite/tests/backtrace/backtrace2.byte.reference +++ b/testsuite/tests/backtrace/backtrace2.byte.reference @@ -2,57 +2,57 @@ a No exception b Uncaught exception Backtrace2.Error("b") -Raised at file "backtrace2.ml", line 8, characters 23-34 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 13, characters 4-11 -Re-raised at file "backtrace2.ml", line 15, characters 68-71 -Called from file "backtrace2.ml", line 58, characters 11-23 +Raised at file "backtrace2.ml", line 17, characters 23-34 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 22, characters 4-11 +Re-raised at file "backtrace2.ml", line 24, characters 68-71 +Called from file "backtrace2.ml", line 67, characters 11-23 Uncaught exception Backtrace2.Error("c") -Raised at file "backtrace2.ml", line 16, characters 26-37 -Called from file "backtrace2.ml", line 58, characters 11-23 +Raised at file "backtrace2.ml", line 25, characters 26-37 +Called from file "backtrace2.ml", line 67, characters 11-23 Uncaught exception Backtrace2.Error("d") -Raised at file "backtrace2.ml", line 8, characters 23-34 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 13, characters 4-11 -Called from file "backtrace2.ml", line 58, characters 11-23 +Raised at file "backtrace2.ml", line 17, characters 23-34 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 22, characters 4-11 +Called from file "backtrace2.ml", line 67, characters 11-23 e Uncaught exception Backtrace2.Error("e") -Raised at file "backtrace2.ml", line 22, characters 56-59 -Called from file "backtrace2.ml", line 58, characters 11-23 +Raised at file "backtrace2.ml", line 31, characters 56-59 +Called from file "backtrace2.ml", line 67, characters 11-23 f Uncaught exception Backtrace2.Error("f") -Raised at file "backtrace2.ml", line 28, characters 68-71 -Called from file "backtrace2.ml", line 58, characters 11-23 +Raised at file "backtrace2.ml", line 37, characters 68-71 +Called from file "backtrace2.ml", line 67, characters 11-23 Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace2.ml", line 58, characters 14-22 +Raised by primitive operation at file "backtrace2.ml", line 67, characters 14-22 test_Not_found Uncaught exception Not_found Raised at file "hashtbl.ml", line 194, characters 19-28 -Called from file "backtrace2.ml", line 39, characters 9-42 -Re-raised at file "backtrace2.ml", line 39, characters 67-70 -Called from file "backtrace2.ml", line 58, characters 11-23 +Called from file "backtrace2.ml", line 48, characters 9-42 +Re-raised at file "backtrace2.ml", line 48, characters 67-70 +Called from file "backtrace2.ml", line 67, characters 11-23 Uncaught exception Not_found -Raised at file "backtrace2.ml", line 43, characters 24-33 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 +Raised at file "backtrace2.ml", line 52, characters 24-33 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 Called from file "camlinternalLazy.ml", line 27, characters 17-27 Re-raised at file "camlinternalLazy.ml", line 34, characters 10-11 -Called from file "backtrace2.ml", line 58, characters 11-23 +Called from file "backtrace2.ml", line 67, characters 11-23 Uncaught exception Not_found Raised at file "hashtbl.ml", line 194, characters 19-28 -Called from file "backtrace2.ml", line 46, characters 8-41 +Called from file "backtrace2.ml", line 55, characters 8-41 Re-raised at file "camlinternalLazy.ml", line 33, characters 62-63 Called from file "camlinternalLazy.ml", line 27, characters 17-27 Re-raised at file "camlinternalLazy.ml", line 34, characters 10-11 -Called from file "backtrace2.ml", line 58, characters 11-23 +Called from file "backtrace2.ml", line 67, characters 11-23 diff --git a/testsuite/tests/backtrace/backtrace2.ml b/testsuite/tests/backtrace/backtrace2.ml index 07cf5ccc..13c85f42 100644 --- a/testsuite/tests/backtrace/backtrace2.ml +++ b/testsuite/tests/backtrace/backtrace2.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/backtrace2.byte.reference" + * native + reference = "${test_source_directory}/backtrace2.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) diff --git a/testsuite/tests/backtrace/backtrace2.native.reference b/testsuite/tests/backtrace/backtrace2.native.reference deleted file mode 100644 index 978bc937..00000000 --- a/testsuite/tests/backtrace/backtrace2.native.reference +++ /dev/null @@ -1,58 +0,0 @@ -a -No exception -b -Uncaught exception Backtrace2.Error("b") -Raised at file "backtrace2.ml", line 8, characters 18-34 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 13, characters 4-11 -Re-raised at file "backtrace2.ml", line 15, characters 62-71 -Called from file "backtrace2.ml", line 58, characters 11-23 -Uncaught exception Backtrace2.Error("c") -Raised at file "backtrace2.ml", line 16, characters 20-37 -Called from file "backtrace2.ml", line 58, characters 11-23 -Uncaught exception Backtrace2.Error("d") -Raised at file "backtrace2.ml", line 8, characters 18-34 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 8, characters 44-55 -Called from file "backtrace2.ml", line 13, characters 4-11 -Called from file "backtrace2.ml", line 58, characters 11-23 -e -Uncaught exception Backtrace2.Error("e") -Raised at file "backtrace2.ml", line 22, characters 50-59 -Called from file "backtrace2.ml", line 58, characters 11-23 -f -Uncaught exception Backtrace2.Error("f") -Raised at file "backtrace2.ml", line 28, characters 62-71 -Called from file "backtrace2.ml", line 58, characters 11-23 -Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace2.ml", line 58, characters 14-22 -test_Not_found -Uncaught exception Not_found -Raised at file "hashtbl.ml", line 194, characters 13-28 -Called from file "backtrace2.ml", line 39, characters 9-42 -Re-raised at file "backtrace2.ml", line 39, characters 61-70 -Called from file "backtrace2.ml", line 58, characters 11-23 -Uncaught exception Not_found -Raised at file "backtrace2.ml", line 43, characters 18-33 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "backtrace2.ml", line 43, characters 43-52 -Called from file "camlinternalLazy.ml", line 27, characters 17-27 -Re-raised at file "camlinternalLazy.ml", line 34, characters 4-11 -Called from file "backtrace2.ml", line 58, characters 11-23 -Uncaught exception Not_found -Raised at file "hashtbl.ml", line 194, characters 13-28 -Called from file "backtrace2.ml", line 46, characters 8-41 -Re-raised at file "camlinternalLazy.ml", line 33, characters 56-63 -Called from file "camlinternalLazy.ml", line 27, characters 17-27 -Re-raised at file "camlinternalLazy.ml", line 34, characters 4-11 -Called from file "backtrace2.ml", line 58, characters 11-23 diff --git a/testsuite/tests/backtrace/backtrace2.opt.reference b/testsuite/tests/backtrace/backtrace2.opt.reference new file mode 100644 index 00000000..cc110b6d --- /dev/null +++ b/testsuite/tests/backtrace/backtrace2.opt.reference @@ -0,0 +1,58 @@ +a +No exception +b +Uncaught exception Backtrace2.Error("b") +Raised at file "backtrace2.ml", line 17, characters 18-34 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 22, characters 4-11 +Re-raised at file "backtrace2.ml", line 24, characters 62-71 +Called from file "backtrace2.ml", line 67, characters 11-23 +Uncaught exception Backtrace2.Error("c") +Raised at file "backtrace2.ml", line 25, characters 20-37 +Called from file "backtrace2.ml", line 67, characters 11-23 +Uncaught exception Backtrace2.Error("d") +Raised at file "backtrace2.ml", line 17, characters 18-34 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 17, characters 44-55 +Called from file "backtrace2.ml", line 22, characters 4-11 +Called from file "backtrace2.ml", line 67, characters 11-23 +e +Uncaught exception Backtrace2.Error("e") +Raised at file "backtrace2.ml", line 31, characters 50-59 +Called from file "backtrace2.ml", line 67, characters 11-23 +f +Uncaught exception Backtrace2.Error("f") +Raised at file "backtrace2.ml", line 37, characters 62-71 +Called from file "backtrace2.ml", line 67, characters 11-23 +Uncaught exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace2.ml", line 67, characters 14-22 +test_Not_found +Uncaught exception Not_found +Raised at file "hashtbl.ml", line 194, characters 13-28 +Called from file "backtrace2.ml", line 48, characters 9-42 +Re-raised at file "backtrace2.ml", line 48, characters 61-70 +Called from file "backtrace2.ml", line 67, characters 11-23 +Uncaught exception Not_found +Raised at file "backtrace2.ml", line 52, characters 18-33 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "backtrace2.ml", line 52, characters 43-52 +Called from file "camlinternalLazy.ml", line 27, characters 17-27 +Re-raised at file "camlinternalLazy.ml", line 34, characters 4-11 +Called from file "backtrace2.ml", line 67, characters 11-23 +Uncaught exception Not_found +Raised at file "hashtbl.ml", line 194, characters 13-28 +Called from file "backtrace2.ml", line 55, characters 8-41 +Re-raised at file "camlinternalLazy.ml", line 33, characters 56-63 +Called from file "camlinternalLazy.ml", line 27, characters 17-27 +Re-raised at file "camlinternalLazy.ml", line 34, characters 4-11 +Called from file "backtrace2.ml", line 67, characters 11-23 diff --git a/testsuite/tests/backtrace/backtrace3.byte.reference b/testsuite/tests/backtrace/backtrace3.byte.reference index 5081640a..c667cacb 100644 --- a/testsuite/tests/backtrace/backtrace3.byte.reference +++ b/testsuite/tests/backtrace/backtrace3.byte.reference @@ -2,26 +2,65 @@ a No exception b Uncaught exception Backtrace3.Error("b") -Raised at file "backtrace3.ml", line 7, characters 21-32 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 11, characters 4-11 -Re-raised at file "backtrace3.ml", line 20, characters 47-50 -Called from file "backtrace3.ml", line 28, characters 11-23 +Raised at file "backtrace3.ml", line 16, characters 21-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 29, characters 47-50 +Called from file "backtrace3.ml", line 54, characters 11-23 +c Uncaught exception Backtrace3.Error("c") -Raised at file "backtrace3.ml", line 24, characters 12-23 -Called from file "backtrace3.ml", line 28, characters 11-23 +Raised at file "backtrace3.ml", line 33, characters 47-58 +Called from file "backtrace3.ml", line 54, characters 11-23 +d Uncaught exception Backtrace3.Error("d") -Raised at file "backtrace3.ml", line 7, characters 21-32 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 11, characters 4-11 -Called from file "backtrace3.ml", line 28, characters 11-23 +Raised at file "backtrace3.ml", line 16, characters 21-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 36, characters 47-50 +Called from file "backtrace3.ml", line 54, characters 11-23 +e +Uncaught exception Backtrace3.Error("e") +Raised at file "backtrace3.ml", line 16, characters 21-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 39, characters 47-51 +Called from file "backtrace3.ml", line 54, characters 11-23 +f +Uncaught exception Backtrace3.Error("f") +Raised at file "backtrace3.ml", line 16, characters 21-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 44, characters 51-54 +Called from file "backtrace3.ml", line 54, characters 11-23 +g +Uncaught exception Backtrace3.Error("g") +Raised at file "backtrace3.ml", line 16, characters 21-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 47, characters 51-55 +Called from file "backtrace3.ml", line 54, characters 11-23 +Uncaught exception Backtrace3.Error("h") +Raised at file "backtrace3.ml", line 50, characters 16-17 +Called from file "backtrace3.ml", line 54, characters 11-23 Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace3.ml", line 28, characters 14-22 +Raised by primitive operation at file "backtrace3.ml", line 54, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace3.ml b/testsuite/tests/backtrace/backtrace3.ml index 7e51aa68..14b7d33d 100644 --- a/testsuite/tests/backtrace/backtrace3.ml +++ b/testsuite/tests/backtrace/backtrace3.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/backtrace3.byte.reference" + * native + reference = "${test_source_directory}/backtrace3.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) @@ -21,7 +30,24 @@ let g msg = | exception (Error "c") -> (* according to the current re-raise policy (a static condition), this does not re-raise *) - raise (Error "c") + print_string "c"; print_newline(); raise (Error "c") + | exception (Error "d" as exn as _exn2) -> + (* this should Re-raise, appending to the current backtrace *) + print_string "d"; print_newline(); raise exn + | exception (Error "e" as _exn as exn2) -> + (* this should Re-raise, appending to the current backtrace *) + print_string "e"; print_newline(); raise exn2 + | exception (exn as exn2) -> + match exn with + | Error "f" -> + (* this should Re-raise, appending to the current backtrace *) + print_string "f"; print_newline(); raise exn + | Error "g" -> + (* this should Re-raise, appending to the current backtrace *) + print_string "g"; print_newline(); raise exn2 + | x -> + (* this should *not* Re-raise *) + raise x let run args = try @@ -36,4 +62,8 @@ let _ = run [| "b" |]; run [| "c" |]; run [| "d" |]; + run [| "e" |]; + run [| "f" |]; + run [| "g" |]; + run [| "h" |]; run [| |] diff --git a/testsuite/tests/backtrace/backtrace3.native.reference b/testsuite/tests/backtrace/backtrace3.native.reference deleted file mode 100644 index c38a51e7..00000000 --- a/testsuite/tests/backtrace/backtrace3.native.reference +++ /dev/null @@ -1,27 +0,0 @@ -a -No exception -b -Uncaught exception Backtrace3.Error("b") -Raised at file "backtrace3.ml", line 7, characters 16-32 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 11, characters 4-11 -Re-raised at file "backtrace3.ml", line 20, characters 41-50 -Called from file "backtrace3.ml", line 28, characters 11-23 -Uncaught exception Backtrace3.Error("c") -Raised at file "backtrace3.ml", line 24, characters 6-23 -Called from file "backtrace3.ml", line 28, characters 11-23 -Uncaught exception Backtrace3.Error("d") -Raised at file "backtrace3.ml", line 7, characters 16-32 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 7, characters 42-53 -Called from file "backtrace3.ml", line 11, characters 4-11 -Called from file "backtrace3.ml", line 28, characters 11-23 -Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace3.ml", line 28, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace3.opt.reference b/testsuite/tests/backtrace/backtrace3.opt.reference new file mode 100644 index 00000000..87740918 --- /dev/null +++ b/testsuite/tests/backtrace/backtrace3.opt.reference @@ -0,0 +1,66 @@ +a +No exception +b +Uncaught exception Backtrace3.Error("b") +Raised at file "backtrace3.ml", line 16, characters 16-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 29, characters 41-50 +Called from file "backtrace3.ml", line 54, characters 11-23 +c +Uncaught exception Backtrace3.Error("c") +Raised at file "backtrace3.ml", line 33, characters 41-58 +Called from file "backtrace3.ml", line 54, characters 11-23 +d +Uncaught exception Backtrace3.Error("d") +Raised at file "backtrace3.ml", line 16, characters 16-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 36, characters 41-50 +Called from file "backtrace3.ml", line 54, characters 11-23 +e +Uncaught exception Backtrace3.Error("e") +Raised at file "backtrace3.ml", line 16, characters 16-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 39, characters 41-51 +Called from file "backtrace3.ml", line 54, characters 11-23 +f +Uncaught exception Backtrace3.Error("f") +Raised at file "backtrace3.ml", line 16, characters 16-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 44, characters 45-54 +Called from file "backtrace3.ml", line 54, characters 11-23 +g +Uncaught exception Backtrace3.Error("g") +Raised at file "backtrace3.ml", line 16, characters 16-32 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 16, characters 42-53 +Called from file "backtrace3.ml", line 20, characters 4-11 +Re-raised at file "backtrace3.ml", line 47, characters 45-55 +Called from file "backtrace3.ml", line 54, characters 11-23 +Uncaught exception Backtrace3.Error("h") +Raised at file "backtrace3.ml", line 50, characters 10-17 +Called from file "backtrace3.ml", line 54, characters 11-23 +Uncaught exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace3.ml", line 54, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_deprecated.byte.reference b/testsuite/tests/backtrace/backtrace_deprecated.byte.reference index e3eee3d6..57158d35 100644 --- a/testsuite/tests/backtrace/backtrace_deprecated.byte.reference +++ b/testsuite/tests/backtrace/backtrace_deprecated.byte.reference @@ -2,26 +2,26 @@ a No exception b Uncaught exception Backtrace_deprecated.Error("b") -Raised at file "backtrace_deprecated.ml", line 10, characters 21-32 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 14, characters 4-11 -Re-raised at file "backtrace_deprecated.ml", line 16, characters 68-71 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 +Raised at file "backtrace_deprecated.ml", line 19, characters 21-32 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 23, characters 4-11 +Re-raised at file "backtrace_deprecated.ml", line 25, characters 68-71 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 Uncaught exception Backtrace_deprecated.Error("c") -Raised at file "backtrace_deprecated.ml", line 17, characters 26-37 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 +Raised at file "backtrace_deprecated.ml", line 26, characters 26-37 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 Uncaught exception Backtrace_deprecated.Error("d") -Raised at file "backtrace_deprecated.ml", line 10, characters 21-32 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 14, characters 4-11 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 +Raised at file "backtrace_deprecated.ml", line 19, characters 21-32 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 23, characters 4-11 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace_deprecated.ml", line 21, characters 14-22 +Raised by primitive operation at file "backtrace_deprecated.ml", line 30, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_deprecated.ml b/testsuite/tests/backtrace/backtrace_deprecated.ml index 945d7730..8d34b6cf 100644 --- a/testsuite/tests/backtrace/backtrace_deprecated.ml +++ b/testsuite/tests/backtrace/backtrace_deprecated.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/backtrace_deprecated.byte.reference" + * native + reference = "${test_source_directory}/backtrace_deprecated.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) diff --git a/testsuite/tests/backtrace/backtrace_deprecated.native.reference b/testsuite/tests/backtrace/backtrace_deprecated.native.reference deleted file mode 100644 index 8d6826ec..00000000 --- a/testsuite/tests/backtrace/backtrace_deprecated.native.reference +++ /dev/null @@ -1,27 +0,0 @@ -a -No exception -b -Uncaught exception Backtrace_deprecated.Error("b") -Raised at file "backtrace_deprecated.ml", line 10, characters 16-32 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 14, characters 4-11 -Re-raised at file "backtrace_deprecated.ml", line 16, characters 62-71 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 -Uncaught exception Backtrace_deprecated.Error("c") -Raised at file "backtrace_deprecated.ml", line 17, characters 20-37 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 -Uncaught exception Backtrace_deprecated.Error("d") -Raised at file "backtrace_deprecated.ml", line 10, characters 16-32 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 10, characters 42-53 -Called from file "backtrace_deprecated.ml", line 14, characters 4-11 -Called from file "backtrace_deprecated.ml", line 21, characters 11-23 -Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace_deprecated.ml", line 21, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_deprecated.opt.reference b/testsuite/tests/backtrace/backtrace_deprecated.opt.reference new file mode 100644 index 00000000..61c47df2 --- /dev/null +++ b/testsuite/tests/backtrace/backtrace_deprecated.opt.reference @@ -0,0 +1,27 @@ +a +No exception +b +Uncaught exception Backtrace_deprecated.Error("b") +Raised at file "backtrace_deprecated.ml", line 19, characters 16-32 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 23, characters 4-11 +Re-raised at file "backtrace_deprecated.ml", line 25, characters 62-71 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 +Uncaught exception Backtrace_deprecated.Error("c") +Raised at file "backtrace_deprecated.ml", line 26, characters 20-37 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 +Uncaught exception Backtrace_deprecated.Error("d") +Raised at file "backtrace_deprecated.ml", line 19, characters 16-32 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 19, characters 42-53 +Called from file "backtrace_deprecated.ml", line 23, characters 4-11 +Called from file "backtrace_deprecated.ml", line 30, characters 11-23 +Uncaught exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace_deprecated.ml", line 30, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_slots.byte.reference b/testsuite/tests/backtrace/backtrace_slots.byte.reference index bfd8f5f4..ce4358b5 100644 --- a/testsuite/tests/backtrace/backtrace_slots.byte.reference +++ b/testsuite/tests/backtrace/backtrace_slots.byte.reference @@ -2,26 +2,26 @@ a No exception b Uncaught exception Backtrace_slots.Error("b") -Raised at file "backtrace_slots.ml", line 36, characters 21-32 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 40, characters 4-11 -Re-raised at file "backtrace_slots.ml", line 42, characters 68-71 -Called from file "backtrace_slots.ml", line 47, characters 11-23 +Raised at file "backtrace_slots.ml", line 45, characters 21-32 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 49, characters 4-11 +Re-raised at file "backtrace_slots.ml", line 51, characters 68-71 +Called from file "backtrace_slots.ml", line 56, characters 11-23 Uncaught exception Backtrace_slots.Error("c") -Raised at file "backtrace_slots.ml", line 43, characters 26-37 -Called from file "backtrace_slots.ml", line 47, characters 11-23 +Raised at file "backtrace_slots.ml", line 52, characters 26-37 +Called from file "backtrace_slots.ml", line 56, characters 11-23 Uncaught exception Backtrace_slots.Error("d") -Raised at file "backtrace_slots.ml", line 36, characters 21-32 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 40, characters 4-11 -Called from file "backtrace_slots.ml", line 47, characters 11-23 +Raised at file "backtrace_slots.ml", line 45, characters 21-32 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 49, characters 4-11 +Called from file "backtrace_slots.ml", line 56, characters 11-23 Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace_slots.ml", line 47, characters 14-22 +Raised by primitive operation at file "backtrace_slots.ml", line 56, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_slots.ml b/testsuite/tests/backtrace/backtrace_slots.ml index 877f8a5a..ef68b3fd 100644 --- a/testsuite/tests/backtrace/backtrace_slots.ml +++ b/testsuite/tests/backtrace/backtrace_slots.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/backtrace_slots.byte.reference" + * native + reference = "${test_source_directory}/backtrace_slots.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) diff --git a/testsuite/tests/backtrace/backtrace_slots.native.reference b/testsuite/tests/backtrace/backtrace_slots.native.reference deleted file mode 100644 index dd47e69d..00000000 --- a/testsuite/tests/backtrace/backtrace_slots.native.reference +++ /dev/null @@ -1,27 +0,0 @@ -a -No exception -b -Uncaught exception Backtrace_slots.Error("b") -Raised at file "backtrace_slots.ml", line 36, characters 16-32 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 40, characters 4-11 -Re-raised at file "backtrace_slots.ml", line 42, characters 62-71 -Called from file "backtrace_slots.ml", line 47, characters 11-23 -Uncaught exception Backtrace_slots.Error("c") -Raised at file "backtrace_slots.ml", line 43, characters 20-37 -Called from file "backtrace_slots.ml", line 47, characters 11-23 -Uncaught exception Backtrace_slots.Error("d") -Raised at file "backtrace_slots.ml", line 36, characters 16-32 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 36, characters 42-53 -Called from file "backtrace_slots.ml", line 40, characters 4-11 -Called from file "backtrace_slots.ml", line 47, characters 11-23 -Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "backtrace_slots.ml", line 47, characters 14-22 diff --git a/testsuite/tests/backtrace/backtrace_slots.opt.reference b/testsuite/tests/backtrace/backtrace_slots.opt.reference new file mode 100644 index 00000000..2d3c55fb --- /dev/null +++ b/testsuite/tests/backtrace/backtrace_slots.opt.reference @@ -0,0 +1,27 @@ +a +No exception +b +Uncaught exception Backtrace_slots.Error("b") +Raised at file "backtrace_slots.ml", line 45, characters 16-32 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 49, characters 4-11 +Re-raised at file "backtrace_slots.ml", line 51, characters 62-71 +Called from file "backtrace_slots.ml", line 56, characters 11-23 +Uncaught exception Backtrace_slots.Error("c") +Raised at file "backtrace_slots.ml", line 52, characters 20-37 +Called from file "backtrace_slots.ml", line 56, characters 11-23 +Uncaught exception Backtrace_slots.Error("d") +Raised at file "backtrace_slots.ml", line 45, characters 16-32 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 45, characters 42-53 +Called from file "backtrace_slots.ml", line 49, characters 4-11 +Called from file "backtrace_slots.ml", line 56, characters 11-23 +Uncaught exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "backtrace_slots.ml", line 56, characters 14-22 diff --git a/testsuite/tests/backtrace/backtraces_and_finalizers.ml b/testsuite/tests/backtrace/backtraces_and_finalizers.ml index 9edf7afb..8ea69593 100644 --- a/testsuite/tests/backtrace/backtraces_and_finalizers.ml +++ b/testsuite/tests/backtrace/backtraces_and_finalizers.ml @@ -1,3 +1,9 @@ +(* TEST + flags = "-g -inline 0" + ocamlrunparam += ",b=1" + compare_programs = "false" + * native +*) let () = Printexc.record_backtrace true diff --git a/testsuite/tests/backtrace/backtraces_and_finalizers.native.reference b/testsuite/tests/backtrace/backtraces_and_finalizers.reference similarity index 100% rename from testsuite/tests/backtrace/backtraces_and_finalizers.native.reference rename to testsuite/tests/backtrace/backtraces_and_finalizers.reference diff --git a/testsuite/tests/backtrace/filter-locations.sh b/testsuite/tests/backtrace/filter-locations.sh new file mode 100755 index 00000000..6d9757f4 --- /dev/null +++ b/testsuite/tests/backtrace/filter-locations.sh @@ -0,0 +1,2 @@ +#!/bin/sh +grep -oE '[a-zA-Z_]+\.ml(:[0-9]+)?|(line|characters) [0-9-]+' diff --git a/testsuite/tests/backtrace/inline_test.byte.reference b/testsuite/tests/backtrace/inline_test.byte.reference index 0cda2efd..ba14898e 100644 --- a/testsuite/tests/backtrace/inline_test.byte.reference +++ b/testsuite/tests/backtrace/inline_test.byte.reference @@ -1,15 +1,15 @@ inline_test.ml -line 5 +line 19 characters 8-24 inline_test.ml -line 8 +line 22 characters 2-5 inline_test.ml -line 11 +line 25 characters 12-17 inline_test.ml -line 14 +line 28 characters 5-8 inline_test.ml -line 18 +line 32 characters 2-6 diff --git a/testsuite/tests/backtrace/inline_test.ml b/testsuite/tests/backtrace/inline_test.ml index ae64e2cd..83f06bf6 100644 --- a/testsuite/tests/backtrace/inline_test.ml +++ b/testsuite/tests/backtrace/inline_test.ml @@ -1,3 +1,17 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/inline_test.byte.reference" + * native + reference = "${test_source_directory}/inline_test.opt.reference" + compare_programs = "false" + * native + ocamlopt_flags = "-O3" + compiler_directory_suffix = ".O3" + reference = "${test_source_directory}/inline_test.opt.reference" + compare_programs = "false" +*) (* A test for inlined stack backtraces *) diff --git a/testsuite/tests/backtrace/inline_test.native.reference b/testsuite/tests/backtrace/inline_test.native.reference deleted file mode 100644 index 644987b9..00000000 --- a/testsuite/tests/backtrace/inline_test.native.reference +++ /dev/null @@ -1,15 +0,0 @@ -inline_test.ml -line 5 -characters 2-24 -inline_test.ml -line 8 -characters 2-5 -inline_test.ml -line 11 -characters 12-17 -inline_test.ml -line 14 -characters 5-8 -inline_test.ml -line 18 -characters 2-6 diff --git a/testsuite/tests/backtrace/inline_test.opt.reference b/testsuite/tests/backtrace/inline_test.opt.reference new file mode 100644 index 00000000..2ee096e0 --- /dev/null +++ b/testsuite/tests/backtrace/inline_test.opt.reference @@ -0,0 +1,15 @@ +inline_test.ml +line 19 +characters 2-24 +inline_test.ml +line 22 +characters 2-5 +inline_test.ml +line 25 +characters 12-17 +inline_test.ml +line 28 +characters 5-8 +inline_test.ml +line 32 +characters 2-6 diff --git a/testsuite/tests/backtrace/inline_test.run b/testsuite/tests/backtrace/inline_test.run new file mode 100755 index 00000000..497b1940 --- /dev/null +++ b/testsuite/tests/backtrace/inline_test.run @@ -0,0 +1,3 @@ +#!/bin/sh +(${program} 2>&1 || true) | \ + ${test_source_directory}/filter-locations.sh > ${output} diff --git a/testsuite/tests/backtrace/inline_traversal_test.byte.reference b/testsuite/tests/backtrace/inline_traversal_test.byte.reference index bcb98c34..dfb7c0d6 100644 --- a/testsuite/tests/backtrace/inline_traversal_test.byte.reference +++ b/testsuite/tests/backtrace/inline_traversal_test.byte.reference @@ -1,5 +1,5 @@ -inline_traversal_test.ml:5 -inline_traversal_test.ml:8 -inline_traversal_test.ml:11 -inline_traversal_test.ml:14 inline_traversal_test.ml:19 +inline_traversal_test.ml:22 +inline_traversal_test.ml:25 +inline_traversal_test.ml:28 +inline_traversal_test.ml:33 diff --git a/testsuite/tests/backtrace/inline_traversal_test.ml b/testsuite/tests/backtrace/inline_traversal_test.ml index 1d918446..1bbcb357 100644 --- a/testsuite/tests/backtrace/inline_traversal_test.ml +++ b/testsuite/tests/backtrace/inline_traversal_test.ml @@ -1,3 +1,17 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/inline_traversal_test.byte.reference" + * native + reference = "${test_source_directory}/inline_traversal_test.opt.reference" + compare_programs = "false" + * native + ocamlopt_flags = "-O3" + compiler_directory_suffix = ".O3" + reference = "${test_source_directory}/inline_traversal_test.opt.reference" + compare_programs = "false" +*) (* A test for inlined stack backtraces *) diff --git a/testsuite/tests/backtrace/inline_traversal_test.native.reference b/testsuite/tests/backtrace/inline_traversal_test.native.reference deleted file mode 100644 index bcb98c34..00000000 --- a/testsuite/tests/backtrace/inline_traversal_test.native.reference +++ /dev/null @@ -1,5 +0,0 @@ -inline_traversal_test.ml:5 -inline_traversal_test.ml:8 -inline_traversal_test.ml:11 -inline_traversal_test.ml:14 -inline_traversal_test.ml:19 diff --git a/testsuite/tests/backtrace/inline_traversal_test.opt.reference b/testsuite/tests/backtrace/inline_traversal_test.opt.reference new file mode 100644 index 00000000..dfb7c0d6 --- /dev/null +++ b/testsuite/tests/backtrace/inline_traversal_test.opt.reference @@ -0,0 +1,5 @@ +inline_traversal_test.ml:19 +inline_traversal_test.ml:22 +inline_traversal_test.ml:25 +inline_traversal_test.ml:28 +inline_traversal_test.ml:33 diff --git a/testsuite/tests/backtrace/inline_traversal_test.run b/testsuite/tests/backtrace/inline_traversal_test.run new file mode 100755 index 00000000..497b1940 --- /dev/null +++ b/testsuite/tests/backtrace/inline_traversal_test.run @@ -0,0 +1,3 @@ +#!/bin/sh +(${program} 2>&1 || true) | \ + ${test_source_directory}/filter-locations.sh > ${output} diff --git a/testsuite/tests/backtrace/ocamltests b/testsuite/tests/backtrace/ocamltests new file mode 100644 index 00000000..166dcd7c --- /dev/null +++ b/testsuite/tests/backtrace/ocamltests @@ -0,0 +1,11 @@ +backtrace.ml +backtrace2.ml +backtrace3.ml +backtrace_deprecated.ml +backtrace_slots.ml +backtraces_and_finalizers.ml +inline_test.ml +inline_traversal_test.ml +pr6920_why_at.ml +pr6920_why_swallow.ml +raw_backtrace.ml diff --git a/testsuite/tests/backtrace/pr6920_why_at.byte.reference b/testsuite/tests/backtrace/pr6920_why_at.byte.reference index dcc2fcc1..44285955 100644 --- a/testsuite/tests/backtrace/pr6920_why_at.byte.reference +++ b/testsuite/tests/backtrace/pr6920_why_at.byte.reference @@ -1,4 +1,4 @@ -Fatal error: exception Pervasives.Exit -Raised at file "pr6920_why_at.ml", line 1, characters 41-45 -Called from file "pr6920_why_at.ml", line 3, characters 2-11 -Called from file "pr6920_why_at.ml", line 9, characters 2-6 +Fatal error: exception Stdlib.Pervasives.Exit +Raised at file "pr6920_why_at.ml", line 13, characters 41-45 +Called from file "pr6920_why_at.ml", line 15, characters 2-11 +Called from file "pr6920_why_at.ml", line 21, characters 2-6 diff --git a/testsuite/tests/backtrace/pr6920_why_at.ml b/testsuite/tests/backtrace/pr6920_why_at.ml index 0cd9f73d..83e78475 100644 --- a/testsuite/tests/backtrace/pr6920_why_at.ml +++ b/testsuite/tests/backtrace/pr6920_why_at.ml @@ -1,3 +1,15 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + ocamlopt_flags = "-inline 0" + exit_status = "2" + * bytecode + reference = "${test_source_directory}/pr6920_why_at.byte.reference" + * native + reference = "${test_source_directory}/pr6920_why_at.opt.reference" + compare_programs = "false" +*) + let why : unit -> unit = fun () -> raise Exit [@@inline never] let f () = why @@ (); diff --git a/testsuite/tests/backtrace/pr6920_why_at.native.reference b/testsuite/tests/backtrace/pr6920_why_at.native.reference deleted file mode 100644 index 057c3895..00000000 --- a/testsuite/tests/backtrace/pr6920_why_at.native.reference +++ /dev/null @@ -1,4 +0,0 @@ -Fatal error: exception Pervasives.Exit -Raised at file "pr6920_why_at.ml", line 1, characters 35-45 -Called from file "pr6920_why_at.ml", line 3, characters 2-11 -Called from file "pr6920_why_at.ml", line 9, characters 2-6 diff --git a/testsuite/tests/backtrace/pr6920_why_at.opt.reference b/testsuite/tests/backtrace/pr6920_why_at.opt.reference new file mode 100644 index 00000000..62a0ef96 --- /dev/null +++ b/testsuite/tests/backtrace/pr6920_why_at.opt.reference @@ -0,0 +1,4 @@ +Fatal error: exception Stdlib.Pervasives.Exit +Raised at file "pr6920_why_at.ml", line 13, characters 35-45 +Called from file "pr6920_why_at.ml", line 15, characters 2-11 +Called from file "pr6920_why_at.ml", line 21, characters 2-6 diff --git a/testsuite/tests/backtrace/pr6920_why_swallow.byte.reference b/testsuite/tests/backtrace/pr6920_why_swallow.byte.reference index f7e3ca34..c262211d 100644 --- a/testsuite/tests/backtrace/pr6920_why_swallow.byte.reference +++ b/testsuite/tests/backtrace/pr6920_why_swallow.byte.reference @@ -1,4 +1,4 @@ -Fatal error: exception Pervasives.Exit -Raised at file "pr6920_why_swallow.ml", line 1, characters 41-45 -Called from file "pr6920_why_swallow.ml", line 4, characters 4-13 -Called from file "pr6920_why_swallow.ml", line 11, characters 2-6 +Fatal error: exception Stdlib.Pervasives.Exit +Raised at file "pr6920_why_swallow.ml", line 13, characters 41-45 +Called from file "pr6920_why_swallow.ml", line 16, characters 4-13 +Called from file "pr6920_why_swallow.ml", line 23, characters 2-6 diff --git a/testsuite/tests/backtrace/pr6920_why_swallow.ml b/testsuite/tests/backtrace/pr6920_why_swallow.ml index def1d485..11b5badb 100644 --- a/testsuite/tests/backtrace/pr6920_why_swallow.ml +++ b/testsuite/tests/backtrace/pr6920_why_swallow.ml @@ -1,3 +1,15 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + ocamlopt_flags = "-inline 0" + exit_status = "2" + * bytecode + reference = "${test_source_directory}/pr6920_why_swallow.byte.reference" + * native + reference = "${test_source_directory}/pr6920_why_swallow.opt.reference" + compare_programs = "false" +*) + let why : unit -> unit = fun () -> raise Exit [@@inline never] let f () = for i = 1 to 10 do diff --git a/testsuite/tests/backtrace/pr6920_why_swallow.native.reference b/testsuite/tests/backtrace/pr6920_why_swallow.native.reference deleted file mode 100644 index 1e28144b..00000000 --- a/testsuite/tests/backtrace/pr6920_why_swallow.native.reference +++ /dev/null @@ -1,4 +0,0 @@ -Fatal error: exception Pervasives.Exit -Raised at file "pr6920_why_swallow.ml", line 1, characters 35-45 -Called from file "pr6920_why_swallow.ml", line 4, characters 4-13 -Called from file "pr6920_why_swallow.ml", line 11, characters 2-6 diff --git a/testsuite/tests/backtrace/pr6920_why_swallow.opt.reference b/testsuite/tests/backtrace/pr6920_why_swallow.opt.reference new file mode 100644 index 00000000..b842cee0 --- /dev/null +++ b/testsuite/tests/backtrace/pr6920_why_swallow.opt.reference @@ -0,0 +1,4 @@ +Fatal error: exception Stdlib.Pervasives.Exit +Raised at file "pr6920_why_swallow.ml", line 13, characters 35-45 +Called from file "pr6920_why_swallow.ml", line 16, characters 4-13 +Called from file "pr6920_why_swallow.ml", line 23, characters 2-6 diff --git a/testsuite/tests/backtrace/raw_backtrace.byte.reference b/testsuite/tests/backtrace/raw_backtrace.byte.reference index ba437e33..59c565cd 100644 --- a/testsuite/tests/backtrace/raw_backtrace.byte.reference +++ b/testsuite/tests/backtrace/raw_backtrace.byte.reference @@ -2,48 +2,48 @@ a No exception b Uncaught exception Raw_backtrace.Error("b") -Raised at file "raw_backtrace.ml", line 7, characters 21-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 18, characters 68-71 -Called from file "raw_backtrace.ml", line 33, characters 11-23 +Raised at file "raw_backtrace.ml", line 16, characters 21-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 27, characters 68-71 +Called from file "raw_backtrace.ml", line 42, characters 11-23 Uncaught exception Raw_backtrace.Error("c") -Raised at file "raw_backtrace.ml", line 19, characters 26-37 -Called from file "raw_backtrace.ml", line 33, characters 11-23 +Raised at file "raw_backtrace.ml", line 28, characters 26-37 +Called from file "raw_backtrace.ml", line 42, characters 11-23 Uncaught exception Raw_backtrace.Error("d") -Raised at file "raw_backtrace.ml", line 7, characters 21-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Called from file "raw_backtrace.ml", line 33, characters 11-23 +Raised at file "raw_backtrace.ml", line 16, characters 21-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Called from file "raw_backtrace.ml", line 42, characters 11-23 e Uncaught exception Raw_backtrace.Error("e") -Raised at file "raw_backtrace.ml", line 7, characters 21-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 25, characters 39-42 -Called from file "raw_backtrace.ml", line 33, characters 11-23 +Raised at file "raw_backtrace.ml", line 16, characters 21-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 34, characters 39-42 +Called from file "raw_backtrace.ml", line 42, characters 11-23 f Uncaught exception Raw_backtrace.Localized(_) -Raised at file "raw_backtrace.ml", line 7, characters 21-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 29, characters 39-54 -Called from file "raw_backtrace.ml", line 33, characters 11-23 +Raised at file "raw_backtrace.ml", line 16, characters 21-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 38, characters 39-54 +Called from file "raw_backtrace.ml", line 42, characters 11-23 Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "raw_backtrace.ml", line 33, characters 14-22 +Raised by primitive operation at file "raw_backtrace.ml", line 42, characters 14-22 diff --git a/testsuite/tests/backtrace/raw_backtrace.ml b/testsuite/tests/backtrace/raw_backtrace.ml index 45822751..824447e7 100644 --- a/testsuite/tests/backtrace/raw_backtrace.ml +++ b/testsuite/tests/backtrace/raw_backtrace.ml @@ -1,3 +1,12 @@ +(* TEST + flags = "-g" + ocamlrunparam += ",b=1" + * bytecode + reference = "${test_source_directory}/raw_backtrace.byte.reference" + * native + reference = "${test_source_directory}/raw_backtrace.opt.reference" + compare_programs = "false" +*) (* A test for stack backtraces *) diff --git a/testsuite/tests/backtrace/raw_backtrace.native.reference b/testsuite/tests/backtrace/raw_backtrace.native.reference deleted file mode 100644 index 06f4f164..00000000 --- a/testsuite/tests/backtrace/raw_backtrace.native.reference +++ /dev/null @@ -1,49 +0,0 @@ -a -No exception -b -Uncaught exception Raw_backtrace.Error("b") -Raised at file "raw_backtrace.ml", line 7, characters 16-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 18, characters 62-71 -Called from file "raw_backtrace.ml", line 33, characters 11-23 -Uncaught exception Raw_backtrace.Error("c") -Raised at file "raw_backtrace.ml", line 19, characters 20-37 -Called from file "raw_backtrace.ml", line 33, characters 11-23 -Uncaught exception Raw_backtrace.Error("d") -Raised at file "raw_backtrace.ml", line 7, characters 16-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Called from file "raw_backtrace.ml", line 33, characters 11-23 -e -Uncaught exception Raw_backtrace.Error("e") -Raised at file "raw_backtrace.ml", line 7, characters 16-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 25, characters 9-45 -Called from file "raw_backtrace.ml", line 33, characters 11-23 -f -Uncaught exception Raw_backtrace.Localized(_) -Raised at file "raw_backtrace.ml", line 7, characters 16-32 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 7, characters 42-53 -Called from file "raw_backtrace.ml", line 16, characters 4-11 -Re-raised at file "raw_backtrace.ml", line 29, characters 9-57 -Called from file "raw_backtrace.ml", line 33, characters 11-23 -Uncaught exception Invalid_argument("index out of bounds") -Raised by primitive operation at file "raw_backtrace.ml", line 33, characters 14-22 diff --git a/testsuite/tests/backtrace/raw_backtrace.opt.reference b/testsuite/tests/backtrace/raw_backtrace.opt.reference new file mode 100644 index 00000000..e170838c --- /dev/null +++ b/testsuite/tests/backtrace/raw_backtrace.opt.reference @@ -0,0 +1,49 @@ +a +No exception +b +Uncaught exception Raw_backtrace.Error("b") +Raised at file "raw_backtrace.ml", line 16, characters 16-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 27, characters 62-71 +Called from file "raw_backtrace.ml", line 42, characters 11-23 +Uncaught exception Raw_backtrace.Error("c") +Raised at file "raw_backtrace.ml", line 28, characters 20-37 +Called from file "raw_backtrace.ml", line 42, characters 11-23 +Uncaught exception Raw_backtrace.Error("d") +Raised at file "raw_backtrace.ml", line 16, characters 16-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Called from file "raw_backtrace.ml", line 42, characters 11-23 +e +Uncaught exception Raw_backtrace.Error("e") +Raised at file "raw_backtrace.ml", line 16, characters 16-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 34, characters 9-45 +Called from file "raw_backtrace.ml", line 42, characters 11-23 +f +Uncaught exception Raw_backtrace.Localized(_) +Raised at file "raw_backtrace.ml", line 16, characters 16-32 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 16, characters 42-53 +Called from file "raw_backtrace.ml", line 25, characters 4-11 +Re-raised at file "raw_backtrace.ml", line 38, characters 9-57 +Called from file "raw_backtrace.ml", line 42, characters 11-23 +Uncaught exception Invalid_argument("index out of bounds") +Raised by primitive operation at file "raw_backtrace.ml", line 42, characters 14-22 diff --git a/testsuite/tests/basic-float/Makefile b/testsuite/tests/basic-float/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/basic-float/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/basic-float/float_compare.ml b/testsuite/tests/basic-float/float_compare.ml index d5b7a9a1..1c9faf39 100644 --- a/testsuite/tests/basic-float/float_compare.ml +++ b/testsuite/tests/basic-float/float_compare.ml @@ -1,6 +1,112 @@ -let compare_nan () = - not (nan < 0.0) +let equal (x : float) (y : float) = + x, "=", y, (x = y) [@@inline never] -let x = print_endline (string_of_bool (compare_nan ())) +let not_equal (x : float) (y : float) = + x, "!=", y, (x <> y) +[@@inline never] + +let less_than (x : float) (y : float) = + x, "<", y, (x < y) +[@@inline never] + +let not_less_than (x : float) (y : float) = + x, "!<", y, not (x < y) +[@@inline never] + +let less_equal (x : float) (y : float) = + x, "<=", y, (x <= y) +[@@inline never] + +let not_less_equal (x : float) (y : float) = + x, "!<=", y, not (x <= y) +[@@inline never] + +let greater_than (x : float) (y : float) = + x, ">", y, (x > y) +[@@inline never] + +let not_greater_than (x : float) (y : float) = + x, "!>", y, not (x > y) +[@@inline never] + +let greater_equal (x : float) (y : float) = + x, ">=", y, (x >= y) +[@@inline never] + +let not_greater_equal (x : float) (y : float) = + x, "!>=", y, not (x >= y) +[@@inline never] + +let show (x, op, y, b) = + print_float x; + print_string " "; + print_string op; + print_string " "; + print_float y; + print_string ": "; + print_endline (string_of_bool b) + +let print_line () = + print_endline "------------------" + +let () = show (equal 1.0 2.0) +let () = show (equal 1.0 1.0) +let () = show (equal 2.0 1.0) +let () = show (equal 1.0 nan) +let () = print_line () + +let () = show (not_equal 1.0 2.0) +let () = show (not_equal 1.0 1.0) +let () = show (not_equal 2.0 1.0) +let () = show (not_equal 1.0 nan) +let () = print_line () + +let () = show (less_than 1.0 2.0) +let () = show (less_than 1.0 1.0) +let () = show (less_than 2.0 1.0) +let () = show (less_than 1.0 nan) +let () = print_line () + +let () = show (not_less_than 1.0 2.0) +let () = show (not_less_than 1.0 1.0) +let () = show (not_less_than 2.0 1.0) +let () = show (not_less_than 1.0 nan) +let () = print_line () + +let () = show (less_equal 1.0 2.0) +let () = show (less_equal 1.0 1.0) +let () = show (less_equal 2.0 1.0) +let () = show (less_equal 1.0 nan) +let () = print_line () + +let () = show (not_less_equal 1.0 2.0) +let () = show (not_less_equal 1.0 1.0) +let () = show (not_less_equal 2.0 1.0) +let () = show (not_less_equal 1.0 nan) +let () = print_line () + +let () = show (greater_than 1.0 2.0) +let () = show (greater_than 1.0 1.0) +let () = show (greater_than 2.0 1.0) +let () = show (greater_than 1.0 nan) +let () = print_line () + +let () = show (not_greater_than 1.0 2.0) +let () = show (not_greater_than 1.0 1.0) +let () = show (not_greater_than 2.0 1.0) +let () = show (not_greater_than 1.0 nan) +let () = print_line () + +let () = show (greater_equal 1.0 2.0) +let () = show (greater_equal 1.0 1.0) +let () = show (greater_equal 2.0 1.0) +let () = show (greater_equal 1.0 nan) +let () = print_line () + +let () = show (not_greater_equal 1.0 2.0) +let () = show (not_greater_equal 1.0 1.0) +let () = show (not_greater_equal 2.0 1.0) +let () = show (not_greater_equal 1.0 nan) +let () = print_line () diff --git a/testsuite/tests/basic-float/float_compare.reference b/testsuite/tests/basic-float/float_compare.reference index 27ba77dd..52efc29a 100644 --- a/testsuite/tests/basic-float/float_compare.reference +++ b/testsuite/tests/basic-float/float_compare.reference @@ -1 +1,50 @@ -true +1. = 2.: false +1. = 1.: true +2. = 1.: false +1. = nan: false +------------------ +1. != 2.: true +1. != 1.: false +2. != 1.: true +1. != nan: true +------------------ +1. < 2.: true +1. < 1.: false +2. < 1.: false +1. < nan: false +------------------ +1. !< 2.: false +1. !< 1.: true +2. !< 1.: true +1. !< nan: true +------------------ +1. <= 2.: true +1. <= 1.: true +2. <= 1.: false +1. <= nan: false +------------------ +1. !<= 2.: false +1. !<= 1.: false +2. !<= 1.: true +1. !<= nan: true +------------------ +1. > 2.: false +1. > 1.: false +2. > 1.: true +1. > nan: false +------------------ +1. !> 2.: true +1. !> 1.: true +2. !> 1.: false +1. !> nan: true +------------------ +1. >= 2.: false +1. >= 1.: true +2. >= 1.: true +1. >= nan: false +------------------ +1. !>= 2.: true +1. !>= 1.: false +2. !>= 1.: false +1. !>= nan: true +------------------ diff --git a/testsuite/tests/basic-float/ocamltests b/testsuite/tests/basic-float/ocamltests new file mode 100644 index 00000000..045a24cc --- /dev/null +++ b/testsuite/tests/basic-float/ocamltests @@ -0,0 +1,3 @@ +tfloat_hex.ml +tfloat_record.ml +zero_sized_float_arrays.ml diff --git a/testsuite/tests/basic-float/tfloat_hex.ml b/testsuite/tests/basic-float/tfloat_hex.ml index 995d50c2..5d7664c9 100644 --- a/testsuite/tests/basic-float/tfloat_hex.ml +++ b/testsuite/tests/basic-float/tfloat_hex.ml @@ -1,3 +1,5 @@ +(* TEST *) + let try_float_of_string str = try print_float (float_of_string str); @@ -13,3 +15,8 @@ let () = try_float_of_string "0x."; try_float_of_string "0xp0"; try_float_of_string "0x.p0"; + + (* MPR#7690 *) + try_float_of_string "0x1.0p-2147483648"; + try_float_of_string "0x123456789ABCDEF0p2147483647"; + try_float_of_string "0x1p2147483648"; diff --git a/testsuite/tests/basic-float/tfloat_hex.reference b/testsuite/tests/basic-float/tfloat_hex.reference index 9fce15f2..222649bc 100644 --- a/testsuite/tests/basic-float/tfloat_hex.reference +++ b/testsuite/tests/basic-float/tfloat_hex.reference @@ -4,3 +4,6 @@ Failure("float_of_string") Failure("float_of_string") Failure("float_of_string") Failure("float_of_string") +0. +inf +inf diff --git a/testsuite/tests/basic-float/tfloat_record.ml b/testsuite/tests/basic-float/tfloat_record.ml index 8df1a005..a0d2e2c7 100644 --- a/testsuite/tests/basic-float/tfloat_record.ml +++ b/testsuite/tests/basic-float/tfloat_record.ml @@ -1,3 +1,5 @@ +(* TEST *) + module Float_record : sig type t = private float;; diff --git a/testsuite/tests/basic-float/zero_sized_float_arrays.ml b/testsuite/tests/basic-float/zero_sized_float_arrays.ml index cc959b47..b207b828 100644 --- a/testsuite/tests/basic-float/zero_sized_float_arrays.ml +++ b/testsuite/tests/basic-float/zero_sized_float_arrays.ml @@ -1,3 +1,5 @@ +(* TEST *) + let non_float_array : int array = [| |] let float_array : float array = [| |] diff --git a/testsuite/tests/basic-manyargs/Makefile b/testsuite/tests/basic-manyargs/Makefile deleted file mode 100644 index b387d6ec..00000000 --- a/testsuite/tests/basic-manyargs/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=manyargs -C_FILES=manyargsprim - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/basic-manyargs/manyargs.ml b/testsuite/tests/basic-manyargs/manyargs.ml index 352f3cfa..53d3a595 100644 --- a/testsuite/tests/basic-manyargs/manyargs.ml +++ b/testsuite/tests/basic-manyargs/manyargs.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "manyargsprim.c" +*) + let manyargs a b c d e f g h i j k l m n o = print_string "a = "; print_int a; print_newline(); print_string "b = "; print_int b; print_newline(); diff --git a/testsuite/tests/basic-manyargs/ocamltests b/testsuite/tests/basic-manyargs/ocamltests new file mode 100644 index 00000000..b381a763 --- /dev/null +++ b/testsuite/tests/basic-manyargs/ocamltests @@ -0,0 +1 @@ +manyargs.ml diff --git a/testsuite/tests/basic-modules/ocamltests b/testsuite/tests/basic-modules/ocamltests index d389d156..57fba04f 100644 --- a/testsuite/tests/basic-modules/ocamltests +++ b/testsuite/tests/basic-modules/ocamltests @@ -1 +1,2 @@ main.ml +recursive_module_evaluation_errors.ml diff --git a/testsuite/tests/basic-modules/recursive_module_evaluation_errors.ml b/testsuite/tests/basic-modules/recursive_module_evaluation_errors.ml new file mode 100644 index 00000000..b937563f --- /dev/null +++ b/testsuite/tests/basic-modules/recursive_module_evaluation_errors.ml @@ -0,0 +1,24 @@ +(* TEST + * expect +*) + +module rec A: sig val x: int end = struct let x = B.x end +and B:sig val x: int end = struct let x = E.y end +and C:sig val x: int end = struct let x = B.x end +and D:sig val x: int end = struct let x = C.x end +and E:sig val x: int val y:int end = struct let x = D.x let y = 0 end +[%%expect {| +Line _, characters 27-49: + and B:sig val x: int end = struct let x = E.y end + ^^^^^^^^^^^^^^^^^^^^^^ +Error: Cannot safely evaluate the definition of the following cycle + of recursively-defined modules: B -> E -> D -> C -> B. + There are no safe modules in this cycle (see manual section 8.4) +|}] + +module rec M: sig val f: unit -> int end = struct let f () = N.x end +and N:sig val x: int end = struct let x = M.f () end;; +[%%expect {| +Exception: Undefined_recursive_module ("", 1, 43). +|}] + diff --git a/testsuite/tests/basic-more/Makefile b/testsuite/tests/basic-more/Makefile deleted file mode 100644 index a71792d6..00000000 --- a/testsuite/tests/basic-more/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=testing - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common -OCOPTFLAGS=-inline 20 diff --git a/testsuite/tests/basic-more/bounds.ml b/testsuite/tests/basic-more/bounds.ml index edaa0c8a..9915853f 100644 --- a/testsuite/tests/basic-more/bounds.ml +++ b/testsuite/tests/basic-more/bounds.ml @@ -1,4 +1,8 @@ -(* Test bound checks with ocamlopt *) +(* TEST + include testing +*) + +(* Test bound checks *) let a = [| 0; 1; 2 |] diff --git a/testsuite/tests/basic-more/div_by_zero.ml b/testsuite/tests/basic-more/div_by_zero.ml index 9dc45e7b..7cd91076 100644 --- a/testsuite/tests/basic-more/div_by_zero.ml +++ b/testsuite/tests/basic-more/div_by_zero.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) let check f n = assert ( diff --git a/testsuite/tests/basic-more/function_in_ref.ml b/testsuite/tests/basic-more/function_in_ref.ml index 3df98d71..48138409 100644 --- a/testsuite/tests/basic-more/function_in_ref.ml +++ b/testsuite/tests/basic-more/function_in_ref.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) let f x = x + 1 let g x = x - 1 diff --git a/testsuite/tests/basic-more/if_in_if.ml b/testsuite/tests/basic-more/if_in_if.ml index cd1e56bb..cf3525d2 100644 --- a/testsuite/tests/basic-more/if_in_if.ml +++ b/testsuite/tests/basic-more/if_in_if.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) let sequor b1 b2 = let b1 = ref b1 in diff --git a/testsuite/tests/basic-more/morematch.compilers.reference b/testsuite/tests/basic-more/morematch.compilers.reference new file mode 100644 index 00000000..7f077dd6 --- /dev/null +++ b/testsuite/tests/basic-more/morematch.compilers.reference @@ -0,0 +1,30 @@ +File "morematch.ml", line 1050, characters 8-65: +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(A `D|B (`B, (`A|`C))) +File "morematch.ml", line 67, characters 2-5: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 68, characters 2-3: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 219, characters 33-47: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 388, characters 2-15: +Warning 11: this match case is unused. +File "morematch.ml", line 401, characters 2-20: +Warning 11: this match case is unused. +File "morematch.ml", line 402, characters 2-16: +Warning 11: this match case is unused. +File "morematch.ml", line 403, characters 2-29: +Warning 11: this match case is unused. +File "morematch.ml", line 413, characters 5-12: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 432, characters 43-44: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 455, characters 7-8: +Warning 12: this sub-pattern is unused. +File "morematch.ml", line 456, characters 2-7: +Warning 11: this match case is unused. +File "morematch.ml", line 1084, characters 5-51: +Warning 11: this match case is unused. +File "morematch.ml", line 1086, characters 5-51: +Warning 11: this match case is unused. diff --git a/testsuite/tests/basic-more/morematch.ml b/testsuite/tests/basic-more/morematch.ml index 349c27e1..99d0d61d 100644 --- a/testsuite/tests/basic-more/morematch.ml +++ b/testsuite/tests/basic-more/morematch.ml @@ -1,20 +1,13 @@ +(* TEST + include testing +*) + (**************************************************************) (* This suite tests the pattern-matching compiler *) (* it should just compile and run. *) (* While compiling the following messages are normal: *) (**************************************************************) -(* -File "morematch.ml", line 38, characters 10-93: -Warning: this pattern-matching is not exhaustive. -Here is an example of a value that is not matched: -0 -File "morematch.ml", line 376, characters 2-15: -Warning: this match case is unused. -File "morematch.ml", line 443, characters 2-7: -Warning: this match case is unused. -*) - let test msg f arg r = if f arg <> r then begin prerr_endline msg ; @@ -74,18 +67,13 @@ let g x= match x with | 4|5|7 -> 100 | 7 | 8 -> 6 | 9 -> 7 -| _ -> 8 [@@ocaml.warning "-12"];; +| _ -> 8 +;; + test "quatre" g 4 4 ; test "quatre" g 7 100 ; () ;; -(* -File "morematch.ml", line 73, characters 2-5: -Warning U: this sub-pattern is unused. -File "morematch.ml", line 74, characters 2-3: -Warning U: this sub-pattern is unused. -*) - let h x = match x with (1,1) -> 1 @@ -229,7 +217,6 @@ test "foo1" f (1,2) (-1) let f = function (([]|[_]) as x)|(_::([] as x))|(_::_::x) -> x - [@@ocaml.warning "-12"] ;; test "zob" f [] [] ; @@ -398,7 +385,7 @@ let yaya = function | A,_,_ -> 1 | _,A,_ -> 2 | B,B,_ -> 3 -| A,_,(100|103) -> 5 [@@ocaml.warning "-11"] +| A,_,(100|103) -> 5 ;; test "yaya" yaya (A,A,0) 1 ; @@ -406,7 +393,7 @@ test "yaya" yaya (B,A,0) 2 ; test "yaya" yaya (B,B,100) 3 ; () ;; -(* + let yoyo = function | [],_,_ -> 1 | _,[],_ -> 2 @@ -432,7 +419,7 @@ test "youyou" youyou 100 1 ; test "youyou" youyou 101 2 ; test "youyou" youyou 1000 3 ;; -*) + type autre = | C | D | E of autre | F of autre * autre | H of autre | I | J | K of string @@ -445,12 +432,10 @@ let rec autre = function | (J,J,((C|D) as x |E x|F (_,x))) | (J,_,((C|J) as x)) -> autre (x,x,x) | (J, J, (I|H _|K _)) -> 9 | I,_,_ -> 6 -| E _,_,_ -> 7 [@@ocaml.warning "-12"] +| E _,_,_ -> 7 ;; -(* -File "morematch.ml", line 437, characters 43-44: -Warning U: this sub-pattern is unused. -*) + + test "autre" autre (J,J,F (D,D)) 3 ; test "autre" autre (J,J,D) 3 ; test "autre" autre (J,J,I) 9 ; @@ -468,14 +453,9 @@ let xyz = function | YB,YB,_ -> 3 | ((YB|YC), (YB|YC), (X|Y|Z|V _|T _)) -> 6 | _,_,(X|U _) -> 8 -| _,_,Y -> 5 [@@ocaml.warning "-11-12"] +| _,_,Y -> 5 ;; -(* -File "morematch.ml", line 459, characters 7-8: -Warning U: this sub-pattern is unused. -File "morematch.ml", line 460, characters 2-7: -Warning U: this match case is unused. -*) + test "xyz" xyz (YC,YC,X) 6 ; test "xyz" xyz (YC,YB,U X) 8 ; test "xyz" xyz (YB,YC,X) 6 ; () @@ -1065,18 +1045,12 @@ test "seb" seb ((0,Uout),Uin) 2 ; false (in Switch) *) -(* -File "morematch.ml", line 1060, characters 8-65: -Warning: this pattern-matching is not exhaustive. -Here is an example of a value that is not matched: -A `D -*) type ('a, 'b) t_j = A of 'a | B of 'b * 'a | C let f = function | A (`A|`C) -> 0 | B (`B,`D) -> 1 - | C -> 2 [@@ocaml.warning "-8"] + | C -> 2 let g x = try f x with Match_failure _ -> 3 @@ -1110,13 +1084,8 @@ let f = function | _, _, _, _, _, A, _, _, _, _, B, _, _, _, _, _ -> "11" | B, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ -> "12" | _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ -> "13" -[@@ocaml.warning "-11"] -(* -File "morematch.ml", line 1094, characters 5-51: -Warning: this match case is unused. -File "morematch.ml", line 1096, characters 5-51: -Warning: this match case is unused. -*) + + let _ = test "luc" f (B, A, A, A, A, A, A, A, A, A, A, B, A, A, A, A) "10" ; test "luc" f (B, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A) "12" ; diff --git a/testsuite/tests/basic-more/ocamltests b/testsuite/tests/basic-more/ocamltests new file mode 100644 index 00000000..7c74cb79 --- /dev/null +++ b/testsuite/tests/basic-more/ocamltests @@ -0,0 +1,17 @@ +bounds.ml +div_by_zero.ml +function_in_ref.ml +if_in_if.ml +morematch.ml +opaque_prim.ml +pr1271.ml +pr2719.ml +pr6216.ml +record_evaluation_order.ml +robustmatch.ml +sequential_and_or.ml +structural_constants.ml +tbuffer.ml +testrandom.ml +top_level_patterns.ml +tprintf.ml diff --git a/testsuite/tests/basic-more/opaque_prim.ml b/testsuite/tests/basic-more/opaque_prim.ml index 1c39f236..bdb60250 100644 --- a/testsuite/tests/basic-more/opaque_prim.ml +++ b/testsuite/tests/basic-more/opaque_prim.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + let f x = Sys.opaque_identity x let () = diff --git a/testsuite/tests/basic-more/pr1271.ml b/testsuite/tests/basic-more/pr1271.ml index 3890d0fb..adbb8734 100644 --- a/testsuite/tests/basic-more/pr1271.ml +++ b/testsuite/tests/basic-more/pr1271.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* GPR#1271 *) module F (X : sig val x : int end) = struct diff --git a/testsuite/tests/basic-more/pr2719.ml b/testsuite/tests/basic-more/pr2719.ml index d0357ea5..cb69aeae 100644 --- a/testsuite/tests/basic-more/pr2719.ml +++ b/testsuite/tests/basic-more/pr2719.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + open Printf let bug () = diff --git a/testsuite/tests/basic-more/pr6216.ml b/testsuite/tests/basic-more/pr6216.ml index 71844f14..3f6b4109 100644 --- a/testsuite/tests/basic-more/pr6216.ml +++ b/testsuite/tests/basic-more/pr6216.ml @@ -1,3 +1,8 @@ +(* TEST + include testing + ocamlopt_flags ="-inline 20" +*) + (* PR6216: wrong inlining of GADT match *) type _ t = diff --git a/testsuite/tests/basic-more/record_evaluation_order.ml b/testsuite/tests/basic-more/record_evaluation_order.ml index 0e18af8c..f8d1d568 100644 --- a/testsuite/tests/basic-more/record_evaluation_order.ml +++ b/testsuite/tests/basic-more/record_evaluation_order.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) type r = { a : unit; diff --git a/testsuite/tests/basic-more/sequential_and_or.ml b/testsuite/tests/basic-more/sequential_and_or.ml index b8aabae0..926cb9ab 100644 --- a/testsuite/tests/basic-more/sequential_and_or.ml +++ b/testsuite/tests/basic-more/sequential_and_or.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + let r = ref 0 let true_effect () = diff --git a/testsuite/tests/basic-more/structural_constants.ml b/testsuite/tests/basic-more/structural_constants.ml index 4249e8c6..21bb5b2f 100644 --- a/testsuite/tests/basic-more/structural_constants.ml +++ b/testsuite/tests/basic-more/structural_constants.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) type t1 = | A | B | C of t1 | D of float diff --git a/testsuite/tests/basic-more/tbuffer.ml b/testsuite/tests/basic-more/tbuffer.ml index b8348575..c3f96b73 100644 --- a/testsuite/tests/basic-more/tbuffer.ml +++ b/testsuite/tests/basic-more/tbuffer.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* Dummy substitute function. *) open Testing;; diff --git a/testsuite/tests/basic-more/testrandom.ml b/testsuite/tests/basic-more/testrandom.ml index 8a7ab475..dd4a76b3 100644 --- a/testsuite/tests/basic-more/testrandom.ml +++ b/testsuite/tests/basic-more/testrandom.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + open Random let _ = diff --git a/testsuite/tests/basic-more/top_level_patterns.ml b/testsuite/tests/basic-more/top_level_patterns.ml index 6b9b83f1..aca641fc 100644 --- a/testsuite/tests/basic-more/top_level_patterns.ml +++ b/testsuite/tests/basic-more/top_level_patterns.ml @@ -1,3 +1,6 @@ +(* TEST + include testing +*) type t = | A of (int * int * int) diff --git a/testsuite/tests/basic-more/tprintf.ml b/testsuite/tests/basic-more/tprintf.ml index 13b54a9e..e1cb4c0a 100644 --- a/testsuite/tests/basic-more/tprintf.ml +++ b/testsuite/tests/basic-more/tprintf.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + open Testing;; open Printf;; diff --git a/testsuite/tests/basic/Makefile b/testsuite/tests/basic/Makefile deleted file mode 100644 index 26cdeadf..00000000 --- a/testsuite/tests/basic/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common - -# The trigraph.ml test always fails under OpenBSD 6 / i386 -# because of an unrelated warning emitted by the linker called by ocamlopt -# (see commit log for details). -# As a temporary workaround, we skip this test. -SKIP=test $$file = trigraph.ml \ - && test `uname -m` = i386 && test `uname -s` = OpenBSD diff --git a/testsuite/tests/basic/arrays.ml b/testsuite/tests/basic/arrays.ml index 1ec4e4eb..83cc796c 100644 --- a/testsuite/tests/basic/arrays.ml +++ b/testsuite/tests/basic/arrays.ml @@ -1,3 +1,5 @@ +(* TEST *) + let bigarray n = [| n+0; n+1; n+2; n+3; n+4; n+5; n+6; n+7; n+8; n+9; n+10; n+11; n+12; n+13; n+14; n+15; n+16; n+17; n+18; n+19; n+20; n+21; n+22; n+23; diff --git a/testsuite/tests/basic/bigints.ml b/testsuite/tests/basic/bigints.ml index 23e571c3..281c1b09 100644 --- a/testsuite/tests/basic/bigints.ml +++ b/testsuite/tests/basic/bigints.ml @@ -1,3 +1,5 @@ +(* TEST *) + let _ = match Sys.word_size with | 32 -> diff --git a/testsuite/tests/basic/boxedints.ml b/testsuite/tests/basic/boxedints.ml index 016916f4..e3ff7000 100644 --- a/testsuite/tests/basic/boxedints.ml +++ b/testsuite/tests/basic/boxedints.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Test the types nativeint, int32, int64 *) open Printf diff --git a/testsuite/tests/basic/constprop.ml b/testsuite/tests/basic/constprop.ml index 89d98883..c89b1824 100644 --- a/testsuite/tests/basic/constprop.ml +++ b/testsuite/tests/basic/constprop.ml @@ -1,104 +1,124 @@ +(* TEST + flags = "-pp '${c_preprocessor}'" + * bytecode + compare_programs = "false" + * native +*) + (* Test constant propagation through inlining *) (* constprop.ml is generated from constprop.mlp using cpp constprop.mlp > constprop.ml *) + +#define tbool(x,y) \ + (x && y, x || y, not x) + +#define tint(x,y,s) \ + (-x, x + y, x - y, x * y, x / y, x mod y, \ + x land y, x lor y, x lxor y, \ + x lsl s, x lsr s, x asr s, \ + x = y, x <> y, x < y, x <= y, x > y, x >= y, \ + succ x, pred y) + +#define tfloat(x,y) \ + (int_of_float x, \ + x +. y, x -. y, x *. y, x /. y, \ + x = y, x <> y, x < y, x <= y, x > y, x >= y) + +#define tconvint(i) \ + (float_of_int i, \ + Int32.of_int i, \ + Nativeint.of_int i, \ + Int64.of_int i) + +#define tconvint32(i) \ + (Int32.to_int i, \ + Nativeint.of_int32 i, \ + Int64.of_int32 i) + +#define tconvnativeint(i) \ + (Nativeint.to_int i, \ + Nativeint.to_int32 i, \ + Int64.of_nativeint i) + +#define tconvint64(i) \ + (Int64.to_int i, \ + Int64.to_int32 i, \ + Int64.to_nativeint i) \ + +#define tint32(x,y,s) \ + Int32.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ + logand x y, logor x y, logxor x y, \ + shift_left x s, shift_right x s, shift_right_logical x s, \ + x = y, x <> y, x < y, x <= y, x > y, x >= y) + +#define tnativeint(x,y,s) \ + Nativeint.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ + logand x y, logor x y, logxor x y, \ + shift_left x s, shift_right x s, shift_right_logical x s, \ + x = y, x <> y, x < y, x <= y, x > y, x >= y) + +#define tint64(x,y,s) \ + Int64.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ + logand x y, logor x y, logxor x y, \ + shift_left x s, shift_right x s, shift_right_logical x s, \ + x = y, x <> y, x < y, x <= y, x > y, x >= y) + let do_test msg res1 res2 = Printf.printf "%s: %s\n" msg (if res1 = res2 then "passed" else "FAILED") + (* Hide a constant from the optimizer, preventing constant propagation *) let hide x = List.nth [x] 0 + let _ = begin let x = true and y = false in let xh = hide x and yh = hide y in - do_test "booleans" ((x && y, x || y, not x)) ((xh && yh, xh || yh, not xh)) + do_test "booleans" (tbool(x, y)) (tbool(xh,yh)) end; begin let x = 89809344 and y = 457455773 and s = 7 in let xh = hide x and yh = hide y and sh = hide s in - do_test "integers" - ((-x, x + y, x - y, x * y, x / y, x mod y, x land y, - x lor y, x lxor y, x lsl s, x lsr s, x asr s, x = y, - x <> y, x < y, x <= y, x > y, x >= y, succ x, pred y)) - ((-xh, xh + yh, xh - yh, xh * yh, xh / yh, xh mod yh, xh land yh, - xh lor yh, xh lxor yh, xh lsl sh, xh lsr sh, xh asr sh, xh = yh, - xh <> yh, xh < yh, xh <= yh, xh > yh, xh >= yh, succ xh, pred yh)) + do_test "integers" (tint(x, y, s)) (tint(xh,yh,sh)) end; begin let x = 3.141592654 and y = 0.341638588598232096 in let xh = hide x and yh = hide y in - do_test "floats" - ((int_of_float x, x +. y, x -. y, x *. y, x /. y, x = y, - x <> y, x < y, x <= y, x > y, x >= y)) - ((int_of_float xh, xh +. yh, xh -. yh, xh *. yh, xh /. yh, xh = yh, - xh <> yh, xh < yh, xh <= yh, xh > yh, xh >= yh)) + do_test "floats" (tfloat(x, y)) (tfloat(xh, yh)) end; begin let x = 781944104l and y = 308219921l and s = 3 in let xh = hide x and yh = hide y and sh = hide s in - do_test "32-bit integers" - (Int32.(neg x, add x y, sub x y, mul x y, div x y, rem x y, - logand x y, logor x y, logxor x y, shift_left x s, - shift_right x s, shift_right_logical x s, x = y, x <> y, - x < y, x <= y, x > y, x >= y)) - (Int32.(neg xh, add xh yh, sub xh yh, mul xh yh, div xh yh, rem xh yh, - logand xh yh, logor xh yh, logxor xh yh, shift_left xh sh, - shift_right xh sh, shift_right_logical xh sh, xh = yh, xh <> yh, - xh < yh, xh <= yh, xh > yh, xh >= yh)) + do_test "32-bit integers" (tint32(x, y, s)) (tint32(xh, yh, sh)) end; begin let x = 1828697041n and y = -521695949n and s = 8 in let xh = hide x and yh = hide y and sh = hide s in - do_test "native integers" - (Nativeint.(neg x, add x y, sub x y, mul x y, div x y, - rem x y, logand x y, logor x y, logxor x y, - shift_left x s, shift_right x s, - shift_right_logical x s, x = y, x <> y, x < y, - x <= y, x > y, x >= y)) - (Nativeint.(neg xh, add xh yh, sub xh yh, mul xh yh, div xh yh, - rem xh yh, logand xh yh, logor xh yh, logxor xh yh, - shift_left xh sh, shift_right xh sh, - shift_right_logical xh sh, xh = yh, xh <> yh, xh < yh, - xh <= yh, xh > yh, xh >= yh)) + do_test "native integers" (tnativeint(x, y, s)) (tnativeint(xh, yh, sh)) end; begin let x = 1511491586921138079L and y = 6677538715441746158L and s = 17 in let xh = hide x and yh = hide y and sh = hide s in - do_test "64-bit integers" - (Int64.(neg x, add x y, sub x y, mul x y, div x y, rem x y, - logand x y, logor x y, logxor x y, shift_left x s, - shift_right x s, shift_right_logical x s, x = y, x <> y, - x < y, x <= y, x > y, x >= y)) - (Int64.(neg xh, add xh yh, sub xh yh, mul xh yh, div xh yh, rem xh yh, - logand xh yh, logor xh yh, logxor xh yh, shift_left xh sh, - shift_right xh sh, shift_right_logical xh sh, xh = yh, xh <> yh, - xh < yh, xh <= yh, xh > yh, xh >= yh)) + do_test "64-bit integers" (tint64(x, y, s)) (tint64(xh, yh, sh)) end; begin let x = 1000807289 in let xh = hide x in - do_test "integer conversions" - ((float_of_int x, Int32.of_int x, Nativeint.of_int x, Int64.of_int x)) - ((float_of_int xh, Int32.of_int xh, Nativeint.of_int xh, Int64.of_int xh)) + do_test "integer conversions" (tconvint(x)) (tconvint(xh)) end; begin let x = 10486393l in let xh = hide x in - do_test "32-bit integer conversions" - ((Int32.to_int x, Nativeint.of_int32 x, Int64.of_int32 x)) - ((Int32.to_int xh, Nativeint.of_int32 xh, Int64.of_int32 xh)) + do_test "32-bit integer conversions" (tconvint32(x)) (tconvint32(xh)) end; begin let x = -131134014n in let xh = hide x in - do_test "native integer conversions" - ((Nativeint.to_int x, Nativeint.to_int32 x, Int64.of_nativeint x)) - ((Nativeint.to_int xh, Nativeint.to_int32 xh, Int64.of_nativeint xh)) + do_test "native integer conversions" (tconvnativeint(x))(tconvnativeint(xh)) end; begin let x = 531871273453404175L in let xh = hide x in - do_test "64-bit integer conversions" - ((Int64.to_int x, Int64.to_int32 x, Int64.to_nativeint x)) - ((Int64.to_int xh, Int64.to_int32 xh, Int64.to_nativeint xh)) + do_test "64-bit integer conversions" (tconvint64(x)) (tconvint64(xh)) end diff --git a/testsuite/tests/basic/constprop.mlp b/testsuite/tests/basic/constprop.mlp deleted file mode 100644 index f08bc50f..00000000 --- a/testsuite/tests/basic/constprop.mlp +++ /dev/null @@ -1,117 +0,0 @@ -(* Test constant propagation through inlining *) - -(* constprop.ml is generated from constprop.mlp using - cpp constprop.mlp > constprop.ml -*) - -#define tbool(x,y) \ - (x && y, x || y, not x) - -#define tint(x,y,s) \ - (-x, x + y, x - y, x * y, x / y, x mod y, \ - x land y, x lor y, x lxor y, \ - x lsl s, x lsr s, x asr s, \ - x = y, x <> y, x < y, x <= y, x > y, x >= y, \ - succ x, pred y) - -#define tfloat(x,y) \ - (int_of_float x, \ - x +. y, x -. y, x *. y, x /. y, \ - x = y, x <> y, x < y, x <= y, x > y, x >= y) - -#define tconvint(i) \ - (float_of_int i, \ - Int32.of_int i, \ - Nativeint.of_int i, \ - Int64.of_int i) - -#define tconvint32(i) \ - (Int32.to_int i, \ - Nativeint.of_int32 i, \ - Int64.of_int32 i) - -#define tconvnativeint(i) \ - (Nativeint.to_int i, \ - Nativeint.to_int32 i, \ - Int64.of_nativeint i) - -#define tconvint64(i) \ - (Int64.to_int i, \ - Int64.to_int32 i, \ - Int64.to_nativeint i) \ - -#define tint32(x,y,s) \ - Int32.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ - logand x y, logor x y, logxor x y, \ - shift_left x s, shift_right x s, shift_right_logical x s, \ - x = y, x <> y, x < y, x <= y, x > y, x >= y) - -#define tnativeint(x,y,s) \ - Nativeint.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ - logand x y, logor x y, logxor x y, \ - shift_left x s, shift_right x s, shift_right_logical x s, \ - x = y, x <> y, x < y, x <= y, x > y, x >= y) - -#define tint64(x,y,s) \ - Int64.(neg x, add x y, sub x y, mul x y, div x y, rem x y, \ - logand x y, logor x y, logxor x y, \ - shift_left x s, shift_right x s, shift_right_logical x s, \ - x = y, x <> y, x < y, x <= y, x > y, x >= y) - -let do_test msg res1 res2 = - Printf.printf "%s: %s\n" msg (if res1 = res2 then "passed" else "FAILED") - -(* Hide a constant from the optimizer, preventing constant propagation *) -let hide x = List.nth [x] 0 - -let _ = - begin - let x = true and y = false in - let xh = hide x and yh = hide y in - do_test "booleans" (tbool(x, y)) (tbool(xh,yh)) - end; - begin - let x = 89809344 and y = 457455773 and s = 7 in - let xh = hide x and yh = hide y and sh = hide s in - do_test "integers" (tint(x, y, s)) (tint(xh,yh,sh)) - end; - begin - let x = 3.141592654 and y = 0.341638588598232096 in - let xh = hide x and yh = hide y in - do_test "floats" (tfloat(x, y)) (tfloat(xh, yh)) - end; - begin - let x = 781944104l and y = 308219921l and s = 3 in - let xh = hide x and yh = hide y and sh = hide s in - do_test "32-bit integers" (tint32(x, y, s)) (tint32(xh, yh, sh)) - end; - begin - let x = 1828697041n and y = -521695949n and s = 8 in - let xh = hide x and yh = hide y and sh = hide s in - do_test "native integers" (tnativeint(x, y, s)) (tnativeint(xh, yh, sh)) - end; - begin - let x = 1511491586921138079L and y = 6677538715441746158L and s = 17 in - let xh = hide x and yh = hide y and sh = hide s in - do_test "64-bit integers" (tint64(x, y, s)) (tint64(xh, yh, sh)) - end; - begin - let x = 1000807289 in - let xh = hide x in - do_test "integer conversions" (tconvint(x)) (tconvint(xh)) - end; - begin - let x = 10486393l in - let xh = hide x in - do_test "32-bit integer conversions" (tconvint32(x)) (tconvint32(xh)) - end; - begin - let x = -131134014n in - let xh = hide x in - do_test "native integer conversions" (tconvnativeint(x))(tconvnativeint(xh)) - end; - begin - let x = 531871273453404175L in - let xh = hide x in - do_test "64-bit integer conversions" (tconvint64(x)) (tconvint64(xh)) - end diff --git a/testsuite/tests/basic/divint.ml b/testsuite/tests/basic/divint.ml index c007edae..e315ad70 100644 --- a/testsuite/tests/basic/divint.ml +++ b/testsuite/tests/basic/divint.ml @@ -1,3 +1,5 @@ +(* TEST *) + open Printf (* Test integer division and modulus, esp. ocamlopt's optimization diff --git a/testsuite/tests/basic/equality.ml b/testsuite/tests/basic/equality.ml index ebf5cf43..19d76e09 100644 --- a/testsuite/tests/basic/equality.ml +++ b/testsuite/tests/basic/equality.ml @@ -1,3 +1,5 @@ +(* TEST *) + let test n check res = print_string "Test "; print_int n; if check res then print_string " passed.\n" else print_string " FAILED.\n"; diff --git a/testsuite/tests/basic/eval_order_1.ml b/testsuite/tests/basic/eval_order_1.ml index 7c20be3f..bad1d054 100644 --- a/testsuite/tests/basic/eval_order_1.ml +++ b/testsuite/tests/basic/eval_order_1.ml @@ -1,3 +1,5 @@ +(* TEST *) + let f x y = Printf.printf "%d %d\n" x y let i = ref 0 diff --git a/testsuite/tests/basic/eval_order_2.ml b/testsuite/tests/basic/eval_order_2.ml index 378398b3..e11da19b 100644 --- a/testsuite/tests/basic/eval_order_2.ml +++ b/testsuite/tests/basic/eval_order_2.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* PR#6136 *) exception Ok diff --git a/testsuite/tests/basic/eval_order_3.ml b/testsuite/tests/basic/eval_order_3.ml index 07c5367e..90a9eba9 100644 --- a/testsuite/tests/basic/eval_order_3.ml +++ b/testsuite/tests/basic/eval_order_3.ml @@ -1,3 +1,5 @@ +(* TEST *) + let i = ref 0 let f x y = diff --git a/testsuite/tests/basic/eval_order_4.ml b/testsuite/tests/basic/eval_order_4.ml index 8e29f455..0e7130a9 100644 --- a/testsuite/tests/basic/eval_order_4.ml +++ b/testsuite/tests/basic/eval_order_4.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* PR#7531 *) let f = diff --git a/testsuite/tests/basic/eval_order_6.ml b/testsuite/tests/basic/eval_order_6.ml index 14526e3c..bec1f7ed 100644 --- a/testsuite/tests/basic/eval_order_6.ml +++ b/testsuite/tests/basic/eval_order_6.ml @@ -1,3 +1,5 @@ +(* TEST *) + type t = { mutable x : int; y : int } diff --git a/testsuite/tests/basic/float.ml b/testsuite/tests/basic/float.ml index 9ebabbc4..a17c70fe 100644 --- a/testsuite/tests/basic/float.ml +++ b/testsuite/tests/basic/float.ml @@ -1 +1,3 @@ +(* TEST *) + Printf.printf "1./.0. = %f\n" (1.0 /. 0.0);; diff --git a/testsuite/tests/basic/float_physical_equality.ml b/testsuite/tests/basic/float_physical_equality.ml index 1fba3578..5e826a71 100644 --- a/testsuite/tests/basic/float_physical_equality.ml +++ b/testsuite/tests/basic/float_physical_equality.ml @@ -1,3 +1,5 @@ +(* TEST *) + let a = -0. let b = +0. diff --git a/testsuite/tests/basic/includestruct.ml b/testsuite/tests/basic/includestruct.ml index a9c4e91b..b141388b 100644 --- a/testsuite/tests/basic/includestruct.ml +++ b/testsuite/tests/basic/includestruct.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Test for "include " inside structures *) module A = diff --git a/testsuite/tests/basic/localexn.ml b/testsuite/tests/basic/localexn.ml index b0f8e85f..2654d9bf 100755 --- a/testsuite/tests/basic/localexn.ml +++ b/testsuite/tests/basic/localexn.ml @@ -1,3 +1,5 @@ +(* TEST *) + let f (type t) () = let exception E of t in (fun x -> E x), (function E _ -> print_endline "OK" | _ -> print_endline "KO") diff --git a/testsuite/tests/basic/maps.ml b/testsuite/tests/basic/maps.ml index cc95eb63..9ed19c0f 100644 --- a/testsuite/tests/basic/maps.ml +++ b/testsuite/tests/basic/maps.ml @@ -1,3 +1,5 @@ +(* TEST *) + module IntMap = Map.Make(struct type t = int let compare x y = x-y end) let m1 = IntMap.add 0 "A" (IntMap.add 4 "Y" (IntMap.singleton 3 "X1")) diff --git a/testsuite/tests/basic/min_int.ml b/testsuite/tests/basic/min_int.ml index fe0dd7c8..0b85db47 100644 --- a/testsuite/tests/basic/min_int.ml +++ b/testsuite/tests/basic/min_int.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* This will test the parsing of the smallest integer on 32-bit architectures. It doesn't do much on 64-bit but at least it doesn't crash. *) diff --git a/testsuite/tests/basic/ocamltests b/testsuite/tests/basic/ocamltests new file mode 100644 index 00000000..593fa408 --- /dev/null +++ b/testsuite/tests/basic/ocamltests @@ -0,0 +1,29 @@ +arrays.ml +bigints.ml +boxedints.ml +constprop.ml +divint.ml +equality.ml +eval_order_1.ml +eval_order_2.ml +eval_order_3.ml +eval_order_4.ml +eval_order_6.ml +float.ml +float_physical_equality.ml +includestruct.ml +localexn.ml +maps.ml +min_int.ml +opt_variants.ml +patmatch.ml +pr7253.ml +pr7533.ml +pr7657.ml +recvalues.ml +sets.ml +stringmatch.ml +switch_opts.ml +tailcalls.ml +trigraph.ml +zero_divided_by_n.ml diff --git a/testsuite/tests/basic/opt_variants.ml b/testsuite/tests/basic/opt_variants.ml index 16966be2..6cc954ef 100755 --- a/testsuite/tests/basic/opt_variants.ml +++ b/testsuite/tests/basic/opt_variants.ml @@ -1,3 +1,5 @@ +(* TEST *) + let () = assert(Sys.getenv_opt "FOOBAR_UNLIKELY_TO_EXIST_42" = None); diff --git a/testsuite/tests/basic/patmatch.ml b/testsuite/tests/basic/patmatch.ml index c1c00239..cbe1ca1e 100644 --- a/testsuite/tests/basic/patmatch.ml +++ b/testsuite/tests/basic/patmatch.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Tests for matchings on integers and characters *) (* Dense integer switch *) diff --git a/testsuite/tests/basic/pr7253.ml b/testsuite/tests/basic/pr7253.ml new file mode 100644 index 00000000..149488d0 --- /dev/null +++ b/testsuite/tests/basic/pr7253.ml @@ -0,0 +1,16 @@ +(* TEST *) + +(* MPR#7253: "at_exit functions get called twice if a callback raises + and prevents earlier handlers to execute." *) + +exception My_exception + +let () = + Printexc.set_uncaught_exception_handler (fun exn bt -> + match exn with + | My_exception -> print_endline "Caught"; exit 0 + | _ -> print_endline "Unexpected uncaught exception"); + at_exit (fun () -> print_endline "Last"); + at_exit (fun () -> print_endline "Raise"; raise My_exception); + at_exit (fun () -> print_endline "First") + diff --git a/testsuite/tests/basic/pr7253.reference b/testsuite/tests/basic/pr7253.reference new file mode 100644 index 00000000..009dd378 --- /dev/null +++ b/testsuite/tests/basic/pr7253.reference @@ -0,0 +1,4 @@ +First +Raise +Last +Caught diff --git a/testsuite/tests/basic/pr7533.ml b/testsuite/tests/basic/pr7533.ml index 47bbeeea..739e4cb8 100644 --- a/testsuite/tests/basic/pr7533.ml +++ b/testsuite/tests/basic/pr7533.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* PR#7533 *) exception Foo diff --git a/testsuite/tests/basic/pr7657.ml b/testsuite/tests/basic/pr7657.ml index 8803cf34..221506d0 100755 --- a/testsuite/tests/basic/pr7657.ml +++ b/testsuite/tests/basic/pr7657.ml @@ -1,3 +1,5 @@ +(* TEST *) + [@@@ocaml.warning "-21-5"] let foo g () = g 1; () diff --git a/testsuite/tests/basic/recvalues.ml b/testsuite/tests/basic/recvalues.ml index df32f5e7..5605202e 100644 --- a/testsuite/tests/basic/recvalues.ml +++ b/testsuite/tests/basic/recvalues.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Recursive value definitions *) let _ = diff --git a/testsuite/tests/basic/sets.ml b/testsuite/tests/basic/sets.ml index 8ce6ad59..ca5b14a1 100644 --- a/testsuite/tests/basic/sets.ml +++ b/testsuite/tests/basic/sets.ml @@ -1,3 +1,5 @@ +(* TEST *) + module IntSet = Set.Make(struct type t = int let compare x y = x-y end) let even = List.fold_right IntSet.add [0; -2; 2; 4; 6; -10] IntSet.empty diff --git a/testsuite/tests/basic/stringmatch.ml b/testsuite/tests/basic/stringmatch.ml index e1f4bdb4..ac14c6de 100644 --- a/testsuite/tests/basic/stringmatch.ml +++ b/testsuite/tests/basic/stringmatch.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Empty string oddities *) let rec tst01 s = match s with diff --git a/testsuite/tests/basic/switch_opts.ml b/testsuite/tests/basic/switch_opts.ml index 67034de3..1a6dfb86 100644 --- a/testsuite/tests/basic/switch_opts.ml +++ b/testsuite/tests/basic/switch_opts.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Test for optimisation of jump tables to arrays of constants *) let p = Printf.printf diff --git a/testsuite/tests/basic/tailcalls.ml b/testsuite/tests/basic/tailcalls.ml index 9e998139..32ac4744 100644 --- a/testsuite/tests/basic/tailcalls.ml +++ b/testsuite/tests/basic/tailcalls.ml @@ -1,3 +1,5 @@ +(* TEST *) + let rec tailcall4 a b c d = if a < 0 then b diff --git a/testsuite/tests/basic/trigraph.ml b/testsuite/tests/basic/trigraph.ml index 3b4914cf..871117fb 100644 --- a/testsuite/tests/basic/trigraph.ml +++ b/testsuite/tests/basic/trigraph.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* PR#6373 *) let () = print_string "??'" diff --git a/testsuite/tests/basic/zero_divided_by_n.ml b/testsuite/tests/basic/zero_divided_by_n.ml index 1523d962..d977c897 100644 --- a/testsuite/tests/basic/zero_divided_by_n.ml +++ b/testsuite/tests/basic/zero_divided_by_n.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Mantis 7201 *) let f () = 0 [@@inline never] diff --git a/testsuite/tests/callback/Makefile b/testsuite/tests/callback/Makefile deleted file mode 100644 index 27b36e58..00000000 --- a/testsuite/tests/callback/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -COMPFLAGS=-I $(OTOPDIR)/otherlibs/unix -LD_PATH=$(TOPDIR)/otherlibs/unix - -.PHONY: default -default: - @case " $(OTHERLIBRARIES) " in \ - *' unix '*) $(SET_LD_PATH) $(MAKE) run-byte; \ - $(SET_LD_PATH) $(MAKE) run-opt;; \ - *) $(MAKE) skip;; \ - esac - -.PHONY: common -common: - @$(CC) -c $(CFLAGS) $(CPPFLAGS) -I$(CTOPDIR)/byterun callbackprim.c - -.PHONY: skip -skip: - @for c in bytecode native; do \ - echo " ... testing '$$c': => skipped" ; \ - done - -.PHONY: run-byte -run-byte: common - @printf " ... testing 'bytecode':" - @$(OCAMLC) $(COMPFLAGS) -c tcallback.ml - @$(OCAMLC) $(COMPFLAGS) -o ./program$(EXE) -custom unix.cma \ - callbackprim.$(O) tcallback.cmo - @./program$(EXE) >bytecode.result - @$(DIFF) reference bytecode.result \ - && echo " => passed" || echo " => failed" - -.PHONY: run-opt -run-opt: common - @if $(BYTECODE_ONLY); then : ; else \ - printf " ... testing 'native':"; \ - $(OCAMLOPT) $(COMPFLAGS) -c tcallback.ml; \ - $(OCAMLOPT) $(COMPFLAGS) -o ./program$(EXE) unix.cmxa \ - callbackprim.$(O) tcallback.cmx; \ - ./program$(EXE) >native.result; \ - $(DIFF) reference native.result \ - && echo " => passed" || echo " => failed"; \ - fi - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result ./program$(EXE) - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/callback/ocamltests b/testsuite/tests/callback/ocamltests new file mode 100644 index 00000000..0484d5ec --- /dev/null +++ b/testsuite/tests/callback/ocamltests @@ -0,0 +1 @@ +tcallback.ml diff --git a/testsuite/tests/callback/tcallback.ml b/testsuite/tests/callback/tcallback.ml index 121d3c57..9e4e09f5 100644 --- a/testsuite/tests/callback/tcallback.ml +++ b/testsuite/tests/callback/tcallback.ml @@ -1,3 +1,11 @@ +(* TEST + include unix + modules = "callbackprim.c" + * libunix + ** bytecode + ** native +*) + (**************************************************************************) external mycallback1 : ('a -> 'b) -> 'a -> 'b = "mycallback1" diff --git a/testsuite/tests/callback/reference b/testsuite/tests/callback/tcallback.reference similarity index 100% rename from testsuite/tests/callback/reference rename to testsuite/tests/callback/tcallback.reference diff --git a/testsuite/tests/docstrings/Makefile b/testsuite/tests/docstrings/Makefile deleted file mode 100644 index ec94f6c1..00000000 --- a/testsuite/tests/docstrings/Makefile +++ /dev/null @@ -1,4 +0,0 @@ - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.dparsetree -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/docstrings/empty.ml b/testsuite/tests/docstrings/empty.ml deleted file mode 100644 index a4394f68..00000000 --- a/testsuite/tests/docstrings/empty.ml +++ /dev/null @@ -1,8 +0,0 @@ -type t = Label (**) -(** attached to t *) - -(**) - -(** Empty docstring comments should not generate attributes *) - -type w (**) diff --git a/testsuite/tests/docstrings/empty.ml.reference b/testsuite/tests/docstrings/empty.ml.reference deleted file mode 100644 index 5a91a65a..00000000 --- a/testsuite/tests/docstrings/empty.ml.reference +++ /dev/null @@ -1,52 +0,0 @@ -[ - structure_item (empty.ml[1,0+0]..[1,0+14]) - Pstr_type Rec - [ - type_declaration "t" (empty.ml[1,0+5]..[1,0+6]) (empty.ml[1,0+0]..[1,0+14]) - attribute "ocaml.doc" - [ - structure_item (empty.ml[2,20+0]..[2,20+20]) - Pstr_eval - expression (empty.ml[2,20+0]..[2,20+20]) - Pexp_constant PConst_string(" attached to t ",None) - ] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_variant - [ - (empty.ml[1,0+9]..[1,0+14]) - "Label" (empty.ml[1,0+9]..[1,0+14]) - [] - None - ] - ptype_private = Public - ptype_manifest = - None - ] - structure_item (empty.ml[6,48+0]..[6,48+62]) - Pstr_attribute "ocaml.text" - [ - structure_item (empty.ml[6,48+0]..[6,48+62]) - Pstr_eval - expression (empty.ml[6,48+0]..[6,48+62]) - Pexp_constant PConst_string(" Empty docstring comments should not generate attributes ",None) - ] - structure_item (empty.ml[8,112+0]..[8,112+6]) - Pstr_type Rec - [ - type_declaration "w" (empty.ml[8,112+5]..[8,112+6]) (empty.ml[8,112+0]..[8,112+6]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - None - ] -] - diff --git a/testsuite/tests/embedded/Makefile b/testsuite/tests/embedded/Makefile deleted file mode 100644 index 679c5b9d..00000000 --- a/testsuite/tests/embedded/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -.PHONY: default -default: - @$(MAKE) compile - @$(MAKE) run - -.PHONY: compile -compile: - @$(OCAMLC) -ccopt -I -ccopt $(CTOPDIR)/byterun cmstub.c - @$(OCAMLC) -ccopt -I -ccopt $(CTOPDIR)/byterun cmmain.c - @$(OCAMLC) -c cmcaml.ml - @$(OCAMLC) -custom -o program cmstub.$(O) cmcaml.cmo cmmain.$(O) - -.PHONY: run -run: - @printf " ... testing 'cmmain':" - @./program >program.result - @$(DIFF) program.reference program.result >/dev/null \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result program - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/embedded/cmcaml.ml b/testsuite/tests/embedded/cmcaml.ml index ae21a1f2..37d1794e 100644 --- a/testsuite/tests/embedded/cmcaml.ml +++ b/testsuite/tests/embedded/cmcaml.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "cmstub.c cmmain.c" +*) + (* OCaml part of the code *) let rec fib n = diff --git a/testsuite/tests/embedded/program.reference b/testsuite/tests/embedded/cmcaml.reference similarity index 100% rename from testsuite/tests/embedded/program.reference rename to testsuite/tests/embedded/cmcaml.reference diff --git a/testsuite/tests/embedded/ocamltests b/testsuite/tests/embedded/ocamltests new file mode 100644 index 00000000..b03fb35a --- /dev/null +++ b/testsuite/tests/embedded/ocamltests @@ -0,0 +1 @@ +cmcaml.ml diff --git a/testsuite/tests/exotic-syntax/Makefile b/testsuite/tests/exotic-syntax/Makefile deleted file mode 100644 index 447b65c7..00000000 --- a/testsuite/tests/exotic-syntax/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MAIN_MODULE=exotic - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/exotic-syntax/exotic.ml b/testsuite/tests/exotic-syntax/exotic.ml index 18280e68..94666e7f 100644 --- a/testsuite/tests/exotic-syntax/exotic.ml +++ b/testsuite/tests/exotic-syntax/exotic.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Exotic OCaml syntax constructs found in the manual that are not *) (* used in the source of the OCaml distribution (even in the tests). *) diff --git a/testsuite/tests/exotic-syntax/ocamltests b/testsuite/tests/exotic-syntax/ocamltests new file mode 100644 index 00000000..7ba0519b --- /dev/null +++ b/testsuite/tests/exotic-syntax/ocamltests @@ -0,0 +1 @@ +exotic.ml diff --git a/testsuite/tests/extension-constructor/Makefile b/testsuite/tests/extension-constructor/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/extension-constructor/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/extension-constructor/ocamltests b/testsuite/tests/extension-constructor/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/extension-constructor/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/extension-constructor/test.ml b/testsuite/tests/extension-constructor/test.ml index d73777a3..f738642a 100644 --- a/testsuite/tests/extension-constructor/test.ml +++ b/testsuite/tests/extension-constructor/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + type t = .. module M = struct diff --git a/testsuite/tests/flambda/Makefile b/testsuite/tests/flambda/Makefile deleted file mode 100644 index cbf581ad..00000000 --- a/testsuite/tests/flambda/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -ADD_OPTFLAGS=-unbox-closures - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/flambda/approx_meet.ml b/testsuite/tests/flambda/approx_meet.ml new file mode 100644 index 00000000..c8a12769 --- /dev/null +++ b/testsuite/tests/flambda/approx_meet.ml @@ -0,0 +1,15 @@ +(* TEST + * flambda + * native +*) + +(* from GPR#1794 *) + +let z = + let x = -0. and y = +0. in + if mod_float x 1. >= 0. then + x + else if false then x else y + +let () = + Printf.printf "%g\n" (1. /. z) diff --git a/testsuite/tests/flambda/approx_meet.reference b/testsuite/tests/flambda/approx_meet.reference new file mode 100644 index 00000000..ebd26be4 --- /dev/null +++ b/testsuite/tests/flambda/approx_meet.reference @@ -0,0 +1 @@ +-inf diff --git a/testsuite/tests/flambda/gpr998.ml b/testsuite/tests/flambda/gpr998.ml index 9f16185d..dfb06833 100644 --- a/testsuite/tests/flambda/gpr998.ml +++ b/testsuite/tests/flambda/gpr998.ml @@ -1,3 +1,7 @@ +(* TEST + ocamlopt_flags = "-unbox-closures" +*) + (* This test attempts to check that unused closures are not deleted during conversion from flambda to clambda. The idea is that there is a direct call to [foo] in [bar] even though the closure for [foo] is diff --git a/testsuite/tests/flambda/ocamltests b/testsuite/tests/flambda/ocamltests new file mode 100644 index 00000000..77176ff6 --- /dev/null +++ b/testsuite/tests/flambda/ocamltests @@ -0,0 +1,3 @@ +approx_meet.ml +gpr998.ml +specialise.ml diff --git a/testsuite/tests/flambda/specialise.ml b/testsuite/tests/flambda/specialise.ml new file mode 100644 index 00000000..a85d0cab --- /dev/null +++ b/testsuite/tests/flambda/specialise.ml @@ -0,0 +1,54 @@ +(* TEST + * flambda + ** native + ocamlopt_flags = "-O2 -inline-call-cost 1=20 -unbox-closures" +*) + +let hide_until_round_2 init_in_hide f_in_hide = + let x1_in_hide = + match init_in_hide with + | 0 -> true + | _ -> false + in + ignore (Sys.opaque_identity x1_in_hide); + let x2_in_hide = + match init_in_hide with + | 0 -> true + | _ -> false + in + ignore (Sys.opaque_identity x2_in_hide); + f_in_hide + +let foo bar init a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 = + let f_outer = + let baz = bar + 1 in + let rec f_inner x_in_f y_in_f b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 = + let dec = + b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9 + b10 + b11 + b12 + b13 + in + match x_in_f with + | Some _ -> g_inner x_in_f (y_in_f - dec) + | None -> g_inner x_in_f (y_in_f - 2) + and g_inner x_in_g y_in_g = + let a1 = baz + 1 in + let a2 = a1 + 1 in + let a3 = a2 + 1 in + let a4 = a3 + 1 in + let a5 = a4 + 1 in + let a6 = a5 + 1 in + let a7 = a6 + 1 in + let a8 = a7 + 1 in + let a9 = a8 + 1 in + let a10 = a9 + 1 in + let a11 = a10 + 1 in + let a12 = a11 + 1 in + let a13 = a12 + 1 in + match x_in_g with + | Some _ -> f_inner x_in_g (y_in_g - baz) a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 + | None -> f_inner x_in_g (y_in_g - baz) a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 + in + f_inner + in + let s = Some init in + let f_through_hide = hide_until_round_2 init f_outer in + (f_through_hide [@specialised]) s 10 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 diff --git a/testsuite/tests/basic/trigraph.ml.silent-compilation b/testsuite/tests/flambda/specialise.reference similarity index 100% rename from testsuite/tests/basic/trigraph.ml.silent-compilation rename to testsuite/tests/flambda/specialise.reference diff --git a/testsuite/tests/float-unboxing/Makefile b/testsuite/tests/float-unboxing/Makefile deleted file mode 100644 index 8f44b4fa..00000000 --- a/testsuite/tests/float-unboxing/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -#(***********************************************************************) -#(* *) -#(* OCaml *) -#(* *) -#(* Mark Shinwell, Jane Street Europe *) -#(* *) -#(* Copyright 2014 Institut National de Recherche en Informatique et *) -#(* en Automatique. All rights reserved. This file is distributed *) -#(* under the terms of the Q Public License version 1.0. *) -#(* *) -#(***********************************************************************) - -BASEDIR=../.. -MODULES=float_inline -MAIN_MODULE=float_subst_boxed_number -ADD_OPTCOMPFLAGS=-inline 20 - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common - -GENERATED_SOURCES=float_inline.ml *.flambda - -float_inline.ml: $(FLAMBDA).flambda -ifeq ($(FLAMBDA),false) - @echo "let eliminate_intermediate_float_record () = ()" > $@ -else - @cat float_flambda.ml > $@ -endif - -%.flambda: - @rm -f float_inline.ml - @touch $@ diff --git a/testsuite/tests/float-unboxing/float_flambda.ml b/testsuite/tests/float-unboxing/float_flambda.ml deleted file mode 100644 index 3c5dfded..00000000 --- a/testsuite/tests/float-unboxing/float_flambda.ml +++ /dev/null @@ -1,9 +0,0 @@ -let eliminate_intermediate_float_record () = - let r = ref 0. in - for n = 1 to 1000 do - let open Complex in - let c = { re = float n; im = 0. } in - r := !r +. (norm [@inlined]) ((add [@inlined]) c i); - done; - ignore (Sys.opaque_identity !r) - diff --git a/testsuite/tests/float-unboxing/float_subst_boxed_number.ml b/testsuite/tests/float-unboxing/float_subst_boxed_number.ml index 672b3ff8..8d3ad834 100644 --- a/testsuite/tests/float-unboxing/float_subst_boxed_number.ml +++ b/testsuite/tests/float-unboxing/float_subst_boxed_number.ml @@ -1,3 +1,23 @@ +(* TEST + include config + flags = "-w -55" + ocamlc_flags = "config.cmo" + ocamlopt_flags = "-inline 20 config.cmx" +*) + +let eliminate_intermediate_float_record () = + let r = ref 0. in + for n = 1 to 1000 do + let open Complex in + let c = { re = float n; im = 0. } in + (* The following line triggers warning 55 twice when compiled without flambda *) + (* It would be better to disable this warning just here but since *) + (* this is a backend-warning, this is not currently possible *) + (* Hence the use of the -w-55 command-line flag for this test *) + r := !r +. (norm [@inlined]) ((add [@inlined]) c i); + done; + ignore (Sys.opaque_identity !r) + module PR_6686 = struct type t = | A of float @@ -33,10 +53,9 @@ let check_noalloc name f = let a2 = Gc.allocated_bytes () in let alloc = (a2 -. 2. *. a1 +. a0) in - (* is there a better to test whether we run in native code? *) - match Filename.basename Sys.argv.(0) with - | "program.byte" | "program.byte.exe" -> () - | "program.native" | "program.native.exe" -> + match Sys.backend_type with + | Sys.Bytecode -> () + | Sys.Native -> if alloc > 100. then failwith (Printf.sprintf "%s; alloc = %.0f" name alloc) | _ -> assert false @@ -149,14 +168,6 @@ let ignore_useless_args () = ignore (g 0 10 5.) let () = - let flambda = - match Sys.getenv "FLAMBDA" with - | "true" -> true - | "false" -> false - | _ -> failwith "Cannot determine is flambda is enabled" - | exception Not_found -> failwith "Cannot determine is flambda is enabled" - in - check_noalloc "classify float" unbox_classify_float; check_noalloc "compare float" unbox_compare_float; check_noalloc "float refs" unbox_float_refs; @@ -164,10 +175,10 @@ let () = check_noalloc "unbox only if useful" unbox_only_if_useful; check_noalloc "ignore useless args" ignore_useless_args; - if flambda then begin + if Config.flambda then begin check_noalloc "float and int32 record" unbox_record; check_noalloc "eliminate intermediate immutable float record" - Float_inline.eliminate_intermediate_float_record; + eliminate_intermediate_float_record; end; check_noalloc "Gc.minor_words" unbox_minor_words; diff --git a/testsuite/tests/float-unboxing/ocamltests b/testsuite/tests/float-unboxing/ocamltests new file mode 100644 index 00000000..a430a13e --- /dev/null +++ b/testsuite/tests/float-unboxing/ocamltests @@ -0,0 +1 @@ +float_subst_boxed_number.ml diff --git a/testsuite/tests/formats-transition/Makefile b/testsuite/tests/formats-transition/Makefile deleted file mode 100644 index 9625a3fb..00000000 --- a/testsuite/tests/formats-transition/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml b/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml index 3127d773..21f4bf42 100644 --- a/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml +++ b/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* %n, %l, %N and %L have a scanf-specific semantics, but are supposed to be interpreted by Printf and Format as %u, despite this interpretation being mildly deprecated *) diff --git a/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml.reference b/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml.reference deleted file mode 100644 index 0afeaa2b..00000000 --- a/testsuite/tests/formats-transition/deprecated_unsigned_printers.ml.reference +++ /dev/null @@ -1,7 +0,0 @@ - -# * * val test : (int -> string, unit, string) format -> string = -# %n: true -# %l: true -# %N: true -# %L: true -# diff --git a/testsuite/tests/formats-transition/deprecated_unsigned_printers.ocaml.reference b/testsuite/tests/formats-transition/deprecated_unsigned_printers.ocaml.reference new file mode 100644 index 00000000..b5dbed86 --- /dev/null +++ b/testsuite/tests/formats-transition/deprecated_unsigned_printers.ocaml.reference @@ -0,0 +1,6 @@ +val test : (int -> string, unit, string) format -> string = +%n: true +%l: true +%N: true +%L: true + diff --git a/testsuite/tests/formats-transition/ignored_scan_counters.ml b/testsuite/tests/formats-transition/ignored_scan_counters.ml index 2186a82d..bc625511 100644 --- a/testsuite/tests/formats-transition/ignored_scan_counters.ml +++ b/testsuite/tests/formats-transition/ignored_scan_counters.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Benoit's patch did not support %_[nlNL]; test their behavior *) (* Ignore OCAMLRUNPARAM=b to be reproducible *) diff --git a/testsuite/tests/formats-transition/ignored_scan_counters.ml.reference b/testsuite/tests/formats-transition/ignored_scan_counters.ml.reference deleted file mode 100644 index 55f8ee68..00000000 --- a/testsuite/tests/formats-transition/ignored_scan_counters.ml.reference +++ /dev/null @@ -1,15 +0,0 @@ - -# - : unit = () -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Exception: Invalid_argument "Printf: bad conversion %_". -# Hello World! -# Hello World! -# Hello World! -# Hello World! -# diff --git a/testsuite/tests/formats-transition/ignored_scan_counters.ocaml.reference b/testsuite/tests/formats-transition/ignored_scan_counters.ocaml.reference new file mode 100644 index 00000000..ed4c7550 --- /dev/null +++ b/testsuite/tests/formats-transition/ignored_scan_counters.ocaml.reference @@ -0,0 +1,14 @@ +- : unit = () +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Exception: Invalid_argument "Printf: bad conversion %_". +Hello World! +Hello World! +Hello World! +Hello World! + diff --git a/testsuite/tests/formats-transition/legacy_incompatible_flags.ml b/testsuite/tests/formats-transition/legacy_incompatible_flags.ml index 53cf5c26..51397447 100644 --- a/testsuite/tests/formats-transition/legacy_incompatible_flags.ml +++ b/testsuite/tests/formats-transition/legacy_incompatible_flags.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* the legacy parser ignores flags on formatters on which they make no sense *) diff --git a/testsuite/tests/formats-transition/legacy_incompatible_flags.ml.reference b/testsuite/tests/formats-transition/legacy_incompatible_flags.ml.reference deleted file mode 100644 index 814a5d33..00000000 --- a/testsuite/tests/formats-transition/legacy_incompatible_flags.ml.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# * toto -# toto -# toto -# toto -# "toto" -# toto -# * * * diff --git a/testsuite/tests/formats-transition/legacy_incompatible_flags.ocaml.reference b/testsuite/tests/formats-transition/legacy_incompatible_flags.ocaml.reference new file mode 100644 index 00000000..efc53ffe --- /dev/null +++ b/testsuite/tests/formats-transition/legacy_incompatible_flags.ocaml.reference @@ -0,0 +1,7 @@ +toto +toto +toto +toto +"toto" +toto + diff --git a/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml b/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml index 16eca40c..73b433ea 100644 --- a/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml +++ b/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* test whether padding modifiers are accepted without any padding size diff --git a/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml.reference b/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml.reference deleted file mode 100644 index 81c05c0d..00000000 --- a/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# * * * * * * * * 3 -# 3 -# 3 -# 3 -# diff --git a/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ocaml.reference b/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ocaml.reference new file mode 100644 index 00000000..37080a7e --- /dev/null +++ b/testsuite/tests/formats-transition/legacy_unfinished_modifiers.ocaml.reference @@ -0,0 +1,5 @@ +3 +3 +3 +3 + diff --git a/testsuite/tests/formats-transition/ocamltests b/testsuite/tests/formats-transition/ocamltests new file mode 100644 index 00000000..a19e8ec2 --- /dev/null +++ b/testsuite/tests/formats-transition/ocamltests @@ -0,0 +1,4 @@ +deprecated_unsigned_printers.ml +ignored_scan_counters.ml +legacy_incompatible_flags.ml +legacy_unfinished_modifiers.ml diff --git a/testsuite/tests/formatting/Makefile b/testsuite/tests/formatting/Makefile deleted file mode 100644 index 3e7e9a52..00000000 --- a/testsuite/tests/formatting/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -BASEDIR=../.. -MAIN_MODULE=margins - -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/formatting/margins.ml b/testsuite/tests/formatting/margins.ml index 92c592f1..7ae3f7cf 100644 --- a/testsuite/tests/formatting/margins.ml +++ b/testsuite/tests/formatting/margins.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + let () = Format.pp_set_margin Format.std_formatter 20;; 1 + "foo";; diff --git a/testsuite/tests/formatting/margins.ml.reference b/testsuite/tests/formatting/margins.ml.reference deleted file mode 100644 index 66d2fc24..00000000 --- a/testsuite/tests/formatting/margins.ml.reference +++ /dev/null @@ -1,14 +0,0 @@ - -# # Characters 5-10: - 1 + "foo";; - ^^^^^ -Error: This expression has type - string - but an expression was expected of type - int -# # Characters 5-10: - 1 + "foo";; - ^^^^^ -Error: This expression has type string but an expression was expected of type - int -# diff --git a/testsuite/tests/formatting/margins.ocaml.reference b/testsuite/tests/formatting/margins.ocaml.reference new file mode 100644 index 00000000..13606fe5 --- /dev/null +++ b/testsuite/tests/formatting/margins.ocaml.reference @@ -0,0 +1,13 @@ +Characters 5-10: + 1 + "foo";; + ^^^^^ +Error: This expression has type + string + but an expression was expected of type + int +Characters 5-10: + 1 + "foo";; + ^^^^^ +Error: This expression has type string but an expression was expected of type + int + diff --git a/testsuite/tests/formatting/ocamltests b/testsuite/tests/formatting/ocamltests new file mode 100644 index 00000000..f780baa3 --- /dev/null +++ b/testsuite/tests/formatting/ocamltests @@ -0,0 +1 @@ +margins.ml diff --git a/testsuite/tests/functors/Makefile b/testsuite/tests/functors/Makefile deleted file mode 100644 index c4223d45..00000000 --- a/testsuite/tests/functors/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BASEDIR=../.. -TOPFLAGS+=-dlambda -include $(BASEDIR)/makefiles/Makefile.dlambda -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/functors/functors.compilers.reference b/testsuite/tests/functors/functors.compilers.reference new file mode 100644 index 00000000..929d8849 --- /dev/null +++ b/testsuite/tests/functors/functors.compilers.reference @@ -0,0 +1,51 @@ +(setglobal Functors! + (let + (O = + (module-defn(O) functors.ml(12):184-279 + (function X is_a_functor always_inline + (let + (cow = (function x (apply (field 0 X) x)) + sheep = (function x (+ 1 (apply cow x)))) + (makeblock 0 cow sheep)))) + F = + (module-defn(F) functors.ml(17):281-392 + (function X Y is_a_functor always_inline + (let + (cow = (function x (apply (field 0 Y) (apply (field 0 X) x))) + sheep = (function x (+ 1 (apply cow x)))) + (makeblock 0 cow sheep)))) + F1 = + (module-defn(F1) functors.ml(31):516-632 + (function X Y is_a_functor always_inline + (let + (cow = (function x (apply (field 0 Y) (apply (field 0 X) x))) + sheep = (function x (+ 1 (apply cow x)))) + (makeblock 0 sheep)))) + F2 = + (module-defn(F2) functors.ml(36):634-784 + (function X Y is_a_functor always_inline + (let + (X =a (makeblock 0 (field 1 X)) + Y =a (makeblock 0 (field 1 Y)) + cow = (function x (apply (field 0 Y) (apply (field 0 X) x))) + sheep = (function x (+ 1 (apply cow x)))) + (makeblock 0 sheep)))) + M = + (module-defn(M) functors.ml(41):786-970 + (let + (F = + (module-defn(F) functors.ml(44):849-966 + (function X Y is_a_functor always_inline + (let + (cow = + (function x (apply (field 0 Y) (apply (field 0 X) x))) + sheep = (function x (+ 1 (apply cow x)))) + (makeblock 0 cow sheep))))) + (makeblock 0 + (function funarg funarg is_a_functor stub + (let + (let = + (apply F (makeblock 0 (field 1 funarg)) + (makeblock 0 (field 1 funarg)))) + (makeblock 0 (field 1 let)))))))) + (makeblock 0 O F F1 F2 M))) diff --git a/testsuite/tests/functors/functors.ml b/testsuite/tests/functors/functors.ml index 32541699..3e40fc61 100644 --- a/testsuite/tests/functors/functors.ml +++ b/testsuite/tests/functors/functors.ml @@ -1,3 +1,10 @@ +(* TEST + * setup-ocamlc.byte-build-env + ** ocamlc.byte + flags = "-dlambda -dno-unique-ids" + *** check-ocamlc.byte-output +*) + module type S = sig val foo : int -> int end diff --git a/testsuite/tests/functors/functors.ml.reference b/testsuite/tests/functors/functors.ml.reference deleted file mode 100644 index 8037fe5e..00000000 --- a/testsuite/tests/functors/functors.ml.reference +++ /dev/null @@ -1,60 +0,0 @@ -(setglobal Functors! - (let - (O = - (module-defn(O) functors.ml(5):48-143 - (function X is_a_functor always_inline - (let - (cow = (function x (apply (field 0 X) x)) - sheep = (function x (+ 1 (apply cow x)))) - (makeblock 0 cow sheep)))) - F = - (module-defn(F) functors.ml(10):145-256 - (function X Y is_a_functor always_inline - (let - (cow = - (function x - (apply (field 0 Y) (apply (field 0 X) x))) - sheep = (function x (+ 1 (apply cow x)))) - (makeblock 0 cow sheep)))) - F1/1022 = - (module-defn(F1/1022) functors.ml(24):380-496 - (function X Y is_a_functor always_inline - (let - (cow = - (function x - (apply (field 0 Y) (apply (field 0 X) x))) - sheep = (function x (+ 1 (apply cow x)))) - (makeblock 0 sheep)))) - F2/1029 = - (module-defn(F2/1029) functors.ml(29):498-648 - (function X Y is_a_functor always_inline - (let - (X =a (makeblock 0 (field 1 X)) - Y =a (makeblock 0 (field 1 Y)) - cow = - (function x - (apply (field 0 Y) (apply (field 0 X) x))) - sheep = (function x (+ 1 (apply cow x)))) - (makeblock 0 sheep)))) - M = - (module-defn(M) functors.ml(34):650-834 - (let - (F = - (module-defn(F) functors.ml(37):713-830 - (function X Y is_a_functor always_inline - (let - (cow = - (function x - (apply (field 0 Y) - (apply (field 0 X) x))) - sheep = - (function x (+ 1 (apply cow x)))) - (makeblock 0 cow sheep))))) - (makeblock 0 - (function funarg funarg is_a_functor stub - (let - (let = - (apply F (makeblock 0 (field 1 funarg)) - (makeblock 0 (field 1 funarg)))) - (makeblock 0 (field 1 let)))))))) - (makeblock 0 O F F1/1022 F2/1029 M))) diff --git a/testsuite/tests/functors/ocamltests b/testsuite/tests/functors/ocamltests new file mode 100644 index 00000000..d5835c07 --- /dev/null +++ b/testsuite/tests/functors/ocamltests @@ -0,0 +1 @@ +functors.ml diff --git a/testsuite/tests/gc-roots/Makefile b/testsuite/tests/gc-roots/Makefile deleted file mode 100644 index c8e24cce..00000000 --- a/testsuite/tests/gc-roots/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=globroots -C_FILES=globrootsprim -ADD_COMPFLAGS=-w a - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/gc-roots/globroots.ml b/testsuite/tests/gc-roots/globroots.ml index 016277cf..8245e85f 100644 --- a/testsuite/tests/gc-roots/globroots.ml +++ b/testsuite/tests/gc-roots/globroots.ml @@ -1,3 +1,8 @@ +(* TEST + flags += " -w a " + modules = "globrootsprim.c" +*) + module type GLOBREF = sig type t val register: string -> t diff --git a/testsuite/tests/gc-roots/ocamltests b/testsuite/tests/gc-roots/ocamltests new file mode 100644 index 00000000..a199679f --- /dev/null +++ b/testsuite/tests/gc-roots/ocamltests @@ -0,0 +1 @@ +globroots.ml diff --git a/testsuite/tests/int64-unboxing/Makefile b/testsuite/tests/int64-unboxing/Makefile deleted file mode 100644 index 926edd17..00000000 --- a/testsuite/tests/int64-unboxing/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Jeremie Dimino, Jane Street Europe * -#* * -#* Copyright 2015 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES= -MAIN_MODULE=test -C_FILES=stubs - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common - -NATIVECODE_ONLY=true diff --git a/testsuite/tests/int64-unboxing/ocamltests b/testsuite/tests/int64-unboxing/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/int64-unboxing/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/int64-unboxing/test.ml b/testsuite/tests/int64-unboxing/test.ml index 4bffcc67..d35e5214 100644 --- a/testsuite/tests/int64-unboxing/test.ml +++ b/testsuite/tests/int64-unboxing/test.ml @@ -1,3 +1,8 @@ +(* TEST + modules = "stubs.c" + * native +*) + external ( + ) : int64 -> int64 -> int64 = "" "test_int64_add" [@@noalloc] [@@unboxed] external ( - ) : int64 -> int64 -> int64 diff --git a/testsuite/tests/lazy/Makefile b/testsuite/tests/lazy/Makefile deleted file mode 100644 index 59613588..00000000 --- a/testsuite/tests/lazy/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Mark Shinwell, Jane Street Europe * -#* * -#* Copyright 2016 Jane Street Group, LLC * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -ADD_OPTFLAGS=-O3 -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lazy/lazy1.ml b/testsuite/tests/lazy/lazy1.ml index 8ec74b6e..f88e93da 100644 --- a/testsuite/tests/lazy/lazy1.ml +++ b/testsuite/tests/lazy/lazy1.ml @@ -1,3 +1,7 @@ +(* TEST + ocamlopt_flags += " -O3 " +*) + (* Mantis 7301, due to A. Frisch *) let foo () = diff --git a/testsuite/tests/lazy/ocamltests b/testsuite/tests/lazy/ocamltests new file mode 100644 index 00000000..0b1f5a93 --- /dev/null +++ b/testsuite/tests/lazy/ocamltests @@ -0,0 +1 @@ +lazy1.ml diff --git a/testsuite/tests/letrec-disallowed/Makefile b/testsuite/tests/letrec-disallowed/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/letrec-disallowed/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/letrec-disallowed/disallowed.ml b/testsuite/tests/letrec-disallowed/disallowed.ml index ded2be96..ae156843 100644 --- a/testsuite/tests/letrec-disallowed/disallowed.ml +++ b/testsuite/tests/letrec-disallowed/disallowed.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + let rec x = let y = () in x;; let rec x = let module M = struct let f = x let g = x () end in fun () -> ();; diff --git a/testsuite/tests/letrec-disallowed/disallowed.ml.reference b/testsuite/tests/letrec-disallowed/disallowed.ml.reference deleted file mode 100644 index c053974b..00000000 --- a/testsuite/tests/letrec-disallowed/disallowed.ml.reference +++ /dev/null @@ -1,126 +0,0 @@ - -# Characters 12-27: - let rec x = let y = () in x;; - ^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x let g = x () end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x () let g = x end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-79: - let rec x = (let module M = struct let f = y 0 let g = () end in fun () -> ()) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-79: - let rec x = let module M = struct module N = struct let y = x end end in M.N.y;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x () and g = x end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# class c : 'a -> object end -# Characters 12-19: - let rec x = new c x;; - ^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-21: - let rec x = ignore x;; - ^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-16: - let rec x = y 0 and y _ = ();; - ^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-40: - let rec c = { c with Complex.re = 1.0 };; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-38: - let rec b = if b then true else false;; - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 28-34: - let rec x = r := x;; - ^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-65: - ..for i = 0 to 1 do - let z = y in ignore z - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-46: - ..for i = 0 to y do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-47: - ..for i = y to 10 do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-62: - ..while false do - let y = x in ignore y - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-39: - ..while y do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-58: - ..while y do - let y = x in ignore y - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-16: - let rec x = y#m and y = object method m = () end;; - ^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-45: - let rec x = (object method m _ = () end)#m x;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-23: - let rec x = y.contents and y = { contents = 3 };; - ^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-59: - let rec x = object val mutable v = 0 method m = v <- y end and y = 1;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-21: - let rec x = assert y and y = true;; - ^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-36: - let rec x = object method m = x end;; - ^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-43: - let rec x = object method m = ignore x end;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# * Characters 230-246: - let rec x = Pervasives.ref y - ^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# * Characters 127-175: - if p then (fun y -> x + g y) else (fun y -> g y) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 37-61: - let rec x = (module (val y : T) : T) - ^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-98: - ..match let _ = y in raise Not_found with - _ -> "x" - | exception Not_found -> "z". -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/disallowed.ocaml.reference b/testsuite/tests/letrec-disallowed/disallowed.ocaml.reference new file mode 100644 index 00000000..7effceb8 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/disallowed.ocaml.reference @@ -0,0 +1,125 @@ +Characters 38-53: + let rec x = let y = () in x;; + ^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-77: + let rec x = let module M = struct let f = x let g = x () end in fun () -> ();; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-77: + let rec x = let module M = struct let f = x () let g = x end in fun () -> ();; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-79: + let rec x = (let module M = struct let f = y 0 let g = () end in fun () -> ()) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-79: + let rec x = let module M = struct module N = struct let y = x end end in M.N.y;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-77: + let rec x = let module M = struct let f = x () and g = x end in fun () -> ();; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +class c : 'a -> object end +Characters 12-19: + let rec x = new c x;; + ^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-21: + let rec x = ignore x;; + ^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-16: + let rec x = y 0 and y _ = ();; + ^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-40: + let rec c = { c with Complex.re = 1.0 };; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-38: + let rec b = if b then true else false;; + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 28-34: + let rec x = r := x;; + ^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-65: + ..for i = 0 to 1 do + let z = y in ignore z + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-46: + ..for i = 0 to y do + () + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-47: + ..for i = y to 10 do + () + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-62: + ..while false do + let y = x in ignore y + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-39: + ..while y do + () + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-58: + ..while y do + let y = x in ignore y + done +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-16: + let rec x = y#m and y = object method m = () end;; + ^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-45: + let rec x = (object method m _ = () end)#m x;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-23: + let rec x = y.contents and y = { contents = 3 };; + ^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-59: + let rec x = object val mutable v = 0 method m = v <- y end and y = 1;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-21: + let rec x = assert y and y = true;; + ^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-36: + let rec x = object method m = x end;; + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 13-43: + let rec x = object method m = ignore x end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 230-246: + let rec x = Pervasives.ref y + ^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 127-175: + if p then (fun y -> x + g y) else (fun y -> g y) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 37-61: + let rec x = (module (val y : T) : T) + ^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 15-98: + ..match let _ = y in raise Not_found with + _ -> "x" + | exception Not_found -> "z". +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/extension_constructor.ml b/testsuite/tests/letrec-disallowed/extension_constructor.ml index eb013ea8..a49fcbd0 100644 --- a/testsuite/tests/letrec-disallowed/extension_constructor.ml +++ b/testsuite/tests/letrec-disallowed/extension_constructor.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Example from Stephen Dolan. Accessing an extension constructor involves accessing the module in which it's defined. diff --git a/testsuite/tests/letrec-disallowed/extension_constructor.ml.reference b/testsuite/tests/letrec-disallowed/extension_constructor.ml.reference deleted file mode 100644 index f680d737..00000000 --- a/testsuite/tests/letrec-disallowed/extension_constructor.ml.reference +++ /dev/null @@ -1,7 +0,0 @@ - -# * * * module type T = sig exception A of int end -# Characters 15-49: - ..let module M = (val m) in - M.A 42 -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/extension_constructor.ocaml.reference b/testsuite/tests/letrec-disallowed/extension_constructor.ocaml.reference new file mode 100644 index 00000000..fcd714e1 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/extension_constructor.ocaml.reference @@ -0,0 +1,6 @@ +module type T = sig exception A of int end +Characters 15-49: + ..let module M = (val m) in + M.A 42 +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/float_block.ml b/testsuite/tests/letrec-disallowed/float_block.ml deleted file mode 100644 index 4f8fc9d9..00000000 --- a/testsuite/tests/letrec-disallowed/float_block.ml +++ /dev/null @@ -1,6 +0,0 @@ -let test = - let rec x = [| y; y |] and y = 1. in - assert (x = [| 1.; 1. |]); - assert (y = 1.); - () -;; diff --git a/testsuite/tests/letrec-disallowed/float_block.ml.reference b/testsuite/tests/letrec-disallowed/float_block.ml.reference deleted file mode 100644 index 58b1e32f..00000000 --- a/testsuite/tests/letrec-disallowed/float_block.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# Characters 25-35: - let rec x = [| y; y |] and y = 1. in - ^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/float_block_allowed.ml b/testsuite/tests/letrec-disallowed/float_block_allowed.ml new file mode 100644 index 00000000..1b9ad983 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/float_block_allowed.ml @@ -0,0 +1,14 @@ +(* TEST + * no-flat-float-array + ** toplevel +*) + +(* these recursive float arrays are allowed when -no-flat-float-array + is set -- the first array element is not forced on array creation + anymore *) +let test = + let rec x = [| y; y |] and y = 1. in + assert (x = [| 1.; 1. |]); + assert (y = 1.); + () +;; diff --git a/testsuite/tests/letrec-disallowed/float_block_allowed.ocaml.reference b/testsuite/tests/letrec-disallowed/float_block_allowed.ocaml.reference new file mode 100644 index 00000000..422a95ec --- /dev/null +++ b/testsuite/tests/letrec-disallowed/float_block_allowed.ocaml.reference @@ -0,0 +1,2 @@ +val test : unit = () + diff --git a/testsuite/tests/letrec-disallowed/float_block_disallowed.ml b/testsuite/tests/letrec-disallowed/float_block_disallowed.ml new file mode 100644 index 00000000..ca9e6dc8 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/float_block_disallowed.ml @@ -0,0 +1,18 @@ +(* TEST + * flat-float-array + ** toplevel +*) + +(* when the -flat-float-array optimization is active (standard in + OCaml versions up to at least 4.07), creating an array inspects its + first element to decide whether it is a float or not; it would thus + be unsound to allow to recursively define a float value and an + array starting with that element (in general we disallow using a + recursively-defined value in an array literal). +*) +let test = + let rec x = [| y; y |] and y = 1. in + assert (x = [| 1.; 1. |]); + assert (y = 1.); + () +;; diff --git a/testsuite/tests/letrec-disallowed/float_block_disallowed.ocaml.reference b/testsuite/tests/letrec-disallowed/float_block_disallowed.ocaml.reference new file mode 100644 index 00000000..f3139c32 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/float_block_disallowed.ocaml.reference @@ -0,0 +1,5 @@ +Characters 470-480: + let rec x = [| y; y |] and y = 1. in + ^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/generic_arrays.ml b/testsuite/tests/letrec-disallowed/generic_arrays.ml index 46d93423..a4735051 100644 --- a/testsuite/tests/letrec-disallowed/generic_arrays.ml +++ b/testsuite/tests/letrec-disallowed/generic_arrays.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* This is not allowed because constructing the generic array 'x' involves inspecting 'y', which is bound in the same recursive group *) let f z = let rec x = [| y; z |] and y = z in x;; diff --git a/testsuite/tests/letrec-disallowed/generic_arrays.ml.reference b/testsuite/tests/letrec-disallowed/generic_arrays.ml.reference deleted file mode 100644 index 449d1a0f..00000000 --- a/testsuite/tests/letrec-disallowed/generic_arrays.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# * Characters 162-172: - let f z = let rec x = [| y; z |] and y = z in x;; - ^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/generic_arrays.ocaml.reference b/testsuite/tests/letrec-disallowed/generic_arrays.ocaml.reference new file mode 100644 index 00000000..cfac91cc --- /dev/null +++ b/testsuite/tests/letrec-disallowed/generic_arrays.ocaml.reference @@ -0,0 +1,5 @@ +Characters 188-198: + let f z = let rec x = [| y; z |] and y = z in x;; + ^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/labels.ml b/testsuite/tests/letrec-disallowed/labels.ml new file mode 100644 index 00000000..ff94719a --- /dev/null +++ b/testsuite/tests/letrec-disallowed/labels.ml @@ -0,0 +1,6 @@ +(* TEST + * toplevel +*) + +let f ~x () = x ();; +let rec x = f ~x;; diff --git a/testsuite/tests/letrec-disallowed/labels.ocaml.reference b/testsuite/tests/letrec-disallowed/labels.ocaml.reference new file mode 100644 index 00000000..2e778e55 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/labels.ocaml.reference @@ -0,0 +1,6 @@ +val f : x:(unit -> 'a) -> unit -> 'a = +Characters 12-16: + let rec x = f ~x;; + ^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/lazy_.ml b/testsuite/tests/letrec-disallowed/lazy_.ml index e958ef1f..38a964ed 100644 --- a/testsuite/tests/letrec-disallowed/lazy_.ml +++ b/testsuite/tests/letrec-disallowed/lazy_.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + let rec a = lazy b and b = 3;; let rec e = lazy (fun _ -> f) and f = ();; diff --git a/testsuite/tests/letrec-disallowed/lazy_.ml.reference b/testsuite/tests/letrec-disallowed/lazy_.ml.reference deleted file mode 100644 index 538bf005..00000000 --- a/testsuite/tests/letrec-disallowed/lazy_.ml.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# Characters 12-18: - let rec a = lazy b and b = 3;; - ^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# val e : ('a -> unit) lazy_t = lazy -val f : unit = () -# diff --git a/testsuite/tests/letrec-disallowed/lazy_.ocaml.reference b/testsuite/tests/letrec-disallowed/lazy_.ocaml.reference new file mode 100644 index 00000000..0c6ebd21 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/lazy_.ocaml.reference @@ -0,0 +1,7 @@ +Characters 39-45: + let rec a = lazy b and b = 3;; + ^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +val e : ('a -> unit) lazy_t = lazy +val f : unit = () + diff --git a/testsuite/tests/letrec-disallowed/module_constraints.ml b/testsuite/tests/letrec-disallowed/module_constraints.ml index faf81f23..29114fea 100644 --- a/testsuite/tests/letrec-disallowed/module_constraints.ml +++ b/testsuite/tests/letrec-disallowed/module_constraints.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + module type S = sig val y : float end;; module type T = sig val x : float val y : float end;; type t = T : (module S) -> t;; diff --git a/testsuite/tests/letrec-disallowed/module_constraints.ml.reference b/testsuite/tests/letrec-disallowed/module_constraints.ml.reference deleted file mode 100644 index b1aec6fc..00000000 --- a/testsuite/tests/letrec-disallowed/module_constraints.ml.reference +++ /dev/null @@ -1,9 +0,0 @@ - -# module type S = sig val y : float end -# module type T = sig val x : float val y : float end -# type t = T : (module S) -> t -# Characters 13-51: - let rec x = let module M = (val m) in T (module M) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/module_constraints.ocaml.reference b/testsuite/tests/letrec-disallowed/module_constraints.ocaml.reference new file mode 100644 index 00000000..b94a8779 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/module_constraints.ocaml.reference @@ -0,0 +1,8 @@ +module type S = sig val y : float end +module type T = sig val x : float val y : float end +type t = T : (module S) -> t +Characters 13-51: + let rec x = let module M = (val m) in T (module M) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/ocamltests b/testsuite/tests/letrec-disallowed/ocamltests new file mode 100644 index 00000000..f7eed7e3 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/ocamltests @@ -0,0 +1,12 @@ +disallowed.ml +extension_constructor.ml +float_block_allowed.ml +float_block_disallowed.ml +generic_arrays.ml +labels.ml +lazy_.ml +module_constraints.ml +pr7215.ml +pr7231.ml +pr7706.ml +unboxed.ml diff --git a/testsuite/tests/letrec-disallowed/pr7215.ml b/testsuite/tests/letrec-disallowed/pr7215.ml index 223434d1..0a13bd6e 100644 --- a/testsuite/tests/letrec-disallowed/pr7215.ml +++ b/testsuite/tests/letrec-disallowed/pr7215.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* From Stephen Dolan *) type (_,_) eq = Refl : ('a, 'a) eq;; let cast (type a) (type b) (Refl : (a, b) eq) (x : a) = (x : b);; diff --git a/testsuite/tests/letrec-disallowed/pr7215.ml.reference b/testsuite/tests/letrec-disallowed/pr7215.ml.reference deleted file mode 100644 index 19735e4f..00000000 --- a/testsuite/tests/letrec-disallowed/pr7215.ml.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# type (_, _) eq = Refl : ('a, 'a) eq -# val cast : ('a, 'b) eq -> 'a -> 'b = -# Characters 53-78: - let rec (p : (int, a) eq) = match p with Refl -> Refl in - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/pr7215.ocaml.reference b/testsuite/tests/letrec-disallowed/pr7215.ocaml.reference new file mode 100644 index 00000000..0c16042e --- /dev/null +++ b/testsuite/tests/letrec-disallowed/pr7215.ocaml.reference @@ -0,0 +1,7 @@ +type (_, _) eq = Refl : ('a, 'a) eq +val cast : ('a, 'b) eq -> 'a -> 'b = +Characters 53-78: + let rec (p : (int, a) eq) = match p with Refl -> Refl in + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/pr7231.ml b/testsuite/tests/letrec-disallowed/pr7231.ml index 5f8282d5..22234b3d 100644 --- a/testsuite/tests/letrec-disallowed/pr7231.ml +++ b/testsuite/tests/letrec-disallowed/pr7231.ml @@ -1 +1,5 @@ +(* TEST + * toplevel +*) + let rec r = let rec x () = r and y () = x () in y () in r "oops";; diff --git a/testsuite/tests/letrec-disallowed/pr7231.ml.reference b/testsuite/tests/letrec-disallowed/pr7231.ml.reference deleted file mode 100644 index a7648155..00000000 --- a/testsuite/tests/letrec-disallowed/pr7231.ml.reference +++ /dev/null @@ -1,10 +0,0 @@ - -# Characters 58-64: - let rec r = let rec x () = r and y () = x () in y () in r "oops";; - ^^^^^^ -Warning 20: this argument will not be used by the function. -Characters 12-52: - let rec r = let rec x () = r and y () = x () in y () in r "oops";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/pr7231.ocaml.reference b/testsuite/tests/letrec-disallowed/pr7231.ocaml.reference new file mode 100644 index 00000000..fb6be21e --- /dev/null +++ b/testsuite/tests/letrec-disallowed/pr7231.ocaml.reference @@ -0,0 +1,9 @@ +Characters 84-90: + let rec r = let rec x () = r and y () = x () in y () in r "oops";; + ^^^^^^ +Warning 20: this argument will not be used by the function. +Characters 38-78: + let rec r = let rec x () = r and y () = x () in y () in r "oops";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec-disallowed/pr7706.ml b/testsuite/tests/letrec-disallowed/pr7706.ml new file mode 100644 index 00000000..87403cd5 --- /dev/null +++ b/testsuite/tests/letrec-disallowed/pr7706.ml @@ -0,0 +1,8 @@ +(* TEST + * toplevel +*) +let rec x = + let y = if false then (fun z -> 1) else (fun z -> x 4 + 1) in + y;; + +let () = ignore (x 42);; diff --git a/testsuite/tests/letrec-disallowed/pr7706.ocaml.reference b/testsuite/tests/letrec-disallowed/pr7706.ocaml.reference new file mode 100644 index 00000000..e0bc36ea --- /dev/null +++ b/testsuite/tests/letrec-disallowed/pr7706.ocaml.reference @@ -0,0 +1,9 @@ +Characters 39-104: + ..let y = if false then (fun z -> 1) else (fun z -> x 4 + 1) in + y.. +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 18-19: + let () = ignore (x 42);; + ^ +Error: Unbound value x + diff --git a/testsuite/tests/letrec-disallowed/unboxed.ml b/testsuite/tests/letrec-disallowed/unboxed.ml index c19fefa6..eaab1c3b 100644 --- a/testsuite/tests/letrec-disallowed/unboxed.ml +++ b/testsuite/tests/letrec-disallowed/unboxed.ml @@ -1,6 +1,29 @@ +(* TEST + * toplevel +*) + type t = {x: int64} [@@unboxed];; let rec x = {x = y} and y = 3L;; type r = A of r [@@unboxed];; let rec y = A y;; +type a = {a: b }[@@unboxed] +and b = X of a | Y + +let rec a = + {a= + (if Sys.opaque_identity true then + X a + else + Y)};; + +type d = D of e [@@unboxed] +and e = V of d | W;; + +let rec d = + D + (if Sys.opaque_identity true then + V d + else + W);; diff --git a/testsuite/tests/letrec-disallowed/unboxed.ml.reference b/testsuite/tests/letrec-disallowed/unboxed.ml.reference deleted file mode 100644 index b824227e..00000000 --- a/testsuite/tests/letrec-disallowed/unboxed.ml.reference +++ /dev/null @@ -1,12 +0,0 @@ - -# type t = { x : int64; } [@@unboxed] -# Characters 12-19: - let rec x = {x = y} and y = 3L;; - ^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# type r = A of r [@@unboxed] -# Characters 12-15: - let rec y = A y;; - ^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec-disallowed/unboxed.ocaml.reference b/testsuite/tests/letrec-disallowed/unboxed.ocaml.reference new file mode 100644 index 00000000..41962dce --- /dev/null +++ b/testsuite/tests/letrec-disallowed/unboxed.ocaml.reference @@ -0,0 +1,27 @@ +type t = { x : int64; } [@@unboxed] +Characters 12-19: + let rec x = {x = y} and y = 3L;; + ^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +type r = A of r [@@unboxed] +Characters 12-15: + let rec y = A y;; + ^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +Characters 77-150: + ..{a= + (if Sys.opaque_identity true then + X a + else + Y)}.. +Error: This kind of expression is not allowed as right-hand side of `let rec' +type d = D of e [@@unboxed] +and e = V of d | W +Characters 15-85: + ..D + (if Sys.opaque_identity true then + V d + else + W).. +Error: This kind of expression is not allowed as right-hand side of `let rec' + diff --git a/testsuite/tests/letrec/Makefile b/testsuite/tests/letrec/Makefile deleted file mode 100644 index ef0afea5..00000000 --- a/testsuite/tests/letrec/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/letrec/allowed.ml b/testsuite/tests/letrec/allowed.ml index f8e89566..8c6910a7 100644 --- a/testsuite/tests/letrec/allowed.ml +++ b/testsuite/tests/letrec/allowed.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec x = (x; ());; let rec x = let x = () in x;; @@ -45,7 +48,7 @@ and y = fun () -> ignore x let rec x = { contents = y } and y = fun () -> ignore x;; - + let r = ref (fun () -> ()) let rec x = fun () -> r := x;; @@ -73,6 +76,33 @@ let rec deep_cycle : [`Tuple of [`Shared of 'a] array] as 'a = `Tuple [| `Shared deep_cycle |];; (* Constructing float arrays was disallowed altogether at one point - by an overzealous check. Constructing float arrays in recursive + by an overzealous check. Constructing float arrays in recursive bindings is fine when they don't partake in the recursion. *) let rec _x = let _ = [| 1.0 |] in 1. in ();; + +(* This test is not allowed if 'a' is unboxed, but should be accepted + as written *) +type a = {a: b} +and b = X of a | Y + +let rec a = + {a= + (if Sys.opaque_identity true then + X a + else + Y)};; + +(* This test is not allowed if 'c' is unboxed, but should be accepted + as written *) +type d = D of e +and e = V of d | W;; + +let rec d = + D + (if Sys.opaque_identity true then + V d + else + W);; + +type r = R of r list [@@unboxed];; +let rec a = R [a];; diff --git a/testsuite/tests/letrec/backreferences.ml b/testsuite/tests/letrec/backreferences.ml index 4a893225..abde8c2d 100644 --- a/testsuite/tests/letrec/backreferences.ml +++ b/testsuite/tests/letrec/backreferences.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* testing backreferences; some compilation scheme may handle differently recursive references to a mutually-recursive RHS depending on whether it is before or after in the bindings list *) diff --git a/testsuite/tests/letrec/class_1.ml b/testsuite/tests/letrec/class_1.ml index a7d03388..4a1fdc9b 100644 --- a/testsuite/tests/letrec/class_1.ml +++ b/testsuite/tests/letrec/class_1.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* class expression are compiled to recursive bindings *) class test = object diff --git a/testsuite/tests/letrec/class_2.ml b/testsuite/tests/letrec/class_2.ml index 71c7880d..a76835d1 100644 --- a/testsuite/tests/letrec/class_2.ml +++ b/testsuite/tests/letrec/class_2.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* class expressions may also contain local recursive bindings *) class test = let rec f = print_endline "f"; fun x -> g x diff --git a/testsuite/tests/letrec/disallowed.reference b/testsuite/tests/letrec/disallowed.reference deleted file mode 100644 index 1c758979..00000000 --- a/testsuite/tests/letrec/disallowed.reference +++ /dev/null @@ -1,149 +0,0 @@ - -# Characters 12-27: - let rec x = let y = () in x;; - ^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x let g = x () end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x () let g = x end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-79: - let rec x = (let module M = struct let f = y 0 let g = () end in fun () -> ()) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-79: - let rec x = let module M = struct module N = struct let y = x end end in M.N.y;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-77: - let rec x = let module M = struct let f = x () and g = x end in fun () -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# class c : 'a -> object end -# Characters 12-19: - let rec x = new c x;; - ^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-21: - let rec x = ignore x;; - ^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-16: - let rec x = y 0 and y _ = ();; - ^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-18: - let rec x = [|y|] - ^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-40: - let rec c = { c with Complex.re = 1.0 };; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-36: - let rec x = { x with contents = 3 };; - ^^^^^^^^^^^^^^^^^^^^^^^ -Warning 23: all the fields are explicitly listed in this record: -the 'with' clause is useless. -Characters 13-36: - let rec x = { x with contents = 3 };; - ^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-38: - let rec b = if b then true else false;; - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 28-34: - let rec x = r := x;; - ^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-65: - ..for i = 0 to 1 do - let z = y in ignore z - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-46: - ..for i = 0 to y do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-47: - ..for i = y to 10 do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-62: - ..while false do - let y = x in ignore y - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-39: - ..while y do - () - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-58: - ..while y do - let y = x in ignore y - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-45: - let rec x = (object method m _ = () end)#m x;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-23: - let rec x = y.contents and y = { contents = 3 };; - ^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-59: - let rec x = object val mutable v = 0 method m = v <- y end and y = 1;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-21: - let rec x = assert y and y = true;; - ^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-36: - let rec x = object method m = x end;; - ^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-43: - let rec x = object method m = ignore x end;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# * Characters 230-246: - let rec x = Pervasives.ref y - ^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# * Characters 127-175: - if p then (fun y -> x + g y) else (fun y -> g y) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 13-33: - let rec x = let y = (x; ()) in y;; - ^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-58: - ..for i = 0 to 1 do - let z = y in z - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 37-61: - let rec x = (module (val y : T) : T) - ^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-55: - ..while false do - let y = x in y - done -Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 15-98: - ..match let _ = y in raise Not_found with - _ -> "x" - | exception Not_found -> "z". -Error: This kind of expression is not allowed as right-hand side of `let rec' -# diff --git a/testsuite/tests/letrec/evaluation_order_1.ml b/testsuite/tests/letrec/evaluation_order_1.ml index 6c94439e..466c20d7 100644 --- a/testsuite/tests/letrec/evaluation_order_1.ml +++ b/testsuite/tests/letrec/evaluation_order_1.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* test evaluation order 'y' is translated into a constant, and is therefore considered diff --git a/testsuite/tests/letrec/evaluation_order_2.ml b/testsuite/tests/letrec/evaluation_order_2.ml index f8a845bd..7d34a099 100644 --- a/testsuite/tests/letrec/evaluation_order_2.ml +++ b/testsuite/tests/letrec/evaluation_order_2.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* A variant of evaluation_order_1.ml where the side-effects are inside the blocks. Effect are not named to allow different evaluation orders (flambda diff --git a/testsuite/tests/letrec/evaluation_order_3.ml b/testsuite/tests/letrec/evaluation_order_3.ml index 8f76a8f8..f330009b 100644 --- a/testsuite/tests/letrec/evaluation_order_3.ml +++ b/testsuite/tests/letrec/evaluation_order_3.ml @@ -1,3 +1,5 @@ +(* TEST *) + type t = { x : t; y : t } let p = print_endline diff --git a/testsuite/tests/letrec/float_block_1.ml b/testsuite/tests/letrec/float_block_1.ml index b2f878bb..a3ff37ad 100644 --- a/testsuite/tests/letrec/float_block_1.ml +++ b/testsuite/tests/letrec/float_block_1.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Effect are not named to allow different evaluation orders (flambda and clambda differ on this point). *) diff --git a/testsuite/tests/letrec/generic_array.ml b/testsuite/tests/letrec/generic_array.ml index f71eb346..3a8c6ff1 100644 --- a/testsuite/tests/letrec/generic_array.ml +++ b/testsuite/tests/letrec/generic_array.ml @@ -1,3 +1,5 @@ +(* TEST *) + let rec x = let _y = [| |] in ();; let rec x = let y = [| |] in y :: x;; diff --git a/testsuite/tests/letrec/labels.ml b/testsuite/tests/letrec/labels.ml new file mode 100644 index 00000000..7a1d29d4 --- /dev/null +++ b/testsuite/tests/letrec/labels.ml @@ -0,0 +1,4 @@ +(* TEST *) + +let f () ~x = x () +let rec x = f ~x diff --git a/testsuite/tests/float-unboxing/float_subst_boxed_number.reference b/testsuite/tests/letrec/labels.reference similarity index 100% rename from testsuite/tests/float-unboxing/float_subst_boxed_number.reference rename to testsuite/tests/letrec/labels.reference diff --git a/testsuite/tests/letrec/lazy_.ml b/testsuite/tests/letrec/lazy_.ml index 08c022f9..6929d81e 100644 --- a/testsuite/tests/letrec/lazy_.ml +++ b/testsuite/tests/letrec/lazy_.ml @@ -1,3 +1,5 @@ +(* TEST *) + let rec c = lazy (0 + d) and d = 3;; let () = Printf.printf "%d\n" (Lazy.force c) diff --git a/testsuite/tests/letrec/lists.ml b/testsuite/tests/letrec/lists.ml index 5686e493..c0581beb 100644 --- a/testsuite/tests/letrec/lists.ml +++ b/testsuite/tests/letrec/lists.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* a test with lists, because cyclic lists are fun *) let test = let rec li = 0::1::2::3::4::5::6::7::8::9::li in diff --git a/testsuite/tests/letrec/mixing_value_closures_1.ml b/testsuite/tests/letrec/mixing_value_closures_1.ml index e79f79ec..c493da9a 100644 --- a/testsuite/tests/letrec/mixing_value_closures_1.ml +++ b/testsuite/tests/letrec/mixing_value_closures_1.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* mixing values and closures may exercise interesting code paths *) type t = A of (int -> int) let test = diff --git a/testsuite/tests/letrec/mixing_value_closures_2.ml b/testsuite/tests/letrec/mixing_value_closures_2.ml index eb5fcb74..27f5f956 100644 --- a/testsuite/tests/letrec/mixing_value_closures_2.ml +++ b/testsuite/tests/letrec/mixing_value_closures_2.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* a polymorphic variant of test3.ml; found a real bug once *) let test = let rec x = `A f diff --git a/testsuite/tests/letrec/mutual_functions.ml b/testsuite/tests/letrec/mutual_functions.ml index a5b6c51f..34b62fe1 100644 --- a/testsuite/tests/letrec/mutual_functions.ml +++ b/testsuite/tests/letrec/mutual_functions.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* a simple test with mutually recursive functions *) let test = let rec even = function diff --git a/testsuite/tests/letrec/nested.ml b/testsuite/tests/letrec/nested.ml index d87a9585..4d461d0a 100644 --- a/testsuite/tests/letrec/nested.ml +++ b/testsuite/tests/letrec/nested.ml @@ -1,7 +1,9 @@ +(* TEST *) + (* Mantis PR7447 *) let rec r = (let rec x = `A r and y = fun () -> x in y) -let (`A x) = r () +let (`A x) = r () let _ = x () diff --git a/testsuite/tests/letrec/ocamltests b/testsuite/tests/letrec/ocamltests new file mode 100644 index 00000000..a92895e6 --- /dev/null +++ b/testsuite/tests/letrec/ocamltests @@ -0,0 +1,19 @@ +allowed.ml +backreferences.ml +class_1.ml +class_2.ml +evaluation_order_1.ml +evaluation_order_2.ml +evaluation_order_3.ml +float_block_1.ml +generic_array.ml +labels.ml +lazy_.ml +lists.ml +mixing_value_closures_1.ml +mixing_value_closures_2.ml +mutual_functions.ml +nested.ml +pr4989.ml +record_with.ml +ref.ml diff --git a/testsuite/tests/letrec/pr4989.ml b/testsuite/tests/letrec/pr4989.ml index d608b3c0..b3ddb2d9 100644 --- a/testsuite/tests/letrec/pr4989.ml +++ b/testsuite/tests/letrec/pr4989.ml @@ -1 +1,3 @@ +(* TEST *) + let rec f = let g = f in fun x -> g x;; diff --git a/testsuite/tests/letrec/record_with.ml b/testsuite/tests/letrec/record_with.ml index 8d2d01c0..3a1a5e68 100644 --- a/testsuite/tests/letrec/record_with.ml +++ b/testsuite/tests/letrec/record_with.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* A regression test for both PR#4141 and PR#5819: when a recursive variable is defined by a { record with ... } expression. *) diff --git a/testsuite/tests/letrec/ref.ml b/testsuite/tests/letrec/ref.ml index 483cdcbb..0f31b0a3 100644 --- a/testsuite/tests/letrec/ref.ml +++ b/testsuite/tests/letrec/ref.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Test construction of cyclic values where the cycles pass through references *) type t = { mutable next : t; mutable inst : n ref } diff --git a/testsuite/tests/lexing/Makefile b/testsuite/tests/lexing/Makefile deleted file mode 100644 index 9625a3fb..00000000 --- a/testsuite/tests/lexing/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lexing/ocamltests b/testsuite/tests/lexing/ocamltests new file mode 100644 index 00000000..c08e182c --- /dev/null +++ b/testsuite/tests/lexing/ocamltests @@ -0,0 +1 @@ +uchar_esc.ml diff --git a/testsuite/tests/lexing/uchar_esc.ml b/testsuite/tests/lexing/uchar_esc.ml index b288ac25..3e7b5379 100644 --- a/testsuite/tests/lexing/uchar_esc.ml +++ b/testsuite/tests/lexing/uchar_esc.ml @@ -1,3 +1,6 @@ +(* TEST + * toplevel +*) (* Correct escapes and their encoding *) diff --git a/testsuite/tests/lexing/uchar_esc.ml.reference b/testsuite/tests/lexing/uchar_esc.ml.reference deleted file mode 100644 index 8730059c..00000000 --- a/testsuite/tests/lexing/uchar_esc.ml.reference +++ /dev/null @@ -1,36 +0,0 @@ - -# # Characters 34-43: - let invalid_sv = "\u{0D800}" ;; - ^^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{0D800}, D800 is not a Unicode scalar value) -# Characters 18-26: - let invalid_sv = "\u{D800}" ;; - ^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{D800}, D800 is not a Unicode scalar value) -# Characters 18-26: - let invalid_sv = "\u{D900}" ;; - ^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{D900}, D900 is not a Unicode scalar value) -# Characters 18-26: - let invalid_sv = "\u{DFFF}" ;; - ^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{DFFF}, DFFF is not a Unicode scalar value) -# Characters 18-28: - let invalid_sv = "\u{110000} ;; - ^^^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{110000}, 110000 is not a Unicode scalar value) -# Characters 24-36: - let too_many_digits = "\u{01234567}" ;; - ^^^^^^^^^^^^ -Error: Illegal backslash escape in string or character (\u{01234567}, too many digits, expected 1 to 6 hexadecimal digits) -# Characters 21-23: - let no_hex_digits = "\u{}" ;; - ^^ -Warning 14: illegal backslash escape in string. -val no_hex_digits : string = "\\u{}" -# Characters 25-27: - let illegal_hex_digit = "\u{u}" ;; - ^^ -Warning 14: illegal backslash escape in string. -val illegal_hex_digit : string = "\\u{u}" -# diff --git a/testsuite/tests/lexing/uchar_esc.ocaml.reference b/testsuite/tests/lexing/uchar_esc.ocaml.reference new file mode 100644 index 00000000..e29a1305 --- /dev/null +++ b/testsuite/tests/lexing/uchar_esc.ocaml.reference @@ -0,0 +1,35 @@ +Characters 34-43: + let invalid_sv = "\u{0D800}" ;; + ^^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{0D800}, D800 is not a Unicode scalar value) +Characters 18-26: + let invalid_sv = "\u{D800}" ;; + ^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{D800}, D800 is not a Unicode scalar value) +Characters 18-26: + let invalid_sv = "\u{D900}" ;; + ^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{D900}, D900 is not a Unicode scalar value) +Characters 18-26: + let invalid_sv = "\u{DFFF}" ;; + ^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{DFFF}, DFFF is not a Unicode scalar value) +Characters 18-28: + let invalid_sv = "\u{110000} ;; + ^^^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{110000}, 110000 is not a Unicode scalar value) +Characters 24-36: + let too_many_digits = "\u{01234567}" ;; + ^^^^^^^^^^^^ +Error: Illegal backslash escape in string or character (\u{01234567}, too many digits, expected 1 to 6 hexadecimal digits) +Characters 21-23: + let no_hex_digits = "\u{}" ;; + ^^ +Warning 14: illegal backslash escape in string. +val no_hex_digits : string = "\\u{}" +Characters 25-27: + let illegal_hex_digit = "\u{u}" ;; + ^^ +Warning 14: illegal backslash escape in string. +val illegal_hex_digit : string = "\\u{u}" + diff --git a/testsuite/tests/lib-arg/Makefile b/testsuite/tests/lib-arg/Makefile deleted file mode 100644 index dd488d43..00000000 --- a/testsuite/tests/lib-arg/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-arg/ocamltests b/testsuite/tests/lib-arg/ocamltests new file mode 100644 index 00000000..af4dd22c --- /dev/null +++ b/testsuite/tests/lib-arg/ocamltests @@ -0,0 +1,2 @@ +testarg.ml +testerror.ml diff --git a/testsuite/tests/lib-arg/testarg.ml b/testsuite/tests/lib-arg/testarg.ml index 77573812..0241bc61 100644 --- a/testsuite/tests/lib-arg/testarg.ml +++ b/testsuite/tests/lib-arg/testarg.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let current = ref 0;; let accum = ref [];; diff --git a/testsuite/tests/lib-arg/testerror.ml b/testsuite/tests/lib-arg/testerror.ml index d4b433ee..8786cfb6 100644 --- a/testsuite/tests/lib-arg/testerror.ml +++ b/testsuite/tests/lib-arg/testerror.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test that the right message errors are emitted by Arg *) diff --git a/testsuite/tests/lib-bigarray-file/Makefile b/testsuite/tests/lib-bigarray-file/Makefile deleted file mode 100644 index 09ee70fa..00000000 --- a/testsuite/tests/lib-bigarray-file/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=unix bigarray -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix \ - -I $(OTOPDIR)/otherlibs/bigarray -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/bigarray - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-bigarray-file/mapfile.ml b/testsuite/tests/lib-bigarray-file/mapfile.ml index aeed7258..bf4bc120 100644 --- a/testsuite/tests/lib-bigarray-file/mapfile.ml +++ b/testsuite/tests/lib-bigarray-file/mapfile.ml @@ -1,3 +1,7 @@ +(* TEST + include unix +*) + open Bigarray (* Test harness *) diff --git a/testsuite/tests/lib-bigarray-file/ocamltests b/testsuite/tests/lib-bigarray-file/ocamltests new file mode 100644 index 00000000..260c6b73 --- /dev/null +++ b/testsuite/tests/lib-bigarray-file/ocamltests @@ -0,0 +1 @@ +mapfile.ml diff --git a/testsuite/tests/lib-bigarray/Makefile b/testsuite/tests/lib-bigarray/Makefile deleted file mode 100644 index 09ee70fa..00000000 --- a/testsuite/tests/lib-bigarray/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=unix bigarray -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix \ - -I $(OTOPDIR)/otherlibs/bigarray -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/bigarray - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-bigarray/bigarrays.ml b/testsuite/tests/lib-bigarray/bigarrays.ml index 31a90bca..57536d67 100644 --- a/testsuite/tests/lib-bigarray/bigarrays.ml +++ b/testsuite/tests/lib-bigarray/bigarrays.ml @@ -1,3 +1,6 @@ +(* TEST +*) + open Bigarray open Printf open Complex diff --git a/testsuite/tests/lib-bigarray/change_layout.ml b/testsuite/tests/lib-bigarray/change_layout.ml index 4f0c37c6..5e481065 100644 --- a/testsuite/tests/lib-bigarray/change_layout.ml +++ b/testsuite/tests/lib-bigarray/change_layout.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test the various change_layout for Genarray and the various Array[n] *) open Bigarray diff --git a/testsuite/tests/lib-bigarray/fftba.ml b/testsuite/tests/lib-bigarray/fftba.ml index 8a01389c..a06ad1bc 100644 --- a/testsuite/tests/lib-bigarray/fftba.ml +++ b/testsuite/tests/lib-bigarray/fftba.ml @@ -1,3 +1,6 @@ +(* TEST +*) + open Bigarray let pi = 3.14159265358979323846 diff --git a/testsuite/tests/lib-bigarray/ocamltests b/testsuite/tests/lib-bigarray/ocamltests new file mode 100644 index 00000000..8f13552d --- /dev/null +++ b/testsuite/tests/lib-bigarray/ocamltests @@ -0,0 +1,5 @@ +bigarrays.ml +change_layout.ml +fftba.ml +pr5115.ml +weak_bigarray.ml diff --git a/testsuite/tests/lib-bigarray/pr5115.ml b/testsuite/tests/lib-bigarray/pr5115.ml index fd16662e..74cbe514 100644 --- a/testsuite/tests/lib-bigarray/pr5115.ml +++ b/testsuite/tests/lib-bigarray/pr5115.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* PR#5115 - multiple evaluation of bigarray expr *) open Bigarray diff --git a/testsuite/tests/lib-bigarray/weak_bigarray.ml b/testsuite/tests/lib-bigarray/weak_bigarray.ml index 62f9b99f..a0758120 100644 --- a/testsuite/tests/lib-bigarray/weak_bigarray.ml +++ b/testsuite/tests/lib-bigarray/weak_bigarray.ml @@ -1,4 +1,5 @@ - +(* TEST +*) (** check that custom block are not copied by Weak.get_copy *) diff --git a/testsuite/tests/lib-buffer/Makefile b/testsuite/tests/lib-buffer/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-buffer/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-buffer/ocamltests b/testsuite/tests/lib-buffer/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-buffer/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-buffer/test.ml b/testsuite/tests/lib-buffer/test.ml index 83adcf83..a63735df 100644 --- a/testsuite/tests/lib-buffer/test.ml +++ b/testsuite/tests/lib-buffer/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + open Printf ;; @@ -44,9 +47,9 @@ let validate f str msg = let () = print_string "Standard Library: Module Buffer\n" ;; -let truncate_neg : unit = +let truncate_neg : unit = let msg = "truncate: negative" in - try + try Buffer.truncate buf (-1); failed msg with @@ -63,7 +66,7 @@ let truncate_large : unit = ;; let truncate_correct : unit = - let n' = n - 1 + let n' = n - 1 and msg = "truncate: in-range" in try Buffer.truncate buf n'; diff --git a/testsuite/tests/lib-bytes/Makefile b/testsuite/tests/lib-bytes/Makefile deleted file mode 100644 index 77b26912..00000000 --- a/testsuite/tests/lib-bytes/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=testing -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-bytes/ocamltests b/testsuite/tests/lib-bytes/ocamltests new file mode 100644 index 00000000..a139cdac --- /dev/null +++ b/testsuite/tests/lib-bytes/ocamltests @@ -0,0 +1 @@ +test_bytes.ml diff --git a/testsuite/tests/lib-bytes/test_bytes.ml b/testsuite/tests/lib-bytes/test_bytes.ml index 49725a5b..2e1d9b6a 100644 --- a/testsuite/tests/lib-bytes/test_bytes.ml +++ b/testsuite/tests/lib-bytes/test_bytes.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + let test_raises_invalid_argument f x = ignore (Testing.test_raises_exc_p (function Invalid_argument _ -> true | _ -> false) @@ -16,10 +20,10 @@ let () = begin (* abcde - ????? + ????? *) Testing.test - (length (extend abcde 7 (-7)) = 5); + (length (extend abcde 7 (-7)) = 5); (* abcde diff --git a/testsuite/tests/lib-digest/Makefile b/testsuite/tests/lib-digest/Makefile deleted file mode 100644 index 8d045d4e..00000000 --- a/testsuite/tests/lib-digest/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=md5 -ADD_COMPFLAGS=-w a - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-digest/md5.ml b/testsuite/tests/lib-digest/md5.ml index 0fb11def..edfe85c4 100644 --- a/testsuite/tests/lib-digest/md5.ml +++ b/testsuite/tests/lib-digest/md5.ml @@ -1,3 +1,7 @@ +(* TEST + flags += " -w a " +*) + (* Test int32 arithmetic and optimizations using the MD5 algorithm *) open Printf @@ -130,10 +134,10 @@ let string_to_data s = data let int32_to_string n s i = - s.[i+3] <- Char.chr (Int32.to_int (Int32.shift_right n 24) land 0xFF); - s.[i+2] <- Char.chr (Int32.to_int (Int32.shift_right n 16) land 0xFF); - s.[i+1] <- Char.chr (Int32.to_int (Int32.shift_right n 8) land 0xFF); - s.[i] <- Char.chr (Int32.to_int n land 0xFF) + Bytes.set s (i+3) (Char.chr (Int32.to_int (Int32.shift_right n 24) land 0xFF)); + Bytes.set s (i+2) (Char.chr (Int32.to_int (Int32.shift_right n 16) land 0xFF)); + Bytes.set s (i+1) (Char.chr (Int32.to_int (Int32.shift_right n 8) land 0xFF)); + Bytes.set s i (Char.chr (Int32.to_int n land 0xFF)) let init () = { buf = Bytes.create 64; diff --git a/testsuite/tests/lib-digest/ocamltests b/testsuite/tests/lib-digest/ocamltests new file mode 100644 index 00000000..b2ebef4e --- /dev/null +++ b/testsuite/tests/lib-digest/ocamltests @@ -0,0 +1 @@ +md5.ml diff --git a/testsuite/tests/lib-dynlink-csharp/main.ml b/testsuite/tests/lib-dynlink-csharp/main.ml index 7c8030a1..93fe830c 100755 --- a/testsuite/tests/lib-dynlink-csharp/main.ml +++ b/testsuite/tests/lib-dynlink-csharp/main.ml @@ -7,7 +7,7 @@ let load s = (* Callback must be linked to load Unix dynamically *) let _ = Callback.register -module CamlinternalBigarray = CamlinternalBigarray +let _ = Stdlib.Bigarray.float32 let () = ignore (Hashtbl.hash 42.0); diff --git a/testsuite/tests/lib-dynlink-native/Makefile b/testsuite/tests/lib-dynlink-native/Makefile index c2e21950..50ed0e8b 100644 --- a/testsuite/tests/lib-dynlink-native/Makefile +++ b/testsuite/tests/lib-dynlink-native/Makefile @@ -37,8 +37,6 @@ PLUGINS=plugin.so plugin2.so sub/plugin.so sub/plugin3.so plugin4.so \ plugin_high_arity.so plugin_ext.so plugin_simple.so bug.so \ plugin_thread.so plugin4_unix.so a.so b.so c.so -ADD_COMPFLAGS=-thread - .PHONY: compile compile: $(PLUGINS) main$(EXE) mylib.so @@ -50,7 +48,7 @@ run: && echo " => passed" || echo " => failed" main$(EXE): api.cmx main.cmx - @$(OCAMLOPT) -thread -o main$(EXE) -linkall unix.cmxa threads.cmxa \ + @$(OCAMLOPT) -I +threads -o main$(EXE) -linkall unix.cmxa threads.cmxa \ dynlink.cmxa api.cmx main.cmx main_ext$(EXE): api.cmx main.cmx factorial.$(O) diff --git a/testsuite/tests/lib-filename/Makefile b/testsuite/tests/lib-filename/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-filename/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-filename/extension.ml b/testsuite/tests/lib-filename/extension.ml index 917c0146..ae7c8b61 100755 --- a/testsuite/tests/lib-filename/extension.ml +++ b/testsuite/tests/lib-filename/extension.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let () = let test f e = assert(Filename.extension f = e); diff --git a/testsuite/tests/lib-filename/ocamltests b/testsuite/tests/lib-filename/ocamltests new file mode 100644 index 00000000..8615801f --- /dev/null +++ b/testsuite/tests/lib-filename/ocamltests @@ -0,0 +1 @@ +extension.ml diff --git a/testsuite/tests/lib-format/Makefile b/testsuite/tests/lib-format/Makefile deleted file mode 100644 index 375d2e4c..00000000 --- a/testsuite/tests/lib-format/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=testing - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-format/ocamltests b/testsuite/tests/lib-format/ocamltests new file mode 100644 index 00000000..9e3d6f21 --- /dev/null +++ b/testsuite/tests/lib-format/ocamltests @@ -0,0 +1,2 @@ +pr6824.ml +tformat.ml diff --git a/testsuite/tests/lib-format/pr6824.ml b/testsuite/tests/lib-format/pr6824.ml index aa5e7eed..7dc92083 100644 --- a/testsuite/tests/lib-format/pr6824.ml +++ b/testsuite/tests/lib-format/pr6824.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + let f = Format.sprintf "[%i]";; print_endline (f 1);; print_endline (f 2);; diff --git a/testsuite/tests/lib-format/tformat.ml b/testsuite/tests/lib-format/tformat.ml index ee39a6a7..325d9277 100644 --- a/testsuite/tests/lib-format/tformat.ml +++ b/testsuite/tests/lib-format/tformat.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* A test file for the Format module. diff --git a/testsuite/tests/lib-hashtbl/Makefile b/testsuite/tests/lib-hashtbl/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-hashtbl/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-hashtbl/hfun.ml b/testsuite/tests/lib-hashtbl/hfun.ml index 4fbb9cfe..3e15596e 100644 --- a/testsuite/tests/lib-hashtbl/hfun.ml +++ b/testsuite/tests/lib-hashtbl/hfun.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Testing the hash function Hashtbl.hash *) (* What is tested: - reproducibility on various platforms, esp. 32/64 bit issues diff --git a/testsuite/tests/lib-hashtbl/htbl.ml b/testsuite/tests/lib-hashtbl/htbl.ml index 0a8001f7..46f5e210 100644 --- a/testsuite/tests/lib-hashtbl/htbl.ml +++ b/testsuite/tests/lib-hashtbl/htbl.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Hashtable operations, using maps as a reference *) open Printf @@ -30,6 +33,21 @@ module Test(H: Hashtbl.S) (M: Map.S with type key = H.key) = struct true with Exit | Not_found -> false + let to_list_ h : _ list = + H.fold (fun k v acc -> (k,v) :: acc) h [] + |> List.sort Pervasives.compare + + let check_to_seq h = + let l = to_list_ h in + let l2 = List.of_seq (H.to_seq h) in + assert (l = List.sort Pervasives.compare l2) + + let check_to_seq_of_seq h = + let h' = H.create (H.length h) in + H.add_seq h' (H.to_seq h); + (*printf "h.len=%d, h'.len=%d\n" (List.length @@ to_list_ h) (List.length @@ to_list_ h');*) + assert (to_list_ h = to_list_ h') + let test data = let n = Array.length data in let h = H.create 51 and m = ref M.empty in @@ -39,6 +57,8 @@ module Test(H: Hashtbl.S) (M: Map.S with type key = H.key) = struct data; printf "Insertion: %s\n" (if incl_mh !m h && domain_hm h !m then "passed" else "FAILED"); + check_to_seq_of_seq h; + check_to_seq h; (* Insert all data with H.replace *) H.clear h; m := M.empty; Array.iter @@ -46,12 +66,17 @@ module Test(H: Hashtbl.S) (M: Map.S with type key = H.key) = struct data; printf "Insertion: %s\n" (if incl_mh !m h && incl_hm h !m then "passed" else "FAILED"); + check_to_seq_of_seq h; + check_to_seq h; (* Remove some of the data *) for i = 0 to n/3 - 1 do let (k, _) = data.(i) in H.remove h k; m := M.remove k !m done; printf "Removal: %s\n" - (if incl_mh !m h && incl_hm h !m then "passed" else "FAILED") + (if incl_mh !m h && incl_hm h !m then "passed" else "FAILED"); + check_to_seq_of_seq h; + check_to_seq h; + () end @@ -115,6 +140,12 @@ module HofM (M: Map.S) : Hashtbl.S with type key = M.key = let length = Hashtbl.length let stats = Hashtbl.stats let filter_map_inplace = Hashtbl.filter_map_inplace + let to_seq = Hashtbl.to_seq + let to_seq_keys = Hashtbl.to_seq_keys + let to_seq_values = Hashtbl.to_seq_values + let of_seq = Hashtbl.of_seq + let add_seq = Hashtbl.add_seq + let replace_seq = Hashtbl.replace_seq end module HS1 = HofM(MS) diff --git a/testsuite/tests/lib-hashtbl/ocamltests b/testsuite/tests/lib-hashtbl/ocamltests new file mode 100644 index 00000000..904a9b55 --- /dev/null +++ b/testsuite/tests/lib-hashtbl/ocamltests @@ -0,0 +1,2 @@ +hfun.ml +htbl.ml diff --git a/testsuite/tests/lib-list/Makefile b/testsuite/tests/lib-list/Makefile deleted file mode 100644 index 4ba0bffc..00000000 --- a/testsuite/tests/lib-list/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-list/ocamltests b/testsuite/tests/lib-list/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-list/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-list/test.ml b/testsuite/tests/lib-list/test.ml index 4898c3d1..68fdd1ac 100644 --- a/testsuite/tests/lib-list/test.ml +++ b/testsuite/tests/lib-list/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Standard test case *) let () = let l = List.init 10 (fun x -> x) in diff --git a/testsuite/tests/lib-marshal/Makefile b/testsuite/tests/lib-marshal/Makefile deleted file mode 100644 index a79f6bdd..00000000 --- a/testsuite/tests/lib-marshal/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=intext -C_FILES=intextaux - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-marshal/intext.ml b/testsuite/tests/lib-marshal/intext.ml index 11633092..66cc714f 100644 --- a/testsuite/tests/lib-marshal/intext.ml +++ b/testsuite/tests/lib-marshal/intext.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "intextaux.c" +*) + (* Test for output_value / input_value *) let max_data_depth = 500000 diff --git a/testsuite/tests/lib-marshal/ocamltests b/testsuite/tests/lib-marshal/ocamltests new file mode 100644 index 00000000..edb5046c --- /dev/null +++ b/testsuite/tests/lib-marshal/ocamltests @@ -0,0 +1 @@ +intext.ml diff --git a/testsuite/tests/lib-obj/Makefile b/testsuite/tests/lib-obj/Makefile deleted file mode 100755 index bb9cfbad..00000000 --- a/testsuite/tests/lib-obj/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES= -MAIN_MODULE=reachable_words - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-obj/ocamltests b/testsuite/tests/lib-obj/ocamltests new file mode 100644 index 00000000..55f0b5b3 --- /dev/null +++ b/testsuite/tests/lib-obj/ocamltests @@ -0,0 +1 @@ +reachable_words.ml diff --git a/testsuite/tests/lib-obj/reachable_words.ml b/testsuite/tests/lib-obj/reachable_words.ml index 68aeca47..1c1709ad 100755 --- a/testsuite/tests/lib-obj/reachable_words.ml +++ b/testsuite/tests/lib-obj/reachable_words.ml @@ -1,8 +1,11 @@ +(* TEST +*) + let native = - match Filename.basename Sys.argv.(0) with - | "program.byte" | "program.byte.exe" -> false - | "program.native" | "program.native.exe" -> true - | s -> print_endline s; assert false + match Sys.backend_type with + | Sys.Native -> true + | Sys.Bytecode -> false + | Sys.Other s -> print_endline s; assert false let size x = Obj.reachable_words (Obj.repr x) diff --git a/testsuite/tests/lib-printf/Makefile b/testsuite/tests/lib-printf/Makefile deleted file mode 100644 index d464524f..00000000 --- a/testsuite/tests/lib-printf/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MODULES=testing -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-printf/ocamltests b/testsuite/tests/lib-printf/ocamltests new file mode 100644 index 00000000..441725e4 --- /dev/null +++ b/testsuite/tests/lib-printf/ocamltests @@ -0,0 +1,3 @@ +pr6534.ml +pr6938.ml +tprintf.ml diff --git a/testsuite/tests/lib-printf/pr6534.ml b/testsuite/tests/lib-printf/pr6534.ml index a356d521..f2329460 100644 --- a/testsuite/tests/lib-printf/pr6534.ml +++ b/testsuite/tests/lib-printf/pr6534.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* these are not valid under -strict-formats, but we test them here for backward-compatibility *) open Printf diff --git a/testsuite/tests/lib-printf/pr6938.ml b/testsuite/tests/lib-printf/pr6938.ml index b081b4ce..b4ab3fc1 100644 --- a/testsuite/tests/lib-printf/pr6938.ml +++ b/testsuite/tests/lib-printf/pr6938.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* these are not valid under -strict-formats, but we test them here for backward-compatibility *) diff --git a/testsuite/tests/lib-printf/tprintf.ml b/testsuite/tests/lib-printf/tprintf.ml index 16e65479..bf7236a7 100644 --- a/testsuite/tests/lib-printf/tprintf.ml +++ b/testsuite/tests/lib-printf/tprintf.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* A test file for the Printf module. diff --git a/testsuite/tests/lib-queue/Makefile b/testsuite/tests/lib-queue/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-queue/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-queue/ocamltests b/testsuite/tests/lib-queue/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-queue/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-queue/test.ml b/testsuite/tests/lib-queue/test.ml index 5574abd8..ac05f4e3 100644 --- a/testsuite/tests/lib-queue/test.ml +++ b/testsuite/tests/lib-queue/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + module Q = struct include Queue diff --git a/testsuite/tests/lib-random/Makefile b/testsuite/tests/lib-random/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-random/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-random/ocamltests b/testsuite/tests/lib-random/ocamltests new file mode 100644 index 00000000..91c37c04 --- /dev/null +++ b/testsuite/tests/lib-random/ocamltests @@ -0,0 +1 @@ +rand.ml diff --git a/testsuite/tests/lib-random/rand.ml b/testsuite/tests/lib-random/rand.ml index a05761ea..50e74d13 100644 --- a/testsuite/tests/lib-random/rand.ml +++ b/testsuite/tests/lib-random/rand.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Test that two Random.self_init() in close succession will not result in the same PRNG state. Note that even when the code is correct this test is expected to fail diff --git a/testsuite/tests/lib-scanf-2/Makefile b/testsuite/tests/lib-scanf-2/Makefile deleted file mode 100644 index baee1d59..00000000 --- a/testsuite/tests/lib-scanf-2/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -MYRUNTIME=`if [ -z "$(CUSTOM)" ]; then echo '$(OCAMLRUN)'; fi` - -.PHONY: default -default: - @$(MAKE) compile - @$(SET_LD_PATH) $(MAKE) run - -.PHONY: compile -compile: tscanf2_io.cmo - @rm -f master.byte master.native master.native.exe - @rm -f slave.byte slave.native slave.native.exe - @$(OCAMLC) unix.cma tscanf2_io.cmo -o master.byte tscanf2_master.ml - @$(OCAMLC) tscanf2_io.cmo -o slave.byte tscanf2_slave.ml - @if $(BYTECODE_ONLY); then : ; else \ - $(MAKE) tscanf2_io.cmx; \ - $(OCAMLOPT) unix.cmxa tscanf2_io.cmx -o master.native$(EXE) \ - tscanf2_master.ml; \ - $(OCAMLOPT) tscanf2_io.cmx -o slave.native$(EXE) tscanf2_slave.ml; \ - fi - -run: - @printf " ... testing with ocamlc" - @$(MYRUNTIME) ./master.byte "$(OTOPDIR)/boot/ocamlrun$(EXE) \ - `$(CYGPATH) ./slave.byte`" \ - >result.byte 2>&1 - @$(DIFF) reference result.byte >/dev/null \ - && if $(BYTECODE_ONLY); then : ; else \ - printf " ocamlopt"; \ - ./master.native$(EXE) "`$(CYGPATH) ./slave.native`" \ - >result.native 2>&1; \ - $(DIFF) reference result.native >/dev/null; \ - fi \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: - @cp result.byte reference - -.PHONY: clean -clean: defaultclean - @rm -f master.* slave.* result.* - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-scanf-2/ocamltests b/testsuite/tests/lib-scanf-2/ocamltests new file mode 100644 index 00000000..0260373e --- /dev/null +++ b/testsuite/tests/lib-scanf-2/ocamltests @@ -0,0 +1 @@ +tscanf2_master.ml diff --git a/testsuite/tests/lib-scanf-2/tscanf2_master.ml b/testsuite/tests/lib-scanf-2/tscanf2_master.ml index 2dd91bc0..988c8a52 100644 --- a/testsuite/tests/lib-scanf-2/tscanf2_master.ml +++ b/testsuite/tests/lib-scanf-2/tscanf2_master.ml @@ -1,3 +1,60 @@ +(* TEST + +include unix +modules = "tscanf2_io.ml" +files = "tscanf2_slave.ml" +reference = "${test_source_directory}/reference" + +(* The bytcode test *) + +* setup-ocamlc.byte-build-env + +program = "${test_build_directory}/master.byte" + +** ocamlc.byte (* Compiles the master *) + +*** ocamlc.byte (* Compiles the slave *) + +all_modules = "tscanf2_io.cmo tscanf2_slave.ml" + +program = "${test_build_directory}/slave.byte" + +**** check-ocamlc.byte-output + +***** run + +program = "${test_build_directory}/master.byte" + +arguments = "${test_build_directory}/slave.byte" + +****** check-program-output + +(* The native test *) + +* setup-ocamlopt.byte-build-env + +program = "${test_build_directory}/master.opt" + +** ocamlopt.byte (* Compiles the master *) + +*** ocamlopt.byte (* Compiles the slave *) + +all_modules = "tscanf2_io.cmx tscanf2_slave.ml" + +program = "${test_build_directory}/slave.opt" + +**** check-ocamlopt.byte-output + +***** run + +program = "${test_build_directory}/master.opt" + +arguments = "${test_build_directory}/slave.opt" + +****** check-program-output + +*) + (* A very simple master: - first launch a slave process, - then repeat a random number of times: diff --git a/testsuite/tests/lib-scanf/Makefile b/testsuite/tests/lib-scanf/Makefile deleted file mode 100644 index 194a7684..00000000 --- a/testsuite/tests/lib-scanf/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=tscanf -ADD_COMPFLAGS=-I $(OTOPDIR)/testsuite/lib -ADD_MODULES=testing -TEST_TEMP_FILES=tscanf_data - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-scanf/ocamltests b/testsuite/tests/lib-scanf/ocamltests new file mode 100644 index 00000000..0618be9c --- /dev/null +++ b/testsuite/tests/lib-scanf/ocamltests @@ -0,0 +1 @@ +tscanf.ml diff --git a/testsuite/tests/lib-scanf/tscanf.ml b/testsuite/tests/lib-scanf/tscanf.ml index 421c1b40..4a48653a 100644 --- a/testsuite/tests/lib-scanf/tscanf.ml +++ b/testsuite/tests/lib-scanf/tscanf.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + (* A testbed file for the module Scanf. diff --git a/testsuite/tests/lib-seq/ocamltests b/testsuite/tests/lib-seq/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-seq/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-seq/test.ml b/testsuite/tests/lib-seq/test.ml new file mode 100644 index 00000000..934a001e --- /dev/null +++ b/testsuite/tests/lib-seq/test.ml @@ -0,0 +1,18 @@ +(* TEST +*) + +let filter1 x = x mod 2 = 0 ;; + +(* Standard test case *) +let () = + assert + ([2;4] = + (List.to_seq [1;2;3;4;5] + |> Seq.filter (fun x -> x mod 2 = 0) + |> List.of_seq)); + () +;; + +let () = print_endline "OK";; + + diff --git a/testsuite/tests/lib-seq/test.reference b/testsuite/tests/lib-seq/test.reference new file mode 100644 index 00000000..d86bac9d --- /dev/null +++ b/testsuite/tests/lib-seq/test.reference @@ -0,0 +1 @@ +OK diff --git a/testsuite/tests/lib-set/Makefile b/testsuite/tests/lib-set/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-set/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-set/ocamltests b/testsuite/tests/lib-set/ocamltests new file mode 100644 index 00000000..fdc3b400 --- /dev/null +++ b/testsuite/tests/lib-set/ocamltests @@ -0,0 +1,2 @@ +testmap.ml +testset.ml diff --git a/testsuite/tests/lib-set/testmap.ml b/testsuite/tests/lib-set/testmap.ml index 5d28cd1e..0be0410b 100644 --- a/testsuite/tests/lib-set/testmap.ml +++ b/testsuite/tests/lib-set/testmap.ml @@ -1,3 +1,6 @@ +(* TEST +*) + module M = Map.Make(struct type t = int let compare (x:t) y = compare x y end) let img x m = try Some(M.find x m) with Not_found -> None @@ -164,7 +167,22 @@ let test x v s1 s2 = fun i -> if i < x then img i l = img i s1 else if i > x then img i r = img i s1 - else p = img i s1) + else p = img i s1); + + checkbool "to_seq_of_seq" + (M.equal (=) s1 (M.of_seq @@ M.to_seq s1)); + + checkbool "to_seq_from" + (let seq = M.to_seq_from x s1 in + let ok1 = List.of_seq seq |> List.for_all (fun (y,_) -> y >= x) in + let ok2 = + (M.to_seq s1 |> List.of_seq |> List.filter (fun (y,_) -> y >= x)) + = + (List.of_seq seq) + in + ok1 && ok2); + + () let rkey() = Random.int 10 diff --git a/testsuite/tests/lib-set/testset.ml b/testsuite/tests/lib-set/testset.ml index 8e9d6d54..378dbfe6 100644 --- a/testsuite/tests/lib-set/testset.ml +++ b/testsuite/tests/lib-set/testset.ml @@ -1,3 +1,6 @@ +(* TEST +*) + module S = Set.Make(struct type t = int let compare (x:t) y = compare x y end) let testvals = [0;1;2;3;4;5;6;7;8;9] @@ -171,7 +174,22 @@ let test x s1 s2 = fun i -> if i < x then S.mem i l = S.mem i s1 else if i > x then S.mem i r = S.mem i s1 - else p = S.mem i s1) + else p = S.mem i s1); + + checkbool "to_seq_of_seq" + (S.equal s1 (S.of_seq @@ S.to_seq s1)); + + checkbool "to_seq_from" + (let seq = S.to_seq_from x s1 in + let ok1 = List.of_seq seq |> List.for_all (fun y -> y >= x) in + let ok2 = + (S.elements s1 |> List.filter (fun y -> y >= x)) + = + (List.of_seq seq) + in + ok1 && ok2); + + () let relt() = Random.int 10 diff --git a/testsuite/tests/lib-stack/Makefile b/testsuite/tests/lib-stack/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-stack/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-stack/ocamltests b/testsuite/tests/lib-stack/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-stack/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-stack/test.ml b/testsuite/tests/lib-stack/test.ml index 7ca64bed..5023b12b 100644 --- a/testsuite/tests/lib-stack/test.ml +++ b/testsuite/tests/lib-stack/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + module S = struct include Stack diff --git a/testsuite/tests/lib-stdlabels/Makefile b/testsuite/tests/lib-stdlabels/Makefile deleted file mode 100644 index fe35955c..00000000 --- a/testsuite/tests/lib-stdlabels/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** -ADD_COMPFLAGS=-nolabels -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-stdlabels/ocamltests b/testsuite/tests/lib-stdlabels/ocamltests new file mode 100644 index 00000000..eb3b0ea4 --- /dev/null +++ b/testsuite/tests/lib-stdlabels/ocamltests @@ -0,0 +1 @@ +test_stdlabels.ml diff --git a/testsuite/tests/lib-stdlabels/test_stdlabels.ml b/testsuite/tests/lib-stdlabels/test_stdlabels.ml index 5e9770d8..fe7ae4f6 100644 --- a/testsuite/tests/lib-stdlabels/test_stdlabels.ml +++ b/testsuite/tests/lib-stdlabels/test_stdlabels.ml @@ -1,10 +1,17 @@ +(* TEST + flags += " -nolabels " +*) + module A : module type of Array = ArrayLabels module B : module type of Bytes = BytesLabels module L : module type of List = ListLabels module S : module type of String = StringLabels -module M : module type of Map = MoreLabels.Map -module Se : module type of Set = MoreLabels.Set +module M : module type of struct include Map end [@remove_aliases] = + MoreLabels.Map + +module Se : module type of struct include Set end [@remove_aliases] = + MoreLabels.Set (* For *) @@ -31,7 +38,7 @@ module Indirection = struct end module type HS = sig type statistics = Indirection.t - include module type of Hashtbl + include module type of struct include Hashtbl end [@remove_aliases] with type statistics := Indirection.t end module H : HS = MoreLabels.Hashtbl diff --git a/testsuite/tests/lib-str/Makefile b/testsuite/tests/lib-str/Makefile deleted file mode 100644 index b25e53f9..00000000 --- a/testsuite/tests/lib-str/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=str -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/str -LD_PATH=$(TOPDIR)/otherlibs/str - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-str/ocamltests b/testsuite/tests/lib-str/ocamltests new file mode 100644 index 00000000..13403709 --- /dev/null +++ b/testsuite/tests/lib-str/ocamltests @@ -0,0 +1 @@ +t01.ml diff --git a/testsuite/tests/lib-str/t01.ml b/testsuite/tests/lib-str/t01.ml index eb75e1cb..1fb7805a 100644 --- a/testsuite/tests/lib-str/t01.ml +++ b/testsuite/tests/lib-str/t01.ml @@ -1,3 +1,7 @@ +(* TEST + include str +*) + open Printf let build_result ngroups input = diff --git a/testsuite/tests/lib-stream/Makefile b/testsuite/tests/lib-stream/Makefile deleted file mode 100644 index 77b26912..00000000 --- a/testsuite/tests/lib-stream/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=testing -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-stream/count_concat_bug.ml b/testsuite/tests/lib-stream/count_concat_bug.ml index 97ec6bce..fc31c76a 100644 --- a/testsuite/tests/lib-stream/count_concat_bug.ml +++ b/testsuite/tests/lib-stream/count_concat_bug.ml @@ -1,3 +1,7 @@ +(* TEST + include testing +*) + let is_empty s = try Stream.empty s; true with Stream.Failure -> false diff --git a/testsuite/tests/lib-stream/mpr7769.ml b/testsuite/tests/lib-stream/mpr7769.ml new file mode 100755 index 00000000..da40a473 --- /dev/null +++ b/testsuite/tests/lib-stream/mpr7769.ml @@ -0,0 +1,9 @@ +(* TEST + files = "mpr7769.txt" +*) + +let () = + let s = Stream.of_channel (open_in "mpr7769.txt") in + Stream.junk s; + print_char (Stream.next s); + print_newline () diff --git a/testsuite/tests/lib-stream/mpr7769.reference b/testsuite/tests/lib-stream/mpr7769.reference new file mode 100755 index 00000000..61780798 --- /dev/null +++ b/testsuite/tests/lib-stream/mpr7769.reference @@ -0,0 +1 @@ +b diff --git a/testsuite/tests/lib-stream/mpr7769.txt b/testsuite/tests/lib-stream/mpr7769.txt new file mode 100644 index 00000000..81bf3969 --- /dev/null +++ b/testsuite/tests/lib-stream/mpr7769.txt @@ -0,0 +1 @@ +ab diff --git a/testsuite/tests/lib-stream/ocamltests b/testsuite/tests/lib-stream/ocamltests new file mode 100644 index 00000000..5cfd70ad --- /dev/null +++ b/testsuite/tests/lib-stream/ocamltests @@ -0,0 +1,2 @@ +count_concat_bug.ml +mpr7769.ml diff --git a/testsuite/tests/lib-string/Makefile b/testsuite/tests/lib-string/Makefile deleted file mode 100644 index b25e53f9..00000000 --- a/testsuite/tests/lib-string/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=str -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/str -LD_PATH=$(TOPDIR)/otherlibs/str - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-string/ocamltests b/testsuite/tests/lib-string/ocamltests new file mode 100644 index 00000000..34e6691d --- /dev/null +++ b/testsuite/tests/lib-string/ocamltests @@ -0,0 +1 @@ +test_string.ml diff --git a/testsuite/tests/lib-string/test_string.ml b/testsuite/tests/lib-string/test_string.ml index 96b8c50f..cd45af62 100644 --- a/testsuite/tests/lib-string/test_string.ml +++ b/testsuite/tests/lib-string/test_string.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec build_string f n accu = if n <= 0 then String.concat "" accu diff --git a/testsuite/tests/lib-sys/Makefile b/testsuite/tests/lib-sys/Makefile deleted file mode 100644 index 07ea06eb..00000000 --- a/testsuite/tests/lib-sys/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common - -# Not really generated sources but temp files that need cleaning -GENERATED_SOURCES=file1.dat file2.dat diff --git a/testsuite/tests/lib-sys/ocamltests b/testsuite/tests/lib-sys/ocamltests new file mode 100644 index 00000000..cdb154ed --- /dev/null +++ b/testsuite/tests/lib-sys/ocamltests @@ -0,0 +1 @@ +rename.ml diff --git a/testsuite/tests/lib-sys/rename.ml b/testsuite/tests/lib-sys/rename.ml index 63c29ece..2091c50b 100644 --- a/testsuite/tests/lib-sys/rename.ml +++ b/testsuite/tests/lib-sys/rename.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Test the Sys.rename function *) let writefile filename contents = diff --git a/testsuite/tests/lib-systhreads/Makefile b/testsuite/tests/lib-systhreads/Makefile deleted file mode 100644 index 280f16d5..00000000 --- a/testsuite/tests/lib-systhreads/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=unix threads -ADD_COMPFLAGS=-thread -I $(OTOPDIR)/otherlibs/systhreads \ - -I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/systhreads:$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-systhreads/ocamltests b/testsuite/tests/lib-systhreads/ocamltests new file mode 100644 index 00000000..e818e548 --- /dev/null +++ b/testsuite/tests/lib-systhreads/ocamltests @@ -0,0 +1,2 @@ +testfork.ml +testpreempt.ml diff --git a/testsuite/tests/lib-systhreads/testfork.ml b/testsuite/tests/lib-systhreads/testfork.ml index 1c1f232f..dbd456ca 100644 --- a/testsuite/tests/lib-systhreads/testfork.ml +++ b/testsuite/tests/lib-systhreads/testfork.ml @@ -1,3 +1,11 @@ +(* TEST + include systhreads + * not-bsd + ** libunix + *** bytecode + *** native +*) + (* POSIX threads and fork() *) let compute_thread c = ignore c diff --git a/testsuite/tests/lib-systhreads/testfork.precheck b/testsuite/tests/lib-systhreads/testfork.precheck deleted file mode 100644 index 0dfed5de..00000000 --- a/testsuite/tests/lib-systhreads/testfork.precheck +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -case `grep '^SYSTEM=' ../../../config/Makefile` in - SYSTEM=bsd_elf) exit 3;; -esac - -case `sed -n -e '/OTHERLIBRARIES=/s// /p' ../../../config/Makefile` in - *' unix'*) exit 0;; - *) exit 3;; -esac diff --git a/testsuite/tests/lib-systhreads/testpreempt.ml b/testsuite/tests/lib-systhreads/testpreempt.ml new file mode 100644 index 00000000..820e3cd0 --- /dev/null +++ b/testsuite/tests/lib-systhreads/testpreempt.ml @@ -0,0 +1,35 @@ +(* TEST + (* + On Windows, we use Sleep(0) for triggering preemption of threads. + However, this does not seem very reliable, so that this test fails + on some Windows configurations. See GPR #1533. + *) + include systhreads + * not-windows + ** bytecode + ** native +*) + +let rec generate_list n = + let rec aux acc = function + | 0 -> acc + | n -> aux (float n :: acc) (n-1) + in + aux [] n + +let rec long_computation time0 = + let long_list = generate_list 100000 in + let res = List.length (List.rev_map sin long_list) in + if Sys.time () -. time0 > 2. then + Printf.printf "Long computation result: %d\n%!" res + else long_computation time0 + +let interaction () = + Thread.delay 0.1; + Printf.printf "Interaction 1\n"; + Thread.delay 0.1; + Printf.printf "Interaction 2\n" + +let () = + ignore (Thread.create interaction ()); + long_computation (Sys.time ()) diff --git a/testsuite/tests/lib-systhreads/testpreempt.reference b/testsuite/tests/lib-systhreads/testpreempt.reference new file mode 100644 index 00000000..95995275 --- /dev/null +++ b/testsuite/tests/lib-systhreads/testpreempt.reference @@ -0,0 +1,3 @@ +Interaction 1 +Interaction 2 +Long computation result: 100000 diff --git a/testsuite/tests/lib-threads/Makefile b/testsuite/tests/lib-threads/Makefile deleted file mode 100644 index 8288dfdc..00000000 --- a/testsuite/tests/lib-threads/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=unix threads -ADD_COMPFLAGS=-thread -I $(OTOPDIR)/otherlibs/systhreads \ - -I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/systhreads:$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -default: - @$(if $(filter msvc mingw,$(TOOLCHAIN)),$(MAKE) sigint.exe,true) - @$(SET_LD_PATH) $(MAKE) run-all - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common - -sigint.exe: sigint.$(O) - @$(CC) $(if $(filter msvc,$(CCOMPTYPE)),/Fe$@,-o $@) $^ - -%.obj: %.c - @$(CC) -c $*.c > /dev/null diff --git a/testsuite/tests/lib-threads/backtrace_threads.ml b/testsuite/tests/lib-threads/backtrace_threads.ml index 79dc8c5b..8044af3b 100644 --- a/testsuite/tests/lib-threads/backtrace_threads.ml +++ b/testsuite/tests/lib-threads/backtrace_threads.ml @@ -1,3 +1,8 @@ +(* TEST + +include systhreads + +*) let () = Printexc.record_backtrace true diff --git a/testsuite/tests/lib-threads/bank.ml b/testsuite/tests/lib-threads/bank.ml index 800d332a..cf00a717 100644 --- a/testsuite/tests/lib-threads/bank.ml +++ b/testsuite/tests/lib-threads/bank.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* The bank account example, using events and channels *) open Printf diff --git a/testsuite/tests/lib-threads/beat.ml b/testsuite/tests/lib-threads/beat.ml index afc8166a..a09980be 100644 --- a/testsuite/tests/lib-threads/beat.ml +++ b/testsuite/tests/lib-threads/beat.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* Test Thread.delay and its scheduling *) open Printf diff --git a/testsuite/tests/lib-threads/bufchan.ml b/testsuite/tests/lib-threads/bufchan.ml index b8ac55c2..4c243c6c 100644 --- a/testsuite/tests/lib-threads/bufchan.ml +++ b/testsuite/tests/lib-threads/bufchan.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + open Event type 'a buffer_channel = { diff --git a/testsuite/tests/lib-threads/close.ml b/testsuite/tests/lib-threads/close.ml index bba0286c..5f8918a3 100644 --- a/testsuite/tests/lib-threads/close.ml +++ b/testsuite/tests/lib-threads/close.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + let main () = let (rd, wr) = Unix.pipe() in let t = Thread.create diff --git a/testsuite/tests/lib-threads/fileio.ml b/testsuite/tests/lib-threads/fileio.ml index 5c02aebd..d380917a 100644 --- a/testsuite/tests/lib-threads/fileio.ml +++ b/testsuite/tests/lib-threads/fileio.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* Test a file copy function *) let test msg producer consumer src dst = diff --git a/testsuite/tests/lib-threads/ocamltests b/testsuite/tests/lib-threads/ocamltests new file mode 100644 index 00000000..1df74eb5 --- /dev/null +++ b/testsuite/tests/lib-threads/ocamltests @@ -0,0 +1,17 @@ +backtrace_threads.ml +bank.ml +beat.ml +bufchan.ml +close.ml +fileio.ml +pr4466.ml +pr5325.ml +pr7638.ml +prodcons.ml +prodcons2.ml +sieve.ml +signal.ml +sockets.ml +swapchan.ml +tls.ml +torture.ml diff --git a/testsuite/tests/lib-threads/pr4466.ml b/testsuite/tests/lib-threads/pr4466.ml index 0598a54e..5d214a6f 100644 --- a/testsuite/tests/lib-threads/pr4466.ml +++ b/testsuite/tests/lib-threads/pr4466.ml @@ -1,3 +1,13 @@ +(* TEST + +include systhreads + +* libunix (* Broken on Windows (missing join?), needs to be fixed *) +** bytecode +** native + +*) + open Printf (* Regression test for PR#4466: select timeout with simultaneous read diff --git a/testsuite/tests/lib-threads/pr5325.ml b/testsuite/tests/lib-threads/pr5325.ml index 884a9a3e..27a83098 100644 --- a/testsuite/tests/lib-threads/pr5325.ml +++ b/testsuite/tests/lib-threads/pr5325.ml @@ -1,3 +1,13 @@ +(* TEST + +include systhreads + +* libunix (* Broken on Windows (missing join?), needs to be fixed *) +** bytecode +** native + +*) + open Printf (* Regression test for PR#5325: simultaneous read and write on socket diff --git a/testsuite/tests/lib-threads/pr7638.ml b/testsuite/tests/lib-threads/pr7638.ml index 95371112..07e1a81c 100644 --- a/testsuite/tests/lib-threads/pr7638.ml +++ b/testsuite/tests/lib-threads/pr7638.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* MPR#7638 repro case *) let crashme v = diff --git a/testsuite/tests/lib-threads/prodcons.ml b/testsuite/tests/lib-threads/prodcons.ml index 81e3ff18..808da43a 100644 --- a/testsuite/tests/lib-threads/prodcons.ml +++ b/testsuite/tests/lib-threads/prodcons.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* Classic producer-consumer *) type 'a prodcons = diff --git a/testsuite/tests/lib-threads/prodcons2.ml b/testsuite/tests/lib-threads/prodcons2.ml index 0b80f5e2..8f3c5b25 100644 --- a/testsuite/tests/lib-threads/prodcons2.ml +++ b/testsuite/tests/lib-threads/prodcons2.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* Producer-consumer with events and multiple producers *) open Event diff --git a/testsuite/tests/lib-threads/sieve.ml b/testsuite/tests/lib-threads/sieve.ml index 13c494cd..9c6414b8 100644 --- a/testsuite/tests/lib-threads/sieve.ml +++ b/testsuite/tests/lib-threads/sieve.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + let sieve primes = Event.sync (Event.send primes 2); let integers = Event.new_channel () in diff --git a/testsuite/tests/lib-threads/sigint.c b/testsuite/tests/lib-threads/sigint.c index a975949a..aa6df5e6 100644 --- a/testsuite/tests/lib-threads/sigint.c +++ b/testsuite/tests/lib-threads/sigint.c @@ -1,10 +1,21 @@ #include -#include + +#ifdef _WIN32 + #include +#else + #include + #include + #include +#endif int main(int argc, char** argv) { +#ifdef _WIN32 DWORD pid; HANDLE hProcess; +#else + pid_t pid; +#endif if (argc != 2) { printf("Usage: %s pid\n", argv[0]); @@ -12,6 +23,7 @@ int main(int argc, char** argv) } pid = atoi(argv[1]); +#ifdef _WIN32 hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid); if (!hProcess) { @@ -32,6 +44,12 @@ int main(int argc, char** argv) WaitForSingleObject(hProcess, INFINITE); CloseHandle(hProcess); FreeConsole(); +#else + if (kill(pid,SIGINT)) { + perror("kill"); + return 1; + } +#endif return 0; } diff --git a/testsuite/tests/lib-threads/signal.check-program-output b/testsuite/tests/lib-threads/signal.check-program-output new file mode 100644 index 00000000..48c0d0e3 --- /dev/null +++ b/testsuite/tests/lib-threads/signal.check-program-output @@ -0,0 +1,6 @@ +if sed -e 1q ${output} | grep -q '^[ab]*Got ctrl-C, exiting$'; +then + exit ${TEST_PASS} +else + exit ${TEST_FAIL}; +fi diff --git a/testsuite/tests/lib-threads/signal.checker b/testsuite/tests/lib-threads/signal.checker deleted file mode 100644 index 8bb0d3da..00000000 --- a/testsuite/tests/lib-threads/signal.checker +++ /dev/null @@ -1,16 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -sed -e 1q signal.result | grep -q '^[ab]*Got ctrl-C, exiting...[ab]\{0,2\}$' diff --git a/testsuite/tests/lib-threads/signal.ml b/testsuite/tests/lib-threads/signal.ml index b9ef7d63..2db8fe44 100644 --- a/testsuite/tests/lib-threads/signal.ml +++ b/testsuite/tests/lib-threads/signal.ml @@ -1,13 +1,71 @@ +(* TEST + +include systhreads + +files = "sigint.c" + +* libunix (* excludes mingw32/64 and msvc32/64 *) + +** setup-ocamlc.byte-build-env + +program = "${test_build_directory}/signal.byte" + +*** ocamlc.byte + +program = "sigint" +all_modules = "sigint.c" + +**** ocamlc.byte + +program = "${test_build_directory}/signal.byte" +all_modules = "signal.ml" + +***** check-ocamlc.byte-output +****** run +******* check-program-output + +** setup-ocamlopt.byte-build-env + +program = "${test_build_directory}/signal.opt" + +*** ocamlopt.byte + +program = "sigint" +all_modules = "sigint.c" + +**** ocamlc.byte + +program = "${test_build_directory}/signal.opt" +all_modules = "signal.ml" + +***** check-ocamlopt.byte-output +****** run +******* check-program-output + +*) + +let signaled = ref false + +let counter = ref 0 + let sighandler _ = - print_string "Got ctrl-C, exiting..."; print_newline(); - exit 0 + signaled := true let print_message delay c = - while true do + while (not !signaled) && (!counter <= 20) do + incr counter; print_char c; flush stdout; Thread.delay delay done let _ = ignore (Sys.signal Sys.sigint (Sys.Signal_handle sighandler)); - ignore (Thread.create (print_message 0.6666666666) 'a'); - print_message 1.0 'b' + let th1 = Thread.create (print_message 0.6666666666) 'a' in + print_message 1.0 'b'; + Thread.join th1; + if !signaled then begin + print_string "Got ctrl-C, exiting"; print_newline(); + exit 0 + end else begin + print_string "not signaled???"; print_newline(); + exit 2 + end diff --git a/testsuite/tests/lib-threads/signal.precheck b/testsuite/tests/lib-threads/signal.precheck deleted file mode 100644 index d04af9a4..00000000 --- a/testsuite/tests/lib-threads/signal.precheck +++ /dev/null @@ -1 +0,0 @@ -test "$TOOLCHAIN" != "msvc" -a "$TOOLCHAIN" != "mingw" diff --git a/testsuite/tests/lib-threads/signal.run b/testsuite/tests/lib-threads/signal.run new file mode 100644 index 00000000..1611435d --- /dev/null +++ b/testsuite/tests/lib-threads/signal.run @@ -0,0 +1,5 @@ +${program} > ${output} & +pid=$! +sleep 2 +./sigint $pid +wait diff --git a/testsuite/tests/lib-threads/signal.runner b/testsuite/tests/lib-threads/signal.runner deleted file mode 100644 index b90139a9..00000000 --- a/testsuite/tests/lib-threads/signal.runner +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -$RUNTIME ./program >signal.result & -pid=$! -sleep 2 -test -e ./sigint.exe && ./sigint $pid || kill -INT $pid diff --git a/testsuite/tests/lib-threads/sockets.ml b/testsuite/tests/lib-threads/sockets.ml index 160446f6..9f767077 100644 --- a/testsuite/tests/lib-threads/sockets.ml +++ b/testsuite/tests/lib-threads/sockets.ml @@ -1,3 +1,13 @@ +(* TEST + +include systhreads + +* libunix (* Broken on Windows (missing join?), needs to be fixed *) +** bytecode +** native + +*) + open Printf (* Threads and sockets *) diff --git a/testsuite/tests/lib-threads/socketsbuf.ml b/testsuite/tests/lib-threads/socketsbuf.ml deleted file mode 100644 index 7eafb1bd..00000000 --- a/testsuite/tests/lib-threads/socketsbuf.ml +++ /dev/null @@ -1,40 +0,0 @@ -open Printf - -(* Threads, sockets, and buffered I/O channels *) -(* Serves as a regression test for PR#5578 *) - -let serve_connection s = - let ic = Unix.in_channel_of_descr s - and oc = Unix.out_channel_of_descr s in - let l = input_line ic in - fprintf oc ">>%s\n" l; - close_out oc - -let server sock = - while true do - let (s, _) = Unix.accept sock in - ignore(Thread.create serve_connection s) - done - -let client (addr, msg) = - let sock = - Unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in - Unix.connect sock addr; - let ic = Unix.in_channel_of_descr sock - and oc = Unix.out_channel_of_descr sock in - output_string oc msg; flush oc; - let l = input_line ic in - printf "%s\n%!" l - -let _ = - let addr = Unix.ADDR_INET(Unix.inet_addr_loopback, 0) in - let sock = - Unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in - Unix.setsockopt sock Unix.SO_REUSEADDR true; - Unix.bind sock addr; - let addr = Unix.getsockname sock in - Unix.listen sock 5; - ignore (Thread.create server sock); - ignore (Thread.create client (addr, "Client #1\n")); - Thread.delay 0.5; - client (addr, "Client #2\n") diff --git a/testsuite/tests/lib-threads/socketsbuf.reference b/testsuite/tests/lib-threads/socketsbuf.reference deleted file mode 100644 index a3f7067d..00000000 --- a/testsuite/tests/lib-threads/socketsbuf.reference +++ /dev/null @@ -1,2 +0,0 @@ ->>Client #1 ->>Client #2 diff --git a/testsuite/tests/lib-threads/swapchan.checker b/testsuite/tests/lib-threads/swapchan.checker deleted file mode 100644 index bf957add..00000000 --- a/testsuite/tests/lib-threads/swapchan.checker +++ /dev/null @@ -1,16 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, Projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2015 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -$SORT swapchan.result | $DIFF swapchan.reference - >/dev/null diff --git a/testsuite/tests/lib-threads/swapchan.ml b/testsuite/tests/lib-threads/swapchan.ml index 1f80beb8..8d7f7522 100644 --- a/testsuite/tests/lib-threads/swapchan.ml +++ b/testsuite/tests/lib-threads/swapchan.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + open Event type 'a swap_chan = ('a * 'a channel) channel diff --git a/testsuite/tests/lib-threads/swapchan.run b/testsuite/tests/lib-threads/swapchan.run new file mode 100644 index 00000000..1e3ecbb3 --- /dev/null +++ b/testsuite/tests/lib-threads/swapchan.run @@ -0,0 +1 @@ +${program} | ${SORT} > ${output} 2>&1 diff --git a/testsuite/tests/lib-threads/tls.checker b/testsuite/tests/lib-threads/tls.checker deleted file mode 100644 index b1d036b0..00000000 --- a/testsuite/tests/lib-threads/tls.checker +++ /dev/null @@ -1,16 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -LC_ALL=C $SORT tls.result | $DIFF tls.reference - diff --git a/testsuite/tests/lib-threads/tls.ml b/testsuite/tests/lib-threads/tls.ml index 6db93fa9..c69db388 100644 --- a/testsuite/tests/lib-threads/tls.ml +++ b/testsuite/tests/lib-threads/tls.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + let private_data = (Hashtbl.create 17 : (Thread.t, string) Hashtbl.t) let private_data_lock = Mutex.create() let output_lock = Mutex.create() diff --git a/testsuite/tests/lib-threads/tls.run b/testsuite/tests/lib-threads/tls.run new file mode 100644 index 00000000..4b586e8f --- /dev/null +++ b/testsuite/tests/lib-threads/tls.run @@ -0,0 +1 @@ +${program} | LC_ALL=C ${SORT} > ${output} 2>&1 diff --git a/testsuite/tests/lib-threads/token2.reference b/testsuite/tests/lib-threads/token2.reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/lib-threads/torture.ml b/testsuite/tests/lib-threads/torture.ml index 9dba8add..9c4a8475 100644 --- a/testsuite/tests/lib-threads/torture.ml +++ b/testsuite/tests/lib-threads/torture.ml @@ -1,3 +1,9 @@ +(* TEST + +include systhreads + +*) + (* Torture test - I/O interspersed with lots of GC *) let finished = ref false diff --git a/testsuite/tests/lib-uchar/Makefile b/testsuite/tests/lib-uchar/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/lib-uchar/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-uchar/ocamltests b/testsuite/tests/lib-uchar/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-uchar/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-uchar/test.ml b/testsuite/tests/lib-uchar/test.ml index 4fdbf925..872a506b 100644 --- a/testsuite/tests/lib-uchar/test.ml +++ b/testsuite/tests/lib-uchar/test.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let assert_raise_invalid_argument f v = assert (try ignore (f v); false with Invalid_argument _ -> true) diff --git a/testsuite/tests/lib-unix/common/Makefile b/testsuite/tests/lib-unix/common/Makefile deleted file mode 100644 index 706137be..00000000 --- a/testsuite/tests/lib-unix/common/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../../.. -LIBRARIES=unix -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -ifeq ($(OS),Windows_NT) -ADD_BYTERUN_FLAGS="-I $(OTOPDIR)/otherlibs/win32unix" -endif - -default: reflector.exe fdstatus.exe cmdline_prog.exe - @$(MAKE) check - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common - -%.exe: %.c -ifeq ($(CCOMPTYPE),msvc) - @set -o pipefail ; \ - $(CC) $(CFLAGS) $(CPPFLAGS) /Fe$*.exe $*.c | tail -n +2 -else - @$(CC) $(CFLAGS) $(CPPFLAGS) -o $*.exe $*.c -endif diff --git a/testsuite/tests/lib-unix/common/cloexec.ml b/testsuite/tests/lib-unix/common/cloexec.ml index d7e1e292..9b528674 100644 --- a/testsuite/tests/lib-unix/common/cloexec.ml +++ b/testsuite/tests/lib-unix/common/cloexec.ml @@ -1,7 +1,56 @@ +(* TEST + +(* + This test is temporarily disabled on the MinGW and MSVC ports, + because since fdstatus has been wrapped in an OCaml program, + it does not work as well as before. + Presumably this is because the OCaml runtime opens files, so that handles + that have actually been closed at execution look open and make the + test fail. + + One possible fix for this would be to make it possible for ocamltest to + compile C-only programs, which will be a bit of work to handle the + output of msvc and will also duplicate what the ocaml compiler itslef + already does. +*) + +include unix +files = "fdstatus_aux.c fdstatus_main.ml" + +*libunix +** setup-ocamlc.byte-build-env +program = "${test_build_directory}/cloexec.byte" +*** ocamlc.byte +program = "${test_build_directory}/fdstatus.exe" +all_modules = "fdstatus_aux.c fdstatus_main.ml" +**** ocamlc.byte +program = "${test_build_directory}/cloexec.byte" +all_modules= "cloexec.ml" +***** check-ocamlc.byte-output +****** run +******* check-program-output + +** setup-ocamlopt.byte-build-env +program = "${test_build_directory}/cloexec.opt" +*** ocamlopt.byte +program = "${test_build_directory}/fdstatus.exe" +all_modules = "fdstatus_aux.c fdstatus_main.ml" +**** ocamlopt.byte +program = "${test_build_directory}/cloexec.opt" +all_modules= "cloexec.ml" +***** check-ocamlopt.byte-output +****** run +******* check-program-output + +*) + (* This is a terrible hack that plays on the internal representation of file descriptors. The result is a number (as a string) that the fdstatus.exe auxiliary program can use to check whether - the fd is open. *) + the fd is open. Moreover, since fdstatus.exe is an OCaml program, + we must take into account that the Windows OCaml runtime opens a few handles + for its own use, hence we do likewise to try to get handle numbers + Windows will not allocate to the OCaml runtime of fdstatus.exe *) let string_of_fd (fd: Unix.file_descr) : string = match Sys.os_type with @@ -13,8 +62,15 @@ let string_of_fd (fd: Unix.file_descr) : string = Int64.to_string (Obj.magic fd : int64) | _ -> assert false +let status_checker = "fdstatus.exe" + let _ = let f0 = Unix.(openfile "tmp.txt" [O_WRONLY; O_CREAT; O_TRUNC] 0o600) in + let untested1 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in + let untested2 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in + let untested3 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in + let untested4 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in + let untested5 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in let f1 = Unix.(openfile "tmp.txt" [O_RDONLY; O_KEEPEXEC] 0) in let f2 = Unix.(openfile "tmp.txt" [O_RDONLY; O_CLOEXEC] 0) in let d0 = Unix.dup f0 in @@ -41,11 +97,16 @@ let _ = p0;p0';p1;p1';p2;p2'; s0;s1;s2; x0;x0';x1;x1';x2;x2' |] in + let untested = + [untested1; untested2; untested3; untested4; untested5] + in let pid = Unix.create_process - (Filename.concat Filename.current_dir_name "fdstatus.exe") - (Array.append [| "fdstatus" |] (Array.map string_of_fd fds)) + (Filename.concat Filename.current_dir_name status_checker) + (Array.append [| status_checker |] (Array.map string_of_fd fds)) Unix.stdin Unix.stdout Unix.stderr in ignore (Unix.waitpid [] pid); - Array.iter (fun fd -> try Unix.close fd with Unix.Unix_error _ -> ()) fds; + let close fd = try Unix.close fd with Unix.Unix_error _ -> () in + Array.iter close fds; + List.iter close untested; Sys.remove "tmp.txt" diff --git a/testsuite/tests/lib-unix/common/cmdline_prog.c b/testsuite/tests/lib-unix/common/cmdline_prog.c deleted file mode 100644 index c67a7563..00000000 --- a/testsuite/tests/lib-unix/common/cmdline_prog.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -int main (int argc, char *argv[]) -{ - int i; - for (i = 1; i < argc; i ++) { - printf ("%s\n", argv[i]); - } - return 0; -} diff --git a/testsuite/tests/lib-unix/common/cmdline_prog.ml b/testsuite/tests/lib-unix/common/cmdline_prog.ml new file mode 100644 index 00000000..69239cb3 --- /dev/null +++ b/testsuite/tests/lib-unix/common/cmdline_prog.ml @@ -0,0 +1,4 @@ +let () = + for i = 1 to (Array.length Sys.argv) - 1 do + Printf.printf "%s\n" Sys.argv.(i) + done diff --git a/testsuite/tests/lib-unix/common/dup.ml b/testsuite/tests/lib-unix/common/dup.ml index d296cb97..2cb8c975 100644 --- a/testsuite/tests/lib-unix/common/dup.ml +++ b/testsuite/tests/lib-unix/common/dup.ml @@ -1,3 +1,7 @@ +(* TEST +include unix +*) + let _ = let f = Unix.dup ~cloexec:true Unix.stdout in let txt = "Some output\n" in diff --git a/testsuite/tests/lib-unix/common/dup2.ml b/testsuite/tests/lib-unix/common/dup2.ml index 055d7e5f..a3dcc120 100644 --- a/testsuite/tests/lib-unix/common/dup2.ml +++ b/testsuite/tests/lib-unix/common/dup2.ml @@ -1,3 +1,8 @@ +(* TEST +include unix +stderr = "/dev/null" +*) + let cat file = let fd = Unix.openfile file [Unix.O_RDONLY] 0 in let buf = Bytes.create 1024 in diff --git a/testsuite/tests/lib-unix/common/fdstatus.c b/testsuite/tests/lib-unix/common/fdstatus.c deleted file mode 100644 index b8770418..00000000 --- a/testsuite/tests/lib-unix/common/fdstatus.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Check if file descriptors are open or not */ - -#include -#include - -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -void process_fd(char * s) -{ - int fd; - HANDLE h; - DWORD flags; - -#ifdef _WIN64 - h = (HANDLE) _atoi64(s); -#else - h = (HANDLE) atoi(s); -#endif - if (GetHandleInformation(h, &flags)) { - printf("open\n"); - } else if (GetLastError() == ERROR_INVALID_HANDLE) { - printf("closed\n"); - } else { - printf("error %lu\n", (unsigned long)(GetLastError())); - } -} - -#else - -#include -#include -#include -#include -#include -#include - -void process_fd(char * s) -{ - long n; - int fd; - char * endp; - struct stat st; - n = strtol(s, &endp, 0); - if (*endp != 0 || n < 0 || n > (long) INT_MAX) { - printf("parsing error\n"); - return; - } - fd = (int) n; - if (fstat(fd, &st) != -1) { - printf("open\n"); - } else if (errno == EBADF) { - printf("closed\n"); - } else { - printf("error %s\n", strerror(errno)); - } -} - -#endif - -int main(int argc, char ** argv) -{ - int i; - for (i = 1; i < argc; i++) { - printf("#%d: ", i); - process_fd(argv[i]); - } - return 0; -} diff --git a/testsuite/tests/lib-unix/common/fdstatus_aux.c b/testsuite/tests/lib-unix/common/fdstatus_aux.c new file mode 100644 index 00000000..199166e8 --- /dev/null +++ b/testsuite/tests/lib-unix/common/fdstatus_aux.c @@ -0,0 +1,74 @@ +/* Check if file descriptors are open or not */ + +#include +#include + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +void process_fd(char * s) +{ + int fd; + HANDLE h; + DWORD flags; + +#ifdef _WIN64 + h = (HANDLE) _atoi64(s); +#else + h = (HANDLE) atoi(s); +#endif + if (GetHandleInformation(h, &flags)) { + printf("open\n"); + } else if (GetLastError() == ERROR_INVALID_HANDLE) { + printf("closed\n"); + } else { + printf("error %lu\n", (unsigned long)(GetLastError())); + } +} + +#else + +#include +#include +#include +#include +#include +#include + +void process_fd(char * s) +{ + long n; + int fd; + char * endp; + struct stat st; + n = strtol(s, &endp, 0); + if (*endp != 0 || n < 0 || n > (long) INT_MAX) { + printf("parsing error\n"); + return; + } + fd = (int) n; + if (fstat(fd, &st) != -1) { + printf("open\n"); + } else if (errno == EBADF) { + printf("closed\n"); + } else { + printf("error %s\n", strerror(errno)); + } +} + +#endif + +#include "caml/mlvalues.h" +#include "caml/memory.h" + +CAMLprim value caml_process_fd(value CAMLnum, value CAMLfd) +{ + CAMLparam2(CAMLnum, CAMLfd); + printf("#%d: ", Int_val(CAMLnum)); + process_fd(String_val(CAMLfd)); + CAMLreturn(Val_unit); +} diff --git a/testsuite/tests/lib-unix/common/fdstatus_main.ml b/testsuite/tests/lib-unix/common/fdstatus_main.ml new file mode 100644 index 00000000..93f3922b --- /dev/null +++ b/testsuite/tests/lib-unix/common/fdstatus_main.ml @@ -0,0 +1,7 @@ +external process_fd : int -> string -> unit = "caml_process_fd" + +let () = + for i = 1 to (Array.length Sys.argv) -1 + do + process_fd i Sys.argv.(i); + done diff --git a/testsuite/tests/lib-unix/common/ocamltests b/testsuite/tests/lib-unix/common/ocamltests new file mode 100644 index 00000000..12da8014 --- /dev/null +++ b/testsuite/tests/lib-unix/common/ocamltests @@ -0,0 +1,9 @@ +cloexec.ml +dup2.ml +dup.ml +pipe_eof.ml +redirections.ml +rename.ml +test_unix_cmdline.ml +utimes.ml +wait_nohang.ml diff --git a/testsuite/tests/lib-unix/common/pipe_eof.ml b/testsuite/tests/lib-unix/common/pipe_eof.ml index 19f5258e..a4c71d7e 100644 --- a/testsuite/tests/lib-unix/common/pipe_eof.ml +++ b/testsuite/tests/lib-unix/common/pipe_eof.ml @@ -1,3 +1,7 @@ +(* TEST +include unix +*) + let drain pipe = let max = 2048 in let buf = Buffer.create 2048 in diff --git a/testsuite/tests/lib-unix/common/redirections.ml b/testsuite/tests/lib-unix/common/redirections.ml index ed1712a4..409ec365 100644 --- a/testsuite/tests/lib-unix/common/redirections.ml +++ b/testsuite/tests/lib-unix/common/redirections.ml @@ -1,3 +1,36 @@ +(* TEST + +files = "reflector.ml" + +* setup-ocamlc.byte-build-env +program = "${test_build_directory}/redirections.byte" +** ocamlc.byte +program = "${test_build_directory}/reflector.exe" +all_modules = "reflector.ml" +*** ocamlc.byte +include unix +program = "${test_build_directory}/redirections.byte" +all_modules= "redirections.ml" +**** check-ocamlc.byte-output +***** run +****** check-program-output + +* setup-ocamlopt.byte-build-env +program = "${test_build_directory}/redirections.opt" +** ocamlopt.byte +program = "${test_build_directory}/reflector.exe" +all_modules = "reflector.ml" +*** ocamlopt.byte +include unix +program = "${test_build_directory}/redirections.opt" +all_modules= "redirections.ml" +**** check-ocamlopt.byte-output +***** run +****** check-program-output + +*) + + let cat file = let fd = Unix.openfile file [Unix.O_RDONLY] 0 in let buf = Bytes.create 1024 in @@ -12,7 +45,7 @@ let out fd txt = let refl = Filename.concat Filename.current_dir_name "reflector.exe" -let test_createprocess () = +let test_createprocess systemenv = let f_out = Unix.(openfile "./tmpout.txt" [O_WRONLY;O_TRUNC;O_CREAT;O_CLOEXEC] 0o600) in let f_err = @@ -22,8 +55,8 @@ let test_createprocess () = let pid = Unix.create_process_env refl - [| refl; "i2o"; "i2e"; "o"; "123"; "e"; "456"; "i2o"; "v"; "XVAR" |] - [| "XVAR=xvar" |] + [| refl; "-i2o"; "-i2e"; "-o"; "123"; "-e"; "456"; "-i2o"; "-v"; "XVAR" |] + (Array.append [| "XVAR=xvar" |] systemenv) p_exit f_out f_err in out p_entrance "aaaa\n"; out p_entrance "bbbb\n"; @@ -43,7 +76,7 @@ let test_2ampsup1 () = (* 2>&1 redirection, cf. GPR#1105 *) let pid = Unix.create_process refl - [| refl; "o"; "123"; "e"; "456"; "o"; "789" |] + [| refl; "-o"; "123"; "-e"; "456"; "-o"; "789" |] Unix.stdin Unix.stdout Unix.stdout in let (_, status) = Unix.waitpid [] pid in if status <> Unix.WEXITED 0 then @@ -55,14 +88,14 @@ let test_swap12 () = (* swapping stdout and stderr *) let pid = Unix.create_process refl - [| refl; "e"; "123" |] + [| refl; "-e"; "123" |] Unix.stdin Unix.stderr Unix.stdout in let (_, status) = Unix.waitpid [] pid in if status <> Unix.WEXITED 0 then out Unix.stdout "!!! reflector exited with an error\n" let test_open_process_in () = - let ic = Unix.open_process_in (refl ^ " o 123 o 456") in + let ic = Unix.open_process_in (refl ^ " -o 123 -o 456") in out Unix.stdout (input_line ic ^ "\n"); out Unix.stdout (input_line ic ^ "\n"); let status = Unix.close_process_in ic in @@ -70,17 +103,17 @@ let test_open_process_in () = out Unix.stdout "!!! reflector exited with an error\n" let test_open_process_out () = - let oc = Unix.open_process_out (refl ^ " i2o i2o i2o") in + let oc = Unix.open_process_out (refl ^ " -i2o -i2o -i2o") in output_string oc "aa\nbbbb\n"; close_out oc; let status = Unix.close_process_out oc in if status <> Unix.WEXITED 0 then out Unix.stdout "!!! reflector exited with an error\n" -let test_open_process_full () = +let test_open_process_full systemenv = let ((o, i, e) as res) = Unix.open_process_full - (refl ^ " o 123 i2o e 456 i2e v XVAR") - [|"XVAR=xvar"|] in + (refl ^ " -o 123 -i2o -e 456 -i2e -v XVAR") + (Array.append [|"XVAR=xvar"|] systemenv) in output_string i "aa\nbbbb\n"; close_out i; for _i = 1 to 3 do out Unix.stdout (input_line o ^ "\n") @@ -93,12 +126,17 @@ let test_open_process_full () = out Unix.stdout "!!! reflector exited with an error\n" let _ = + let ocamlrunparam = + match Sys.getenv_opt "OCAMLRUNPARAM" with + | None -> [||] + | Some v -> [|"OCAMLRUNPARAM=" ^ v|] + in (* The following 'close' makes things more difficult. Under Unix it works fine, but under Win32 create_process gives an error if one of the standard handles is closed. *) (* Unix.close Unix.stdin; *) out Unix.stdout "** create_process\n"; - test_createprocess(); + test_createprocess ocamlrunparam; out Unix.stdout "** create_process 2>&1 redirection\n"; test_2ampsup1(); out Unix.stdout "** create_process swap 1-2\n"; @@ -108,6 +146,4 @@ let _ = out Unix.stdout "** open_process_out\n"; test_open_process_out(); out Unix.stdout "** open_process_full\n"; - test_open_process_full() - - + test_open_process_full ocamlrunparam diff --git a/testsuite/tests/lib-unix/common/reflector.c b/testsuite/tests/lib-unix/common/reflector.c deleted file mode 100644 index f8bbbf31..00000000 --- a/testsuite/tests/lib-unix/common/reflector.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#if defined(_WIN32) -#include -#include -#endif - -/* A tool to read data from standard input and send it to standard - output or standard error. */ - -void copyline(FILE * in, FILE * out) -{ - int c; - do { - c = getc(in); - if (c == EOF) { - fputs("\n", out); - break; - } - putc(c, out); - } while (c != '\n'); - fflush(out); -} - -/* Command language: - i2o copy one line from stdin to stdout - i2e copy one line from stdin to stderr - o write plus newline to stdout - e write plus newline to stderr - v write value of environment variable to stdout -*/ - -int main(int argc, char ** argv) -{ - int i; - char * cmd; -#if defined(_WIN32) - _setmode(_fileno(stdin), _O_BINARY); - _setmode(_fileno(stdout), _O_BINARY); - _setmode(_fileno(stderr), _O_BINARY); -#endif - i = 1; - while (i < argc) { - cmd = argv[i]; - if (strcmp(cmd, "i2o") == 0) { - copyline(stdin, stdout); - i++; - } else if (strcmp(cmd, "i2e") == 0) { - copyline(stdin, stderr); - i++; - } else if (strcmp(cmd, "o") == 0 && i + 1 < argc) { - fputs(argv[i + 1], stdout); - fputc('\n', stdout); - fflush(stdout); - i += 2; - } else if (strcmp(cmd, "e") == 0 && i + 1 < argc) { - fputs(argv[i + 1], stderr); - fputc('\n', stderr); - fflush(stderr); - i += 2; - } else if (strcmp(cmd, "v") == 0 && i + 1 < argc) { - char * v = getenv(argv[i + 1]); - fputs((v == NULL ? "" : v), stdout); - fputc('\n', stdout); - fflush(stdout); - i += 2; - } else { - fputs("\n", stderr); - return 2; - } - } - return 0; -} diff --git a/testsuite/tests/lib-unix/common/reflector.ml b/testsuite/tests/lib-unix/common/reflector.ml new file mode 100644 index 00000000..9188019a --- /dev/null +++ b/testsuite/tests/lib-unix/common/reflector.ml @@ -0,0 +1,51 @@ +let copyline input output = + let rec copy() = match input_char input with + | exception End_of_file -> + output_string output "\n" + | char -> + output_char output char; + if char='\n' then () else copy() + in + copy(); + flush output + +let output_endline output str = + output_string output str; + output_char output '\n'; + flush output + +let output_env_var output env_var = + let value = match Sys.getenv_opt env_var with + | None -> "" + | Some v -> v + in + output_endline stdout value + +let options = +[ + ("-i2o", + Arg.Unit (fun () -> (copyline stdin stdout)), + "copy one line from stdin to stdout"); + ("-i2e", + Arg.Unit (fun () -> (copyline stdin stderr)), + "copy one line from stdin to stderr"); + ("-o", + Arg.String (output_endline stdout), + "-o write plus newline to stdout"); + ("-e", + Arg.String (output_endline stderr), + "-e write plus newline to stderr"); + ("-v", + Arg.String (output_env_var stdout), + "-v write value of environment variable to stdout"); +] + +let report_bad_argument _arg = + output_endline stderr "" + +let () = + set_binary_mode_in stdin true; + set_binary_mode_out stdout true; + set_binary_mode_out stderr true; + Arg.parse options report_bad_argument "" + \ No newline at end of file diff --git a/testsuite/tests/lib-unix/common/rename.ml b/testsuite/tests/lib-unix/common/rename.ml index 713c6dd4..46000bb3 100644 --- a/testsuite/tests/lib-unix/common/rename.ml +++ b/testsuite/tests/lib-unix/common/rename.ml @@ -1,3 +1,7 @@ +(* TEST +include unix +*) + (* Test the Unix.rename function *) let writefile filename contents = diff --git a/testsuite/tests/lib-unix/common/test_unix_cmdline.ml b/testsuite/tests/lib-unix/common/test_unix_cmdline.ml index f0f7679b..4c782a32 100644 --- a/testsuite/tests/lib-unix/common/test_unix_cmdline.ml +++ b/testsuite/tests/lib-unix/common/test_unix_cmdline.ml @@ -1,3 +1,35 @@ +(* TEST + +files = "cmdline_prog.ml" + +* setup-ocamlc.byte-build-env +program = "${test_build_directory}/test_unix_cmdline.byte" +** ocamlc.byte +program = "${test_build_directory}/cmdline_prog.exe" +all_modules = "cmdline_prog.ml" +*** ocamlc.byte +include unix +program = "${test_build_directory}/test_unix_cmdline.byte" +all_modules= "test_unix_cmdline.ml" +**** check-ocamlc.byte-output +***** run +****** check-program-output + +* setup-ocamlopt.byte-build-env +program = "${test_build_directory}/test_unix_cmdline.opt" +** ocamlc.byte +program = "${test_build_directory}/cmdline_prog.exe" +all_modules = "cmdline_prog.ml" +*** ocamlopt.byte +include unix +program = "${test_build_directory}/test_unix_cmdline.opt" +all_modules= "test_unix_cmdline.ml" +**** check-ocamlopt.byte-output +***** run +****** check-program-output + +*) + open Unix let prog_name = "cmdline_prog.exe" diff --git a/testsuite/tests/lib-unix/common/utimes.ml b/testsuite/tests/lib-unix/common/utimes.ml new file mode 100644 index 00000000..c353544a --- /dev/null +++ b/testsuite/tests/lib-unix/common/utimes.ml @@ -0,0 +1,32 @@ +(* TEST +include unix +files = "utimes.txt" +*) + +(* We do not check setting the "last access time" because it is hard to do so on + some file systems. FAT, for example, only has a 1d resolution for this + timestamp, and even NTFS can potentially delay the update of this timestamp + by up to an hour. +*) + +let txt = "utimes.txt" + +(* To account for filesystems with large timestamp resolution (e.g. FAT - 2 + seconds for mtime) +*) +let close s t = + abs_float (s -. t) < 10. + +let check tm = + let tm' = (Unix.stat txt).Unix.st_mtime in + Printf.printf "tm ~ tm' (%B)\n" (close tm tm') + +let () = + let oc = open_out_bin txt in + close_out oc; + let tm = 1508391026.124 in + Unix.utimes txt tm tm; + check tm; + let tn = Unix.time () in + Unix.utimes txt 0. 0.; + check tn diff --git a/testsuite/tests/lib-unix/common/utimes.reference b/testsuite/tests/lib-unix/common/utimes.reference new file mode 100644 index 00000000..8c474fc4 --- /dev/null +++ b/testsuite/tests/lib-unix/common/utimes.reference @@ -0,0 +1,2 @@ +tm ~ tm' (true) +tm ~ tm' (true) diff --git a/testsuite/tests/letrec/float_block_2.reference b/testsuite/tests/lib-unix/common/utimes.txt similarity index 100% rename from testsuite/tests/letrec/float_block_2.reference rename to testsuite/tests/lib-unix/common/utimes.txt diff --git a/testsuite/tests/lib-unix/common/wait_nohang.ml b/testsuite/tests/lib-unix/common/wait_nohang.ml index 7af3838d..a9d6c5d1 100644 --- a/testsuite/tests/lib-unix/common/wait_nohang.ml +++ b/testsuite/tests/lib-unix/common/wait_nohang.ml @@ -1,3 +1,7 @@ +(* TEST +include unix +*) + let () = let fd = Unix.openfile "plop" [O_CREAT; O_WRONLY] 0o666 in let pid = diff --git a/testsuite/tests/lib-unix/isatty/Makefile b/testsuite/tests/lib-unix/isatty/Makefile deleted file mode 100644 index ea6482fd..00000000 --- a/testsuite/tests/lib-unix/isatty/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -BASEDIR=../../.. -LIBRARIES=unix -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix -MAIN_MODULE=isatty -PROGRAM_ARGS=2>/dev/null skipped (using the system-provided execvpe())"; \ - else $(MAKE) compile && $(SET_LD_PATH) $(MAKE) myrun; \ - fi - -myrun: - @printf " ... testing with" - @if $(NATIVECODE_ONLY); then : ; else \ - printf " ocamlc"; \ - ./exec.run "$(MYRUNTIME) ./program.byte$(EXE)" $(EXEC_ARGS) \ - >$(MAIN_MODULE).result \ - && $(DIFF) $(MAIN_MODULE).reference $(MAIN_MODULE).result \ - >/dev/null; \ - fi \ - && if $(BYTECODE_ONLY); then : ; else \ - printf " ocamlopt"; \ - ./exec.run ./program.native$(EXE) $(EXEC_ARGS) \ - > $(MAIN_MODULE).result \ - && $(DIFF) $(MAIN_MODULE).reference $(MAIN_MODULE).result \ - >/dev/null; \ - fi \ - && echo " => passed" || echo " => failed" - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-unix/unix-execvpe/exec.ml b/testsuite/tests/lib-unix/unix-execvpe/exec.ml index 8eb62320..1c36643e 100644 --- a/testsuite/tests/lib-unix/unix-execvpe/exec.ml +++ b/testsuite/tests/lib-unix/unix-execvpe/exec.ml @@ -1,3 +1,11 @@ +(* TEST + include unix + script = "sh ${test_source_directory}/has-execvpe.sh" + * script + ** bytecode + ** native +*) + open Printf let _ = diff --git a/testsuite/tests/lib-unix/unix-execvpe/exec.run b/testsuite/tests/lib-unix/unix-execvpe/exec.run index 86f8eb86..55028c27 100755 --- a/testsuite/tests/lib-unix/unix-execvpe/exec.run +++ b/testsuite/tests/lib-unix/unix-execvpe/exec.run @@ -1,11 +1,16 @@ #!/bin/sh -program=$1 -if test -z "$program"; then echo "Usage: exec.run " 1&>2; exit 2; fi +if test -z "$program"; then echo "Define the program env var" 1&>2; exit 2; fi -exec 2>&1 +output=$program.output +exec > ${output} 2>&1 -export PATH="/bin:/usr/bin:./subdir:" +subdir=${test_source_directory}/subdir + +# Let ocamltest know where we write our output +echo output=\"${output}\" > ${ocamltest_response} + +export PATH="/bin:/usr/bin:${subdir}:" export BAR=bar echo "## Test 1: a binary program in the path" @@ -15,13 +20,14 @@ $program script1 2 3 4 || echo "script1 failed" echo "## Test 3: a script without #! in the path" $program script2 5 6 7 || echo "script2 failed" echo "## Test 4: a script in the current directory" +cd ${test_source_directory} $program script3 8 9 || echo "script3 failed" echo "## Test 5: a non-existent program" $program nosuchprogram echo "## Test 6: a non-executable program" $program nonexec -export PATH="/bin:/usr/bin:./subdir" +export PATH="/bin:/usr/bin:${subdir}" echo "## Test 7: a script in the current directory" $program script3 9 && echo "script3 should have failed" exit 0 diff --git a/testsuite/tests/lib-unix/unix-execvpe/has-execvpe.sh b/testsuite/tests/lib-unix/unix-execvpe/has-execvpe.sh new file mode 100755 index 00000000..18f3311f --- /dev/null +++ b/testsuite/tests/lib-unix/unix-execvpe/has-execvpe.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# This script is related to the 'exec.ml' test. +# It tests whether the OS implements execvpe or not. +# It makes sense to run the tests only if execvpe is nt implemented. +# If it is implemented, the test is skipped. + +if grep -q HAS_EXECVPE ${ocamlsrcdir}/byterun/caml/s.h; then + exit ${TEST_SKIP}; +fi +exit ${TEST_PASS} diff --git a/testsuite/tests/lib-unix/unix-execvpe/ocamltests b/testsuite/tests/lib-unix/unix-execvpe/ocamltests new file mode 100644 index 00000000..5280ba49 --- /dev/null +++ b/testsuite/tests/lib-unix/unix-execvpe/ocamltests @@ -0,0 +1 @@ +exec.ml diff --git a/testsuite/tests/lib-unix/win-env/Makefile b/testsuite/tests/lib-unix/win-env/Makefile deleted file mode 100755 index 9077597c..00000000 --- a/testsuite/tests/lib-unix/win-env/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -BASEDIR=../../.. -LIBRARIES=unix -ADD_COMPFLAGS= \ - -I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix \ - -strict-sequence -safe-string -w A -warn-error A -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix -C_FILES=stubs - -.PHONY: test -test: - @if echo 'let () = exit (if Sys.win32 then 0 else 1)' | $(OCAML) -stdin; then \ - $(MAKE) check; \ - else \ - $(MAKE) SKIP=true C_FILES= run-all; \ - fi - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-unix/win-env/ocamltests b/testsuite/tests/lib-unix/win-env/ocamltests new file mode 100644 index 00000000..515d330e --- /dev/null +++ b/testsuite/tests/lib-unix/win-env/ocamltests @@ -0,0 +1 @@ +test_env.ml diff --git a/testsuite/tests/lib-unix/win-env/stubs.c b/testsuite/tests/lib-unix/win-env/stubs.c index 607103a9..61a7b2d5 100644 --- a/testsuite/tests/lib-unix/win-env/stubs.c +++ b/testsuite/tests/lib-unix/win-env/stubs.c @@ -8,7 +8,7 @@ #include -CAMLprim value caml_SetEnvironmentVariable(value s1, value s2) +CAMLprim value stub_SetEnvironmentVariable(value s1, value s2) { WCHAR *w1, *w2; w1 = caml_stat_strdup_to_utf16(String_val(s1)); diff --git a/testsuite/tests/lib-unix/win-env/test_env.ml b/testsuite/tests/lib-unix/win-env/test_env.ml old mode 100755 new mode 100644 index a13da932..3a12eb91 --- a/testsuite/tests/lib-unix/win-env/test_env.ml +++ b/testsuite/tests/lib-unix/win-env/test_env.ml @@ -1,4 +1,13 @@ -external set_environment_variable: string -> string -> unit = "caml_SetEnvironmentVariable" +(* TEST +include unix +flags += "-strict-sequence -safe-string -w A -warn-error A" +modules = "stubs.c" +* libwin32unix +** bytecode +** native +*) + +external set_environment_variable: string -> string -> unit = "stub_SetEnvironmentVariable" let find_env s = let env = Unix.environment () in @@ -22,9 +31,9 @@ let print title = function | Some s -> Printf.printf "%s -> Some %S\n%!" title s -let foo = "FOO" - let () = - set_environment_variable foo "BAR"; - print "Sys.getenv FOO" (Sys.getenv_opt foo); - print "Unix.environment FOO" (find_env foo) + set_environment_variable "FOO" "BAR"; + Unix.putenv "FOO2" "BAR2"; + print "Sys.getenv FOO" (Sys.getenv_opt "FOO"); + print "Unix.environment FOO" (find_env "FOO"); + print "Sys.getenv FOO2" (Sys.getenv_opt "FOO2") diff --git a/testsuite/tests/lib-unix/win-env/test_env.reference b/testsuite/tests/lib-unix/win-env/test_env.reference index 63bdda30..a64be064 100644 --- a/testsuite/tests/lib-unix/win-env/test_env.reference +++ b/testsuite/tests/lib-unix/win-env/test_env.reference @@ -1,2 +1,3 @@ -Sys.getenv FOO -> None -Unix.environment FOO -> None +Sys.getenv FOO -> Some "BAR" +Unix.environment FOO -> Some "BAR" +Sys.getenv FOO2 -> Some "BAR2" diff --git a/testsuite/tests/lib-unix/win-env/test_env2.ml b/testsuite/tests/lib-unix/win-env/test_env2.ml deleted file mode 100755 index f2616ef9..00000000 --- a/testsuite/tests/lib-unix/win-env/test_env2.ml +++ /dev/null @@ -1,17 +0,0 @@ -(* This test is disabled (see test_env2.precheck) as it fails due to MPR#4499: - the Windows POSIX environment does not get updated when using the native - Windows API SetEnvironmentVariable. *) - -external set_environment_variable: string -> string -> unit = "caml_SetEnvironmentVariable" - -let print title = function - | None -> - Printf.printf "%s -> None\n%!" title - | Some s -> - Printf.printf "%s -> Some %S\n%!" title s - -let foo = "FOO" - -let () = - set_environment_variable foo "BAR"; - print "Sys.getenv FOO" (Sys.getenv_opt foo) diff --git a/testsuite/tests/lib-unix/win-env/test_env2.precheck b/testsuite/tests/lib-unix/win-env/test_env2.precheck deleted file mode 100755 index 8a1936f9..00000000 --- a/testsuite/tests/lib-unix/win-env/test_env2.precheck +++ /dev/null @@ -1,4 +0,0 @@ -# test_env2.ml disabled because it fails due to the fact that -# Windows POSIX environment is not updated when using the native -# API SetEnvironmentVariable (see MPR#4499) -exit 1 diff --git a/testsuite/tests/lib-unix/win-env/test_env2.reference b/testsuite/tests/lib-unix/win-env/test_env2.reference deleted file mode 100755 index 19e10cb9..00000000 --- a/testsuite/tests/lib-unix/win-env/test_env2.reference +++ /dev/null @@ -1 +0,0 @@ -Sys.getenv FOO -> Some "BAR" diff --git a/testsuite/tests/lib-unix/win-stat/Makefile b/testsuite/tests/lib-unix/win-stat/Makefile deleted file mode 100644 index 3018bdf3..00000000 --- a/testsuite/tests/lib-unix/win-stat/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -BASEDIR=../../.. -LIBRARIES=unix -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix -C_FILES=fakeclock -MAIN_MODULE=test -TEST_TEMP_FILES=dst-file non-dst-file - -ifeq ($(OS),Windows_NT) -test: - @TZ=utc touch -m -t 201707011200 dst-file - @TZ=utc touch -m -t 201702011200 non-dst-file - @$(MAKE) default -else -skip: - @echo " ... testing => skipped (not on Windows)" -endif - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-unix/win-stat/ocamltests b/testsuite/tests/lib-unix/win-stat/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/lib-unix/win-stat/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/lib-unix/win-stat/test.ml b/testsuite/tests/lib-unix/win-stat/test.ml index 1a6df643..d83d4add 100644 --- a/testsuite/tests/lib-unix/win-stat/test.ml +++ b/testsuite/tests/lib-unix/win-stat/test.ml @@ -1,3 +1,11 @@ +(* TEST +include unix +modules = "fakeclock.c" +* windows +** bytecode +** native +*) + open Unix external set_fake_clock : int64 -> unit = "set_fake_clock" diff --git a/testsuite/tests/lib-unix/win-stat/test.run b/testsuite/tests/lib-unix/win-stat/test.run new file mode 100644 index 00000000..f39310fc --- /dev/null +++ b/testsuite/tests/lib-unix/win-stat/test.run @@ -0,0 +1,4 @@ +#!/bin/sh +TZ=utc touch -m -t 201707011200 dst-file +TZ=utc touch -m -t 201702011200 non-dst-file +`cygpath -m "${program}"` > `cygpath -m "${output}"` 2>&1 diff --git a/testsuite/tests/lib-unix/win-symlink/Makefile b/testsuite/tests/lib-unix/win-symlink/Makefile deleted file mode 100755 index c0c031ac..00000000 --- a/testsuite/tests/lib-unix/win-symlink/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -BASEDIR=../../.. -LIBRARIES=unix -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix -MAIN_MODULE=test -TEST_TEMP_FILES=link1 link2 test.txt - -test: - @if $(OCAML) $(ADD_COMPFLAGS) unix.cma precheck.ml; then \ - $(MAKE) default; \ - else \ - echo " ... testing => skipped (not on Windows and/or symlinks not allowed)"; \ - fi - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/lib-unix/win-symlink/precheck.ml b/testsuite/tests/lib-unix/win-symlink/precheck.ml deleted file mode 100755 index 85c9550f..00000000 --- a/testsuite/tests/lib-unix/win-symlink/precheck.ml +++ /dev/null @@ -1,2 +0,0 @@ -let () = - exit (if Sys.win32 && Unix.has_symlink () then 0 else 1) diff --git a/testsuite/tests/lib-unix/win-symlink/test.ml b/testsuite/tests/lib-unix/win-symlink/test.ml old mode 100755 new mode 100644 index 0c8556d2..f47abbde --- a/testsuite/tests/lib-unix/win-symlink/test.ml +++ b/testsuite/tests/lib-unix/win-symlink/test.ml @@ -1,3 +1,13 @@ +(* TEST + + include unix +* windows +** has_symlink +*** bytecode +*** native + +*) + let link1 = "link1" let link2 = "link2" diff --git a/testsuite/tests/link-test/Makefile b/testsuite/tests/link-test/Makefile deleted file mode 100644 index ffef5988..00000000 --- a/testsuite/tests/link-test/Makefile +++ /dev/null @@ -1,65 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Thomas Refis, Jane Street Europe * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* Copyright 2016 Jane Street Group LLC * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -default: - @$(MAKE) byte - @if $(BYTECODE_ONLY) ; then \ - echo " ... testing native 'test.reference': => skipped"; \ - else \ - $(MAKE) native; \ - fi - -native: - @printf " ... testing native 'test.reference':" - @$(OCAMLOPT) -c submodule.ml - @$(OCAMLOPT) -c aliases.ml - @$(OCAMLOPT) -c external.mli external.ml - @$(OCAMLOPT) -c external_for_pack.mli external_for_pack.ml - @$(OCAMLOPT) -c test.ml - @$(OCAMLOPT) -a submodule.cmx aliases.cmx external.cmx \ - external_for_pack.cmx -o mylib.cmxa - @$(OCAMLOPT) -c -for-pack P use_in_pack.ml - @$(OCAMLOPT) -pack use_in_pack.cmx -o p.cmx - @$(OCAMLOPT) mylib.cmxa p.cmx test.cmx -o test.native - @./test.native > test.result - @$(DIFF) test.result test.reference >/dev/null \ - && echo " => passed" || echo " => failed" - -byte: - @printf " ... testing byte 'test.reference':" - @$(OCAMLC) -c submodule.ml - @$(OCAMLC) -c aliases.ml - @$(OCAMLC) -c external.mli external.ml - @$(OCAMLC) -c external_for_pack.mli external_for_pack.ml - @$(OCAMLC) -c test.ml - @$(OCAMLC) -a submodule.cmo aliases.cmo external.cmo \ - external_for_pack.cmo -o mylib.cma - @$(OCAMLC) -c -for-pack P use_in_pack.ml - @$(OCAMLC) -pack use_in_pack.cmo -o p.cmo - @$(OCAMLC) mylib.cma p.cmo test.cmo -o test.byte - @$(OCAMLRUN) ./test.byte > test.result - @$(DIFF) test.result test.reference >/dev/null \ - && echo " => passed" || echo " => failed" - -promote: defaultpromote - -clean: defaultclean - @rm -f *.result - @rm -f test.native test.byte - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common -COMPFLAGS = -no-alias-deps diff --git a/testsuite/tests/link-test/ocamltests b/testsuite/tests/link-test/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/link-test/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/link-test/test.ml b/testsuite/tests/link-test/test.ml index 24d870ac..bf4f6013 100644 --- a/testsuite/tests/link-test/test.ml +++ b/testsuite/tests/link-test/test.ml @@ -1,2 +1,84 @@ +(* TEST + +modules = "aliases.ml external_for_pack.ml external.ml submodule.ml test.ml use_in_pack.ml" + +* setup-ocamlc.byte-build-env +program = "${test_build_directory}/test.byte" +** ocamlc.byte +module = "submodule.ml" +flags = "-no-alias-deps" +*** ocamlc.byte +module = "aliases.ml" +**** ocamlc.byte +module = "external.mli" +***** ocamlc.byte +module = "external.ml" +****** ocamlc.byte +module = "external_for_pack.mli" +******* ocamlc.byte +module = "external_for_pack.ml" +******** ocamlc.byte +module = "test.ml" +********* ocamlc.byte +module = "" +flags = "-a -no-alias-deps" +all_modules = "submodule.cmo aliases.cmo external.cmo external_for_pack.cmo" +program = "mylib.cma" +********** ocamlc.byte +flags = "-no-alias-deps -for-pack P" +module = "use_in_pack.ml" +*********** ocamlc.byte +module = "" +program = "p.cmo" +flags = "-no-alias-deps -pack" +all_modules = "use_in_pack.cmo" +************ ocamlc.byte +program = "${test_build_directory}/test.byte" +all_modules = "mylib.cma p.cmo test.cmo" +flags= "-no-alias-deps" +************* check-ocamlc.byte-output +************** run +*************** check-program-output + +* setup-ocamlopt.byte-build-env +program = "${test_build_directory}/test.opt" +** ocamlopt.byte +module = "submodule.ml" +flags = "-no-alias-deps" +*** ocamlopt.byte +module = "aliases.ml" +**** ocamlopt.byte +module = "external.mli" +***** ocamlopt.byte +module = "external.ml" +****** ocamlopt.byte +module = "external_for_pack.mli" +******* ocamlopt.byte +module = "external_for_pack.ml" +******** ocamlopt.byte +module = "test.ml" +********* ocamlopt.byte +module = "" +flags = "-no-alias-deps -a" +all_modules = "submodule.cmx aliases.cmx external.cmx external_for_pack.cmx" +program = "mylib.cmxa" +********** ocamlopt.byte +flags = "-no-alias-deps -for-pack P" +module = "use_in_pack.ml" +*********** ocamlopt.byte +module = "" +program = "p.cmx" +flags = "-no-alias-deps -pack" +all_modules = "use_in_pack.cmx" +************ ocamlopt.byte +program = "${test_build_directory}/test.opt" +all_modules = "mylib.cmxa p.cmx test.cmx" +flags = "-no-alias-deps" +************* check-ocamlopt.byte-output +************** run +*************** check-program-output + +*) + include Aliases.Submodule.M let _, _ = External.frexp 3. diff --git a/testsuite/tests/manual-intf-c/Makefile b/testsuite/tests/manual-intf-c/Makefile deleted file mode 100644 index 4601ff99..00000000 --- a/testsuite/tests/manual-intf-c/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# Tests from manual, section intf-c -# main.ml: error message when equality is missing -# main_ok.ml: allow path expansion even when the target is missing (GPR#816) - -SOURCES = curses.ml prog.ml -CSOURCES = curses_stubs.c -CLIBS = -cclib "$(BYTECCLIBS)" -LIBUNIX = -I $(BASEDIR)/../otherlibs/unix unix.cma - -# Disable this test until we figure out how to test for the availability -# of curses. -.PHONY: disable -disable: - @printf " ... testing prog => skipped\n" - @printf " ... testing prog2 => skipped\n" - -.PHONY: default -default: clean $(SOURCES) $(CSOURCES) - @printf " ... testing prog" - @$(MAKE) prog > /dev/null && echo " => passed" || echo " => failed" - @printf " ... testing prog2" - @$(MAKE) prog2 REDIRECT=">prog2.result 2>&1" \ - >/dev/null 2>/dev/null || : - @$(DIFF) prog2.reference prog2.result >/dev/null \ - && echo " => passed" || echo " => failed" - -# Should succeed -prog: - $(OCAMLC) -custom -o prog $(LIBUNIX) $(SOURCES) $(CSOURCES) $(CLIBS) - -# Should fail -prog2: curses.cmo - $(OCAMLC) -custom -o prog2 $(LIBUNIX) prog.ml $(CSOURCES) $(CLIBS) $(REDIRECT) - -.PHONY: clean -clean: - @rm -f *.cm* *.o *~ prog prog2 - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/manual-intf-c/ocamltests b/testsuite/tests/manual-intf-c/ocamltests new file mode 100644 index 00000000..a825cb25 --- /dev/null +++ b/testsuite/tests/manual-intf-c/ocamltests @@ -0,0 +1 @@ +prog.ml diff --git a/testsuite/tests/manual-intf-c/prog.ml b/testsuite/tests/manual-intf-c/prog.ml index a913fd91..82eaeac8 100644 --- a/testsuite/tests/manual-intf-c/prog.ml +++ b/testsuite/tests/manual-intf-c/prog.ml @@ -1,3 +1,15 @@ +(* TEST +(* Tests from manual, section intf-c *) +(* + This test is currently skipped because there is no proper way to + figure out whether Curses is avaiblable or not. If it becomes possible + to figure that out, it would be nice to be able to check that the test + compiles. Executing seems lessrelevant. +*) +* skip +reason = "curses can not be properly detected at the moment" +*) + (* File prog.ml -- main program using curses *) open Curses;; let main_window = initscr () in diff --git a/testsuite/tests/match-exception-warnings/Makefile b/testsuite/tests/match-exception-warnings/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/match-exception-warnings/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ml b/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ml index 742038db..11661d05 100644 --- a/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ml +++ b/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (** Test exhaustiveness. match clauses should continue to give warnings about inexhaustive diff --git a/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ocaml.reference b/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ocaml.reference new file mode 100644 index 00000000..20f6afbb --- /dev/null +++ b/testsuite/tests/match-exception-warnings/exhaustiveness_warnings.ocaml.reference @@ -0,0 +1,10 @@ +Characters 236-315: + ....match None with + | exception e -> () + | Some false -> () + | None -> () +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some true +val test_match_exhaustiveness : unit -> unit = + diff --git a/testsuite/tests/match-exception-warnings/ocamltests b/testsuite/tests/match-exception-warnings/ocamltests new file mode 100644 index 00000000..101da881 --- /dev/null +++ b/testsuite/tests/match-exception-warnings/ocamltests @@ -0,0 +1 @@ +exhaustiveness_warnings.ml diff --git a/testsuite/tests/match-exception/Makefile b/testsuite/tests/match-exception/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/match-exception/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/match-exception/allocation.ml b/testsuite/tests/match-exception/allocation.ml index 72055c3a..a99dc83e 100644 --- a/testsuite/tests/match-exception/allocation.ml +++ b/testsuite/tests/match-exception/allocation.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test that matching multiple values doesn't allocate a block. *) let f x y = diff --git a/testsuite/tests/match-exception/exception_propagation.ml b/testsuite/tests/match-exception/exception_propagation.ml index eedde784..759ec386 100644 --- a/testsuite/tests/match-exception/exception_propagation.ml +++ b/testsuite/tests/match-exception/exception_propagation.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test that match allows exceptions to propagate. *) diff --git a/testsuite/tests/match-exception/match_failure.ml b/testsuite/tests/match-exception/match_failure.ml index 7b2cd300..a6c3d812 100644 --- a/testsuite/tests/match-exception/match_failure.ml +++ b/testsuite/tests/match-exception/match_failure.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test that value match failure in a match block raises Match_failure. *) diff --git a/testsuite/tests/match-exception/nested_handlers.ml b/testsuite/tests/match-exception/nested_handlers.ml index 7f2a6514..6f019d4b 100644 --- a/testsuite/tests/match-exception/nested_handlers.ml +++ b/testsuite/tests/match-exception/nested_handlers.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Test that multiple handlers coexist happily. *) diff --git a/testsuite/tests/match-exception/ocamltests b/testsuite/tests/match-exception/ocamltests new file mode 100644 index 00000000..1ea017da --- /dev/null +++ b/testsuite/tests/match-exception/ocamltests @@ -0,0 +1,7 @@ +allocation.ml +exception_propagation.ml +match_failure.ml +nested_handlers.ml +raise_from_success_continuation.ml +streams.ml +tail_calls.ml diff --git a/testsuite/tests/match-exception/raise_from_success_continuation.ml b/testsuite/tests/match-exception/raise_from_success_continuation.ml index 34fb6471..69a82371 100644 --- a/testsuite/tests/match-exception/raise_from_success_continuation.ml +++ b/testsuite/tests/match-exception/raise_from_success_continuation.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test raising exceptions from a value-matching branch. *) diff --git a/testsuite/tests/match-exception/streams.ml b/testsuite/tests/match-exception/streams.ml index 43a31510..b4382271 100644 --- a/testsuite/tests/match-exception/streams.ml +++ b/testsuite/tests/match-exception/streams.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** Test the stream example . *) diff --git a/testsuite/tests/match-exception/tail_calls.ml b/testsuite/tests/match-exception/tail_calls.ml index 61cf0266..ae72fc93 100644 --- a/testsuite/tests/match-exception/tail_calls.ml +++ b/testsuite/tests/match-exception/tail_calls.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** The success continuation expression is in tail position. *) diff --git a/testsuite/tests/messages/Makefile b/testsuite/tests/messages/Makefile deleted file mode 100644 index 07f67998..00000000 --- a/testsuite/tests/messages/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/messages/ocamltests b/testsuite/tests/messages/ocamltests new file mode 100644 index 00000000..83912757 --- /dev/null +++ b/testsuite/tests/messages/ocamltests @@ -0,0 +1 @@ +precise_locations.ml diff --git a/testsuite/tests/messages/precise_locations.ml b/testsuite/tests/messages/precise_locations.ml index d370f8c5..c204d461 100644 --- a/testsuite/tests/messages/precise_locations.ml +++ b/testsuite/tests/messages/precise_locations.ml @@ -1,8 +1,14 @@ +(* TEST + * expect +*) + type t = (unit, unit, unit, unit) bar ;; (* PR#7315: we expect the error location on "bar" instead of "(...) bar" *) [%%expect{| Line _, characters 34-37: + type t = (unit, unit, unit, unit) bar + ^^^ Error: Unbound type constructor bar |}];; @@ -11,6 +17,8 @@ function (x : (* we expect the location on "bar" instead of "#bar" *) [%%expect{| Line _, characters 1-4: + #bar) -> ();; + ^^^ Error: Unbound class bar |}];; @@ -20,6 +28,8 @@ function (* we expect the location on "bar" instead of "#bar" *) [%%expect{| Line _, characters 1-4: + #bar -> () + ^^^ Error: Unbound type constructor bar |}];; @@ -27,6 +37,8 @@ new bar;; (* we expect the location on "bar" instead of "new bar" *) [%%expect{| Line _, characters 4-7: + new bar;; + ^^^ Error: Unbound class bar |}];; @@ -40,6 +52,8 @@ Foo ();; [%%expect{| type t = Foo of unit | Bar Line _, characters 0-6: + Foo ();; + ^^^^^^ Error (warning 3): deprecated: Foo |}];; function @@ -47,6 +61,8 @@ Foo _ -> () | Bar -> ();; (* "Foo _", the whole construct is deprecated *) [%%expect{| Line _, characters 0-5: + Foo _ -> () | Bar -> ();; + ^^^^^ Error (warning 3): deprecated: Foo |}];; @@ -55,6 +71,8 @@ open Foo;; (* the error location should be on "Foo" *) [%%expect{| Line _, characters 5-8: + open Foo;; + ^^^ Error: Unbound module Foo |}];; @@ -66,13 +84,17 @@ end);; on "open List" as whole rather than "List" *) [%%expect{| Line _, characters 0-9: -Error (warning 33): unused open List. + open List + ^^^^^^^^^ +Error (warning 33): unused open Stdlib.List. |}];; type unknown += Foo;; (* unknown, not the whole line *) [%%expect{| Line _, characters 5-12: + type unknown += Foo;; + ^^^^^^^ Error: Unbound type constructor unknown |}];; @@ -83,5 +105,7 @@ Foo = Foobar;; [%%expect{| type t = .. Line _, characters 6-12: + Foo = Foobar;; + ^^^^^^ Error: Unbound constructor Foobar |}];; diff --git a/testsuite/tests/misc-kb/Makefile b/testsuite/tests/misc-kb/Makefile deleted file mode 100644 index 1ce51aca..00000000 --- a/testsuite/tests/misc-kb/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=terms equations orderings kb -MAIN_MODULE=kbmain -ADD_COMPFLAGS=-w a - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/misc-kb/kbmain.ml b/testsuite/tests/misc-kb/kbmain.ml index e5c53dc8..6e94ecd0 100644 --- a/testsuite/tests/misc-kb/kbmain.ml +++ b/testsuite/tests/misc-kb/kbmain.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "terms.ml equations.ml orderings.ml kb.ml" +*) + open Terms open Equations open Orderings diff --git a/testsuite/tests/misc-kb/ocamltests b/testsuite/tests/misc-kb/ocamltests new file mode 100644 index 00000000..bc74409e --- /dev/null +++ b/testsuite/tests/misc-kb/ocamltests @@ -0,0 +1 @@ +kbmain.ml diff --git a/testsuite/tests/misc-unsafe/Makefile b/testsuite/tests/misc-unsafe/Makefile deleted file mode 100644 index 2afaa5d2..00000000 --- a/testsuite/tests/misc-unsafe/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -UNSAFE=ON -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/misc-unsafe/almabench.ml b/testsuite/tests/misc-unsafe/almabench.ml index 05fe3bba..253db390 100644 --- a/testsuite/tests/misc-unsafe/almabench.ml +++ b/testsuite/tests/misc-unsafe/almabench.ml @@ -1,3 +1,7 @@ +(* TEST + flags += " -unsafe " +*) + (* * ALMABENCH 1.0.1 * OCaml version diff --git a/testsuite/tests/misc-unsafe/fft.ml b/testsuite/tests/misc-unsafe/fft.ml index 7c030a85..463e5c9d 100644 --- a/testsuite/tests/misc-unsafe/fft.ml +++ b/testsuite/tests/misc-unsafe/fft.ml @@ -1,3 +1,7 @@ +(* TEST + flags += " -unsafe " +*) + let pi = 3.14159265358979323846 let tpi = 2.0 *. pi diff --git a/testsuite/tests/misc-unsafe/ocamltests b/testsuite/tests/misc-unsafe/ocamltests new file mode 100644 index 00000000..8c3cf30a --- /dev/null +++ b/testsuite/tests/misc-unsafe/ocamltests @@ -0,0 +1,4 @@ +almabench.ml +fft.ml +quicksort.ml +soli.ml diff --git a/testsuite/tests/misc-unsafe/quicksort.ml b/testsuite/tests/misc-unsafe/quicksort.ml index 21491b70..208e2052 100644 --- a/testsuite/tests/misc-unsafe/quicksort.ml +++ b/testsuite/tests/misc-unsafe/quicksort.ml @@ -1,3 +1,7 @@ +(* TEST + flags += " -unsafe " +*) + (* Good test for loops. Best compiled with -unsafe. *) let rec qsort lo hi (a : int array) = diff --git a/testsuite/tests/misc-unsafe/soli.ml b/testsuite/tests/misc-unsafe/soli.ml index 65488ba5..127cd699 100644 --- a/testsuite/tests/misc-unsafe/soli.ml +++ b/testsuite/tests/misc-unsafe/soli.ml @@ -1,3 +1,7 @@ +(* TEST + flags += " -unsafe " +*) + type peg = Out | Empty | Peg let board = [| diff --git a/testsuite/tests/misc/Makefile b/testsuite/tests/misc/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/misc/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/misc/bdd.ml b/testsuite/tests/misc/bdd.ml index ce7d931d..30de85e0 100644 --- a/testsuite/tests/misc/bdd.ml +++ b/testsuite/tests/misc/bdd.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Translated to OCaml by Xavier Leroy *) (* Original code written in SML by ... *) diff --git a/testsuite/tests/misc/boyer.ml b/testsuite/tests/misc/boyer.ml index 38b0a4bd..53e18813 100644 --- a/testsuite/tests/misc/boyer.ml +++ b/testsuite/tests/misc/boyer.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Manipulations over terms *) type term = diff --git a/testsuite/tests/misc/ephetest.ml b/testsuite/tests/misc/ephetest.ml index a125300c..5db285ae 100644 --- a/testsuite/tests/misc/ephetest.ml +++ b/testsuite/tests/misc/ephetest.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let debug = false open Printf diff --git a/testsuite/tests/misc/ephetest2.ml b/testsuite/tests/misc/ephetest2.ml index d8a8a41b..6d9a87c9 100644 --- a/testsuite/tests/misc/ephetest2.ml +++ b/testsuite/tests/misc/ephetest2.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (*** This test evaluate boolean formula composed by conjunction and disjunction using ephemeron: diff --git a/testsuite/tests/misc/ephetest3.ml b/testsuite/tests/misc/ephetest3.ml index f0f52d2b..e9c2b0f1 100644 --- a/testsuite/tests/misc/ephetest3.ml +++ b/testsuite/tests/misc/ephetest3.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (** This test weak table by application to the memoization of collatz (also known as syracuse) algorithm suite computation *) diff --git a/testsuite/tests/misc/fib.ml b/testsuite/tests/misc/fib.ml index 15228173..46c34193 100644 --- a/testsuite/tests/misc/fib.ml +++ b/testsuite/tests/misc/fib.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec fib n = if n < 2 then 1 else fib(n-1) + fib(n-2) diff --git a/testsuite/tests/misc/finaliser.ml b/testsuite/tests/misc/finaliser.ml index 316c0da1..68cb7b26 100644 --- a/testsuite/tests/misc/finaliser.ml +++ b/testsuite/tests/misc/finaliser.ml @@ -1,4 +1,5 @@ - +(* TEST +*) let m = 1000 let m' = 100 diff --git a/testsuite/tests/misc/gcwords.ml b/testsuite/tests/misc/gcwords.ml index 61cb8495..45125adc 100644 --- a/testsuite/tests/misc/gcwords.ml +++ b/testsuite/tests/misc/gcwords.ml @@ -1,3 +1,6 @@ +(* TEST +*) + type t = Leaf of int | Branch of t * t type floatref = { mutable f : float } diff --git a/testsuite/tests/misc/gpr1370.ml b/testsuite/tests/misc/gpr1370.ml new file mode 100644 index 00000000..9cd0fedf --- /dev/null +++ b/testsuite/tests/misc/gpr1370.ml @@ -0,0 +1,22 @@ +(* TEST +*) + +type t = A|B|C|D +type s = + | G of t + | E of t + | H of t + | F of (unit list * t) + | I of t + +let r = ref 0 + +let set x = r := x + +let f x = + match x with + | E B | F ([()], B) -> set 0 + | E x | F ([()], x) when Sys.opaque_identity true -> set 1 + | E _ -> set 2 + | F _ -> set 3 + | G _ | H _ | I _ -> set 4 diff --git a/testsuite/tests/lib-threads/backtrace_threads.reference b/testsuite/tests/misc/gpr1370.reference similarity index 100% rename from testsuite/tests/lib-threads/backtrace_threads.reference rename to testsuite/tests/misc/gpr1370.reference diff --git a/testsuite/tests/misc/hamming.ml b/testsuite/tests/misc/hamming.ml index c98dea3d..f4010ac4 100644 --- a/testsuite/tests/misc/hamming.ml +++ b/testsuite/tests/misc/hamming.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* We cannot use bignums because we don't do custom runtimes, but int64 is a bit short, so we roll our own 37-digit numbers... *) diff --git a/testsuite/tests/misc/nucleic.ml b/testsuite/tests/misc/nucleic.ml index a31b4166..f83bc046 100644 --- a/testsuite/tests/misc/nucleic.ml +++ b/testsuite/tests/misc/nucleic.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Use floating-point arithmetic *) external (+) : float -> float -> float = "%addfloat" diff --git a/testsuite/tests/misc/ocamltests b/testsuite/tests/misc/ocamltests new file mode 100644 index 00000000..e76a5813 --- /dev/null +++ b/testsuite/tests/misc/ocamltests @@ -0,0 +1,19 @@ +bdd.ml +boyer.ml +ephetest.ml +ephetest2.ml +ephetest3.ml +fib.ml +finaliser.ml +gcwords.ml +gpr1370.ml +hamming.ml +nucleic.ml +pr7168.ml +sieve.ml +sorts.ml +takc.ml +taku.ml +weaklifetime.ml +weaklifetime2.ml +weaktest.ml diff --git a/testsuite/tests/misc/pr7168.ml b/testsuite/tests/misc/pr7168.ml index fb0ef7d2..0d41593c 100644 --- a/testsuite/tests/misc/pr7168.ml +++ b/testsuite/tests/misc/pr7168.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec f x = let x = x+x in let x = x+x in let x = x+x in let x = x+x in let x = x+x in let x = x+x in let x = x+x in let x = x+x in diff --git a/testsuite/tests/misc/sieve.ml b/testsuite/tests/misc/sieve.ml index 0b9ac4c9..1dd83a0e 100644 --- a/testsuite/tests/misc/sieve.ml +++ b/testsuite/tests/misc/sieve.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Eratosthene's sieve *) (* interval min max = [min; min+1; ...; max-1; max] *) diff --git a/testsuite/tests/misc/sorts.ml b/testsuite/tests/misc/sorts.ml index 43c53078..1f76de0c 100644 --- a/testsuite/tests/misc/sorts.ml +++ b/testsuite/tests/misc/sorts.ml @@ -1,3 +1,6 @@ +(* TEST +*) + (* Test bench for sorting algorithms. *) diff --git a/testsuite/tests/misc/takc.ml b/testsuite/tests/misc/takc.ml index dbb17e2a..bfdf11c4 100644 --- a/testsuite/tests/misc/takc.ml +++ b/testsuite/tests/misc/takc.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec tak x y z = if x > y then tak (tak (x-1) y z) (tak (y-1) z x) (tak (z-1) x y) else z diff --git a/testsuite/tests/misc/taku.ml b/testsuite/tests/misc/taku.ml index 6a6753b3..dac1a3f6 100644 --- a/testsuite/tests/misc/taku.ml +++ b/testsuite/tests/misc/taku.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let rec tak (x, y, z) = if x > y then tak(tak (x-1, y, z), tak (y-1, z, x), tak (z-1, x, y)) else z diff --git a/testsuite/tests/misc/weaklifetime.ml b/testsuite/tests/misc/weaklifetime.ml index a05c1623..49c701a9 100644 --- a/testsuite/tests/misc/weaklifetime.ml +++ b/testsuite/tests/misc/weaklifetime.ml @@ -1,3 +1,6 @@ +(* TEST +*) + Random.init 12345;; let size = 1000;; diff --git a/testsuite/tests/misc/weaklifetime2.ml b/testsuite/tests/misc/weaklifetime2.ml index 59f9ef4c..2c75b00b 100644 --- a/testsuite/tests/misc/weaklifetime2.ml +++ b/testsuite/tests/misc/weaklifetime2.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let n = 500 let loop = 2 diff --git a/testsuite/tests/misc/weaktest.ml b/testsuite/tests/misc/weaktest.ml index a8e4b084..292e7662 100644 --- a/testsuite/tests/misc/weaktest.ml +++ b/testsuite/tests/misc/weaktest.ml @@ -1,3 +1,6 @@ +(* TEST +*) + let debug = false;; open Printf;; diff --git a/testsuite/tests/no-alias-deps/Makefile b/testsuite/tests/no-alias-deps/Makefile deleted file mode 100644 index d80c2ea5..00000000 --- a/testsuite/tests/no-alias-deps/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -default: b.cmi c.cmi d.cmi aliases.ml - @$(OCAMLC) -c aliases.ml > aliases.ml.result 2>&1 || true - @$(OBJINFO) aliases.cmo | \ - sed -e "s/[a-f0-9]\{32\}/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/g" \ - > aliases.cmo.result 2>&1 || true - @for file in *.reference; do \ - printf " ... testing '$$file':"; \ - $(DIFF) $$file `basename $$file reference`result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -promote: defaultpromote - -clean: defaultclean - @rm -f *.result - -b.cmi: b.cmi.pre - @cp b.cmi.pre b.cmi - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common -COMPFLAGS = -no-alias-deps diff --git a/testsuite/tests/no-alias-deps/aliases.cmo.reference b/testsuite/tests/no-alias-deps/aliases.cmo.reference deleted file mode 100644 index b236b1dc..00000000 --- a/testsuite/tests/no-alias-deps/aliases.cmo.reference +++ /dev/null @@ -1,15 +0,0 @@ -File aliases.cmo -Unit name: Aliases -Interfaces imported: - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Pervasives - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa D - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa CamlinternalFormatBasics - -------------------------------- C - -------------------------------- B - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aliases - -------------------------------- A -Required globals: - D - Pervasives -Uses unsafe features: no -Force link: no diff --git a/testsuite/tests/no-alias-deps/aliases.compilers.reference b/testsuite/tests/no-alias-deps/aliases.compilers.reference new file mode 100644 index 00000000..4e611b8c --- /dev/null +++ b/testsuite/tests/no-alias-deps/aliases.compilers.reference @@ -0,0 +1,5 @@ +File "aliases.ml", line 16, characters 12-13: +Warning 49: no cmi file was found in path for module A +File "aliases.ml", line 17, characters 12-13: +Warning 49: no valid cmi file was found in path for module B. b.cmi +is not a compiled interface diff --git a/testsuite/tests/no-alias-deps/aliases.ml b/testsuite/tests/no-alias-deps/aliases.ml index c74dcae6..c0c48056 100644 --- a/testsuite/tests/no-alias-deps/aliases.ml +++ b/testsuite/tests/no-alias-deps/aliases.ml @@ -1,3 +1,18 @@ +(* TEST +flags = "-no-alias-deps" +compile_only = "true" +files = "c.mli d.mli" +* setup-ocamlc.byte-build-env +** script +script = "cp ${test_source_directory}/b.cmi.invalid ${test_build_directory}/b.cmi" +*** ocamlc.byte +all_modules = "c.mli d.mli aliases.ml" +**** check-ocamlc.byte-output +***** ocamlobjinfo +program = "aliases.cmo" +****** check-program-output +*) + module A' = A (* missing a.cmi *) module B' = B (* broken b.cmi *) module C' = C (* valid c.cmi *) diff --git a/testsuite/tests/no-alias-deps/aliases.ml.reference b/testsuite/tests/no-alias-deps/aliases.ml.reference deleted file mode 100644 index ce6a3d1b..00000000 --- a/testsuite/tests/no-alias-deps/aliases.ml.reference +++ /dev/null @@ -1,5 +0,0 @@ -File "_none_", line 1: -Warning 49: no cmi file was found in path for module A -File "_none_", line 1: -Warning 49: no valid cmi file was found in path for module B. b.cmi -is not a compiled interface diff --git a/testsuite/tests/no-alias-deps/aliases.reference b/testsuite/tests/no-alias-deps/aliases.reference new file mode 100644 index 00000000..a49cb19b --- /dev/null +++ b/testsuite/tests/no-alias-deps/aliases.reference @@ -0,0 +1,15 @@ +File aliases.cmo +Unit name: Aliases +Interfaces imported: + 00000000000000000000000000000000 Stdlib + 00000000000000000000000000000000 D + 00000000000000000000000000000000 CamlinternalFormatBasics + -------------------------------- C + -------------------------------- B + 00000000000000000000000000000000 Aliases + -------------------------------- A +Required globals: + D + Stdlib +Uses unsafe features: no +Force link: no diff --git a/testsuite/tests/no-alias-deps/b.cmi.pre b/testsuite/tests/no-alias-deps/b.cmi.invalid similarity index 100% rename from testsuite/tests/no-alias-deps/b.cmi.pre rename to testsuite/tests/no-alias-deps/b.cmi.invalid diff --git a/testsuite/tests/no-alias-deps/ocamltests b/testsuite/tests/no-alias-deps/ocamltests new file mode 100644 index 00000000..b42a42fd --- /dev/null +++ b/testsuite/tests/no-alias-deps/ocamltests @@ -0,0 +1 @@ +aliases.ml diff --git a/testsuite/tests/opaque/Makefile b/testsuite/tests/opaque/Makefile deleted file mode 100644 index 247ee8ce..00000000 --- a/testsuite/tests/opaque/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -.PHONY: default -default: - @if $(BYTECODE_ONLY); then $(MAKE) skip ; else \ - $(MAKE) compile; \ - fi - -.PHONY: skip -skip: - @echo " ... testing 'test' with ordinary compilation => skipped" - @echo " ... testing 'test' with change to opaque interface => skipped" - @echo " ... testing 'test' with change to opaque implementation \ - => skipped" - @echo " ... testing 'test' with change to non-opaque implementation \ - => skipped" - -.PHONY: compile -compile: - @$(OCAMLOPT) -I intf -opaque -c intf/opaque_intf.mli - @$(OCAMLOPT) -I intf -c intf/opaque_impl.mli - @$(OCAMLOPT) -I intf -c intf/regular.mli - @cp intf/*.mli intf/*.cmi fst - @cp intf/*.mli intf/*.cmi snd - @$(OCAMLOPT) -I fst -c fst/opaque_intf.ml - @$(OCAMLOPT) -I fst -opaque -c fst/opaque_impl.ml - @$(OCAMLOPT) -I fst -c fst/regular.ml - @$(OCAMLOPT) -I snd -c snd/opaque_intf.ml - @$(OCAMLOPT) -I snd -opaque -c snd/opaque_impl.ml - @$(OCAMLOPT) -I snd -c snd/regular.ml - @$(OCAMLOPT) -I fst -c test.ml - @ - @printf " ... testing 'test' with ordinary compilation"; \ - $(OCAMLOPT) fst/opaque_intf.cmx fst/opaque_impl.cmx \ - fst/regular.cmx test.cmx 2>/dev/null \ - && echo " => passed" || echo " => failed"; \ - printf " ... testing 'test' with change to opaque interface"; \ - $(OCAMLOPT) snd/opaque_intf.cmx fst/opaque_impl.cmx \ - fst/regular.cmx test.cmx 2>/dev/null \ - && echo " => passed" || echo " => failed"; \ - printf " ... testing 'test' with change to opaque implementation"; \ - $(OCAMLOPT) fst/opaque_intf.cmx snd/opaque_impl.cmx \ - fst/regular.cmx test.cmx 2>/dev/null \ - && echo " => passed" || echo " => failed"; \ - printf " ... testing 'test' with change to non-opaque implementation";\ - $(OCAMLOPT) fst/opaque_intf.cmx fst/opaque_impl.cmx \ - snd/regular.cmx test.cmx 2>/dev/null \ - && echo " => failed" || echo " => passed"; \ - -.PHONY: promote -promote: - -.PHONY: clean -clean: defaultclean - @rm -f *.cmi *.cmx *.$(O) a.out camlprog.exe - @rm -f intf/*.cmi - @rm -f fst/*.cmi fst/*.cmx fst/*.$(O) fst/*.mli - @rm -f snd/*.cmi snd/*.cmx snd/*.$(O) snd/*.mli - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/opaque/ocamltests b/testsuite/tests/opaque/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/opaque/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/opaque/test.ml b/testsuite/tests/opaque/test.ml index 020c1385..e597f36e 100644 --- a/testsuite/tests/opaque/test.ml +++ b/testsuite/tests/opaque/test.ml @@ -1,3 +1,62 @@ +(* TEST + +compile_only = "true" + +* setup-ocamlopt.byte-build-env +** script +script = "cp -r ${test_source_directory}/fst ${test_source_directory}/intf ${test_source_directory}/snd ${test_build_directory}" +*** ocamlopt.byte +flags = "-I intf -opaque" +all_modules = "intf/opaque_intf.mli" +**** ocamlopt.byte +flags = "-I intf" +all_modules = "intf/opaque_impl.mli intf/regular.mli" +***** script +script = "cp intf/opaque_intf.cmi intf/opaque_impl.cmi intf/regular.cmi intf/opaque_intf.mli intf/opaque_impl.mli intf/regular.mli fst" +****** script +script = "cp intf/opaque_intf.cmi intf/opaque_impl.cmi intf/regular.cmi intf/opaque_intf.mli intf/opaque_impl.mli intf/regular.mli snd" +******* ocamlopt.byte +flags = "-I fst -opaque" +all_modules = "fst/opaque_impl.ml" +******** ocamlopt.byte +flags = "-I snd -opaque" +all_modules = "snd/opaque_impl.ml" +********* ocamlopt.byte +flags = "-I fst" +all_modules = "fst/opaque_intf.ml fst/regular.ml" +********** ocamlopt.byte +flags = "-I snd" +all_modules = "snd/opaque_intf.ml snd/regular.ml" +*********** ocamlopt.byte +flags = "-I fst" +all_modules = "test.ml" + +(* ordinary compilation *) +************ ocamlopt.byte +compile_only = "false" +all_modules = "fst/opaque_intf.cmx fst/opaque_impl.cmx fst/regular.cmx test.cmx" +program = "${test_build_directory}/p1.exe" + +(* change to opaque interface *) +************ ocamlopt.byte +compile_only = "false" +all_modules = "snd/opaque_intf.cmx fst/opaque_impl.cmx fst/regular.cmx test.cmx" +program = "${test_build_directory}/p2.exe" + +(* change to opaque implementation *) +************ ocamlopt.byte +compile_only = "false" +all_modules = "fst/opaque_intf.cmx snd/opaque_impl.cmx fst/regular.cmx test.cmx" +program = "${test_build_directory}/p3.exe" + +(* change to non-opaque implementation *) +************ ocamlopt.byte +compile_only = "false" +all_modules = "fst/opaque_intf.cmx fst/opaque_impl.cmx snd/regular.cmx test.cmx" +program = "${test_build_directory}/p4.exe" +ocamlopt_byte_exit_status = "2" + +*) let () = print_endline (Opaque_intf.choose "Opaque_intf: First" "Opaque_intf: Second") diff --git a/testsuite/tests/parsetree/Makefile b/testsuite/tests/parsetree/Makefile deleted file mode 100644 index 8e917a02..00000000 --- a/testsuite/tests/parsetree/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/parsing -MODULES= -MAIN_MODULE=test -LIBRARIES=../../../compilerlibs/ocamlcommon - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/parsetree/ocamltests b/testsuite/tests/parsetree/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/parsetree/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/parsetree/source.ml b/testsuite/tests/parsetree/source.ml index 28fb4a40..37590863 100644 --- a/testsuite/tests/parsetree/source.ml +++ b/testsuite/tests/parsetree/source.ml @@ -152,6 +152,18 @@ module type S = (module type of[@foo] M) -> (sig[@foo] end) +module type S = S -> S -> S +module type S = (S -> S) -> S +module type S = functor (M : S) -> S -> S +module type S = (functor (M : S) -> S) -> S +module type S = (S -> S)[@foo] -> S +module type S = (functor[@foo] (M : S) -> S) -> S + +module type S = sig + module rec A : (S with type t = t) + and B : (S with type t = t) +end + (* Structure items *) let%foo[@foo] x = 4 and[@foo] y = x @@ -7340,3 +7352,5 @@ module Indexop = struct h.Def.%{"three"} <- 3 let x,y,z = Def.(h.%["one"], h.%("two"), h.%{"three"}) end + +type t = | diff --git a/testsuite/tests/parsetree/test.ml b/testsuite/tests/parsetree/test.ml index 9b96a378..02533bd4 100644 --- a/testsuite/tests/parsetree/test.ml +++ b/testsuite/tests/parsetree/test.ml @@ -1,3 +1,8 @@ +(* TEST + include ocamlcommon + files = "source.ml" +*) + (* (c) Alain Frisch / Lexifi *) (* cf. PR#7200 *) diff --git a/testsuite/tests/parsing/Makefile b/testsuite/tests/parsing/Makefile deleted file mode 100644 index eac3f246..00000000 --- a/testsuite/tests/parsing/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Jeremie Dimino, Jane Street Europe * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -TOPFLAGS+=-dparsetree -include $(BASEDIR)/makefiles/Makefile.dparsetree -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/parsing/attributes.compilers.reference b/testsuite/tests/parsing/attributes.compilers.reference new file mode 100644 index 00000000..bc3967be --- /dev/null +++ b/testsuite/tests/parsing/attributes.compilers.reference @@ -0,0 +1,153 @@ +[ + structure_item (attributes.ml[8,120+0]..[8,120+8]) + Pstr_attribute "foo" + [] + structure_item (attributes.ml[10,130+0]..[11,169+9]) + Pstr_value Nonrec + [ + + attribute "foo" + [] + pattern (attributes.ml[10,130+4]..[10,130+38]) ghost + Ppat_constraint + pattern (attributes.ml[10,130+4]..[10,130+13]) + attribute "foo" + [] + Ppat_var "x" (attributes.ml[10,130+5]..[10,130+6]) + core_type (attributes.ml[10,130+16]..[10,130+20]) + attribute "foo" + [] + Ptyp_constr "unit" (attributes.ml[10,130+16]..[10,130+20]) + [] + expression (attributes.ml[10,130+30]..[10,130+32]) + attribute "foo" + [] + Pexp_construct "()" (attributes.ml[10,130+30]..[10,130+32]) + None + ] + structure_item (attributes.ml[13,180+0]..[15,217+7]) + Pstr_type Rec + [ + type_declaration "t" (attributes.ml[13,180+5]..[13,180+6]) (attributes.ml[13,180+0]..[15,217+7]) + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_variant + [ + (attributes.ml[14,189+2]..[14,189+27]) + "Foo" (attributes.ml[14,189+4]..[14,189+7]) + attribute "foo" + [] + [ + core_type (attributes.ml[14,189+12]..[14,189+13]) + attribute "foo" + [] + Ptyp_constr "t" (attributes.ml[14,189+12]..[14,189+13]) + [] + ] + None + ] + ptype_private = Public + ptype_manifest = + None + ] + structure_item (attributes.ml[17,226+0]..[17,226+8]) + Pstr_attribute "foo" + [] + structure_item (attributes.ml[20,237+0]..[29,344+7]) + Pstr_module + "M" (attributes.ml[20,237+7]..[20,237+8]) + attribute "foo" + [] + module_expr (attributes.ml[20,237+11]..[28,334+3]) + attribute "foo" + [] + Pmod_structure + [ + structure_item (attributes.ml[21,255+2]..[25,310+11]) + Pstr_type Rec + [ + type_declaration "t" (attributes.ml[21,255+7]..[21,255+8]) (attributes.ml[21,255+2]..[25,310+11]) + attribute "foo" + [] + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_record + [ + (attributes.ml[22,268+4]..[22,268+25]) + attribute "foo" + [] + Immutable + "l" (attributes.ml[22,268+4]..[22,268+5]) core_type (attributes.ml[22,268+9]..[22,268+10]) + attribute "foo" + [] + Ptyp_constr "t" (attributes.ml[22,268+9]..[22,268+10]) + [] + ] + ptype_private = Public + ptype_manifest = + None + ] + structure_item (attributes.ml[27,323+2]..[27,323+10]) + Pstr_attribute "foo" + [] + ] + structure_item (attributes.ml[31,353+0]..[39,477+7]) + Pstr_modtype "S" (attributes.ml[31,353+12]..[31,353+13]) + attribute "foo" + [] + module_type (attributes.ml[31,353+16]..[38,467+3]) + attribute "foo" + [] + Pmty_signature + [ + signature_item (attributes.ml[33,374+2]..[34,442+11]) + Psig_include + module_type (attributes.ml[33,374+10]..[33,374+61]) + attribute "foo" + [] + Pmty_with + module_type (attributes.ml[33,374+11]..[33,374+35]) + attribute "foo" + [] + Pmty_typeof + module_expr (attributes.ml[33,374+27]..[33,374+28]) + attribute "foo" + [] + Pmod_ident "M" (attributes.ml[33,374+27]..[33,374+28]) + [ + Pwith_typesubst "t" (attributes.ml[33,374+53]..[33,374+54]) + type_declaration "t" (attributes.ml[33,374+53]..[33,374+54]) (attributes.ml[33,374+48]..[33,374+61]) + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (attributes.ml[33,374+58]..[33,374+61]) + Ptyp_constr "M.t" (attributes.ml[33,374+58]..[33,374+61]) + [] + ] + attribute "foo" + [] + signature_item (attributes.ml[36,455+2]..[36,455+10]) + Psig_attribute "foo" + [] + ] + structure_item (attributes.ml[41,486+0]..[41,486+8]) + Pstr_attribute "foo" + [] +] + diff --git a/testsuite/tests/parsing/attributes.ml b/testsuite/tests/parsing/attributes.ml index 8276380e..8bee64d6 100644 --- a/testsuite/tests/parsing/attributes.ml +++ b/testsuite/tests/parsing/attributes.ml @@ -1,3 +1,10 @@ +(* TEST + flags = "-dparsetree" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + [@@@foo] let (x[@foo]) : unit [@foo] = ()[@foo] diff --git a/testsuite/tests/parsing/attributes.ml.reference b/testsuite/tests/parsing/attributes.ml.reference deleted file mode 100644 index 5a39357f..00000000 --- a/testsuite/tests/parsing/attributes.ml.reference +++ /dev/null @@ -1,153 +0,0 @@ -[ - structure_item (attributes.ml[1,0+0]..[1,0+8]) - Pstr_attribute "foo" - [] - structure_item (attributes.ml[3,10+0]..[4,49+9]) - Pstr_value Nonrec - [ - - attribute "foo" - [] - pattern (attributes.ml[3,10+4]..[3,10+38]) ghost - Ppat_constraint - pattern (attributes.ml[3,10+4]..[3,10+13]) - attribute "foo" - [] - Ppat_var "x" (attributes.ml[3,10+5]..[3,10+6]) - core_type (attributes.ml[3,10+16]..[3,10+20]) - attribute "foo" - [] - Ptyp_constr "unit" (attributes.ml[3,10+16]..[3,10+20]) - [] - expression (attributes.ml[3,10+30]..[3,10+32]) - attribute "foo" - [] - Pexp_construct "()" (attributes.ml[3,10+30]..[3,10+32]) - None - ] - structure_item (attributes.ml[6,60+0]..[8,97+7]) - Pstr_type Rec - [ - type_declaration "t" (attributes.ml[6,60+5]..[6,60+6]) (attributes.ml[6,60+0]..[8,97+7]) - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_variant - [ - (attributes.ml[7,69+2]..[7,69+27]) - "Foo" (attributes.ml[7,69+4]..[7,69+7]) - attribute "foo" - [] - [ - core_type (attributes.ml[7,69+12]..[7,69+13]) - attribute "foo" - [] - Ptyp_constr "t" (attributes.ml[7,69+12]..[7,69+13]) - [] - ] - None - ] - ptype_private = Public - ptype_manifest = - None - ] - structure_item (attributes.ml[10,106+0]..[10,106+8]) - Pstr_attribute "foo" - [] - structure_item (attributes.ml[13,117+0]..[22,224+7]) - Pstr_module - "M" (attributes.ml[13,117+7]..[13,117+8]) - attribute "foo" - [] - module_expr (attributes.ml[13,117+11]..[21,214+3]) - attribute "foo" - [] - Pmod_structure - [ - structure_item (attributes.ml[14,135+2]..[18,190+11]) - Pstr_type Rec - [ - type_declaration "t" (attributes.ml[14,135+7]..[14,135+8]) (attributes.ml[14,135+2]..[18,190+11]) - attribute "foo" - [] - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_record - [ - (attributes.ml[15,148+4]..[15,148+25]) - attribute "foo" - [] - Immutable - "l" (attributes.ml[15,148+4]..[15,148+5]) core_type (attributes.ml[15,148+9]..[15,148+10]) - attribute "foo" - [] - Ptyp_constr "t" (attributes.ml[15,148+9]..[15,148+10]) - [] - ] - ptype_private = Public - ptype_manifest = - None - ] - structure_item (attributes.ml[20,203+2]..[20,203+10]) - Pstr_attribute "foo" - [] - ] - structure_item (attributes.ml[24,233+0]..[32,357+7]) - Pstr_modtype "S" (attributes.ml[24,233+12]..[24,233+13]) - attribute "foo" - [] - module_type (attributes.ml[24,233+16]..[31,347+3]) - attribute "foo" - [] - Pmty_signature - [ - signature_item (attributes.ml[26,254+2]..[27,322+11]) - Psig_include - module_type (attributes.ml[26,254+10]..[26,254+61]) - attribute "foo" - [] - Pmty_with - module_type (attributes.ml[26,254+11]..[26,254+35]) - attribute "foo" - [] - Pmty_typeof - module_expr (attributes.ml[26,254+27]..[26,254+28]) - attribute "foo" - [] - Pmod_ident "M" (attributes.ml[26,254+27]..[26,254+28]) - [ - Pwith_typesubst "t" (attributes.ml[26,254+53]..[26,254+54]) - type_declaration "t" (attributes.ml[26,254+53]..[26,254+54]) (attributes.ml[26,254+48]..[26,254+61]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (attributes.ml[26,254+58]..[26,254+61]) - Ptyp_constr "M.t" (attributes.ml[26,254+58]..[26,254+61]) - [] - ] - attribute "foo" - [] - signature_item (attributes.ml[29,335+2]..[29,335+10]) - Psig_attribute "foo" - [] - ] - structure_item (attributes.ml[34,366+0]..[34,366+8]) - Pstr_attribute "foo" - [] -] - diff --git a/testsuite/tests/parsing/docstrings.ml b/testsuite/tests/parsing/docstrings.ml index ea847113..199c876d 100644 --- a/testsuite/tests/parsing/docstrings.ml +++ b/testsuite/tests/parsing/docstrings.ml @@ -1,16 +1,617 @@ +(* TEST + * expect + flags += " -dsource " +*) + +(***********************************************************************) +(* Test based on the example in the ocamldoc manual + Obviously some parts are different due to the simplified + rules used by the compiler *) + +module Manual : sig + + (** Special comments can be placed between elements and are kept + by the OCamldoc tool, but are not associated to any element. + @-tags in these comments are ignored.*) + + (*******************************************************************) + (** Comments like the one above, with more than two asterisks, + are ignored. *) + + (** The comment for function f. *) + val f : int -> int -> int + (** The continuation of the comment for function f. *) + + (** Comment for exception My_exception, even with a simple comment + between the special comment and the exception.*) + (* Hello, I'm a simple comment :-) *) + exception My_exception of (int -> int) * int + + (** Comment for type weather *) + type weather = + | Rain of int (** The comment for constructor Rain *) + | Sun (** The comment for constructor Sun *) + + (** Comment for type weather2 *) + type weather2 = + | Rain of int (** The comment for constructor Rain *) + | Sun (** The comment for constructor Sun *) + (** I can continue the comment for type weather2 here + because there is already a comment associated to the last constructor.*) + + (** The comment for type my_record *) + type my_record = { + foo : int ; (** Comment for field foo *) + bar : string ; (** Comment for field bar *) + } + (** Continuation of comment for type my_record *) + + (** Comment for foo *) + val foo : string + (** This comment is ambiguous and associated to both foo and bar. *) + val bar : string + (** This comment is associated to bar. *) + + (** The comment for class my_class *) + class my_class : object + (** A comment to describe inheritance from cl *) + inherit cl + + (** The comment for attribute tutu *) + val mutable tutu : string + + (** The comment for attribute toto. *) + val toto : int + + (** This comment is not attached to titi since + there is a blank line before titi, but is kept + as a comment in the class. *) + + val titi : string + + (** Comment for method toto *) + method toto : string + + (** Comment for method m *) + method m : float -> int + end + + (** The comment for the class type my_class_type *) + class type my_class_type = object + (** The comment for variable x. *) + val mutable x : int + + (** The commend for method m. *) + method m : int -> int + end + + (** The comment for module Foo *) + module Foo : sig + (** The comment for x *) + val x : int + + (** A special comment that is kept but not associated to any element *) + end + + (** The comment for module type my_module_type. *) + module type my_module_type = sig + (** The comment for value x. *) + val x : int + + (** The comment for module M. *) + module M : sig + (** The comment for value y. *) + val y : int + + (* ... *) + end + + end + +end = struct + + (** The comment for function f *) + let f x y = x + y + + (** This comment is not attached to any element since there is another + special comment just before the next element. *) + + (** Comment for exception My_exception, even with a simple comment + between the special comment and the exception.*) + (* A simple comment. *) + exception My_exception of (int -> int) * int + + (** Comment for type weather *) + type weather = + | Rain of int (** The comment for constructor Rain *) + | Sun (** The comment for constructor Sun *) + + (** The comment for type my_record *) + type my_record = { + foo : int ; (** Comment for field foo *) + bar : string ; (** Comment for field bar *) + } + + (** The comment for class my_class *) + class my_class = object + (** A comment to describe inheritance from cl *) + inherit cl + + (** The comment for the instance variable tutu *) + val mutable tutu = "tutu" + + (** The comment for toto *) + val toto = 1 + val titi = "titi" + (** Ambiguous comment on both titi and toto *) + method toto = tutu ^ "!" + + (** The comment for method m *) + method m (f : float) = 1 + end + + (** The comment for class type my_class_type *) + class type my_class_type = object + (** The comment for the instance variable x. *) + val mutable x : int + + (** The comment for method m. *) + method m : int -> int + end + + (** The comment for module Foo *) + module Foo = struct + (** The comment for x *) + val x : int + (** Another comment for x *) + end + + (** The comment for module type my_module_type. *) + module type my_module_type = sig + (* Comment for value x. *) + val x : int + (* ... *) + end + +end;; +[%%expect {| + +module Manual : + sig + [@@@ocaml.text + " Special comments can be placed between elements and are kept\n by the OCamldoc tool, but are not associated to any element.\n @-tags in these comments are ignored."] + [@@@ocaml.text + " Comments like the one above, with more than two asterisks,\n are ignored. "] + val f : int -> int -> int[@@ocaml.doc " The comment for function f. "] + [@@ocaml.doc " The continuation of the comment for function f. "] + exception My_exception of (int -> int) * int + [@ocaml.doc + " Comment for exception My_exception, even with a simple comment\n between the special comment and the exception."] + type weather = + | Rain of int [@ocaml.doc " The comment for constructor Rain "] + | Sun [@ocaml.doc " The comment for constructor Sun "][@@ocaml.doc + " Comment for type weather "] + type weather2 = + | Rain of int [@ocaml.doc " The comment for constructor Rain "] + | Sun [@ocaml.doc " The comment for constructor Sun "][@@ocaml.doc + " Comment for type weather2 "] + [@@ocaml.doc + " I can continue the comment for type weather2 here\n because there is already a comment associated to the last constructor."] + type my_record = + { + foo: int [@ocaml.doc " Comment for field foo "]; + bar: string [@ocaml.doc " Comment for field bar "]}[@@ocaml.doc + " The comment for type my_record "] + [@@ocaml.doc " Continuation of comment for type my_record "] + val foo : string[@@ocaml.doc " Comment for foo "][@@ocaml.doc + " This comment is ambiguous and associated to both foo and bar. "] + val bar : string[@@ocaml.doc + " This comment is ambiguous and associated to both foo and bar. "] + [@@ocaml.doc " This comment is associated to bar. "] + class my_class : + object + inherit cl[@@ocaml.doc " A comment to describe inheritance from cl "] + val mutable tutu : string[@@ocaml.doc + " The comment for attribute tutu "] + val toto : int[@@ocaml.doc " The comment for attribute toto. "] + [@@@ocaml.text + " This comment is not attached to titi since\n there is a blank line before titi, but is kept\n as a comment in the class. "] + val titi : string + method toto : string[@@ocaml.doc " Comment for method toto "] + method m : float -> int[@@ocaml.doc " Comment for method m "] + end[@@ocaml.doc " The comment for class my_class "] + class type my_class_type = + object + val mutable x : int[@@ocaml.doc " The comment for variable x. "] + method m : int -> int[@@ocaml.doc " The commend for method m. "] + end[@@ocaml.doc " The comment for the class type my_class_type "] + module Foo : + sig + val x : int[@@ocaml.doc " The comment for x "] + [@@@ocaml.text + " A special comment that is kept but not associated to any element "] + end[@@ocaml.doc " The comment for module Foo "] + module type my_module_type = + sig + val x : int[@@ocaml.doc " The comment for value x. "] + module M : + sig val y : int[@@ocaml.doc " The comment for value y. "] end + [@@ocaml.doc " The comment for module M. "] + end[@@ocaml.doc " The comment for module type my_module_type. "] + end = + struct + let f x y = x + y[@@ocaml.doc " The comment for function f "] + [@@@ocaml.text + " This comment is not attached to any element since there is another\n special comment just before the next element. "] + exception My_exception of (int -> int) * int + [@ocaml.doc + " Comment for exception My_exception, even with a simple comment\n between the special comment and the exception."] + type weather = + | Rain of int [@ocaml.doc " The comment for constructor Rain "] + | Sun [@ocaml.doc " The comment for constructor Sun "][@@ocaml.doc + " Comment for type weather "] + type my_record = + { + foo: int [@ocaml.doc " Comment for field foo "]; + bar: string [@ocaml.doc " Comment for field bar "]}[@@ocaml.doc + " The comment for type my_record "] + class my_class = + object + inherit cl[@@ocaml.doc + " A comment to describe inheritance from cl "] + val mutable tutu = "tutu"[@@ocaml.doc + " The comment for the instance variable tutu "] + val toto = 1[@@ocaml.doc " The comment for toto "] + val titi = "titi"[@@ocaml.doc + " Ambiguous comment on both titi and toto "] + method toto = tutu ^ "!"[@@ocaml.doc + " Ambiguous comment on both titi and toto "] + method m (f : float) = 1[@@ocaml.doc " The comment for method m "] + end[@@ocaml.doc " The comment for class my_class "] + class type my_class_type = + object + val mutable x : int[@@ocaml.doc + " The comment for the instance variable x. "] + method m : int -> int[@@ocaml.doc " The comment for method m. "] + end[@@ocaml.doc " The comment for class type my_class_type "] + module Foo = + struct + external x : int[@@ocaml.doc " The comment for x "][@@ocaml.doc + " Another comment for x "] + end[@@ocaml.doc " The comment for module Foo "] + module type my_module_type = sig val x : int end[@@ocaml.doc + " The comment for module type my_module_type. "] + end ;; +Line _, characters 12-14: + inherit cl + ^^ +Error: Unbound class cl +|}] + +(***********************************************************************) +(* Empty doc comments (GPR#548) *) + +module M = struct + type t = Label (**) + (** attached to t *) + + (**) + + (** Empty docstring comments should not generate attributes *) + + type w (**) +end;; +[%%expect {| + +module M = + struct + type t = + | Label [@@ocaml.doc " attached to t "] + [@@@ocaml.text + " Empty docstring comments should not generate attributes "] + type w + end;; +module M : sig type t = Label type w end +|}] + +(***********************************************************************) +(* Comments at the beginning and end of structures (MPR#7701) *) + +module M = struct + (** foo *) + type t + + type s + (** bar *) +end;; +[%%expect {| + +module M = struct type t[@@ocaml.doc " foo "] + type s[@@ocaml.doc " bar "] end;; +module M : sig type t type s end +|}] + +module M = struct + + (** foo *) + type t + + type s + (** bar *) + +end;; +[%%expect {| + +module M = struct type t[@@ocaml.doc " foo "] + type s[@@ocaml.doc " bar "] end;; +module M : sig type t type s end +|}] + +module M = struct + (** foo *) + + type t + + type s + + (** bar *) +end;; +[%%expect {| + +module M = + struct [@@@ocaml.text " foo "] + type t + type s + [@@@ocaml.text " bar "] end;; +module M : sig type t type s end +|}] + +module M = struct + + (** foo *) + + type t + + type s + + (** bar *) + +end;; +[%%expect {| + +module M = + struct [@@@ocaml.text " foo "] + type t + type s + [@@@ocaml.text " bar "] end;; +module M : sig type t type s end +|}] + +module M = struct + + (** foo1: this comment is unattached *) + (** foo2 *) + type t + + type s + (** bar1 *) + (** bar2: this comment is unattached *) + +end;; +[%%expect {| + +module M = + struct type t[@@ocaml.doc " foo2 "] + type s[@@ocaml.doc " bar1 "] end;; +module M : sig type t type s end +|}] + +module M = struct + (** foo1 *) + + (** foo2 *) + + type t + + type s + + (** bar1 *) + + (** bar2 *) +end;; +[%%expect {| + +module M = + struct + [@@@ocaml.text " foo1 "] + [@@@ocaml.text " foo2 "] + type t + type s + [@@@ocaml.text " bar1 "] + [@@@ocaml.text " bar2 "] + end;; +module M : sig type t type s end +|}] + +module M = struct + + (** foo1 *) + + (** foo2 *) + + type t + + type s + + (** bar1 *) + + (** bar2 *) + +end;; +[%%expect {| + +module M = + struct + [@@@ocaml.text " foo1 "] + [@@@ocaml.text " foo2 "] + type t + type s + [@@@ocaml.text " bar1 "] + [@@@ocaml.text " bar2 "] + end;; +module M : sig type t type s end +|}] + +module M = struct (** foo *) type t (** bar *) end;; +[%%expect {| + +module M = struct type t[@@ocaml.doc " foo "][@@ocaml.doc " bar "] end;; +module M : sig type t end +|}] + +module M = struct (** foo *) + +type t + +(** bar *) end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] + type t + [@@@ocaml.text " bar "] end;; +module M : sig type t end +|}] + +module M = struct (** foo *) end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct (** foo *) + +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct + +(** foo *) end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct +(** foo *) +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct + +(** foo *) +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct +(** foo *) + +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct + +(** foo *) + +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] end;; +module M : sig end +|}] + +module M = struct + +(** foo *) + +(** bar *) + +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] + [@@@ocaml.text " bar "] end;; +module M : sig end +|}] + +module M = struct +(** foo *) + +(** bar *) +end;; +[%%expect {| + +module M = struct [@@@ocaml.text " foo "] + [@@@ocaml.text " bar "] end;; +module M : sig end +|}] + + +(*****************************************************************************) +(* Comments on parameters, variant constructors and object methods (GPR#477) *) + type 'a with_default = ?size:int (** default [42] *) -> ?resizable:bool (** default [true] *) - -> 'a + -> 'a;; +[%%expect {| + +type 'a with_default = + ?size:((int)[@ocaml.doc " default [42] "]) -> + ?resizable:((bool)[@ocaml.doc " default [true] "]) -> 'a;; +type 'a with_default = ?size:int -> ?resizable:bool -> 'a +|}] type obj = < meth1 : int -> int; (** method 1 *) meth2: unit -> float (** method 2 *); -> +>;; +[%%expect {| + +type obj = + < + meth1: int -> int [@ocaml.doc " method 1 "] ;meth2: unit -> float + [@ocaml.doc " method 2 "] + > ;; +type obj = < meth1 : int -> int; meth2 : unit -> float > +|}] type var = [ | `Foo (** foo *) | `Bar of int * string (** bar *) -] +];; +[%%expect {| + +type var = + [ `Foo [@ocaml.doc " foo "] | `Bar of (int * string) [@ocaml.doc " bar "]];; +type var = [ `Bar of int * string | `Foo ] +|}] diff --git a/testsuite/tests/parsing/docstrings.ml.reference b/testsuite/tests/parsing/docstrings.ml.reference deleted file mode 100644 index da40ede7..00000000 --- a/testsuite/tests/parsing/docstrings.ml.reference +++ /dev/null @@ -1,146 +0,0 @@ -[ - structure_item (docstrings.ml[1,0+0]..[4,105+7]) - Pstr_type Rec - [ - type_declaration "with_default" (docstrings.ml[1,0+8]..[1,0+20]) (docstrings.ml[1,0+0]..[4,105+7]) - ptype_params = - [ - core_type (docstrings.ml[1,0+5]..[1,0+7]) - Ptyp_var a - ] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (docstrings.ml[2,21+5]..[4,105+7]) - Ptyp_arrow - Optional "size" - core_type (docstrings.ml[2,21+11]..[2,21+14]) - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[2,21+21]..[2,21+40]) - Pstr_eval - expression (docstrings.ml[2,21+21]..[2,21+40]) - Pexp_constant PConst_string(" default [42] ",None) - ] - Ptyp_constr "int" (docstrings.ml[2,21+11]..[2,21+14]) - [] - core_type (docstrings.ml[3,62+5]..[4,105+7]) - Ptyp_arrow - Optional "resizable" - core_type (docstrings.ml[3,62+16]..[3,62+20]) - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[3,62+21]..[3,62+42]) - Pstr_eval - expression (docstrings.ml[3,62+21]..[3,62+42]) - Pexp_constant PConst_string(" default [true] ",None) - ] - Ptyp_constr "bool" (docstrings.ml[3,62+16]..[3,62+20]) - [] - core_type (docstrings.ml[4,105+5]..[4,105+7]) - Ptyp_var a - ] - structure_item (docstrings.ml[6,114+0]..[11,208+1]) - Pstr_type Rec - [ - type_declaration "obj" (docstrings.ml[6,114+5]..[6,114+8]) (docstrings.ml[6,114+0]..[11,208+1]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (docstrings.ml[6,114+11]..[11,208+1]) - Ptyp_object Closed - method meth1 - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[8,149+2]..[8,149+17]) - Pstr_eval - expression (docstrings.ml[8,149+2]..[8,149+17]) - Pexp_constant PConst_string(" method 1 ",None) - ] - core_type (docstrings.ml[7,127+10]..[7,127+20]) - Ptyp_arrow - Nolabel - core_type (docstrings.ml[7,127+10]..[7,127+13]) - Ptyp_constr "int" (docstrings.ml[7,127+10]..[7,127+13]) - [] - core_type (docstrings.ml[7,127+17]..[7,127+20]) - Ptyp_constr "int" (docstrings.ml[7,127+17]..[7,127+20]) - [] - method meth2 - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[10,168+23]..[10,168+38]) - Pstr_eval - expression (docstrings.ml[10,168+23]..[10,168+38]) - Pexp_constant PConst_string(" method 2 ",None) - ] - core_type (docstrings.ml[10,168+9]..[10,168+22]) - Ptyp_arrow - Nolabel - core_type (docstrings.ml[10,168+9]..[10,168+13]) - Ptyp_constr "unit" (docstrings.ml[10,168+9]..[10,168+13]) - [] - core_type (docstrings.ml[10,168+17]..[10,168+22]) - Ptyp_constr "float" (docstrings.ml[10,168+17]..[10,168+22]) - [] - ] - structure_item (docstrings.ml[13,211+0]..[16,280+1]) - Pstr_type Rec - [ - type_declaration "var" (docstrings.ml[13,211+5]..[13,211+8]) (docstrings.ml[13,211+0]..[16,280+1]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (docstrings.ml[13,211+11]..[16,280+1]) - Ptyp_variant closed=Closed - [ - Rtag "Foo" true - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[14,224+9]..[14,224+19]) - Pstr_eval - expression (docstrings.ml[14,224+9]..[14,224+19]) - Pexp_constant PConst_string(" foo ",None) - ] - [] - Rtag "Bar" false - attribute "ocaml.doc" - [ - structure_item (docstrings.ml[15,244+25]..[15,244+35]) - Pstr_eval - expression (docstrings.ml[15,244+25]..[15,244+35]) - Pexp_constant PConst_string(" bar ",None) - ] - [ - core_type (docstrings.ml[15,244+12]..[15,244+24]) - Ptyp_tuple - [ - core_type (docstrings.ml[15,244+12]..[15,244+15]) - Ptyp_constr "int" (docstrings.ml[15,244+12]..[15,244+15]) - [] - core_type (docstrings.ml[15,244+18]..[15,244+24]) - Ptyp_constr "string" (docstrings.ml[15,244+18]..[15,244+24]) - [] - ] - ] - ] - None - ] -] - diff --git a/testsuite/tests/parsing/extended_indexoperators.compilers.reference b/testsuite/tests/parsing/extended_indexoperators.compilers.reference new file mode 100644 index 00000000..783bbc2b --- /dev/null +++ b/testsuite/tests/parsing/extended_indexoperators.compilers.reference @@ -0,0 +1,327 @@ +[ + structure_item (extended_indexoperators.ml[8,120+0]..[8,120+29]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[8,120+4]..[8,120+10]) + Ppat_var ".?[]" (extended_indexoperators.ml[8,120+4]..[8,120+10]) + expression (extended_indexoperators.ml[8,120+13]..[8,120+29]) + Pexp_ident "Hashtbl.find_opt" (extended_indexoperators.ml[8,120+13]..[8,120+29]) + ] + structure_item (extended_indexoperators.ml[9,150+0]..[9,150+25]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[9,150+4]..[9,150+10]) + Ppat_var ".@[]" (extended_indexoperators.ml[9,150+4]..[9,150+10]) + expression (extended_indexoperators.ml[9,150+13]..[9,150+25]) + Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[9,150+13]..[9,150+25]) + ] + structure_item (extended_indexoperators.ml[10,176+0]..[10,176+28]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[10,176+4]..[10,176+14]) + Ppat_var ".@[]<-" (extended_indexoperators.ml[10,176+4]..[10,176+14]) + expression (extended_indexoperators.ml[10,176+17]..[10,176+28]) + Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[10,176+17]..[10,176+28]) + ] + structure_item (extended_indexoperators.ml[11,205+0]..[11,205+25]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[11,205+4]..[11,205+10]) + Ppat_var ".@{}" (extended_indexoperators.ml[11,205+4]..[11,205+10]) + expression (extended_indexoperators.ml[11,205+13]..[11,205+25]) + Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[11,205+13]..[11,205+25]) + ] + structure_item (extended_indexoperators.ml[12,231+0]..[12,231+28]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[12,231+4]..[12,231+14]) + Ppat_var ".@{}<-" (extended_indexoperators.ml[12,231+4]..[12,231+14]) + expression (extended_indexoperators.ml[12,231+17]..[12,231+28]) + Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[12,231+17]..[12,231+28]) + ] + structure_item (extended_indexoperators.ml[13,260+0]..[13,260+25]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[13,260+4]..[13,260+10]) + Ppat_var ".@()" (extended_indexoperators.ml[13,260+4]..[13,260+10]) + expression (extended_indexoperators.ml[13,260+13]..[13,260+25]) + Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[13,260+13]..[13,260+25]) + ] + structure_item (extended_indexoperators.ml[14,286+0]..[14,286+28]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[14,286+4]..[14,286+14]) + Ppat_var ".@()<-" (extended_indexoperators.ml[14,286+4]..[14,286+14]) + expression (extended_indexoperators.ml[14,286+17]..[14,286+28]) + Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[14,286+17]..[14,286+28]) + ] + structure_item (extended_indexoperators.ml[16,316+0]..[16,316+25]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[16,316+4]..[16,316+5]) + Ppat_var "h" (extended_indexoperators.ml[16,316+4]..[16,316+5]) + expression (extended_indexoperators.ml[16,316+8]..[16,316+25]) + Pexp_apply + expression (extended_indexoperators.ml[16,316+8]..[16,316+22]) + Pexp_ident "Hashtbl.create" (extended_indexoperators.ml[16,316+8]..[16,316+22]) + [ + + Nolabel + expression (extended_indexoperators.ml[16,316+23]..[16,316+25]) + Pexp_constant PConst_int (17,None) + ] + ] + structure_item (extended_indexoperators.ml[19,346+2]..[22,413+28]) + Pstr_eval + expression (extended_indexoperators.ml[19,346+2]..[22,413+28]) + Pexp_sequence + expression (extended_indexoperators.ml[19,346+2]..[19,346+17]) + Pexp_apply + expression (extended_indexoperators.ml[19,346+2]..[19,346+17]) + Pexp_ident ".@()<-" (extended_indexoperators.ml[19,346+2]..[19,346+17]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[19,346+2]..[19,346+3]) + Pexp_ident "h" (extended_indexoperators.ml[19,346+2]..[19,346+3]) + + Nolabel + expression (extended_indexoperators.ml[19,346+6]..[19,346+11]) + Pexp_constant PConst_string("One",None) + + Nolabel + expression (extended_indexoperators.ml[19,346+16]..[19,346+17]) + Pexp_constant PConst_int (1,None) + ] + expression (extended_indexoperators.ml[20,364+2]..[22,413+28]) + Pexp_sequence + expression (extended_indexoperators.ml[20,364+2]..[20,364+25]) + Pexp_assert + expression (extended_indexoperators.ml[20,364+9]..[20,364+25]) + Pexp_apply + expression (extended_indexoperators.ml[20,364+21]..[20,364+22]) + Pexp_ident "=" (extended_indexoperators.ml[20,364+21]..[20,364+22]) + [ + + Nolabel + expression (extended_indexoperators.ml[20,364+10]..[20,364+20]) + Pexp_apply + expression (extended_indexoperators.ml[20,364+10]..[20,364+20]) + Pexp_ident ".@{}" (extended_indexoperators.ml[20,364+10]..[20,364+20]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[20,364+10]..[20,364+11]) + Pexp_ident "h" (extended_indexoperators.ml[20,364+10]..[20,364+11]) + + Nolabel + expression (extended_indexoperators.ml[20,364+14]..[20,364+19]) + Pexp_constant PConst_string("One",None) + ] + + Nolabel + expression (extended_indexoperators.ml[20,364+23]..[20,364+24]) + Pexp_constant PConst_int (1,None) + ] + expression (extended_indexoperators.ml[21,390+2]..[22,413+28]) + Pexp_sequence + expression (extended_indexoperators.ml[21,390+2]..[21,390+22]) + Pexp_apply + expression (extended_indexoperators.ml[21,390+2]..[21,390+11]) + Pexp_ident "print_int" (extended_indexoperators.ml[21,390+2]..[21,390+11]) + [ + + Nolabel + expression (extended_indexoperators.ml[21,390+12]..[21,390+22]) + Pexp_apply + expression (extended_indexoperators.ml[21,390+12]..[21,390+22]) + Pexp_ident ".@{}" (extended_indexoperators.ml[21,390+12]..[21,390+22]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[21,390+12]..[21,390+13]) + Pexp_ident "h" (extended_indexoperators.ml[21,390+12]..[21,390+13]) + + Nolabel + expression (extended_indexoperators.ml[21,390+16]..[21,390+21]) + Pexp_constant PConst_string("One",None) + ] + ] + expression (extended_indexoperators.ml[22,413+2]..[22,413+28]) + Pexp_assert + expression (extended_indexoperators.ml[22,413+9]..[22,413+28]) + Pexp_apply + expression (extended_indexoperators.ml[22,413+21]..[22,413+22]) + Pexp_ident "=" (extended_indexoperators.ml[22,413+21]..[22,413+22]) + [ + + Nolabel + expression (extended_indexoperators.ml[22,413+10]..[22,413+20]) + Pexp_apply + expression (extended_indexoperators.ml[22,413+10]..[22,413+20]) + Pexp_ident ".?[]" (extended_indexoperators.ml[22,413+10]..[22,413+20]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[22,413+10]..[22,413+11]) + Pexp_ident "h" (extended_indexoperators.ml[22,413+10]..[22,413+11]) + + Nolabel + expression (extended_indexoperators.ml[22,413+14]..[22,413+19]) + Pexp_constant PConst_string("Two",None) + ] + + Nolabel + expression (extended_indexoperators.ml[22,413+23]..[22,413+27]) + Pexp_construct "None" (extended_indexoperators.ml[22,413+23]..[22,413+27]) + None + ] + structure_item (extended_indexoperators.ml[26,464+0]..[26,464+23]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[26,464+4]..[26,464+10]) + Ppat_var "#?" (extended_indexoperators.ml[26,464+4]..[26,464+10]) + expression (extended_indexoperators.ml[26,464+11]..[26,464+23]) ghost + Pexp_fun + Nolabel + None + pattern (extended_indexoperators.ml[26,464+11]..[26,464+12]) + Ppat_var "x" (extended_indexoperators.ml[26,464+11]..[26,464+12]) + expression (extended_indexoperators.ml[26,464+13]..[26,464+23]) ghost + Pexp_fun + Nolabel + None + pattern (extended_indexoperators.ml[26,464+13]..[26,464+14]) + Ppat_var "y" (extended_indexoperators.ml[26,464+13]..[26,464+14]) + expression (extended_indexoperators.ml[26,464+17]..[26,464+23]) + Pexp_tuple + [ + expression (extended_indexoperators.ml[26,464+18]..[26,464+19]) + Pexp_ident "x" (extended_indexoperators.ml[26,464+18]..[26,464+19]) + expression (extended_indexoperators.ml[26,464+21]..[26,464+22]) + Pexp_ident "y" (extended_indexoperators.ml[26,464+21]..[26,464+22]) + ] + ] + structure_item (extended_indexoperators.ml[27,490+0]..[27,490+24]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[27,490+4]..[27,490+12]) + Ppat_var ".%()" (extended_indexoperators.ml[27,490+4]..[27,490+12]) + expression (extended_indexoperators.ml[27,490+13]..[27,490+24]) ghost + Pexp_fun + Nolabel + None + pattern (extended_indexoperators.ml[27,490+13]..[27,490+14]) + Ppat_var "x" (extended_indexoperators.ml[27,490+13]..[27,490+14]) + expression (extended_indexoperators.ml[27,490+15]..[27,490+24]) ghost + Pexp_fun + Nolabel + None + pattern (extended_indexoperators.ml[27,490+15]..[27,490+16]) + Ppat_var "y" (extended_indexoperators.ml[27,490+15]..[27,490+16]) + expression (extended_indexoperators.ml[27,490+19]..[27,490+24]) + Pexp_apply + expression (extended_indexoperators.ml[27,490+19]..[27,490+24]) ghost + Pexp_ident "Array.get" (extended_indexoperators.ml[27,490+19]..[27,490+24]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[27,490+19]..[27,490+20]) + Pexp_ident "x" (extended_indexoperators.ml[27,490+19]..[27,490+20]) + + Nolabel + expression (extended_indexoperators.ml[27,490+22]..[27,490+23]) + Pexp_ident "y" (extended_indexoperators.ml[27,490+22]..[27,490+23]) + ] + ] + structure_item (extended_indexoperators.ml[28,517+0]..[28,517+15]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[28,517+4]..[28,517+5]) + Ppat_var "x" (extended_indexoperators.ml[28,517+4]..[28,517+5]) + expression (extended_indexoperators.ml[28,517+8]..[28,517+15]) + Pexp_array + [ + expression (extended_indexoperators.ml[28,517+11]..[28,517+12]) + Pexp_constant PConst_int (0,None) + ] + ] + structure_item (extended_indexoperators.ml[29,535+0]..[29,535+18]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[29,535+4]..[29,535+5]) + Ppat_any + expression (extended_indexoperators.ml[29,535+8]..[29,535+18]) + Pexp_apply + expression (extended_indexoperators.ml[29,535+10]..[29,535+12]) + Pexp_ident "#?" (extended_indexoperators.ml[29,535+10]..[29,535+12]) + [ + + Nolabel + expression (extended_indexoperators.ml[29,535+8]..[29,535+9]) + Pexp_constant PConst_int (1,None) + + Nolabel + expression (extended_indexoperators.ml[29,535+13]..[29,535+18]) + Pexp_apply + expression (extended_indexoperators.ml[29,535+13]..[29,535+18]) ghost + Pexp_ident "Array.get" (extended_indexoperators.ml[29,535+13]..[29,535+18]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[29,535+13]..[29,535+14]) + Pexp_ident "x" (extended_indexoperators.ml[29,535+13]..[29,535+14]) + + Nolabel + expression (extended_indexoperators.ml[29,535+16]..[29,535+17]) + Pexp_constant PConst_int (0,None) + ] + ] + ] + structure_item (extended_indexoperators.ml[30,556+0]..[30,556+19]) + Pstr_value Nonrec + [ + + pattern (extended_indexoperators.ml[30,556+4]..[30,556+5]) + Ppat_any + expression (extended_indexoperators.ml[30,556+8]..[30,556+19]) + Pexp_apply + expression (extended_indexoperators.ml[30,556+10]..[30,556+12]) + Pexp_ident "#?" (extended_indexoperators.ml[30,556+10]..[30,556+12]) + [ + + Nolabel + expression (extended_indexoperators.ml[30,556+8]..[30,556+9]) + Pexp_constant PConst_int (1,None) + + Nolabel + expression (extended_indexoperators.ml[30,556+13]..[30,556+19]) + Pexp_apply + expression (extended_indexoperators.ml[30,556+13]..[30,556+19]) + Pexp_ident ".%()" (extended_indexoperators.ml[30,556+13]..[30,556+19]) ghost + [ + + Nolabel + expression (extended_indexoperators.ml[30,556+13]..[30,556+14]) + Pexp_ident "x" (extended_indexoperators.ml[30,556+13]..[30,556+14]) + + Nolabel + expression (extended_indexoperators.ml[30,556+17]..[30,556+18]) + Pexp_constant PConst_int (0,None) + ] + ] + ] +] + diff --git a/testsuite/tests/parsing/extended_indexoperators.ml b/testsuite/tests/parsing/extended_indexoperators.ml index ddbc84ad..e4ddc7a6 100644 --- a/testsuite/tests/parsing/extended_indexoperators.ml +++ b/testsuite/tests/parsing/extended_indexoperators.ml @@ -1,3 +1,10 @@ +(* TEST + flags = "-dparsetree" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + let (.?[]) = Hashtbl.find_opt let (.@[]) = Hashtbl.find let ( .@[]<- ) = Hashtbl.add diff --git a/testsuite/tests/parsing/extended_indexoperators.ml.reference b/testsuite/tests/parsing/extended_indexoperators.ml.reference deleted file mode 100644 index fe60fc6a..00000000 --- a/testsuite/tests/parsing/extended_indexoperators.ml.reference +++ /dev/null @@ -1,327 +0,0 @@ -[ - structure_item (extended_indexoperators.ml[1,0+0]..[1,0+29]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[1,0+4]..[1,0+10]) - Ppat_var ".?[]" (extended_indexoperators.ml[1,0+4]..[1,0+10]) - expression (extended_indexoperators.ml[1,0+13]..[1,0+29]) - Pexp_ident "Hashtbl.find_opt" (extended_indexoperators.ml[1,0+13]..[1,0+29]) - ] - structure_item (extended_indexoperators.ml[2,30+0]..[2,30+25]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[2,30+4]..[2,30+10]) - Ppat_var ".@[]" (extended_indexoperators.ml[2,30+4]..[2,30+10]) - expression (extended_indexoperators.ml[2,30+13]..[2,30+25]) - Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[2,30+13]..[2,30+25]) - ] - structure_item (extended_indexoperators.ml[3,56+0]..[3,56+28]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[3,56+4]..[3,56+14]) - Ppat_var ".@[]<-" (extended_indexoperators.ml[3,56+4]..[3,56+14]) - expression (extended_indexoperators.ml[3,56+17]..[3,56+28]) - Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[3,56+17]..[3,56+28]) - ] - structure_item (extended_indexoperators.ml[4,85+0]..[4,85+25]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[4,85+4]..[4,85+10]) - Ppat_var ".@{}" (extended_indexoperators.ml[4,85+4]..[4,85+10]) - expression (extended_indexoperators.ml[4,85+13]..[4,85+25]) - Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[4,85+13]..[4,85+25]) - ] - structure_item (extended_indexoperators.ml[5,111+0]..[5,111+28]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[5,111+4]..[5,111+14]) - Ppat_var ".@{}<-" (extended_indexoperators.ml[5,111+4]..[5,111+14]) - expression (extended_indexoperators.ml[5,111+17]..[5,111+28]) - Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[5,111+17]..[5,111+28]) - ] - structure_item (extended_indexoperators.ml[6,140+0]..[6,140+25]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[6,140+4]..[6,140+10]) - Ppat_var ".@()" (extended_indexoperators.ml[6,140+4]..[6,140+10]) - expression (extended_indexoperators.ml[6,140+13]..[6,140+25]) - Pexp_ident "Hashtbl.find" (extended_indexoperators.ml[6,140+13]..[6,140+25]) - ] - structure_item (extended_indexoperators.ml[7,166+0]..[7,166+28]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[7,166+4]..[7,166+14]) - Ppat_var ".@()<-" (extended_indexoperators.ml[7,166+4]..[7,166+14]) - expression (extended_indexoperators.ml[7,166+17]..[7,166+28]) - Pexp_ident "Hashtbl.add" (extended_indexoperators.ml[7,166+17]..[7,166+28]) - ] - structure_item (extended_indexoperators.ml[9,196+0]..[9,196+25]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[9,196+4]..[9,196+5]) - Ppat_var "h" (extended_indexoperators.ml[9,196+4]..[9,196+5]) - expression (extended_indexoperators.ml[9,196+8]..[9,196+25]) - Pexp_apply - expression (extended_indexoperators.ml[9,196+8]..[9,196+22]) - Pexp_ident "Hashtbl.create" (extended_indexoperators.ml[9,196+8]..[9,196+22]) - [ - - Nolabel - expression (extended_indexoperators.ml[9,196+23]..[9,196+25]) - Pexp_constant PConst_int (17,None) - ] - ] - structure_item (extended_indexoperators.ml[12,226+2]..[15,293+28]) - Pstr_eval - expression (extended_indexoperators.ml[12,226+2]..[15,293+28]) - Pexp_sequence - expression (extended_indexoperators.ml[12,226+2]..[12,226+17]) - Pexp_apply - expression (extended_indexoperators.ml[12,226+2]..[12,226+17]) - Pexp_ident ".@()<-" (extended_indexoperators.ml[12,226+2]..[12,226+17]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[12,226+2]..[12,226+3]) - Pexp_ident "h" (extended_indexoperators.ml[12,226+2]..[12,226+3]) - - Nolabel - expression (extended_indexoperators.ml[12,226+6]..[12,226+11]) - Pexp_constant PConst_string("One",None) - - Nolabel - expression (extended_indexoperators.ml[12,226+16]..[12,226+17]) - Pexp_constant PConst_int (1,None) - ] - expression (extended_indexoperators.ml[13,244+2]..[15,293+28]) - Pexp_sequence - expression (extended_indexoperators.ml[13,244+2]..[13,244+25]) - Pexp_assert - expression (extended_indexoperators.ml[13,244+9]..[13,244+25]) - Pexp_apply - expression (extended_indexoperators.ml[13,244+21]..[13,244+22]) - Pexp_ident "=" (extended_indexoperators.ml[13,244+21]..[13,244+22]) - [ - - Nolabel - expression (extended_indexoperators.ml[13,244+10]..[13,244+20]) - Pexp_apply - expression (extended_indexoperators.ml[13,244+10]..[13,244+20]) - Pexp_ident ".@{}" (extended_indexoperators.ml[13,244+10]..[13,244+20]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[13,244+10]..[13,244+11]) - Pexp_ident "h" (extended_indexoperators.ml[13,244+10]..[13,244+11]) - - Nolabel - expression (extended_indexoperators.ml[13,244+14]..[13,244+19]) - Pexp_constant PConst_string("One",None) - ] - - Nolabel - expression (extended_indexoperators.ml[13,244+23]..[13,244+24]) - Pexp_constant PConst_int (1,None) - ] - expression (extended_indexoperators.ml[14,270+2]..[15,293+28]) - Pexp_sequence - expression (extended_indexoperators.ml[14,270+2]..[14,270+22]) - Pexp_apply - expression (extended_indexoperators.ml[14,270+2]..[14,270+11]) - Pexp_ident "print_int" (extended_indexoperators.ml[14,270+2]..[14,270+11]) - [ - - Nolabel - expression (extended_indexoperators.ml[14,270+12]..[14,270+22]) - Pexp_apply - expression (extended_indexoperators.ml[14,270+12]..[14,270+22]) - Pexp_ident ".@{}" (extended_indexoperators.ml[14,270+12]..[14,270+22]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[14,270+12]..[14,270+13]) - Pexp_ident "h" (extended_indexoperators.ml[14,270+12]..[14,270+13]) - - Nolabel - expression (extended_indexoperators.ml[14,270+16]..[14,270+21]) - Pexp_constant PConst_string("One",None) - ] - ] - expression (extended_indexoperators.ml[15,293+2]..[15,293+28]) - Pexp_assert - expression (extended_indexoperators.ml[15,293+9]..[15,293+28]) - Pexp_apply - expression (extended_indexoperators.ml[15,293+21]..[15,293+22]) - Pexp_ident "=" (extended_indexoperators.ml[15,293+21]..[15,293+22]) - [ - - Nolabel - expression (extended_indexoperators.ml[15,293+10]..[15,293+20]) - Pexp_apply - expression (extended_indexoperators.ml[15,293+10]..[15,293+20]) - Pexp_ident ".?[]" (extended_indexoperators.ml[15,293+10]..[15,293+20]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[15,293+10]..[15,293+11]) - Pexp_ident "h" (extended_indexoperators.ml[15,293+10]..[15,293+11]) - - Nolabel - expression (extended_indexoperators.ml[15,293+14]..[15,293+19]) - Pexp_constant PConst_string("Two",None) - ] - - Nolabel - expression (extended_indexoperators.ml[15,293+23]..[15,293+27]) - Pexp_construct "None" (extended_indexoperators.ml[15,293+23]..[15,293+27]) - None - ] - structure_item (extended_indexoperators.ml[19,344+0]..[19,344+23]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[19,344+4]..[19,344+10]) - Ppat_var "#?" (extended_indexoperators.ml[19,344+4]..[19,344+10]) - expression (extended_indexoperators.ml[19,344+11]..[19,344+23]) ghost - Pexp_fun - Nolabel - None - pattern (extended_indexoperators.ml[19,344+11]..[19,344+12]) - Ppat_var "x" (extended_indexoperators.ml[19,344+11]..[19,344+12]) - expression (extended_indexoperators.ml[19,344+13]..[19,344+23]) ghost - Pexp_fun - Nolabel - None - pattern (extended_indexoperators.ml[19,344+13]..[19,344+14]) - Ppat_var "y" (extended_indexoperators.ml[19,344+13]..[19,344+14]) - expression (extended_indexoperators.ml[19,344+17]..[19,344+23]) - Pexp_tuple - [ - expression (extended_indexoperators.ml[19,344+18]..[19,344+19]) - Pexp_ident "x" (extended_indexoperators.ml[19,344+18]..[19,344+19]) - expression (extended_indexoperators.ml[19,344+21]..[19,344+22]) - Pexp_ident "y" (extended_indexoperators.ml[19,344+21]..[19,344+22]) - ] - ] - structure_item (extended_indexoperators.ml[20,370+0]..[20,370+24]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[20,370+4]..[20,370+12]) - Ppat_var ".%()" (extended_indexoperators.ml[20,370+4]..[20,370+12]) - expression (extended_indexoperators.ml[20,370+13]..[20,370+24]) ghost - Pexp_fun - Nolabel - None - pattern (extended_indexoperators.ml[20,370+13]..[20,370+14]) - Ppat_var "x" (extended_indexoperators.ml[20,370+13]..[20,370+14]) - expression (extended_indexoperators.ml[20,370+15]..[20,370+24]) ghost - Pexp_fun - Nolabel - None - pattern (extended_indexoperators.ml[20,370+15]..[20,370+16]) - Ppat_var "y" (extended_indexoperators.ml[20,370+15]..[20,370+16]) - expression (extended_indexoperators.ml[20,370+19]..[20,370+24]) - Pexp_apply - expression (extended_indexoperators.ml[20,370+19]..[20,370+24]) ghost - Pexp_ident "Array.get" (extended_indexoperators.ml[20,370+19]..[20,370+24]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[20,370+19]..[20,370+20]) - Pexp_ident "x" (extended_indexoperators.ml[20,370+19]..[20,370+20]) - - Nolabel - expression (extended_indexoperators.ml[20,370+22]..[20,370+23]) - Pexp_ident "y" (extended_indexoperators.ml[20,370+22]..[20,370+23]) - ] - ] - structure_item (extended_indexoperators.ml[21,397+0]..[21,397+15]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[21,397+4]..[21,397+5]) - Ppat_var "x" (extended_indexoperators.ml[21,397+4]..[21,397+5]) - expression (extended_indexoperators.ml[21,397+8]..[21,397+15]) - Pexp_array - [ - expression (extended_indexoperators.ml[21,397+11]..[21,397+12]) - Pexp_constant PConst_int (0,None) - ] - ] - structure_item (extended_indexoperators.ml[22,415+0]..[22,415+18]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[22,415+4]..[22,415+5]) - Ppat_any - expression (extended_indexoperators.ml[22,415+8]..[22,415+18]) - Pexp_apply - expression (extended_indexoperators.ml[22,415+10]..[22,415+12]) - Pexp_ident "#?" (extended_indexoperators.ml[22,415+10]..[22,415+12]) - [ - - Nolabel - expression (extended_indexoperators.ml[22,415+8]..[22,415+9]) - Pexp_constant PConst_int (1,None) - - Nolabel - expression (extended_indexoperators.ml[22,415+13]..[22,415+18]) - Pexp_apply - expression (extended_indexoperators.ml[22,415+13]..[22,415+18]) ghost - Pexp_ident "Array.get" (extended_indexoperators.ml[22,415+13]..[22,415+18]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[22,415+13]..[22,415+14]) - Pexp_ident "x" (extended_indexoperators.ml[22,415+13]..[22,415+14]) - - Nolabel - expression (extended_indexoperators.ml[22,415+16]..[22,415+17]) - Pexp_constant PConst_int (0,None) - ] - ] - ] - structure_item (extended_indexoperators.ml[23,436+0]..[23,436+19]) - Pstr_value Nonrec - [ - - pattern (extended_indexoperators.ml[23,436+4]..[23,436+5]) - Ppat_any - expression (extended_indexoperators.ml[23,436+8]..[23,436+19]) - Pexp_apply - expression (extended_indexoperators.ml[23,436+10]..[23,436+12]) - Pexp_ident "#?" (extended_indexoperators.ml[23,436+10]..[23,436+12]) - [ - - Nolabel - expression (extended_indexoperators.ml[23,436+8]..[23,436+9]) - Pexp_constant PConst_int (1,None) - - Nolabel - expression (extended_indexoperators.ml[23,436+13]..[23,436+19]) - Pexp_apply - expression (extended_indexoperators.ml[23,436+13]..[23,436+19]) - Pexp_ident ".%()" (extended_indexoperators.ml[23,436+13]..[23,436+19]) ghost - [ - - Nolabel - expression (extended_indexoperators.ml[23,436+13]..[23,436+14]) - Pexp_ident "x" (extended_indexoperators.ml[23,436+13]..[23,436+14]) - - Nolabel - expression (extended_indexoperators.ml[23,436+17]..[23,436+18]) - Pexp_constant PConst_int (0,None) - ] - ] - ] -] - diff --git a/testsuite/tests/parsing/extensions.compilers.reference b/testsuite/tests/parsing/extensions.compilers.reference new file mode 100644 index 00000000..dfad2ad7 --- /dev/null +++ b/testsuite/tests/parsing/extensions.compilers.reference @@ -0,0 +1,326 @@ +[ + structure_item (extensions.ml[9,153+0]..[9,153+22]) + Pstr_extension "foo" + [ + structure_item (extensions.ml[9,153+7]..[9,153+21]) + Pstr_eval + expression (extensions.ml[9,153+7]..[9,153+21]) + Pexp_let Nonrec + [ + + pattern (extensions.ml[9,153+11]..[9,153+12]) + Ppat_var "x" (extensions.ml[9,153+11]..[9,153+12]) + expression (extensions.ml[9,153+15]..[9,153+16]) + Pexp_constant PConst_int (1,None) + ] + expression (extensions.ml[9,153+20]..[9,153+21]) + Pexp_ident "x" (extensions.ml[9,153+20]..[9,153+21]) + ] + structure_item (extensions.ml[10,176+0]..[10,176+46]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[10,176+4]..[10,176+46]) ghost + Ppat_constraint + pattern (extensions.ml[10,176+4]..[10,176+14]) + Ppat_extension "foo" + [ + structure_item (extensions.ml[10,176+10]..[10,176+13]) + Pstr_eval + expression (extensions.ml[10,176+10]..[10,176+13]) + Pexp_apply + expression (extensions.ml[10,176+11]..[10,176+12]) + Pexp_ident "+" (extensions.ml[10,176+11]..[10,176+12]) + [ + + Nolabel + expression (extensions.ml[10,176+10]..[10,176+11]) + Pexp_constant PConst_int (2,None) + + Nolabel + expression (extensions.ml[10,176+12]..[10,176+13]) + Pexp_constant PConst_int (1,None) + ] + ] + core_type (extensions.ml[10,176+17]..[10,176+31]) + Ptyp_extension "foo" + [ + structure_item (extensions.ml[10,176+23]..[10,176+30]) + Pstr_eval + expression (extensions.ml[10,176+23]..[10,176+30]) + Pexp_field + expression (extensions.ml[10,176+23]..[10,176+26]) + Pexp_ident "bar" (extensions.ml[10,176+23]..[10,176+26]) + "baz" (extensions.ml[10,176+27]..[10,176+30]) + ] + expression (extensions.ml[10,176+34]..[10,176+46]) + Pexp_extension "foo" + [ + structure_item (extensions.ml[10,176+40]..[10,176+45]) + Pstr_eval + expression (extensions.ml[10,176+40]..[10,176+45]) + Pexp_constant PConst_string("foo",None) + ] + ] + structure_item (extensions.ml[12,224+0]..[12,224+26]) + Pstr_extension "foo" + [ + structure_item (extensions.ml[12,224+7]..[12,224+24]) + Pstr_module + "M" (extensions.ml[12,224+14]..[12,224+15]) + module_expr (extensions.ml[12,224+18]..[12,224+24]) + Pmod_extension "bar" + [] + ] + structure_item (extensions.ml[13,251+0]..[13,251+74]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[13,251+4]..[13,251+74]) ghost + Ppat_constraint + pattern (extensions.ml[13,251+4]..[13,251+23]) + Ppat_extension "foo" + [ + structure_item (extensions.ml[13,251+10]..[13,251+21]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[13,251+14]..[13,251+16]) + Ppat_construct "()" (extensions.ml[13,251+14]..[13,251+16]) + None + expression (extensions.ml[13,251+19]..[13,251+21]) + Pexp_construct "()" (extensions.ml[13,251+19]..[13,251+21]) + None + ] + ] + core_type (extensions.ml[13,251+26]..[13,251+44]) + Ptyp_extension "foo" + [ + structure_item (extensions.ml[13,251+32]..[13,251+42]) + Pstr_type Rec + [ + type_declaration "t" (extensions.ml[13,251+37]..[13,251+38]) (extensions.ml[13,251+32]..[13,251+42]) + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (extensions.ml[13,251+41]..[13,251+42]) + Ptyp_constr "t" (extensions.ml[13,251+41]..[13,251+42]) + [] + ] + ] + expression (extensions.ml[13,251+47]..[13,251+74]) + Pexp_extension "foo" + [ + structure_item (extensions.ml[13,251+53]..[13,251+73]) + Pstr_class + [ + class_declaration (extensions.ml[13,251+53]..[13,251+73]) + pci_virt = Concrete + pci_params = + [] + pci_name = "c" (extensions.ml[13,251+59]..[13,251+60]) + pci_expr = + class_expr (extensions.ml[13,251+63]..[13,251+73]) + Pcl_structure + class_structure + pattern (extensions.ml[13,251+69]..[13,251+69]) ghost + Ppat_any + [] + ] + ] + ] + structure_item (extensions.ml[15,327+0]..[15,327+16]) + Pstr_extension "foo" + core_type (extensions.ml[15,327+8]..[15,327+15]) + Ptyp_constr "list" (extensions.ml[15,327+11]..[15,327+15]) + [ + core_type (extensions.ml[15,327+8]..[15,327+10]) + Ptyp_var a + ] + structure_item (extensions.ml[16,344+0]..[16,344+60]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[16,344+4]..[16,344+60]) ghost + Ppat_constraint + pattern (extensions.ml[16,344+4]..[16,344+19]) + Ppat_extension "foo" + core_type (extensions.ml[16,344+11]..[16,344+17]) + Ptyp_variant closed=Closed + [ + Rtag "Foo" true + [] + ] + None + core_type (extensions.ml[16,344+22]..[16,344+37]) + Ptyp_extension "foo" + core_type (extensions.ml[16,344+29]..[16,344+35]) + Ptyp_arrow + Nolabel + core_type (extensions.ml[16,344+29]..[16,344+30]) + Ptyp_constr "t" (extensions.ml[16,344+29]..[16,344+30]) + [] + core_type (extensions.ml[16,344+34]..[16,344+35]) + Ptyp_constr "t" (extensions.ml[16,344+34]..[16,344+35]) + [] + expression (extensions.ml[16,344+40]..[16,344+60]) + Pexp_extension "foo" + core_type (extensions.ml[16,344+47]..[16,344+58]) + Ptyp_object Closed + method foo + core_type (extensions.ml[16,344+55]..[16,344+56]) + Ptyp_constr "t" (extensions.ml[16,344+55]..[16,344+56]) + [] + ] + structure_item (extensions.ml[18,406+0]..[18,406+11]) + Pstr_extension "foo" + pattern (extensions.ml[18,406+8]..[18,406+9]) + Ppat_any + structure_item (extensions.ml[19,418+0]..[19,418+26]) + Pstr_extension "foo" + pattern (extensions.ml[19,418+8]..[19,418+14]) + Ppat_construct "Some" (extensions.ml[19,418+8]..[19,418+12]) + Some + pattern (extensions.ml[19,418+13]..[19,418+14]) + Ppat_var "y" (extensions.ml[19,418+13]..[19,418+14]) + + expression (extensions.ml[19,418+20]..[19,418+25]) + Pexp_apply + expression (extensions.ml[19,418+22]..[19,418+23]) + Pexp_ident ">" (extensions.ml[19,418+22]..[19,418+23]) + [ + + Nolabel + expression (extensions.ml[19,418+20]..[19,418+21]) + Pexp_ident "y" (extensions.ml[19,418+20]..[19,418+21]) + + Nolabel + expression (extensions.ml[19,418+24]..[19,418+25]) + Pexp_constant PConst_int (0,None) + ] + structure_item (extensions.ml[20,445+0]..[20,445+60]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[20,445+4]..[20,445+60]) ghost + Ppat_constraint + pattern (extensions.ml[20,445+4]..[20,445+28]) + Ppat_extension "foo" + pattern (extensions.ml[20,445+11]..[20,445+26]) + Ppat_or + pattern (extensions.ml[20,445+12]..[20,445+17]) + Ppat_construct "Bar" (extensions.ml[20,445+12]..[20,445+15]) + Some + pattern (extensions.ml[20,445+16]..[20,445+17]) + Ppat_var "x" (extensions.ml[20,445+16]..[20,445+17]) + pattern (extensions.ml[20,445+20]..[20,445+25]) + Ppat_construct "Baz" (extensions.ml[20,445+20]..[20,445+23]) + Some + pattern (extensions.ml[20,445+24]..[20,445+25]) + Ppat_var "x" (extensions.ml[20,445+24]..[20,445+25]) + core_type (extensions.ml[20,445+31]..[20,445+44]) + Ptyp_extension "foo" + pattern (extensions.ml[20,445+38]..[20,445+42]) + Ppat_type + "bar" (extensions.ml[20,445+39]..[20,445+42]) + expression (extensions.ml[20,445+47]..[20,445+60]) + Pexp_extension "foo" + pattern (extensions.ml[20,445+54]..[20,445+59]) + Ppat_record Closed + [ + "x" (extensions.ml[20,445+56]..[20,445+57]) + pattern (extensions.ml[20,445+56]..[20,445+57]) + Ppat_var "x" (extensions.ml[20,445+56]..[20,445+57]) + ] + ] + structure_item (extensions.ml[22,507+0]..[22,507+26]) + Pstr_extension "foo" + [ + signature_item (extensions.ml[22,507+8]..[22,507+25]) + Psig_module "M" (extensions.ml[22,507+15]..[22,507+16]) + module_type (extensions.ml[22,507+19]..[22,507+25]) + Pmod_extension "baz" + [] + ] + structure_item (extensions.ml[23,534+0]..[25,606+23]) + Pstr_value Nonrec + [ + + pattern (extensions.ml[23,534+4]..[25,606+23]) ghost + Ppat_constraint + pattern (extensions.ml[23,534+4]..[23,534+38]) + Ppat_extension "foo" + [ + signature_item (extensions.ml[23,534+11]..[23,534+36]) + Psig_include + module_type (extensions.ml[23,534+19]..[23,534+36]) + Pmty_with + module_type (extensions.ml[23,534+19]..[23,534+20]) + Pmty_ident "S" (extensions.ml[23,534+19]..[23,534+20]) + [ + Pwith_type "t" (extensions.ml[23,534+31]..[23,534+32]) + type_declaration "t" (extensions.ml[23,534+31]..[23,534+32]) (extensions.ml[23,534+26]..[23,534+36]) + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (extensions.ml[23,534+35]..[23,534+36]) + Ptyp_constr "t" (extensions.ml[23,534+35]..[23,534+36]) + [] + ] + ] + core_type (extensions.ml[24,573+4]..[24,573+32]) + Ptyp_extension "foo" + [ + signature_item (extensions.ml[24,573+11]..[24,573+20]) + Psig_value + value_description "x" (extensions.ml[24,573+15]..[24,573+16]) (extensions.ml[24,573+11]..[24,573+20]) + core_type (extensions.ml[24,573+19]..[24,573+20]) + Ptyp_constr "t" (extensions.ml[24,573+19]..[24,573+20]) + [] + [] + signature_item (extensions.ml[24,573+22]..[24,573+31]) + Psig_value + value_description "y" (extensions.ml[24,573+26]..[24,573+27]) (extensions.ml[24,573+22]..[24,573+31]) + core_type (extensions.ml[24,573+30]..[24,573+31]) + Ptyp_constr "t" (extensions.ml[24,573+30]..[24,573+31]) + [] + [] + ] + expression (extensions.ml[25,606+4]..[25,606+23]) + Pexp_extension "foo" + [ + signature_item (extensions.ml[25,606+11]..[25,606+21]) + Psig_type Rec + [ + type_declaration "t" (extensions.ml[25,606+16]..[25,606+17]) (extensions.ml[25,606+11]..[25,606+21]) + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (extensions.ml[25,606+20]..[25,606+21]) + Ptyp_constr "t" (extensions.ml[25,606+20]..[25,606+21]) + [] + ] + ] + ] +] + +File "extensions.ml", line 9, characters 3-6: +Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/parsing/extensions.ml b/testsuite/tests/parsing/extensions.ml index e0feab8b..326d2a47 100644 --- a/testsuite/tests/parsing/extensions.ml +++ b/testsuite/tests/parsing/extensions.ml @@ -1,3 +1,10 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) [%%foo let x = 1 in x] let [%foo 2+1] : [%foo bar.baz] = [%foo "foo"] diff --git a/testsuite/tests/parsing/extensions.ml.reference b/testsuite/tests/parsing/extensions.ml.reference deleted file mode 100644 index e904d7e9..00000000 --- a/testsuite/tests/parsing/extensions.ml.reference +++ /dev/null @@ -1,326 +0,0 @@ -[ - structure_item (extensions.ml[2,1+0]..[2,1+22]) - Pstr_extension "foo" - [ - structure_item (extensions.ml[2,1+7]..[2,1+21]) - Pstr_eval - expression (extensions.ml[2,1+7]..[2,1+21]) - Pexp_let Nonrec - [ - - pattern (extensions.ml[2,1+11]..[2,1+12]) - Ppat_var "x" (extensions.ml[2,1+11]..[2,1+12]) - expression (extensions.ml[2,1+15]..[2,1+16]) - Pexp_constant PConst_int (1,None) - ] - expression (extensions.ml[2,1+20]..[2,1+21]) - Pexp_ident "x" (extensions.ml[2,1+20]..[2,1+21]) - ] - structure_item (extensions.ml[3,24+0]..[3,24+46]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[3,24+4]..[3,24+46]) ghost - Ppat_constraint - pattern (extensions.ml[3,24+4]..[3,24+14]) - Ppat_extension "foo" - [ - structure_item (extensions.ml[3,24+10]..[3,24+13]) - Pstr_eval - expression (extensions.ml[3,24+10]..[3,24+13]) - Pexp_apply - expression (extensions.ml[3,24+11]..[3,24+12]) - Pexp_ident "+" (extensions.ml[3,24+11]..[3,24+12]) - [ - - Nolabel - expression (extensions.ml[3,24+10]..[3,24+11]) - Pexp_constant PConst_int (2,None) - - Nolabel - expression (extensions.ml[3,24+12]..[3,24+13]) - Pexp_constant PConst_int (1,None) - ] - ] - core_type (extensions.ml[3,24+17]..[3,24+31]) - Ptyp_extension "foo" - [ - structure_item (extensions.ml[3,24+23]..[3,24+30]) - Pstr_eval - expression (extensions.ml[3,24+23]..[3,24+30]) - Pexp_field - expression (extensions.ml[3,24+23]..[3,24+26]) - Pexp_ident "bar" (extensions.ml[3,24+23]..[3,24+26]) - "baz" (extensions.ml[3,24+27]..[3,24+30]) - ] - expression (extensions.ml[3,24+34]..[3,24+46]) - Pexp_extension "foo" - [ - structure_item (extensions.ml[3,24+40]..[3,24+45]) - Pstr_eval - expression (extensions.ml[3,24+40]..[3,24+45]) - Pexp_constant PConst_string("foo",None) - ] - ] - structure_item (extensions.ml[5,72+0]..[5,72+26]) - Pstr_extension "foo" - [ - structure_item (extensions.ml[5,72+7]..[5,72+24]) - Pstr_module - "M" (extensions.ml[5,72+14]..[5,72+15]) - module_expr (extensions.ml[5,72+18]..[5,72+24]) - Pmod_extension "bar" - [] - ] - structure_item (extensions.ml[6,99+0]..[6,99+74]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[6,99+4]..[6,99+74]) ghost - Ppat_constraint - pattern (extensions.ml[6,99+4]..[6,99+23]) - Ppat_extension "foo" - [ - structure_item (extensions.ml[6,99+10]..[6,99+21]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[6,99+14]..[6,99+16]) - Ppat_construct "()" (extensions.ml[6,99+14]..[6,99+16]) - None - expression (extensions.ml[6,99+19]..[6,99+21]) - Pexp_construct "()" (extensions.ml[6,99+19]..[6,99+21]) - None - ] - ] - core_type (extensions.ml[6,99+26]..[6,99+44]) - Ptyp_extension "foo" - [ - structure_item (extensions.ml[6,99+32]..[6,99+42]) - Pstr_type Rec - [ - type_declaration "t" (extensions.ml[6,99+37]..[6,99+38]) (extensions.ml[6,99+32]..[6,99+42]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (extensions.ml[6,99+41]..[6,99+42]) - Ptyp_constr "t" (extensions.ml[6,99+41]..[6,99+42]) - [] - ] - ] - expression (extensions.ml[6,99+47]..[6,99+74]) - Pexp_extension "foo" - [ - structure_item (extensions.ml[6,99+53]..[6,99+73]) - Pstr_class - [ - class_declaration (extensions.ml[6,99+53]..[6,99+73]) - pci_virt = Concrete - pci_params = - [] - pci_name = "c" (extensions.ml[6,99+59]..[6,99+60]) - pci_expr = - class_expr (extensions.ml[6,99+63]..[6,99+73]) - Pcl_structure - class_structure - pattern (extensions.ml[6,99+69]..[6,99+69]) ghost - Ppat_any - [] - ] - ] - ] - structure_item (extensions.ml[8,175+0]..[8,175+16]) - Pstr_extension "foo" - core_type (extensions.ml[8,175+8]..[8,175+15]) - Ptyp_constr "list" (extensions.ml[8,175+11]..[8,175+15]) - [ - core_type (extensions.ml[8,175+8]..[8,175+10]) - Ptyp_var a - ] - structure_item (extensions.ml[9,192+0]..[9,192+60]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[9,192+4]..[9,192+60]) ghost - Ppat_constraint - pattern (extensions.ml[9,192+4]..[9,192+19]) - Ppat_extension "foo" - core_type (extensions.ml[9,192+11]..[9,192+17]) - Ptyp_variant closed=Closed - [ - Rtag "Foo" true - [] - ] - None - core_type (extensions.ml[9,192+22]..[9,192+37]) - Ptyp_extension "foo" - core_type (extensions.ml[9,192+29]..[9,192+35]) - Ptyp_arrow - Nolabel - core_type (extensions.ml[9,192+29]..[9,192+30]) - Ptyp_constr "t" (extensions.ml[9,192+29]..[9,192+30]) - [] - core_type (extensions.ml[9,192+34]..[9,192+35]) - Ptyp_constr "t" (extensions.ml[9,192+34]..[9,192+35]) - [] - expression (extensions.ml[9,192+40]..[9,192+60]) - Pexp_extension "foo" - core_type (extensions.ml[9,192+47]..[9,192+58]) - Ptyp_object Closed - method foo - core_type (extensions.ml[9,192+55]..[9,192+56]) - Ptyp_constr "t" (extensions.ml[9,192+55]..[9,192+56]) - [] - ] - structure_item (extensions.ml[11,254+0]..[11,254+11]) - Pstr_extension "foo" - pattern (extensions.ml[11,254+8]..[11,254+9]) - Ppat_any - structure_item (extensions.ml[12,266+0]..[12,266+26]) - Pstr_extension "foo" - pattern (extensions.ml[12,266+8]..[12,266+14]) - Ppat_construct "Some" (extensions.ml[12,266+8]..[12,266+12]) - Some - pattern (extensions.ml[12,266+13]..[12,266+14]) - Ppat_var "y" (extensions.ml[12,266+13]..[12,266+14]) - - expression (extensions.ml[12,266+20]..[12,266+25]) - Pexp_apply - expression (extensions.ml[12,266+22]..[12,266+23]) - Pexp_ident ">" (extensions.ml[12,266+22]..[12,266+23]) - [ - - Nolabel - expression (extensions.ml[12,266+20]..[12,266+21]) - Pexp_ident "y" (extensions.ml[12,266+20]..[12,266+21]) - - Nolabel - expression (extensions.ml[12,266+24]..[12,266+25]) - Pexp_constant PConst_int (0,None) - ] - structure_item (extensions.ml[13,293+0]..[13,293+60]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[13,293+4]..[13,293+60]) ghost - Ppat_constraint - pattern (extensions.ml[13,293+4]..[13,293+28]) - Ppat_extension "foo" - pattern (extensions.ml[13,293+11]..[13,293+26]) - Ppat_or - pattern (extensions.ml[13,293+12]..[13,293+17]) - Ppat_construct "Bar" (extensions.ml[13,293+12]..[13,293+15]) - Some - pattern (extensions.ml[13,293+16]..[13,293+17]) - Ppat_var "x" (extensions.ml[13,293+16]..[13,293+17]) - pattern (extensions.ml[13,293+20]..[13,293+25]) - Ppat_construct "Baz" (extensions.ml[13,293+20]..[13,293+23]) - Some - pattern (extensions.ml[13,293+24]..[13,293+25]) - Ppat_var "x" (extensions.ml[13,293+24]..[13,293+25]) - core_type (extensions.ml[13,293+31]..[13,293+44]) - Ptyp_extension "foo" - pattern (extensions.ml[13,293+38]..[13,293+42]) - Ppat_type - "bar" (extensions.ml[13,293+39]..[13,293+42]) - expression (extensions.ml[13,293+47]..[13,293+60]) - Pexp_extension "foo" - pattern (extensions.ml[13,293+54]..[13,293+59]) - Ppat_record Closed - [ - "x" (extensions.ml[13,293+56]..[13,293+57]) - pattern (extensions.ml[13,293+56]..[13,293+57]) - Ppat_var "x" (extensions.ml[13,293+56]..[13,293+57]) - ] - ] - structure_item (extensions.ml[15,355+0]..[15,355+26]) - Pstr_extension "foo" - [ - signature_item (extensions.ml[15,355+8]..[15,355+25]) - Psig_module "M" (extensions.ml[15,355+15]..[15,355+16]) - module_type (extensions.ml[15,355+19]..[15,355+25]) - Pmod_extension "baz" - [] - ] - structure_item (extensions.ml[16,382+0]..[18,454+23]) - Pstr_value Nonrec - [ - - pattern (extensions.ml[16,382+4]..[18,454+23]) ghost - Ppat_constraint - pattern (extensions.ml[16,382+4]..[16,382+38]) - Ppat_extension "foo" - [ - signature_item (extensions.ml[16,382+11]..[16,382+36]) - Psig_include - module_type (extensions.ml[16,382+19]..[16,382+36]) - Pmty_with - module_type (extensions.ml[16,382+19]..[16,382+20]) - Pmty_ident "S" (extensions.ml[16,382+19]..[16,382+20]) - [ - Pwith_type "t" (extensions.ml[16,382+31]..[16,382+32]) - type_declaration "t" (extensions.ml[16,382+31]..[16,382+32]) (extensions.ml[16,382+26]..[16,382+36]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (extensions.ml[16,382+35]..[16,382+36]) - Ptyp_constr "t" (extensions.ml[16,382+35]..[16,382+36]) - [] - ] - ] - core_type (extensions.ml[17,421+4]..[17,421+32]) - Ptyp_extension "foo" - [ - signature_item (extensions.ml[17,421+11]..[17,421+20]) - Psig_value - value_description "x" (extensions.ml[17,421+15]..[17,421+16]) (extensions.ml[17,421+11]..[17,421+20]) - core_type (extensions.ml[17,421+19]..[17,421+20]) - Ptyp_constr "t" (extensions.ml[17,421+19]..[17,421+20]) - [] - [] - signature_item (extensions.ml[17,421+22]..[17,421+31]) - Psig_value - value_description "y" (extensions.ml[17,421+26]..[17,421+27]) (extensions.ml[17,421+22]..[17,421+31]) - core_type (extensions.ml[17,421+30]..[17,421+31]) - Ptyp_constr "t" (extensions.ml[17,421+30]..[17,421+31]) - [] - [] - ] - expression (extensions.ml[18,454+4]..[18,454+23]) - Pexp_extension "foo" - [ - signature_item (extensions.ml[18,454+11]..[18,454+21]) - Psig_type Rec - [ - type_declaration "t" (extensions.ml[18,454+16]..[18,454+17]) (extensions.ml[18,454+11]..[18,454+21]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (extensions.ml[18,454+20]..[18,454+21]) - Ptyp_constr "t" (extensions.ml[18,454+20]..[18,454+21]) - [] - ] - ] - ] -] - -File "extensions.ml", line 2, characters 3-6: -Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/parsing/int_and_float_with_modifier.compilers.reference b/testsuite/tests/parsing/int_and_float_with_modifier.compilers.reference new file mode 100644 index 00000000..84eddc7c --- /dev/null +++ b/testsuite/tests/parsing/int_and_float_with_modifier.compilers.reference @@ -0,0 +1,86 @@ +[ + structure_item (int_and_float_with_modifier.ml[9,153+0]..[10,184+57]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[9,153+4]..[9,153+28]) + Ppat_var "int_with_custom_modifier" (int_and_float_with_modifier.ml[9,153+4]..[9,153+28]) + expression (int_and_float_with_modifier.ml[10,184+2]..[10,184+57]) + Pexp_constant PConst_int (1234567890_1234567890_1234567890_1234567890_1234567890,Some z) + ] + structure_item (int_and_float_with_modifier.ml[11,242+0]..[12,275+58]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[11,242+4]..[11,242+30]) + Ppat_var "float_with_custom_modifier" (int_and_float_with_modifier.ml[11,242+4]..[11,242+30]) + expression (int_and_float_with_modifier.ml[12,275+2]..[12,275+58]) + Pexp_constant PConst_float (1234567890_1234567890_1234567890_1234567890_1234567890.,Some z) + ] + structure_item (int_and_float_with_modifier.ml[14,335+0]..[14,335+21]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[14,335+4]..[14,335+9]) + Ppat_var "int32" (int_and_float_with_modifier.ml[14,335+4]..[14,335+9]) + expression (int_and_float_with_modifier.ml[14,335+16]..[14,335+21]) + Pexp_constant PConst_int (1234,Some l) + ] + structure_item (int_and_float_with_modifier.ml[15,357+0]..[15,357+21]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[15,357+4]..[15,357+9]) + Ppat_var "int64" (int_and_float_with_modifier.ml[15,357+4]..[15,357+9]) + expression (int_and_float_with_modifier.ml[15,357+16]..[15,357+21]) + Pexp_constant PConst_int (1234,Some L) + ] + structure_item (int_and_float_with_modifier.ml[16,379+0]..[16,379+21]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[16,379+4]..[16,379+13]) + Ppat_var "nativeint" (int_and_float_with_modifier.ml[16,379+4]..[16,379+13]) + expression (int_and_float_with_modifier.ml[16,379+16]..[16,379+21]) + Pexp_constant PConst_int (1234,Some n) + ] + structure_item (int_and_float_with_modifier.ml[18,402+0]..[18,402+32]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[18,402+4]..[18,402+24]) + Ppat_var "hex_without_modifier" (int_and_float_with_modifier.ml[18,402+4]..[18,402+24]) + expression (int_and_float_with_modifier.ml[18,402+27]..[18,402+32]) + Pexp_constant PConst_int (0x32f,None) + ] + structure_item (int_and_float_with_modifier.ml[19,435+0]..[19,435+32]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[19,435+4]..[19,435+21]) + Ppat_var "hex_with_modifier" (int_and_float_with_modifier.ml[19,435+4]..[19,435+21]) + expression (int_and_float_with_modifier.ml[19,435+27]..[19,435+32]) + Pexp_constant PConst_int (0x32,Some g) + ] + structure_item (int_and_float_with_modifier.ml[21,469+0]..[21,469+33]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[21,469+4]..[21,469+25]) + Ppat_var "float_without_modifer" (int_and_float_with_modifier.ml[21,469+4]..[21,469+25]) + expression (int_and_float_with_modifier.ml[21,469+28]..[21,469+33]) + Pexp_constant PConst_float (1.2e3,None) + ] + structure_item (int_and_float_with_modifier.ml[22,503+0]..[22,503+32]) + Pstr_value Nonrec + [ + + pattern (int_and_float_with_modifier.ml[22,503+4]..[22,503+22]) + Ppat_var "float_with_modifer" (int_and_float_with_modifier.ml[22,503+4]..[22,503+22]) + expression (int_and_float_with_modifier.ml[22,503+28]..[22,503+32]) + Pexp_constant PConst_float (1.2,Some g) + ] +] + +File "int_and_float_with_modifier.ml", line 10, characters 2-57: +Error: Unknown modifier 'z' for literal 1234567890_1234567890_1234567890_1234567890_1234567890z diff --git a/testsuite/tests/parsing/int_and_float_with_modifier.ml b/testsuite/tests/parsing/int_and_float_with_modifier.ml index 06384257..444964be 100644 --- a/testsuite/tests/parsing/int_and_float_with_modifier.ml +++ b/testsuite/tests/parsing/int_and_float_with_modifier.ml @@ -1,3 +1,11 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + let int_with_custom_modifier = 1234567890_1234567890_1234567890_1234567890_1234567890z let float_with_custom_modifier = diff --git a/testsuite/tests/parsing/int_and_float_with_modifier.ml.reference b/testsuite/tests/parsing/int_and_float_with_modifier.ml.reference deleted file mode 100644 index fd3bee0e..00000000 --- a/testsuite/tests/parsing/int_and_float_with_modifier.ml.reference +++ /dev/null @@ -1,86 +0,0 @@ -[ - structure_item (int_and_float_with_modifier.ml[1,0+0]..[2,31+57]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[1,0+4]..[1,0+28]) - Ppat_var "int_with_custom_modifier" (int_and_float_with_modifier.ml[1,0+4]..[1,0+28]) - expression (int_and_float_with_modifier.ml[2,31+2]..[2,31+57]) - Pexp_constant PConst_int (1234567890_1234567890_1234567890_1234567890_1234567890,Some z) - ] - structure_item (int_and_float_with_modifier.ml[3,89+0]..[4,122+58]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[3,89+4]..[3,89+30]) - Ppat_var "float_with_custom_modifier" (int_and_float_with_modifier.ml[3,89+4]..[3,89+30]) - expression (int_and_float_with_modifier.ml[4,122+2]..[4,122+58]) - Pexp_constant PConst_float (1234567890_1234567890_1234567890_1234567890_1234567890.,Some z) - ] - structure_item (int_and_float_with_modifier.ml[6,182+0]..[6,182+21]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[6,182+4]..[6,182+9]) - Ppat_var "int32" (int_and_float_with_modifier.ml[6,182+4]..[6,182+9]) - expression (int_and_float_with_modifier.ml[6,182+16]..[6,182+21]) - Pexp_constant PConst_int (1234,Some l) - ] - structure_item (int_and_float_with_modifier.ml[7,204+0]..[7,204+21]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[7,204+4]..[7,204+9]) - Ppat_var "int64" (int_and_float_with_modifier.ml[7,204+4]..[7,204+9]) - expression (int_and_float_with_modifier.ml[7,204+16]..[7,204+21]) - Pexp_constant PConst_int (1234,Some L) - ] - structure_item (int_and_float_with_modifier.ml[8,226+0]..[8,226+21]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[8,226+4]..[8,226+13]) - Ppat_var "nativeint" (int_and_float_with_modifier.ml[8,226+4]..[8,226+13]) - expression (int_and_float_with_modifier.ml[8,226+16]..[8,226+21]) - Pexp_constant PConst_int (1234,Some n) - ] - structure_item (int_and_float_with_modifier.ml[10,249+0]..[10,249+32]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[10,249+4]..[10,249+24]) - Ppat_var "hex_without_modifier" (int_and_float_with_modifier.ml[10,249+4]..[10,249+24]) - expression (int_and_float_with_modifier.ml[10,249+27]..[10,249+32]) - Pexp_constant PConst_int (0x32f,None) - ] - structure_item (int_and_float_with_modifier.ml[11,282+0]..[11,282+32]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[11,282+4]..[11,282+21]) - Ppat_var "hex_with_modifier" (int_and_float_with_modifier.ml[11,282+4]..[11,282+21]) - expression (int_and_float_with_modifier.ml[11,282+27]..[11,282+32]) - Pexp_constant PConst_int (0x32,Some g) - ] - structure_item (int_and_float_with_modifier.ml[13,316+0]..[13,316+33]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[13,316+4]..[13,316+25]) - Ppat_var "float_without_modifer" (int_and_float_with_modifier.ml[13,316+4]..[13,316+25]) - expression (int_and_float_with_modifier.ml[13,316+28]..[13,316+33]) - Pexp_constant PConst_float (1.2e3,None) - ] - structure_item (int_and_float_with_modifier.ml[14,350+0]..[14,350+32]) - Pstr_value Nonrec - [ - - pattern (int_and_float_with_modifier.ml[14,350+4]..[14,350+22]) - Ppat_var "float_with_modifer" (int_and_float_with_modifier.ml[14,350+4]..[14,350+22]) - expression (int_and_float_with_modifier.ml[14,350+28]..[14,350+32]) - Pexp_constant PConst_float (1.2,Some g) - ] -] - -File "int_and_float_with_modifier.ml", line 2, characters 2-57: -Error: Unknown modifier 'z' for literal 1234567890_1234567890_1234567890_1234567890_1234567890z diff --git a/testsuite/tests/parsing/ocamltests b/testsuite/tests/parsing/ocamltests new file mode 100644 index 00000000..b509fdb8 --- /dev/null +++ b/testsuite/tests/parsing/ocamltests @@ -0,0 +1,11 @@ +attributes.ml +docstrings.ml +extended_indexoperators.ml +extensions.ml +int_and_float_with_modifier.ml +pr6604_2.ml +pr6604_3.ml +pr6604.ml +pr6865.ml +pr7165.ml +shortcut_ext_attr.ml diff --git a/testsuite/tests/parsing/pr6604.compilers.reference b/testsuite/tests/parsing/pr6604.compilers.reference new file mode 100644 index 00000000..634351de --- /dev/null +++ b/testsuite/tests/parsing/pr6604.compilers.reference @@ -0,0 +1,2 @@ +File "pr6604.ml", line 9, characters 0-1: +Error: Syntax error diff --git a/testsuite/tests/parsing/pr6604.ml b/testsuite/tests/parsing/pr6604.ml new file mode 100644 index 00000000..806f9c37 --- /dev/null +++ b/testsuite/tests/parsing/pr6604.ml @@ -0,0 +1,9 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + +#1 diff --git a/testsuite/tests/parsing/pr6604_2.compilers.reference b/testsuite/tests/parsing/pr6604_2.compilers.reference new file mode 100644 index 00000000..3d5c60ef --- /dev/null +++ b/testsuite/tests/parsing/pr6604_2.compilers.reference @@ -0,0 +1,2 @@ +File "pr6604_2.ml", line 9, characters 1-2: +Error: Syntax error diff --git a/testsuite/tests/parsing/pr6604_2.ml b/testsuite/tests/parsing/pr6604_2.ml new file mode 100644 index 00000000..995e242d --- /dev/null +++ b/testsuite/tests/parsing/pr6604_2.ml @@ -0,0 +1,9 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + + #1 "pr6604.ml" diff --git a/testsuite/tests/parsing/pr6604_3.compilers.reference b/testsuite/tests/parsing/pr6604_3.compilers.reference new file mode 100644 index 00000000..7dd43875 --- /dev/null +++ b/testsuite/tests/parsing/pr6604_3.compilers.reference @@ -0,0 +1,2 @@ +[] + diff --git a/testsuite/tests/parsing/pr6604_3.ml b/testsuite/tests/parsing/pr6604_3.ml new file mode 100644 index 00000000..ef15c5c0 --- /dev/null +++ b/testsuite/tests/parsing/pr6604_3.ml @@ -0,0 +1,11 @@ +(* TEST + flags = "-dparsetree" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + +# 1 "pr6604.ml" + +# 3 "pr6604.ml" +# 4 "pr6604.ml" diff --git a/testsuite/tests/parsing/pr6865.compilers.reference b/testsuite/tests/parsing/pr6865.compilers.reference new file mode 100644 index 00000000..fb417c36 --- /dev/null +++ b/testsuite/tests/parsing/pr6865.compilers.reference @@ -0,0 +1,52 @@ +[ + structure_item (pr6865.ml[9,153+0]..[9,153+14]) ghost + Pstr_extension "foo" + [ + structure_item (pr6865.ml[9,153+0]..[9,153+14]) + Pstr_value Nonrec + [ + + pattern (pr6865.ml[9,153+8]..[9,153+9]) + Ppat_var "x" (pr6865.ml[9,153+8]..[9,153+9]) + expression (pr6865.ml[9,153+12]..[9,153+14]) + Pexp_constant PConst_int (42,None) + ] + ] + structure_item (pr6865.ml[10,168+0]..[10,168+25]) ghost + Pstr_extension "foo" + [ + structure_item (pr6865.ml[10,168+0]..[10,168+25]) + Pstr_value Nonrec + [ + + pattern (pr6865.ml[10,168+8]..[10,168+9]) + Ppat_any + expression (pr6865.ml[10,168+12]..[10,168+14]) + Pexp_construct "()" (pr6865.ml[10,168+12]..[10,168+14]) + None + + pattern (pr6865.ml[10,168+19]..[10,168+20]) + Ppat_any + expression (pr6865.ml[10,168+23]..[10,168+25]) + Pexp_construct "()" (pr6865.ml[10,168+23]..[10,168+25]) + None + ] + ] + structure_item (pr6865.ml[11,194+0]..[11,194+14]) ghost + Pstr_extension "foo" + [ + structure_item (pr6865.ml[11,194+0]..[11,194+14]) + Pstr_value Nonrec + [ + + pattern (pr6865.ml[11,194+8]..[11,194+9]) + Ppat_any + expression (pr6865.ml[11,194+12]..[11,194+14]) + Pexp_construct "()" (pr6865.ml[11,194+12]..[11,194+14]) + None + ] + ] +] + +File "pr6865.ml", line 9, characters 4-7: +Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/parsing/pr6865.ml b/testsuite/tests/parsing/pr6865.ml index 78cd602f..c673e2a6 100644 --- a/testsuite/tests/parsing/pr6865.ml +++ b/testsuite/tests/parsing/pr6865.ml @@ -1,3 +1,11 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + let%foo x = 42 let%foo _ = () and _ = () let%foo _ = () diff --git a/testsuite/tests/parsing/pr6865.ml.reference b/testsuite/tests/parsing/pr6865.ml.reference deleted file mode 100644 index 72abd40e..00000000 --- a/testsuite/tests/parsing/pr6865.ml.reference +++ /dev/null @@ -1,52 +0,0 @@ -[ - structure_item (pr6865.ml[1,0+0]..[1,0+14]) ghost - Pstr_extension "foo" - [ - structure_item (pr6865.ml[1,0+0]..[1,0+14]) - Pstr_value Nonrec - [ - - pattern (pr6865.ml[1,0+8]..[1,0+9]) - Ppat_var "x" (pr6865.ml[1,0+8]..[1,0+9]) - expression (pr6865.ml[1,0+12]..[1,0+14]) - Pexp_constant PConst_int (42,None) - ] - ] - structure_item (pr6865.ml[2,15+0]..[2,15+25]) ghost - Pstr_extension "foo" - [ - structure_item (pr6865.ml[2,15+0]..[2,15+25]) - Pstr_value Nonrec - [ - - pattern (pr6865.ml[2,15+8]..[2,15+9]) - Ppat_any - expression (pr6865.ml[2,15+12]..[2,15+14]) - Pexp_construct "()" (pr6865.ml[2,15+12]..[2,15+14]) - None - - pattern (pr6865.ml[2,15+19]..[2,15+20]) - Ppat_any - expression (pr6865.ml[2,15+23]..[2,15+25]) - Pexp_construct "()" (pr6865.ml[2,15+23]..[2,15+25]) - None - ] - ] - structure_item (pr6865.ml[3,41+0]..[3,41+14]) ghost - Pstr_extension "foo" - [ - structure_item (pr6865.ml[3,41+0]..[3,41+14]) - Pstr_value Nonrec - [ - - pattern (pr6865.ml[3,41+8]..[3,41+9]) - Ppat_any - expression (pr6865.ml[3,41+12]..[3,41+14]) - Pexp_construct "()" (pr6865.ml[3,41+12]..[3,41+14]) - None - ] - ] -] - -File "pr6865.ml", line 1, characters 4-7: -Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/parsing/pr7165.compilers.reference b/testsuite/tests/parsing/pr7165.compilers.reference new file mode 100644 index 00000000..55fe3c49 --- /dev/null +++ b/testsuite/tests/parsing/pr7165.compilers.reference @@ -0,0 +1,2 @@ +File "pr7165.ml", line 12, characters 1-23: +Error: Invalid lexer directive "#9342101923012312312 \"\"": line number out of range diff --git a/testsuite/tests/parsing/pr7165.ml b/testsuite/tests/parsing/pr7165.ml index ba6835b4..e25708c1 100644 --- a/testsuite/tests/parsing/pr7165.ml +++ b/testsuite/tests/parsing/pr7165.ml @@ -1,4 +1,12 @@ +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) + (* this is a lexer directive with an out-of-bound integer; it should result in a lexing error instead of an uncaught exception as in PR#7165 *) -#9342101923012312312 +#9342101923012312312 "" diff --git a/testsuite/tests/parsing/pr7165.ml.reference b/testsuite/tests/parsing/pr7165.ml.reference deleted file mode 100644 index fd59df84..00000000 --- a/testsuite/tests/parsing/pr7165.ml.reference +++ /dev/null @@ -1,2 +0,0 @@ -File "pr7165.ml", line 4, characters 0-21: -Error: Invalid lexer directive "#9342101923012312312": line number out of range diff --git a/testsuite/tests/parsing/shortcut_ext_attr.compilers.reference b/testsuite/tests/parsing/shortcut_ext_attr.compilers.reference new file mode 100644 index 00000000..d8ceb058 --- /dev/null +++ b/testsuite/tests/parsing/shortcut_ext_attr.compilers.reference @@ -0,0 +1,978 @@ +[ + structure_item (shortcut_ext_attr.ml[9,170+0]..[30,721+31]) + Pstr_value Nonrec + [ + + pattern (shortcut_ext_attr.ml[9,170+4]..[9,170+6]) + Ppat_construct "()" (shortcut_ext_attr.ml[9,170+4]..[9,170+6]) + None + expression (shortcut_ext_attr.ml[10,179+2]..[30,721+31]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[10,179+2]..[30,721+31]) + Pstr_eval + expression (shortcut_ext_attr.ml[10,179+2]..[30,721+31]) + Pexp_let Nonrec + [ + + attribute "foo" + [] + pattern (shortcut_ext_attr.ml[10,179+16]..[10,179+17]) + Ppat_var "x" (shortcut_ext_attr.ml[10,179+16]..[10,179+17]) + expression (shortcut_ext_attr.ml[10,179+20]..[10,179+21]) + Pexp_constant PConst_int (3,None) + + attribute "foo" + [] + pattern (shortcut_ext_attr.ml[11,201+12]..[11,201+13]) + Ppat_var "y" (shortcut_ext_attr.ml[11,201+12]..[11,201+13]) + expression (shortcut_ext_attr.ml[11,201+16]..[11,201+17]) + Pexp_constant PConst_int (4,None) + ] + expression (shortcut_ext_attr.ml[12,222+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[12,222+2]..[12,222+36]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[12,222+3]..[12,222+35]) + Pstr_eval + expression (shortcut_ext_attr.ml[12,222+3]..[12,222+35]) + attribute "foo" + [] + Pexp_letmodule "M" (shortcut_ext_attr.ml[12,222+24]..[12,222+25]) + module_expr (shortcut_ext_attr.ml[12,222+28]..[12,222+29]) + Pmod_ident "M" (shortcut_ext_attr.ml[12,222+28]..[12,222+29]) + expression (shortcut_ext_attr.ml[12,222+33]..[12,222+35]) + Pexp_construct "()" (shortcut_ext_attr.ml[12,222+33]..[12,222+35]) + None + ] + expression (shortcut_ext_attr.ml[13,261+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[13,261+2]..[13,261+30]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[13,261+3]..[13,261+29]) + Pstr_eval + expression (shortcut_ext_attr.ml[13,261+3]..[13,261+29]) + attribute "foo" + [] + Pexp_open Fresh ""M" (shortcut_ext_attr.ml[13,261+22]..[13,261+23])" + expression (shortcut_ext_attr.ml[13,261+27]..[13,261+29]) + Pexp_construct "()" (shortcut_ext_attr.ml[13,261+27]..[13,261+29]) + None + ] + expression (shortcut_ext_attr.ml[14,294+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[14,294+2]..[14,294+25]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[14,294+3]..[14,294+24]) + Pstr_eval + expression (shortcut_ext_attr.ml[14,294+3]..[14,294+24]) + attribute "foo" + [] + Pexp_fun + Nolabel + None + pattern (shortcut_ext_attr.ml[14,294+17]..[14,294+18]) + Ppat_var "x" (shortcut_ext_attr.ml[14,294+17]..[14,294+18]) + expression (shortcut_ext_attr.ml[14,294+22]..[14,294+24]) + Pexp_construct "()" (shortcut_ext_attr.ml[14,294+22]..[14,294+24]) + None + ] + expression (shortcut_ext_attr.ml[15,322+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[15,322+2]..[15,322+30]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[15,322+3]..[15,322+29]) + Pstr_eval + expression (shortcut_ext_attr.ml[15,322+3]..[15,322+29]) + attribute "foo" + [] + Pexp_function + [ + + pattern (shortcut_ext_attr.ml[15,322+22]..[15,322+23]) + Ppat_var "x" (shortcut_ext_attr.ml[15,322+22]..[15,322+23]) + expression (shortcut_ext_attr.ml[15,322+27]..[15,322+29]) + Pexp_construct "()" (shortcut_ext_attr.ml[15,322+27]..[15,322+29]) + None + ] + ] + expression (shortcut_ext_attr.ml[16,355+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[16,355+2]..[16,355+33]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[16,355+3]..[16,355+32]) + Pstr_eval + expression (shortcut_ext_attr.ml[16,355+3]..[16,355+32]) + attribute "foo" + [] + Pexp_try + expression (shortcut_ext_attr.ml[16,355+17]..[16,355+19]) + Pexp_construct "()" (shortcut_ext_attr.ml[16,355+17]..[16,355+19]) + None + [ + + pattern (shortcut_ext_attr.ml[16,355+25]..[16,355+26]) + Ppat_any + expression (shortcut_ext_attr.ml[16,355+30]..[16,355+32]) + Pexp_construct "()" (shortcut_ext_attr.ml[16,355+30]..[16,355+32]) + None + ] + ] + expression (shortcut_ext_attr.ml[17,391+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[17,391+2]..[17,391+35]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[17,391+3]..[17,391+34]) + Pstr_eval + expression (shortcut_ext_attr.ml[17,391+3]..[17,391+34]) + attribute "foo" + [] + Pexp_ifthenelse + expression (shortcut_ext_attr.ml[17,391+16]..[17,391+18]) + Pexp_construct "()" (shortcut_ext_attr.ml[17,391+16]..[17,391+18]) + None + expression (shortcut_ext_attr.ml[17,391+24]..[17,391+26]) + Pexp_construct "()" (shortcut_ext_attr.ml[17,391+24]..[17,391+26]) + None + Some + expression (shortcut_ext_attr.ml[17,391+32]..[17,391+34]) + Pexp_construct "()" (shortcut_ext_attr.ml[17,391+32]..[17,391+34]) + None + ] + expression (shortcut_ext_attr.ml[18,429+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[18,429+2]..[18,429+31]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[18,429+2]..[18,429+31]) + Pstr_eval + expression (shortcut_ext_attr.ml[18,429+2]..[18,429+31]) + attribute "foo" + [] + Pexp_while + expression (shortcut_ext_attr.ml[18,429+18]..[18,429+20]) + Pexp_construct "()" (shortcut_ext_attr.ml[18,429+18]..[18,429+20]) + None + expression (shortcut_ext_attr.ml[18,429+24]..[18,429+26]) + Pexp_construct "()" (shortcut_ext_attr.ml[18,429+24]..[18,429+26]) + None + ] + expression (shortcut_ext_attr.ml[19,463+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[19,463+2]..[19,463+39]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[19,463+2]..[19,463+39]) + Pstr_eval + expression (shortcut_ext_attr.ml[19,463+2]..[19,463+39]) + attribute "foo" + [] + Pexp_for Up + pattern (shortcut_ext_attr.ml[19,463+16]..[19,463+17]) + Ppat_var "x" (shortcut_ext_attr.ml[19,463+16]..[19,463+17]) + expression (shortcut_ext_attr.ml[19,463+20]..[19,463+22]) + Pexp_construct "()" (shortcut_ext_attr.ml[19,463+20]..[19,463+22]) + None + expression (shortcut_ext_attr.ml[19,463+26]..[19,463+28]) + Pexp_construct "()" (shortcut_ext_attr.ml[19,463+26]..[19,463+28]) + None + expression (shortcut_ext_attr.ml[19,463+32]..[19,463+34]) + Pexp_construct "()" (shortcut_ext_attr.ml[19,463+32]..[19,463+34]) + None + ] + expression (shortcut_ext_attr.ml[20,505+2]..[30,721+31]) + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[20,505+2]..[30,721+31]) + Pstr_eval + expression (shortcut_ext_attr.ml[20,505+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[20,505+2]..[20,505+4]) + Pexp_construct "()" (shortcut_ext_attr.ml[20,505+2]..[20,505+4]) + None + expression (shortcut_ext_attr.ml[20,505+11]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[20,505+11]..[20,505+13]) + Pexp_construct "()" (shortcut_ext_attr.ml[20,505+11]..[20,505+13]) + None + expression (shortcut_ext_attr.ml[21,521+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[21,521+2]..[21,521+23]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[21,521+2]..[21,521+23]) + Pstr_eval + expression (shortcut_ext_attr.ml[21,521+2]..[21,521+23]) + attribute "foo" + [] + Pexp_assert + expression (shortcut_ext_attr.ml[21,521+19]..[21,521+23]) + Pexp_construct "true" (shortcut_ext_attr.ml[21,521+19]..[21,521+23]) + None + ] + expression (shortcut_ext_attr.ml[22,547+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[22,547+2]..[22,547+18]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[22,547+2]..[22,547+18]) + Pstr_eval + expression (shortcut_ext_attr.ml[22,547+2]..[22,547+18]) + attribute "foo" + [] + Pexp_lazy + expression (shortcut_ext_attr.ml[22,547+17]..[22,547+18]) + Pexp_ident "x" (shortcut_ext_attr.ml[22,547+17]..[22,547+18]) + ] + expression (shortcut_ext_attr.ml[23,568+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[23,568+2]..[23,568+22]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[23,568+2]..[23,568+22]) + Pstr_eval + expression (shortcut_ext_attr.ml[23,568+2]..[23,568+22]) + attribute "foo" + [] + Pexp_object + class_structure + pattern (shortcut_ext_attr.ml[23,568+18]..[23,568+18]) ghost + Ppat_any + [] + ] + expression (shortcut_ext_attr.ml[24,593+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[24,593+2]..[24,593+23]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[24,593+2]..[24,593+23]) + Pstr_eval + expression (shortcut_ext_attr.ml[24,593+2]..[24,593+23]) + attribute "foo" + [] + Pexp_constant PConst_int (3,None) + ] + expression (shortcut_ext_attr.ml[25,619+2]..[30,721+31]) + Pexp_sequence + expression (shortcut_ext_attr.ml[25,619+2]..[25,619+17]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[25,619+2]..[25,619+17]) + Pstr_eval + expression (shortcut_ext_attr.ml[25,619+2]..[25,619+17]) + attribute "foo" + [] + Pexp_new "x" (shortcut_ext_attr.ml[25,619+16]..[25,619+17]) + ] + expression (shortcut_ext_attr.ml[27,640+2]..[30,721+31]) ghost + Pexp_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[27,640+2]..[30,721+31]) + Pstr_eval + expression (shortcut_ext_attr.ml[27,640+2]..[30,721+31]) + attribute "foo" + [] + Pexp_match + expression (shortcut_ext_attr.ml[27,640+18]..[27,640+20]) + Pexp_construct "()" (shortcut_ext_attr.ml[27,640+18]..[27,640+20]) + None + [ + + pattern (shortcut_ext_attr.ml[29,694+4]..[29,694+20]) ghost + Ppat_extension "foo" + pattern (shortcut_ext_attr.ml[29,694+4]..[29,694+20]) + attribute "foo" + [] + Ppat_lazy + pattern (shortcut_ext_attr.ml[29,694+19]..[29,694+20]) + Ppat_var "x" (shortcut_ext_attr.ml[29,694+19]..[29,694+20]) + expression (shortcut_ext_attr.ml[29,694+24]..[29,694+26]) + Pexp_construct "()" (shortcut_ext_attr.ml[29,694+24]..[29,694+26]) + None + + pattern (shortcut_ext_attr.ml[30,721+4]..[30,721+25]) ghost + Ppat_extension "foo" + pattern (shortcut_ext_attr.ml[30,721+4]..[30,721+25]) + attribute "foo" + [] + Ppat_exception + pattern (shortcut_ext_attr.ml[30,721+24]..[30,721+25]) + Ppat_var "x" (shortcut_ext_attr.ml[30,721+24]..[30,721+25]) + expression (shortcut_ext_attr.ml[30,721+29]..[30,721+31]) + Pexp_construct "()" (shortcut_ext_attr.ml[30,721+29]..[30,721+31]) + None + ] + ] + ] + ] + ] + structure_item (shortcut_ext_attr.ml[34,779+0]..[46,1049+5]) + Pstr_class + [ + class_declaration (shortcut_ext_attr.ml[34,779+0]..[46,1049+5]) + pci_virt = Concrete + pci_params = + [] + pci_name = "x" (shortcut_ext_attr.ml[34,779+6]..[34,779+7]) + pci_expr = + class_expr (shortcut_ext_attr.ml[35,789+12]..[46,1049+5]) + attribute "foo" + [] + Pcl_fun + Nolabel + None + pattern (shortcut_ext_attr.ml[35,789+12]..[35,789+13]) + Ppat_var "x" (shortcut_ext_attr.ml[35,789+12]..[35,789+13]) + class_expr (shortcut_ext_attr.ml[36,806+2]..[46,1049+5]) + Pcl_let Nonrec + [ + + attribute "foo" + [] + pattern (shortcut_ext_attr.ml[36,806+12]..[36,806+13]) + Ppat_var "x" (shortcut_ext_attr.ml[36,806+12]..[36,806+13]) + expression (shortcut_ext_attr.ml[36,806+16]..[36,806+17]) + Pexp_constant PConst_int (3,None) + ] + class_expr (shortcut_ext_attr.ml[37,827+2]..[46,1049+5]) + attribute "foo" + [] + Pcl_structure + class_structure + pattern (shortcut_ext_attr.ml[37,827+14]..[37,827+14]) ghost + Ppat_any + [ + class_field (shortcut_ext_attr.ml[38,842+4]..[38,842+19]) + attribute "foo" + [] + Pcf_inherit Fresh + class_expr (shortcut_ext_attr.ml[38,842+18]..[38,842+19]) + Pcl_constr "x" (shortcut_ext_attr.ml[38,842+18]..[38,842+19]) + [] + None + class_field (shortcut_ext_attr.ml[39,862+4]..[39,862+19]) + attribute "foo" + [] + Pcf_val Immutable + "x" (shortcut_ext_attr.ml[39,862+14]..[39,862+15]) + Concrete Fresh + expression (shortcut_ext_attr.ml[39,862+18]..[39,862+19]) + Pexp_constant PConst_int (3,None) + class_field (shortcut_ext_attr.ml[40,882+4]..[40,882+27]) + attribute "foo" + [] + Pcf_val Immutable + "x" (shortcut_ext_attr.ml[40,882+22]..[40,882+23]) + Virtual + core_type (shortcut_ext_attr.ml[40,882+26]..[40,882+27]) + Ptyp_constr "t" (shortcut_ext_attr.ml[40,882+26]..[40,882+27]) + [] + class_field (shortcut_ext_attr.ml[41,910+4]..[41,910+28]) + attribute "foo" + [] + Pcf_val Mutable + "x" (shortcut_ext_attr.ml[41,910+23]..[41,910+24]) + Concrete Override + expression (shortcut_ext_attr.ml[41,910+27]..[41,910+28]) + Pexp_constant PConst_int (3,None) + class_field (shortcut_ext_attr.ml[42,939+4]..[42,939+22]) + attribute "foo" + [] + Pcf_method Public + "x" (shortcut_ext_attr.ml[42,939+17]..[42,939+18]) + Concrete Fresh + expression (shortcut_ext_attr.ml[42,939+10]..[42,939+22]) ghost + Pexp_poly + expression (shortcut_ext_attr.ml[42,939+21]..[42,939+22]) + Pexp_constant PConst_int (3,None) + None + class_field (shortcut_ext_attr.ml[43,962+4]..[43,962+30]) + attribute "foo" + [] + Pcf_method Public + "x" (shortcut_ext_attr.ml[43,962+25]..[43,962+26]) + Virtual + core_type (shortcut_ext_attr.ml[43,962+29]..[43,962+30]) + Ptyp_constr "t" (shortcut_ext_attr.ml[43,962+29]..[43,962+30]) + [] + class_field (shortcut_ext_attr.ml[44,993+4]..[44,993+31]) + attribute "foo" + [] + Pcf_method Private + "x" (shortcut_ext_attr.ml[44,993+26]..[44,993+27]) + Concrete Override + expression (shortcut_ext_attr.ml[44,993+10]..[44,993+31]) ghost + Pexp_poly + expression (shortcut_ext_attr.ml[44,993+30]..[44,993+31]) + Pexp_constant PConst_int (3,None) + None + class_field (shortcut_ext_attr.ml[45,1025+4]..[45,1025+23]) + attribute "foo" + [] + Pcf_initializer + expression (shortcut_ext_attr.ml[45,1025+22]..[45,1025+23]) + Pexp_ident "x" (shortcut_ext_attr.ml[45,1025+22]..[45,1025+23]) + ] + ] + structure_item (shortcut_ext_attr.ml[49,1085+0]..[57,1265+5]) + Pstr_class_type + [ + class_type_declaration (shortcut_ext_attr.ml[49,1085+0]..[57,1265+5]) + pci_virt = Concrete + pci_params = + [] + pci_name = "t" (shortcut_ext_attr.ml[49,1085+11]..[49,1085+12]) + pci_expr = + class_type (shortcut_ext_attr.ml[50,1100+2]..[57,1265+5]) + attribute "foo" + [] + Pcty_signature + class_signature + core_type (shortcut_ext_attr.ml[50,1100+14]..[50,1100+14]) + Ptyp_any + [ + class_type_field (shortcut_ext_attr.ml[51,1115+4]..[51,1115+19]) + attribute "foo" + [] + Pctf_inherit + class_type (shortcut_ext_attr.ml[51,1115+18]..[51,1115+19]) + Pcty_constr "t" (shortcut_ext_attr.ml[51,1115+18]..[51,1115+19]) + [] + class_type_field (shortcut_ext_attr.ml[52,1135+4]..[52,1135+19]) + attribute "foo" + [] + Pctf_val "x" Immutable Concrete + core_type (shortcut_ext_attr.ml[52,1135+18]..[52,1135+19]) + Ptyp_constr "t" (shortcut_ext_attr.ml[52,1135+18]..[52,1135+19]) + [] + class_type_field (shortcut_ext_attr.ml[53,1155+4]..[53,1155+27]) + attribute "foo" + [] + Pctf_val "x" Mutable Concrete + core_type (shortcut_ext_attr.ml[53,1155+26]..[53,1155+27]) + Ptyp_constr "t" (shortcut_ext_attr.ml[53,1155+26]..[53,1155+27]) + [] + class_type_field (shortcut_ext_attr.ml[54,1183+4]..[54,1183+22]) + attribute "foo" + [] + Pctf_method "x" Public Concrete + core_type (shortcut_ext_attr.ml[54,1183+21]..[54,1183+22]) + Ptyp_constr "t" (shortcut_ext_attr.ml[54,1183+21]..[54,1183+22]) + [] + class_type_field (shortcut_ext_attr.ml[55,1206+4]..[55,1206+30]) + attribute "foo" + [] + Pctf_method "x" Private Concrete + core_type (shortcut_ext_attr.ml[55,1206+29]..[55,1206+30]) + Ptyp_constr "t" (shortcut_ext_attr.ml[55,1206+29]..[55,1206+30]) + [] + class_type_field (shortcut_ext_attr.ml[56,1237+4]..[56,1237+27]) + attribute "foo" + [] + Pctf_constraint + core_type (shortcut_ext_attr.ml[56,1237+21]..[56,1237+22]) + Ptyp_constr "t" (shortcut_ext_attr.ml[56,1237+21]..[56,1237+22]) + [] + core_type (shortcut_ext_attr.ml[56,1237+25]..[56,1237+27]) + Ptyp_constr "t'" (shortcut_ext_attr.ml[56,1237+25]..[56,1237+27]) + [] + ] + ] + structure_item (shortcut_ext_attr.ml[60,1295+0]..[61,1304+22]) + Pstr_type Rec + [ + type_declaration "t" (shortcut_ext_attr.ml[60,1295+5]..[60,1295+6]) (shortcut_ext_attr.ml[60,1295+0]..[61,1304+22]) + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (shortcut_ext_attr.ml[61,1304+2]..[61,1304+22]) ghost + Ptyp_extension "foo" + core_type (shortcut_ext_attr.ml[61,1304+2]..[61,1304+22]) + attribute "foo" + [] + Ptyp_package "M" (shortcut_ext_attr.ml[61,1304+20]..[61,1304+21]) + [] + ] + structure_item (shortcut_ext_attr.ml[64,1353+0]..[67,1409+22]) + Pstr_module + "M" (shortcut_ext_attr.ml[64,1353+7]..[64,1353+8]) + module_expr (shortcut_ext_attr.ml[65,1364+2]..[67,1409+22]) + attribute "foo" + [] + Pmod_functor "M" (shortcut_ext_attr.ml[65,1364+17]..[65,1364+18]) + module_type (shortcut_ext_attr.ml[65,1364+21]..[65,1364+22]) + Pmty_ident "S" (shortcut_ext_attr.ml[65,1364+21]..[65,1364+22]) + module_expr (shortcut_ext_attr.ml[66,1391+4]..[67,1409+22]) + Pmod_apply + module_expr (shortcut_ext_attr.ml[66,1391+4]..[66,1391+17]) + attribute "foo" + [] + Pmod_unpack + expression (shortcut_ext_attr.ml[66,1391+15]..[66,1391+16]) + Pexp_ident "x" (shortcut_ext_attr.ml[66,1391+15]..[66,1391+16]) + module_expr (shortcut_ext_attr.ml[67,1409+5]..[67,1409+21]) + attribute "foo" + [] + Pmod_structure + [] + structure_item (shortcut_ext_attr.ml[70,1462+0]..[73,1535+19]) + Pstr_modtype "S" (shortcut_ext_attr.ml[70,1462+12]..[70,1462+13]) + module_type (shortcut_ext_attr.ml[71,1478+2]..[73,1535+19]) + attribute "foo" + [] + Pmty_functor "M" (shortcut_ext_attr.ml[71,1478+17]..[71,1478+18]) + module_type (shortcut_ext_attr.ml[71,1478+19]..[71,1478+20]) + Pmty_ident "S" (shortcut_ext_attr.ml[71,1478+19]..[71,1478+20]) + module_type (shortcut_ext_attr.ml[72,1503+4]..[73,1535+19]) + Pmty_functor "_" (_none_[1,0+-1]..[1,0+-1]) ghost + module_type (shortcut_ext_attr.ml[72,1503+5]..[72,1503+27]) + attribute "foo" + [] + Pmty_typeof + module_expr (shortcut_ext_attr.ml[72,1503+26]..[72,1503+27]) + Pmod_ident "M" (shortcut_ext_attr.ml[72,1503+26]..[72,1503+27]) + module_type (shortcut_ext_attr.ml[73,1535+5]..[73,1535+18]) + attribute "foo" + [] + Pmty_signature + [] + structure_item (shortcut_ext_attr.ml[76,1578+0]..[77,1598+15]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[76,1578+0]..[77,1598+15]) + Pstr_value Nonrec + [ + + attribute "foo" + [] + pattern (shortcut_ext_attr.ml[76,1578+14]..[76,1578+15]) + Ppat_var "x" (shortcut_ext_attr.ml[76,1578+14]..[76,1578+15]) + expression (shortcut_ext_attr.ml[76,1578+18]..[76,1578+19]) + Pexp_constant PConst_int (4,None) + + attribute "foo" + [] + pattern (shortcut_ext_attr.ml[77,1598+10]..[77,1598+11]) + Ppat_var "y" (shortcut_ext_attr.ml[77,1598+10]..[77,1598+11]) + expression (shortcut_ext_attr.ml[77,1598+14]..[77,1598+15]) + Pexp_ident "x" (shortcut_ext_attr.ml[77,1598+14]..[77,1598+15]) + ] + ] + structure_item (shortcut_ext_attr.ml[79,1615+0]..[80,1638+17]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[79,1615+0]..[80,1638+17]) + Pstr_type Rec + [ + type_declaration "t" (shortcut_ext_attr.ml[79,1615+15]..[79,1615+16]) (shortcut_ext_attr.ml[79,1615+0]..[79,1615+22]) + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (shortcut_ext_attr.ml[79,1615+19]..[79,1615+22]) + Ptyp_constr "int" (shortcut_ext_attr.ml[79,1615+19]..[79,1615+22]) + [] + type_declaration "t" (shortcut_ext_attr.ml[80,1638+10]..[80,1638+11]) (shortcut_ext_attr.ml[80,1638+0]..[80,1638+17]) + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (shortcut_ext_attr.ml[80,1638+14]..[80,1638+17]) + Ptyp_constr "int" (shortcut_ext_attr.ml[80,1638+14]..[80,1638+17]) + [] + ] + ] + structure_item (shortcut_ext_attr.ml[81,1656+0]..[81,1656+21]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[81,1656+0]..[81,1656+21]) + Pstr_typext + type_extension + attribute "foo" + [] + ptyext_path = "t" (shortcut_ext_attr.ml[81,1656+15]..[81,1656+16]) + ptyext_params = + [] + ptyext_constructors = + [ + extension_constructor (shortcut_ext_attr.ml[81,1656+20]..[81,1656+21]) + pext_name = "T" + pext_kind = + Pext_decl + [] + None + ] + ptyext_private = Public + ] + structure_item (shortcut_ext_attr.ml[83,1679+0]..[83,1679+21]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[83,1679+0]..[83,1679+21]) + Pstr_class + [ + class_declaration (shortcut_ext_attr.ml[83,1679+0]..[83,1679+21]) + attribute "foo" + [] + pci_virt = Concrete + pci_params = + [] + pci_name = "x" (shortcut_ext_attr.ml[83,1679+16]..[83,1679+17]) + pci_expr = + class_expr (shortcut_ext_attr.ml[83,1679+20]..[83,1679+21]) + Pcl_constr "x" (shortcut_ext_attr.ml[83,1679+20]..[83,1679+21]) + [] + ] + ] + structure_item (shortcut_ext_attr.ml[84,1701+0]..[84,1701+26]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[84,1701+0]..[84,1701+26]) + Pstr_class_type + [ + class_type_declaration (shortcut_ext_attr.ml[84,1701+0]..[84,1701+26]) + attribute "foo" + [] + pci_virt = Concrete + pci_params = + [] + pci_name = "x" (shortcut_ext_attr.ml[84,1701+21]..[84,1701+22]) + pci_expr = + class_type (shortcut_ext_attr.ml[84,1701+25]..[84,1701+26]) + Pcty_constr "x" (shortcut_ext_attr.ml[84,1701+25]..[84,1701+26]) + [] + ] + ] + structure_item (shortcut_ext_attr.ml[85,1728+0]..[85,1728+30]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[85,1728+0]..[85,1728+30]) + Pstr_primitive + value_description "x" (shortcut_ext_attr.ml[85,1728+19]..[85,1728+20]) (shortcut_ext_attr.ml[85,1728+0]..[85,1728+30]) + attribute "foo" + [] + core_type (shortcut_ext_attr.ml[85,1728+23]..[85,1728+24]) + Ptyp_any + [ + "" + ] + ] + structure_item (shortcut_ext_attr.ml[86,1759+0]..[86,1759+21]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[86,1759+0]..[86,1759+21]) + Pstr_exception + extension_constructor (shortcut_ext_attr.ml[86,1759+0]..[86,1759+21]) + attribute "foo" + [] + pext_name = "X" + pext_kind = + Pext_decl + [] + None + ] + structure_item (shortcut_ext_attr.ml[88,1782+0]..[88,1782+22]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[88,1782+0]..[88,1782+22]) + Pstr_module + "M" (shortcut_ext_attr.ml[88,1782+17]..[88,1782+18]) + attribute "foo" + [] + module_expr (shortcut_ext_attr.ml[88,1782+21]..[88,1782+22]) + Pmod_ident "M" (shortcut_ext_attr.ml[88,1782+21]..[88,1782+22]) + ] + structure_item (shortcut_ext_attr.ml[89,1805+0]..[90,1836+19]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[89,1805+0]..[90,1836+19]) + Pstr_recmodule + [ + "M" (shortcut_ext_attr.ml[89,1805+21]..[89,1805+22]) + attribute "foo" + [] + module_expr (shortcut_ext_attr.ml[89,1805+23]..[89,1805+30]) + Pmod_constraint + module_expr (shortcut_ext_attr.ml[89,1805+29]..[89,1805+30]) + Pmod_ident "M" (shortcut_ext_attr.ml[89,1805+29]..[89,1805+30]) + module_type (shortcut_ext_attr.ml[89,1805+25]..[89,1805+26]) + Pmty_ident "S" (shortcut_ext_attr.ml[89,1805+25]..[89,1805+26]) + "M" (shortcut_ext_attr.ml[90,1836+10]..[90,1836+11]) + attribute "foo" + [] + module_expr (shortcut_ext_attr.ml[90,1836+12]..[90,1836+19]) + Pmod_constraint + module_expr (shortcut_ext_attr.ml[90,1836+18]..[90,1836+19]) + Pmod_ident "M" (shortcut_ext_attr.ml[90,1836+18]..[90,1836+19]) + module_type (shortcut_ext_attr.ml[90,1836+14]..[90,1836+15]) + Pmty_ident "S" (shortcut_ext_attr.ml[90,1836+14]..[90,1836+15]) + ] + ] + structure_item (shortcut_ext_attr.ml[91,1856+0]..[91,1856+27]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[91,1856+0]..[91,1856+27]) + Pstr_modtype "S" (shortcut_ext_attr.ml[91,1856+22]..[91,1856+23]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[91,1856+26]..[91,1856+27]) + Pmty_ident "S" (shortcut_ext_attr.ml[91,1856+26]..[91,1856+27]) + ] + structure_item (shortcut_ext_attr.ml[93,1885+0]..[93,1885+19]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[93,1885+0]..[93,1885+19]) + Pstr_include attribute "foo" + [] + module_expr (shortcut_ext_attr.ml[93,1885+18]..[93,1885+19]) + Pmod_ident "M" (shortcut_ext_attr.ml[93,1885+18]..[93,1885+19]) + ] + structure_item (shortcut_ext_attr.ml[94,1905+0]..[94,1905+16]) ghost + Pstr_extension "foo" + [ + structure_item (shortcut_ext_attr.ml[94,1905+0]..[94,1905+16]) + Pstr_open Fresh "M" (shortcut_ext_attr.ml[94,1905+15]..[94,1905+16]) + attribute "foo" + [] + ] + structure_item (shortcut_ext_attr.ml[97,1945+0]..[120,2341+3]) + Pstr_modtype "S" (shortcut_ext_attr.ml[97,1945+12]..[97,1945+13]) + module_type (shortcut_ext_attr.ml[97,1945+16]..[120,2341+3]) + Pmty_signature + [ + signature_item (shortcut_ext_attr.ml[98,1965+2]..[98,1965+21]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[98,1965+2]..[98,1965+21]) + Psig_value + value_description "x" (shortcut_ext_attr.ml[98,1965+16]..[98,1965+17]) (shortcut_ext_attr.ml[98,1965+2]..[98,1965+21]) + attribute "foo" + [] + core_type (shortcut_ext_attr.ml[98,1965+20]..[98,1965+21]) + Ptyp_constr "t" (shortcut_ext_attr.ml[98,1965+20]..[98,1965+21]) + [] + [] + ] + signature_item (shortcut_ext_attr.ml[99,1987+2]..[99,1987+31]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[99,1987+2]..[99,1987+31]) + Psig_value + value_description "x" (shortcut_ext_attr.ml[99,1987+21]..[99,1987+22]) (shortcut_ext_attr.ml[99,1987+2]..[99,1987+31]) + attribute "foo" + [] + core_type (shortcut_ext_attr.ml[99,1987+25]..[99,1987+26]) + Ptyp_constr "t" (shortcut_ext_attr.ml[99,1987+25]..[99,1987+26]) + [] + [ + "" + ] + ] + signature_item (shortcut_ext_attr.ml[101,2020+2]..[102,2045+20]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[101,2020+2]..[102,2045+20]) + Psig_type Rec + [ + type_declaration "t" (shortcut_ext_attr.ml[101,2020+17]..[101,2020+18]) (shortcut_ext_attr.ml[101,2020+2]..[101,2020+24]) + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (shortcut_ext_attr.ml[101,2020+21]..[101,2020+24]) + Ptyp_constr "int" (shortcut_ext_attr.ml[101,2020+21]..[101,2020+24]) + [] + type_declaration "t'" (shortcut_ext_attr.ml[102,2045+12]..[102,2045+14]) (shortcut_ext_attr.ml[102,2045+2]..[102,2045+20]) + attribute "foo" + [] + ptype_params = + [] + ptype_cstrs = + [] + ptype_kind = + Ptype_abstract + ptype_private = Public + ptype_manifest = + Some + core_type (shortcut_ext_attr.ml[102,2045+17]..[102,2045+20]) + Ptyp_constr "int" (shortcut_ext_attr.ml[102,2045+17]..[102,2045+20]) + [] + ] + ] + signature_item (shortcut_ext_attr.ml[103,2066+2]..[103,2066+23]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[103,2066+2]..[103,2066+23]) + Psig_typext + type_extension + attribute "foo" + [] + ptyext_path = "t" (shortcut_ext_attr.ml[103,2066+17]..[103,2066+18]) + ptyext_params = + [] + ptyext_constructors = + [ + extension_constructor (shortcut_ext_attr.ml[103,2066+22]..[103,2066+23]) + pext_name = "T" + pext_kind = + Pext_decl + [] + None + ] + ptyext_private = Public + ] + signature_item (shortcut_ext_attr.ml[105,2091+2]..[105,2091+23]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[105,2091+2]..[105,2091+23]) + Psig_exception + extension_constructor (shortcut_ext_attr.ml[105,2091+2]..[105,2091+23]) + attribute "foo" + [] + pext_name = "X" + pext_kind = + Pext_decl + [] + None + ] + signature_item (shortcut_ext_attr.ml[107,2116+2]..[107,2116+24]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[107,2116+2]..[107,2116+24]) + Psig_module "M" (shortcut_ext_attr.ml[107,2116+19]..[107,2116+20]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[107,2116+23]..[107,2116+24]) + Pmty_ident "S" (shortcut_ext_attr.ml[107,2116+23]..[107,2116+24]) + ] + signature_item (shortcut_ext_attr.ml[108,2141+2]..[109,2170+17]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[108,2141+2]..[109,2170+17]) + Psig_recmodule + [ + "M" (shortcut_ext_attr.ml[108,2141+23]..[108,2141+24]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[108,2141+27]..[108,2141+28]) + Pmty_ident "S" (shortcut_ext_attr.ml[108,2141+27]..[108,2141+28]) + "M" (shortcut_ext_attr.ml[109,2170+12]..[109,2170+13]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[109,2170+16]..[109,2170+17]) + Pmty_ident "S" (shortcut_ext_attr.ml[109,2170+16]..[109,2170+17]) + ] + ] + signature_item (shortcut_ext_attr.ml[110,2188+2]..[110,2188+24]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[110,2188+2]..[110,2188+24]) + Psig_module "M" (shortcut_ext_attr.ml[110,2188+19]..[110,2188+20]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[110,2188+23]..[110,2188+24]) + Pmty_alias "M" (shortcut_ext_attr.ml[110,2188+23]..[110,2188+24]) + ] + signature_item (shortcut_ext_attr.ml[112,2214+2]..[112,2214+29]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[112,2214+2]..[112,2214+29]) + Psig_modtype "S" (shortcut_ext_attr.ml[112,2214+24]..[112,2214+25]) + attribute "foo" + [] + module_type (shortcut_ext_attr.ml[112,2214+28]..[112,2214+29]) + Pmty_ident "S" (shortcut_ext_attr.ml[112,2214+28]..[112,2214+29]) + ] + signature_item (shortcut_ext_attr.ml[114,2245+2]..[114,2245+21]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[114,2245+2]..[114,2245+21]) + Psig_include + module_type (shortcut_ext_attr.ml[114,2245+20]..[114,2245+21]) + Pmty_ident "M" (shortcut_ext_attr.ml[114,2245+20]..[114,2245+21]) + attribute "foo" + [] + ] + signature_item (shortcut_ext_attr.ml[115,2267+2]..[115,2267+18]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[115,2267+2]..[115,2267+18]) + Psig_open Fresh "M" (shortcut_ext_attr.ml[115,2267+17]..[115,2267+18]) + attribute "foo" + [] + ] + signature_item (shortcut_ext_attr.ml[117,2287+2]..[117,2287+23]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[117,2287+2]..[117,2287+23]) + Psig_class + [ + class_description (shortcut_ext_attr.ml[117,2287+2]..[117,2287+23]) + attribute "foo" + [] + pci_virt = Concrete + pci_params = + [] + pci_name = "x" (shortcut_ext_attr.ml[117,2287+18]..[117,2287+19]) + pci_expr = + class_type (shortcut_ext_attr.ml[117,2287+22]..[117,2287+23]) + Pcty_constr "t" (shortcut_ext_attr.ml[117,2287+22]..[117,2287+23]) + [] + ] + ] + signature_item (shortcut_ext_attr.ml[118,2311+2]..[118,2311+28]) ghost + Psig_extension "foo" + [ + signature_item (shortcut_ext_attr.ml[118,2311+2]..[118,2311+28]) + Psig_class_type + [ + class_type_declaration (shortcut_ext_attr.ml[118,2311+2]..[118,2311+28]) + attribute "foo" + [] + pci_virt = Concrete + pci_params = + [] + pci_name = "x" (shortcut_ext_attr.ml[118,2311+23]..[118,2311+24]) + pci_expr = + class_type (shortcut_ext_attr.ml[118,2311+27]..[118,2311+28]) + Pcty_constr "x" (shortcut_ext_attr.ml[118,2311+27]..[118,2311+28]) + [] + ] + ] + ] +] + +File "shortcut_ext_attr.ml", line 10, characters 6-9: +Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/parsing/shortcut_ext_attr.ml b/testsuite/tests/parsing/shortcut_ext_attr.ml index 7f6d1f51..222e7a0c 100644 --- a/testsuite/tests/parsing/shortcut_ext_attr.ml +++ b/testsuite/tests/parsing/shortcut_ext_attr.ml @@ -1,4 +1,10 @@ - +(* TEST + flags = "-dparsetree" + ocamlc_byte_exit_status = "2" + * setup-ocamlc.byte-build-env + ** ocamlc.byte + *** check-ocamlc.byte-output +*) (* Expressions *) let () = let%foo[@foo] x = 3 diff --git a/testsuite/tests/parsing/shortcut_ext_attr.ml.reference b/testsuite/tests/parsing/shortcut_ext_attr.ml.reference deleted file mode 100644 index c3101349..00000000 --- a/testsuite/tests/parsing/shortcut_ext_attr.ml.reference +++ /dev/null @@ -1,978 +0,0 @@ -[ - structure_item (shortcut_ext_attr.ml[3,19+0]..[24,570+31]) - Pstr_value Nonrec - [ - - pattern (shortcut_ext_attr.ml[3,19+4]..[3,19+6]) - Ppat_construct "()" (shortcut_ext_attr.ml[3,19+4]..[3,19+6]) - None - expression (shortcut_ext_attr.ml[4,28+2]..[24,570+31]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[4,28+2]..[24,570+31]) - Pstr_eval - expression (shortcut_ext_attr.ml[4,28+2]..[24,570+31]) - Pexp_let Nonrec - [ - - attribute "foo" - [] - pattern (shortcut_ext_attr.ml[4,28+16]..[4,28+17]) - Ppat_var "x" (shortcut_ext_attr.ml[4,28+16]..[4,28+17]) - expression (shortcut_ext_attr.ml[4,28+20]..[4,28+21]) - Pexp_constant PConst_int (3,None) - - attribute "foo" - [] - pattern (shortcut_ext_attr.ml[5,50+12]..[5,50+13]) - Ppat_var "y" (shortcut_ext_attr.ml[5,50+12]..[5,50+13]) - expression (shortcut_ext_attr.ml[5,50+16]..[5,50+17]) - Pexp_constant PConst_int (4,None) - ] - expression (shortcut_ext_attr.ml[6,71+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[6,71+2]..[6,71+36]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[6,71+3]..[6,71+35]) - Pstr_eval - expression (shortcut_ext_attr.ml[6,71+3]..[6,71+35]) - attribute "foo" - [] - Pexp_letmodule "M" (shortcut_ext_attr.ml[6,71+24]..[6,71+25]) - module_expr (shortcut_ext_attr.ml[6,71+28]..[6,71+29]) - Pmod_ident "M" (shortcut_ext_attr.ml[6,71+28]..[6,71+29]) - expression (shortcut_ext_attr.ml[6,71+33]..[6,71+35]) - Pexp_construct "()" (shortcut_ext_attr.ml[6,71+33]..[6,71+35]) - None - ] - expression (shortcut_ext_attr.ml[7,110+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[7,110+2]..[7,110+30]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[7,110+3]..[7,110+29]) - Pstr_eval - expression (shortcut_ext_attr.ml[7,110+3]..[7,110+29]) - attribute "foo" - [] - Pexp_open Fresh ""M" (shortcut_ext_attr.ml[7,110+22]..[7,110+23])" - expression (shortcut_ext_attr.ml[7,110+27]..[7,110+29]) - Pexp_construct "()" (shortcut_ext_attr.ml[7,110+27]..[7,110+29]) - None - ] - expression (shortcut_ext_attr.ml[8,143+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[8,143+2]..[8,143+25]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[8,143+3]..[8,143+24]) - Pstr_eval - expression (shortcut_ext_attr.ml[8,143+3]..[8,143+24]) - attribute "foo" - [] - Pexp_fun - Nolabel - None - pattern (shortcut_ext_attr.ml[8,143+17]..[8,143+18]) - Ppat_var "x" (shortcut_ext_attr.ml[8,143+17]..[8,143+18]) - expression (shortcut_ext_attr.ml[8,143+22]..[8,143+24]) - Pexp_construct "()" (shortcut_ext_attr.ml[8,143+22]..[8,143+24]) - None - ] - expression (shortcut_ext_attr.ml[9,171+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[9,171+2]..[9,171+30]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[9,171+3]..[9,171+29]) - Pstr_eval - expression (shortcut_ext_attr.ml[9,171+3]..[9,171+29]) - attribute "foo" - [] - Pexp_function - [ - - pattern (shortcut_ext_attr.ml[9,171+22]..[9,171+23]) - Ppat_var "x" (shortcut_ext_attr.ml[9,171+22]..[9,171+23]) - expression (shortcut_ext_attr.ml[9,171+27]..[9,171+29]) - Pexp_construct "()" (shortcut_ext_attr.ml[9,171+27]..[9,171+29]) - None - ] - ] - expression (shortcut_ext_attr.ml[10,204+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[10,204+2]..[10,204+33]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[10,204+3]..[10,204+32]) - Pstr_eval - expression (shortcut_ext_attr.ml[10,204+3]..[10,204+32]) - attribute "foo" - [] - Pexp_try - expression (shortcut_ext_attr.ml[10,204+17]..[10,204+19]) - Pexp_construct "()" (shortcut_ext_attr.ml[10,204+17]..[10,204+19]) - None - [ - - pattern (shortcut_ext_attr.ml[10,204+25]..[10,204+26]) - Ppat_any - expression (shortcut_ext_attr.ml[10,204+30]..[10,204+32]) - Pexp_construct "()" (shortcut_ext_attr.ml[10,204+30]..[10,204+32]) - None - ] - ] - expression (shortcut_ext_attr.ml[11,240+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[11,240+2]..[11,240+35]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[11,240+3]..[11,240+34]) - Pstr_eval - expression (shortcut_ext_attr.ml[11,240+3]..[11,240+34]) - attribute "foo" - [] - Pexp_ifthenelse - expression (shortcut_ext_attr.ml[11,240+16]..[11,240+18]) - Pexp_construct "()" (shortcut_ext_attr.ml[11,240+16]..[11,240+18]) - None - expression (shortcut_ext_attr.ml[11,240+24]..[11,240+26]) - Pexp_construct "()" (shortcut_ext_attr.ml[11,240+24]..[11,240+26]) - None - Some - expression (shortcut_ext_attr.ml[11,240+32]..[11,240+34]) - Pexp_construct "()" (shortcut_ext_attr.ml[11,240+32]..[11,240+34]) - None - ] - expression (shortcut_ext_attr.ml[12,278+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[12,278+2]..[12,278+31]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[12,278+2]..[12,278+31]) - Pstr_eval - expression (shortcut_ext_attr.ml[12,278+2]..[12,278+31]) - attribute "foo" - [] - Pexp_while - expression (shortcut_ext_attr.ml[12,278+18]..[12,278+20]) - Pexp_construct "()" (shortcut_ext_attr.ml[12,278+18]..[12,278+20]) - None - expression (shortcut_ext_attr.ml[12,278+24]..[12,278+26]) - Pexp_construct "()" (shortcut_ext_attr.ml[12,278+24]..[12,278+26]) - None - ] - expression (shortcut_ext_attr.ml[13,312+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[13,312+2]..[13,312+39]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[13,312+2]..[13,312+39]) - Pstr_eval - expression (shortcut_ext_attr.ml[13,312+2]..[13,312+39]) - attribute "foo" - [] - Pexp_for Up - pattern (shortcut_ext_attr.ml[13,312+16]..[13,312+17]) - Ppat_var "x" (shortcut_ext_attr.ml[13,312+16]..[13,312+17]) - expression (shortcut_ext_attr.ml[13,312+20]..[13,312+22]) - Pexp_construct "()" (shortcut_ext_attr.ml[13,312+20]..[13,312+22]) - None - expression (shortcut_ext_attr.ml[13,312+26]..[13,312+28]) - Pexp_construct "()" (shortcut_ext_attr.ml[13,312+26]..[13,312+28]) - None - expression (shortcut_ext_attr.ml[13,312+32]..[13,312+34]) - Pexp_construct "()" (shortcut_ext_attr.ml[13,312+32]..[13,312+34]) - None - ] - expression (shortcut_ext_attr.ml[14,354+2]..[24,570+31]) - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[14,354+2]..[24,570+31]) - Pstr_eval - expression (shortcut_ext_attr.ml[14,354+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[14,354+2]..[14,354+4]) - Pexp_construct "()" (shortcut_ext_attr.ml[14,354+2]..[14,354+4]) - None - expression (shortcut_ext_attr.ml[14,354+11]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[14,354+11]..[14,354+13]) - Pexp_construct "()" (shortcut_ext_attr.ml[14,354+11]..[14,354+13]) - None - expression (shortcut_ext_attr.ml[15,370+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[15,370+2]..[15,370+23]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[15,370+2]..[15,370+23]) - Pstr_eval - expression (shortcut_ext_attr.ml[15,370+2]..[15,370+23]) - attribute "foo" - [] - Pexp_assert - expression (shortcut_ext_attr.ml[15,370+19]..[15,370+23]) - Pexp_construct "true" (shortcut_ext_attr.ml[15,370+19]..[15,370+23]) - None - ] - expression (shortcut_ext_attr.ml[16,396+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[16,396+2]..[16,396+18]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[16,396+2]..[16,396+18]) - Pstr_eval - expression (shortcut_ext_attr.ml[16,396+2]..[16,396+18]) - attribute "foo" - [] - Pexp_lazy - expression (shortcut_ext_attr.ml[16,396+17]..[16,396+18]) - Pexp_ident "x" (shortcut_ext_attr.ml[16,396+17]..[16,396+18]) - ] - expression (shortcut_ext_attr.ml[17,417+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[17,417+2]..[17,417+22]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[17,417+2]..[17,417+22]) - Pstr_eval - expression (shortcut_ext_attr.ml[17,417+2]..[17,417+22]) - attribute "foo" - [] - Pexp_object - class_structure - pattern (shortcut_ext_attr.ml[17,417+18]..[17,417+18]) ghost - Ppat_any - [] - ] - expression (shortcut_ext_attr.ml[18,442+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[18,442+2]..[18,442+23]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[18,442+2]..[18,442+23]) - Pstr_eval - expression (shortcut_ext_attr.ml[18,442+2]..[18,442+23]) - attribute "foo" - [] - Pexp_constant PConst_int (3,None) - ] - expression (shortcut_ext_attr.ml[19,468+2]..[24,570+31]) - Pexp_sequence - expression (shortcut_ext_attr.ml[19,468+2]..[19,468+17]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[19,468+2]..[19,468+17]) - Pstr_eval - expression (shortcut_ext_attr.ml[19,468+2]..[19,468+17]) - attribute "foo" - [] - Pexp_new "x" (shortcut_ext_attr.ml[19,468+16]..[19,468+17]) - ] - expression (shortcut_ext_attr.ml[21,489+2]..[24,570+31]) ghost - Pexp_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[21,489+2]..[24,570+31]) - Pstr_eval - expression (shortcut_ext_attr.ml[21,489+2]..[24,570+31]) - attribute "foo" - [] - Pexp_match - expression (shortcut_ext_attr.ml[21,489+18]..[21,489+20]) - Pexp_construct "()" (shortcut_ext_attr.ml[21,489+18]..[21,489+20]) - None - [ - - pattern (shortcut_ext_attr.ml[23,543+4]..[23,543+20]) ghost - Ppat_extension "foo" - pattern (shortcut_ext_attr.ml[23,543+4]..[23,543+20]) - attribute "foo" - [] - Ppat_lazy - pattern (shortcut_ext_attr.ml[23,543+19]..[23,543+20]) - Ppat_var "x" (shortcut_ext_attr.ml[23,543+19]..[23,543+20]) - expression (shortcut_ext_attr.ml[23,543+24]..[23,543+26]) - Pexp_construct "()" (shortcut_ext_attr.ml[23,543+24]..[23,543+26]) - None - - pattern (shortcut_ext_attr.ml[24,570+4]..[24,570+25]) ghost - Ppat_extension "foo" - pattern (shortcut_ext_attr.ml[24,570+4]..[24,570+25]) - attribute "foo" - [] - Ppat_exception - pattern (shortcut_ext_attr.ml[24,570+24]..[24,570+25]) - Ppat_var "x" (shortcut_ext_attr.ml[24,570+24]..[24,570+25]) - expression (shortcut_ext_attr.ml[24,570+29]..[24,570+31]) - Pexp_construct "()" (shortcut_ext_attr.ml[24,570+29]..[24,570+31]) - None - ] - ] - ] - ] - ] - structure_item (shortcut_ext_attr.ml[28,628+0]..[40,898+5]) - Pstr_class - [ - class_declaration (shortcut_ext_attr.ml[28,628+0]..[40,898+5]) - pci_virt = Concrete - pci_params = - [] - pci_name = "x" (shortcut_ext_attr.ml[28,628+6]..[28,628+7]) - pci_expr = - class_expr (shortcut_ext_attr.ml[29,638+12]..[40,898+5]) - attribute "foo" - [] - Pcl_fun - Nolabel - None - pattern (shortcut_ext_attr.ml[29,638+12]..[29,638+13]) - Ppat_var "x" (shortcut_ext_attr.ml[29,638+12]..[29,638+13]) - class_expr (shortcut_ext_attr.ml[30,655+2]..[40,898+5]) - Pcl_let Nonrec - [ - - attribute "foo" - [] - pattern (shortcut_ext_attr.ml[30,655+12]..[30,655+13]) - Ppat_var "x" (shortcut_ext_attr.ml[30,655+12]..[30,655+13]) - expression (shortcut_ext_attr.ml[30,655+16]..[30,655+17]) - Pexp_constant PConst_int (3,None) - ] - class_expr (shortcut_ext_attr.ml[31,676+2]..[40,898+5]) - attribute "foo" - [] - Pcl_structure - class_structure - pattern (shortcut_ext_attr.ml[31,676+14]..[31,676+14]) ghost - Ppat_any - [ - class_field (shortcut_ext_attr.ml[32,691+4]..[32,691+19]) - attribute "foo" - [] - Pcf_inherit Fresh - class_expr (shortcut_ext_attr.ml[32,691+18]..[32,691+19]) - Pcl_constr "x" (shortcut_ext_attr.ml[32,691+18]..[32,691+19]) - [] - None - class_field (shortcut_ext_attr.ml[33,711+4]..[33,711+19]) - attribute "foo" - [] - Pcf_val Immutable - "x" (shortcut_ext_attr.ml[33,711+14]..[33,711+15]) - Concrete Fresh - expression (shortcut_ext_attr.ml[33,711+18]..[33,711+19]) - Pexp_constant PConst_int (3,None) - class_field (shortcut_ext_attr.ml[34,731+4]..[34,731+27]) - attribute "foo" - [] - Pcf_val Immutable - "x" (shortcut_ext_attr.ml[34,731+22]..[34,731+23]) - Virtual - core_type (shortcut_ext_attr.ml[34,731+26]..[34,731+27]) - Ptyp_constr "t" (shortcut_ext_attr.ml[34,731+26]..[34,731+27]) - [] - class_field (shortcut_ext_attr.ml[35,759+4]..[35,759+28]) - attribute "foo" - [] - Pcf_val Mutable - "x" (shortcut_ext_attr.ml[35,759+23]..[35,759+24]) - Concrete Override - expression (shortcut_ext_attr.ml[35,759+27]..[35,759+28]) - Pexp_constant PConst_int (3,None) - class_field (shortcut_ext_attr.ml[36,788+4]..[36,788+22]) - attribute "foo" - [] - Pcf_method Public - "x" (shortcut_ext_attr.ml[36,788+17]..[36,788+18]) - Concrete Fresh - expression (shortcut_ext_attr.ml[36,788+10]..[36,788+22]) ghost - Pexp_poly - expression (shortcut_ext_attr.ml[36,788+21]..[36,788+22]) - Pexp_constant PConst_int (3,None) - None - class_field (shortcut_ext_attr.ml[37,811+4]..[37,811+30]) - attribute "foo" - [] - Pcf_method Public - "x" (shortcut_ext_attr.ml[37,811+25]..[37,811+26]) - Virtual - core_type (shortcut_ext_attr.ml[37,811+29]..[37,811+30]) - Ptyp_constr "t" (shortcut_ext_attr.ml[37,811+29]..[37,811+30]) - [] - class_field (shortcut_ext_attr.ml[38,842+4]..[38,842+31]) - attribute "foo" - [] - Pcf_method Private - "x" (shortcut_ext_attr.ml[38,842+26]..[38,842+27]) - Concrete Override - expression (shortcut_ext_attr.ml[38,842+10]..[38,842+31]) ghost - Pexp_poly - expression (shortcut_ext_attr.ml[38,842+30]..[38,842+31]) - Pexp_constant PConst_int (3,None) - None - class_field (shortcut_ext_attr.ml[39,874+4]..[39,874+23]) - attribute "foo" - [] - Pcf_initializer - expression (shortcut_ext_attr.ml[39,874+22]..[39,874+23]) - Pexp_ident "x" (shortcut_ext_attr.ml[39,874+22]..[39,874+23]) - ] - ] - structure_item (shortcut_ext_attr.ml[43,934+0]..[51,1114+5]) - Pstr_class_type - [ - class_type_declaration (shortcut_ext_attr.ml[43,934+0]..[51,1114+5]) - pci_virt = Concrete - pci_params = - [] - pci_name = "t" (shortcut_ext_attr.ml[43,934+11]..[43,934+12]) - pci_expr = - class_type (shortcut_ext_attr.ml[44,949+2]..[51,1114+5]) - attribute "foo" - [] - Pcty_signature - class_signature - core_type (shortcut_ext_attr.ml[44,949+14]..[44,949+14]) - Ptyp_any - [ - class_type_field (shortcut_ext_attr.ml[45,964+4]..[45,964+19]) - attribute "foo" - [] - Pctf_inherit - class_type (shortcut_ext_attr.ml[45,964+18]..[45,964+19]) - Pcty_constr "t" (shortcut_ext_attr.ml[45,964+18]..[45,964+19]) - [] - class_type_field (shortcut_ext_attr.ml[46,984+4]..[46,984+19]) - attribute "foo" - [] - Pctf_val "x" Immutable Concrete - core_type (shortcut_ext_attr.ml[46,984+18]..[46,984+19]) - Ptyp_constr "t" (shortcut_ext_attr.ml[46,984+18]..[46,984+19]) - [] - class_type_field (shortcut_ext_attr.ml[47,1004+4]..[47,1004+27]) - attribute "foo" - [] - Pctf_val "x" Mutable Concrete - core_type (shortcut_ext_attr.ml[47,1004+26]..[47,1004+27]) - Ptyp_constr "t" (shortcut_ext_attr.ml[47,1004+26]..[47,1004+27]) - [] - class_type_field (shortcut_ext_attr.ml[48,1032+4]..[48,1032+22]) - attribute "foo" - [] - Pctf_method "x" Public Concrete - core_type (shortcut_ext_attr.ml[48,1032+21]..[48,1032+22]) - Ptyp_constr "t" (shortcut_ext_attr.ml[48,1032+21]..[48,1032+22]) - [] - class_type_field (shortcut_ext_attr.ml[49,1055+4]..[49,1055+30]) - attribute "foo" - [] - Pctf_method "x" Private Concrete - core_type (shortcut_ext_attr.ml[49,1055+29]..[49,1055+30]) - Ptyp_constr "t" (shortcut_ext_attr.ml[49,1055+29]..[49,1055+30]) - [] - class_type_field (shortcut_ext_attr.ml[50,1086+4]..[50,1086+27]) - attribute "foo" - [] - Pctf_constraint - core_type (shortcut_ext_attr.ml[50,1086+21]..[50,1086+22]) - Ptyp_constr "t" (shortcut_ext_attr.ml[50,1086+21]..[50,1086+22]) - [] - core_type (shortcut_ext_attr.ml[50,1086+25]..[50,1086+27]) - Ptyp_constr "t'" (shortcut_ext_attr.ml[50,1086+25]..[50,1086+27]) - [] - ] - ] - structure_item (shortcut_ext_attr.ml[54,1144+0]..[55,1153+22]) - Pstr_type Rec - [ - type_declaration "t" (shortcut_ext_attr.ml[54,1144+5]..[54,1144+6]) (shortcut_ext_attr.ml[54,1144+0]..[55,1153+22]) - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (shortcut_ext_attr.ml[55,1153+2]..[55,1153+22]) ghost - Ptyp_extension "foo" - core_type (shortcut_ext_attr.ml[55,1153+2]..[55,1153+22]) - attribute "foo" - [] - Ptyp_package "M" (shortcut_ext_attr.ml[55,1153+20]..[55,1153+21]) - [] - ] - structure_item (shortcut_ext_attr.ml[58,1202+0]..[61,1258+22]) - Pstr_module - "M" (shortcut_ext_attr.ml[58,1202+7]..[58,1202+8]) - module_expr (shortcut_ext_attr.ml[59,1213+2]..[61,1258+22]) - attribute "foo" - [] - Pmod_functor "M" (shortcut_ext_attr.ml[59,1213+17]..[59,1213+18]) - module_type (shortcut_ext_attr.ml[59,1213+21]..[59,1213+22]) - Pmty_ident "S" (shortcut_ext_attr.ml[59,1213+21]..[59,1213+22]) - module_expr (shortcut_ext_attr.ml[60,1240+4]..[61,1258+22]) - Pmod_apply - module_expr (shortcut_ext_attr.ml[60,1240+4]..[60,1240+17]) - attribute "foo" - [] - Pmod_unpack - expression (shortcut_ext_attr.ml[60,1240+15]..[60,1240+16]) - Pexp_ident "x" (shortcut_ext_attr.ml[60,1240+15]..[60,1240+16]) - module_expr (shortcut_ext_attr.ml[61,1258+5]..[61,1258+21]) - attribute "foo" - [] - Pmod_structure - [] - structure_item (shortcut_ext_attr.ml[64,1311+0]..[67,1384+19]) - Pstr_modtype "S" (shortcut_ext_attr.ml[64,1311+12]..[64,1311+13]) - module_type (shortcut_ext_attr.ml[65,1327+2]..[67,1384+19]) - attribute "foo" - [] - Pmty_functor "M" (shortcut_ext_attr.ml[65,1327+17]..[65,1327+18]) - module_type (shortcut_ext_attr.ml[65,1327+19]..[65,1327+20]) - Pmty_ident "S" (shortcut_ext_attr.ml[65,1327+19]..[65,1327+20]) - module_type (shortcut_ext_attr.ml[66,1352+4]..[67,1384+19]) - Pmty_functor "_" (_none_[1,0+-1]..[1,0+-1]) ghost - module_type (shortcut_ext_attr.ml[66,1352+5]..[66,1352+27]) - attribute "foo" - [] - Pmty_typeof - module_expr (shortcut_ext_attr.ml[66,1352+26]..[66,1352+27]) - Pmod_ident "M" (shortcut_ext_attr.ml[66,1352+26]..[66,1352+27]) - module_type (shortcut_ext_attr.ml[67,1384+5]..[67,1384+18]) - attribute "foo" - [] - Pmty_signature - [] - structure_item (shortcut_ext_attr.ml[70,1427+0]..[71,1447+15]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[70,1427+0]..[71,1447+15]) - Pstr_value Nonrec - [ - - attribute "foo" - [] - pattern (shortcut_ext_attr.ml[70,1427+14]..[70,1427+15]) - Ppat_var "x" (shortcut_ext_attr.ml[70,1427+14]..[70,1427+15]) - expression (shortcut_ext_attr.ml[70,1427+18]..[70,1427+19]) - Pexp_constant PConst_int (4,None) - - attribute "foo" - [] - pattern (shortcut_ext_attr.ml[71,1447+10]..[71,1447+11]) - Ppat_var "y" (shortcut_ext_attr.ml[71,1447+10]..[71,1447+11]) - expression (shortcut_ext_attr.ml[71,1447+14]..[71,1447+15]) - Pexp_ident "x" (shortcut_ext_attr.ml[71,1447+14]..[71,1447+15]) - ] - ] - structure_item (shortcut_ext_attr.ml[73,1464+0]..[74,1487+17]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[73,1464+0]..[74,1487+17]) - Pstr_type Rec - [ - type_declaration "t" (shortcut_ext_attr.ml[73,1464+15]..[73,1464+16]) (shortcut_ext_attr.ml[73,1464+0]..[73,1464+22]) - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (shortcut_ext_attr.ml[73,1464+19]..[73,1464+22]) - Ptyp_constr "int" (shortcut_ext_attr.ml[73,1464+19]..[73,1464+22]) - [] - type_declaration "t" (shortcut_ext_attr.ml[74,1487+10]..[74,1487+11]) (shortcut_ext_attr.ml[74,1487+0]..[74,1487+17]) - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (shortcut_ext_attr.ml[74,1487+14]..[74,1487+17]) - Ptyp_constr "int" (shortcut_ext_attr.ml[74,1487+14]..[74,1487+17]) - [] - ] - ] - structure_item (shortcut_ext_attr.ml[75,1505+0]..[75,1505+21]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[75,1505+0]..[75,1505+21]) - Pstr_typext - type_extension - attribute "foo" - [] - ptyext_path = "t" (shortcut_ext_attr.ml[75,1505+15]..[75,1505+16]) - ptyext_params = - [] - ptyext_constructors = - [ - extension_constructor (shortcut_ext_attr.ml[75,1505+20]..[75,1505+21]) - pext_name = "T" - pext_kind = - Pext_decl - [] - None - ] - ptyext_private = Public - ] - structure_item (shortcut_ext_attr.ml[77,1528+0]..[77,1528+21]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[77,1528+0]..[77,1528+21]) - Pstr_class - [ - class_declaration (shortcut_ext_attr.ml[77,1528+0]..[77,1528+21]) - attribute "foo" - [] - pci_virt = Concrete - pci_params = - [] - pci_name = "x" (shortcut_ext_attr.ml[77,1528+16]..[77,1528+17]) - pci_expr = - class_expr (shortcut_ext_attr.ml[77,1528+20]..[77,1528+21]) - Pcl_constr "x" (shortcut_ext_attr.ml[77,1528+20]..[77,1528+21]) - [] - ] - ] - structure_item (shortcut_ext_attr.ml[78,1550+0]..[78,1550+26]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[78,1550+0]..[78,1550+26]) - Pstr_class_type - [ - class_type_declaration (shortcut_ext_attr.ml[78,1550+0]..[78,1550+26]) - attribute "foo" - [] - pci_virt = Concrete - pci_params = - [] - pci_name = "x" (shortcut_ext_attr.ml[78,1550+21]..[78,1550+22]) - pci_expr = - class_type (shortcut_ext_attr.ml[78,1550+25]..[78,1550+26]) - Pcty_constr "x" (shortcut_ext_attr.ml[78,1550+25]..[78,1550+26]) - [] - ] - ] - structure_item (shortcut_ext_attr.ml[79,1577+0]..[79,1577+30]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[79,1577+0]..[79,1577+30]) - Pstr_primitive - value_description "x" (shortcut_ext_attr.ml[79,1577+19]..[79,1577+20]) (shortcut_ext_attr.ml[79,1577+0]..[79,1577+30]) - attribute "foo" - [] - core_type (shortcut_ext_attr.ml[79,1577+23]..[79,1577+24]) - Ptyp_any - [ - "" - ] - ] - structure_item (shortcut_ext_attr.ml[80,1608+0]..[80,1608+21]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[80,1608+0]..[80,1608+21]) - Pstr_exception - extension_constructor (shortcut_ext_attr.ml[80,1608+0]..[80,1608+21]) - attribute "foo" - [] - pext_name = "X" - pext_kind = - Pext_decl - [] - None - ] - structure_item (shortcut_ext_attr.ml[82,1631+0]..[82,1631+22]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[82,1631+0]..[82,1631+22]) - Pstr_module - "M" (shortcut_ext_attr.ml[82,1631+17]..[82,1631+18]) - attribute "foo" - [] - module_expr (shortcut_ext_attr.ml[82,1631+21]..[82,1631+22]) - Pmod_ident "M" (shortcut_ext_attr.ml[82,1631+21]..[82,1631+22]) - ] - structure_item (shortcut_ext_attr.ml[83,1654+0]..[84,1685+19]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[83,1654+0]..[84,1685+19]) - Pstr_recmodule - [ - "M" (shortcut_ext_attr.ml[83,1654+21]..[83,1654+22]) - attribute "foo" - [] - module_expr (shortcut_ext_attr.ml[83,1654+23]..[83,1654+30]) - Pmod_constraint - module_expr (shortcut_ext_attr.ml[83,1654+29]..[83,1654+30]) - Pmod_ident "M" (shortcut_ext_attr.ml[83,1654+29]..[83,1654+30]) - module_type (shortcut_ext_attr.ml[83,1654+25]..[83,1654+26]) - Pmty_ident "S" (shortcut_ext_attr.ml[83,1654+25]..[83,1654+26]) - "M" (shortcut_ext_attr.ml[84,1685+10]..[84,1685+11]) - attribute "foo" - [] - module_expr (shortcut_ext_attr.ml[84,1685+12]..[84,1685+19]) - Pmod_constraint - module_expr (shortcut_ext_attr.ml[84,1685+18]..[84,1685+19]) - Pmod_ident "M" (shortcut_ext_attr.ml[84,1685+18]..[84,1685+19]) - module_type (shortcut_ext_attr.ml[84,1685+14]..[84,1685+15]) - Pmty_ident "S" (shortcut_ext_attr.ml[84,1685+14]..[84,1685+15]) - ] - ] - structure_item (shortcut_ext_attr.ml[85,1705+0]..[85,1705+27]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[85,1705+0]..[85,1705+27]) - Pstr_modtype "S" (shortcut_ext_attr.ml[85,1705+22]..[85,1705+23]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[85,1705+26]..[85,1705+27]) - Pmty_ident "S" (shortcut_ext_attr.ml[85,1705+26]..[85,1705+27]) - ] - structure_item (shortcut_ext_attr.ml[87,1734+0]..[87,1734+19]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[87,1734+0]..[87,1734+19]) - Pstr_include attribute "foo" - [] - module_expr (shortcut_ext_attr.ml[87,1734+18]..[87,1734+19]) - Pmod_ident "M" (shortcut_ext_attr.ml[87,1734+18]..[87,1734+19]) - ] - structure_item (shortcut_ext_attr.ml[88,1754+0]..[88,1754+16]) ghost - Pstr_extension "foo" - [ - structure_item (shortcut_ext_attr.ml[88,1754+0]..[88,1754+16]) - Pstr_open Fresh "M" (shortcut_ext_attr.ml[88,1754+15]..[88,1754+16]) - attribute "foo" - [] - ] - structure_item (shortcut_ext_attr.ml[91,1794+0]..[114,2190+3]) - Pstr_modtype "S" (shortcut_ext_attr.ml[91,1794+12]..[91,1794+13]) - module_type (shortcut_ext_attr.ml[91,1794+16]..[114,2190+3]) - Pmty_signature - [ - signature_item (shortcut_ext_attr.ml[92,1814+2]..[92,1814+21]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[92,1814+2]..[92,1814+21]) - Psig_value - value_description "x" (shortcut_ext_attr.ml[92,1814+16]..[92,1814+17]) (shortcut_ext_attr.ml[92,1814+2]..[92,1814+21]) - attribute "foo" - [] - core_type (shortcut_ext_attr.ml[92,1814+20]..[92,1814+21]) - Ptyp_constr "t" (shortcut_ext_attr.ml[92,1814+20]..[92,1814+21]) - [] - [] - ] - signature_item (shortcut_ext_attr.ml[93,1836+2]..[93,1836+31]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[93,1836+2]..[93,1836+31]) - Psig_value - value_description "x" (shortcut_ext_attr.ml[93,1836+21]..[93,1836+22]) (shortcut_ext_attr.ml[93,1836+2]..[93,1836+31]) - attribute "foo" - [] - core_type (shortcut_ext_attr.ml[93,1836+25]..[93,1836+26]) - Ptyp_constr "t" (shortcut_ext_attr.ml[93,1836+25]..[93,1836+26]) - [] - [ - "" - ] - ] - signature_item (shortcut_ext_attr.ml[95,1869+2]..[96,1894+20]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[95,1869+2]..[96,1894+20]) - Psig_type Rec - [ - type_declaration "t" (shortcut_ext_attr.ml[95,1869+17]..[95,1869+18]) (shortcut_ext_attr.ml[95,1869+2]..[95,1869+24]) - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (shortcut_ext_attr.ml[95,1869+21]..[95,1869+24]) - Ptyp_constr "int" (shortcut_ext_attr.ml[95,1869+21]..[95,1869+24]) - [] - type_declaration "t'" (shortcut_ext_attr.ml[96,1894+12]..[96,1894+14]) (shortcut_ext_attr.ml[96,1894+2]..[96,1894+20]) - attribute "foo" - [] - ptype_params = - [] - ptype_cstrs = - [] - ptype_kind = - Ptype_abstract - ptype_private = Public - ptype_manifest = - Some - core_type (shortcut_ext_attr.ml[96,1894+17]..[96,1894+20]) - Ptyp_constr "int" (shortcut_ext_attr.ml[96,1894+17]..[96,1894+20]) - [] - ] - ] - signature_item (shortcut_ext_attr.ml[97,1915+2]..[97,1915+23]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[97,1915+2]..[97,1915+23]) - Psig_typext - type_extension - attribute "foo" - [] - ptyext_path = "t" (shortcut_ext_attr.ml[97,1915+17]..[97,1915+18]) - ptyext_params = - [] - ptyext_constructors = - [ - extension_constructor (shortcut_ext_attr.ml[97,1915+22]..[97,1915+23]) - pext_name = "T" - pext_kind = - Pext_decl - [] - None - ] - ptyext_private = Public - ] - signature_item (shortcut_ext_attr.ml[99,1940+2]..[99,1940+23]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[99,1940+2]..[99,1940+23]) - Psig_exception - extension_constructor (shortcut_ext_attr.ml[99,1940+2]..[99,1940+23]) - attribute "foo" - [] - pext_name = "X" - pext_kind = - Pext_decl - [] - None - ] - signature_item (shortcut_ext_attr.ml[101,1965+2]..[101,1965+24]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[101,1965+2]..[101,1965+24]) - Psig_module "M" (shortcut_ext_attr.ml[101,1965+19]..[101,1965+20]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[101,1965+23]..[101,1965+24]) - Pmty_ident "S" (shortcut_ext_attr.ml[101,1965+23]..[101,1965+24]) - ] - signature_item (shortcut_ext_attr.ml[102,1990+2]..[103,2019+17]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[102,1990+2]..[103,2019+17]) - Psig_recmodule - [ - "M" (shortcut_ext_attr.ml[102,1990+23]..[102,1990+24]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[102,1990+27]..[102,1990+28]) - Pmty_ident "S" (shortcut_ext_attr.ml[102,1990+27]..[102,1990+28]) - "M" (shortcut_ext_attr.ml[103,2019+12]..[103,2019+13]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[103,2019+16]..[103,2019+17]) - Pmty_ident "S" (shortcut_ext_attr.ml[103,2019+16]..[103,2019+17]) - ] - ] - signature_item (shortcut_ext_attr.ml[104,2037+2]..[104,2037+24]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[104,2037+2]..[104,2037+24]) - Psig_module "M" (shortcut_ext_attr.ml[104,2037+19]..[104,2037+20]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[104,2037+23]..[104,2037+24]) - Pmty_alias "M" (shortcut_ext_attr.ml[104,2037+23]..[104,2037+24]) - ] - signature_item (shortcut_ext_attr.ml[106,2063+2]..[106,2063+29]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[106,2063+2]..[106,2063+29]) - Psig_modtype "S" (shortcut_ext_attr.ml[106,2063+24]..[106,2063+25]) - attribute "foo" - [] - module_type (shortcut_ext_attr.ml[106,2063+28]..[106,2063+29]) - Pmty_ident "S" (shortcut_ext_attr.ml[106,2063+28]..[106,2063+29]) - ] - signature_item (shortcut_ext_attr.ml[108,2094+2]..[108,2094+21]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[108,2094+2]..[108,2094+21]) - Psig_include - module_type (shortcut_ext_attr.ml[108,2094+20]..[108,2094+21]) - Pmty_ident "M" (shortcut_ext_attr.ml[108,2094+20]..[108,2094+21]) - attribute "foo" - [] - ] - signature_item (shortcut_ext_attr.ml[109,2116+2]..[109,2116+18]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[109,2116+2]..[109,2116+18]) - Psig_open Fresh "M" (shortcut_ext_attr.ml[109,2116+17]..[109,2116+18]) - attribute "foo" - [] - ] - signature_item (shortcut_ext_attr.ml[111,2136+2]..[111,2136+23]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[111,2136+2]..[111,2136+23]) - Psig_class - [ - class_description (shortcut_ext_attr.ml[111,2136+2]..[111,2136+23]) - attribute "foo" - [] - pci_virt = Concrete - pci_params = - [] - pci_name = "x" (shortcut_ext_attr.ml[111,2136+18]..[111,2136+19]) - pci_expr = - class_type (shortcut_ext_attr.ml[111,2136+22]..[111,2136+23]) - Pcty_constr "t" (shortcut_ext_attr.ml[111,2136+22]..[111,2136+23]) - [] - ] - ] - signature_item (shortcut_ext_attr.ml[112,2160+2]..[112,2160+28]) ghost - Psig_extension "foo" - [ - signature_item (shortcut_ext_attr.ml[112,2160+2]..[112,2160+28]) - Psig_class_type - [ - class_type_declaration (shortcut_ext_attr.ml[112,2160+2]..[112,2160+28]) - attribute "foo" - [] - pci_virt = Concrete - pci_params = - [] - pci_name = "x" (shortcut_ext_attr.ml[112,2160+23]..[112,2160+24]) - pci_expr = - class_type (shortcut_ext_attr.ml[112,2160+27]..[112,2160+28]) - Pcty_constr "x" (shortcut_ext_attr.ml[112,2160+27]..[112,2160+28]) - [] - ] - ] - ] -] - -File "shortcut_ext_attr.ml", line 4, characters 6-9: -Error: Uninterpreted extension 'foo'. diff --git a/testsuite/tests/ppx-attributes/Makefile b/testsuite/tests/ppx-attributes/Makefile deleted file mode 100644 index bf9c06cf..00000000 --- a/testsuite/tests/ppx-attributes/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Peter Zotov * -#* * -#* Copyright 2014 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/ppx-attributes/ocamltests b/testsuite/tests/ppx-attributes/ocamltests new file mode 100644 index 00000000..b49aabbf --- /dev/null +++ b/testsuite/tests/ppx-attributes/ocamltests @@ -0,0 +1 @@ +warning.ml diff --git a/testsuite/tests/ppx-attributes/warning.ml b/testsuite/tests/ppx-attributes/warning.ml index f50c3d60..0c74ae7a 100644 --- a/testsuite/tests/ppx-attributes/warning.ml +++ b/testsuite/tests/ppx-attributes/warning.ml @@ -1,3 +1,6 @@ +(* TEST +*) + [@@@ocaml.warning "@A"] (* Fixture *) diff --git a/testsuite/tests/ppx-contexts/Makefile b/testsuite/tests/ppx-contexts/Makefile deleted file mode 100644 index fe936074..00000000 --- a/testsuite/tests/ppx-contexts/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -BASEDIR=../.. - -INCLUDES=\ - -I $(OTOPDIR)/parsing \ - -I $(OTOPDIR)/utils \ - -I $(OTOPDIR)/compilerlibs - -myppx=$(shell $(CYGPATH) '$(OCAMLRUN)') ./program$(EXE) - -.PHONY: run -run: program$(EXE) test.reference - @echo " ... testing -thread and -vmthread are propagated to PPX:" - @( $(OCAMLC) -c -thread -ppx '$(myppx)' test.ml \ - && $(OCAMLC) -c -vmthread -ppx '$(myppx)' test.ml ) 2> test.result - @$(DIFF) test.reference test.result >/dev/null \ - && echo " => passed" || echo " => failed" - -program$(EXE): program.ml Makefile - @$(OCAMLC) -o program$(EXE) $(INCLUDES) ocamlcommon.cma ./program.ml - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f program$(EXE) test.result *.cm* - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/ppx-contexts/program.ml b/testsuite/tests/ppx-contexts/myppx.ml similarity index 100% rename from testsuite/tests/ppx-contexts/program.ml rename to testsuite/tests/ppx-contexts/myppx.ml diff --git a/testsuite/tests/ppx-contexts/ocamltests b/testsuite/tests/ppx-contexts/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/ppx-contexts/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/ppx-contexts/test.reference b/testsuite/tests/ppx-contexts/test.compilers.reference similarity index 100% rename from testsuite/tests/ppx-contexts/test.reference rename to testsuite/tests/ppx-contexts/test.compilers.reference diff --git a/testsuite/tests/ppx-contexts/test.ml b/testsuite/tests/ppx-contexts/test.ml index e790aeb7..4ad226e9 100644 --- a/testsuite/tests/ppx-contexts/test.ml +++ b/testsuite/tests/ppx-contexts/test.ml @@ -1 +1,17 @@ +(* TEST +files = "myppx.ml" +include ocamlcommon +* setup-ocamlc.byte-build-env +** ocamlc.byte +program = "${test_build_directory}/myppx.exe" +all_modules = "myppx.ml" +*** ocamlc.byte +module = "test.ml" +flags = "-thread -ppx ${program}" +**** ocamlc.byte +module = "test.ml" +flags = "-vmthread -ppx ${program}" +***** check-ocamlc.byte-output +*) + (* empty *) diff --git a/testsuite/tests/prim-bigstring/Makefile b/testsuite/tests/prim-bigstring/Makefile deleted file mode 100644 index 379dba99..00000000 --- a/testsuite/tests/prim-bigstring/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -BASEDIR=../.. -LIBRARIES=unix bigarray -ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/$(UNIXLIBVAR)unix \ - -I $(OTOPDIR)/otherlibs/bigarray -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/bigarray - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/prim-bigstring/bigstring_access.ml b/testsuite/tests/prim-bigstring/bigstring_access.ml index 392caecd..0014de3d 100644 --- a/testsuite/tests/prim-bigstring/bigstring_access.ml +++ b/testsuite/tests/prim-bigstring/bigstring_access.ml @@ -1,3 +1,5 @@ +(* TEST +*) open Bigarray type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t diff --git a/testsuite/tests/prim-bigstring/ocamltests b/testsuite/tests/prim-bigstring/ocamltests new file mode 100644 index 00000000..5167a3dd --- /dev/null +++ b/testsuite/tests/prim-bigstring/ocamltests @@ -0,0 +1,2 @@ +bigstring_access.ml +string_access.ml diff --git a/testsuite/tests/prim-bigstring/string_access.ml b/testsuite/tests/prim-bigstring/string_access.ml index 3fbb9664..82c32f2f 100644 --- a/testsuite/tests/prim-bigstring/string_access.ml +++ b/testsuite/tests/prim-bigstring/string_access.ml @@ -1,17 +1,19 @@ +(* TEST +*) -external caml_string_get_16 : string -> int -> int = "%caml_string_get16" -external caml_string_get_32 : string -> int -> int32 = "%caml_string_get32" -external caml_string_get_64 : string -> int -> int64 = "%caml_string_get64" +external caml_bytes_get_16 : bytes -> int -> int = "%caml_bytes_get16" +external caml_bytes_get_32 : bytes -> int -> int32 = "%caml_bytes_get32" +external caml_bytes_get_64 : bytes -> int -> int64 = "%caml_bytes_get64" -external caml_string_set_16 : string -> int -> int -> unit = - "%caml_string_set16" -external caml_string_set_32 : string -> int -> int32 -> unit = - "%caml_string_set32" -external caml_string_set_64 : string -> int -> int64 -> unit = - "%caml_string_set64" +external caml_bytes_set_16 : bytes -> int -> int -> unit = + "%caml_bytes_set16" +external caml_bytes_set_32 : bytes -> int -> int32 -> unit = + "%caml_bytes_set32" +external caml_bytes_set_64 : bytes -> int -> int64 -> unit = + "%caml_bytes_set64" -let s = String.make 10 '\x00' -let empty_s = "" +let s = Bytes.make 10 '\x00' +let empty_s = Bytes.create 0 let assert_bound_check2 f v1 v2 = try @@ -28,27 +30,27 @@ let assert_bound_check3 f v1 v2 v3 = | Invalid_argument _ -> () let () = - assert_bound_check2 caml_string_get_16 s (-1); - assert_bound_check2 caml_string_get_16 s 9; - assert_bound_check2 caml_string_get_32 s (-1); - assert_bound_check2 caml_string_get_32 s 7; - assert_bound_check2 caml_string_get_64 s (-1); - assert_bound_check2 caml_string_get_64 s 3; - - assert_bound_check3 caml_string_set_16 s (-1) 0; - assert_bound_check3 caml_string_set_16 s 9 0; - assert_bound_check3 caml_string_set_32 s (-1) 0l; - assert_bound_check3 caml_string_set_32 s 7 0l; - assert_bound_check3 caml_string_set_64 s (-1) 0L; - assert_bound_check3 caml_string_set_64 s 3 0L; - - assert_bound_check2 caml_string_get_16 empty_s 0; - assert_bound_check2 caml_string_get_32 empty_s 0; - assert_bound_check2 caml_string_get_64 empty_s 0; - - assert_bound_check3 caml_string_set_16 empty_s 0 0; - assert_bound_check3 caml_string_set_32 empty_s 0 0l; - assert_bound_check3 caml_string_set_64 empty_s 0 0L + assert_bound_check2 caml_bytes_get_16 s (-1); + assert_bound_check2 caml_bytes_get_16 s 9; + assert_bound_check2 caml_bytes_get_32 s (-1); + assert_bound_check2 caml_bytes_get_32 s 7; + assert_bound_check2 caml_bytes_get_64 s (-1); + assert_bound_check2 caml_bytes_get_64 s 3; + + assert_bound_check3 caml_bytes_set_16 s (-1) 0; + assert_bound_check3 caml_bytes_set_16 s 9 0; + assert_bound_check3 caml_bytes_set_32 s (-1) 0l; + assert_bound_check3 caml_bytes_set_32 s 7 0l; + assert_bound_check3 caml_bytes_set_64 s (-1) 0L; + assert_bound_check3 caml_bytes_set_64 s 3 0L; + + assert_bound_check2 caml_bytes_get_16 empty_s 0; + assert_bound_check2 caml_bytes_get_32 empty_s 0; + assert_bound_check2 caml_bytes_get_64 empty_s 0; + + assert_bound_check3 caml_bytes_set_16 empty_s 0 0; + assert_bound_check3 caml_bytes_set_32 empty_s 0 0l; + assert_bound_check3 caml_bytes_set_64 empty_s 0 0L external bswap16: int -> int = "%bswap16" external bswap32: int32 -> int32 = "%bswap_int32" @@ -70,37 +72,37 @@ let swap64 x = else x let () = - caml_string_set_16 s 0 (swap16 0x1234); + caml_bytes_set_16 s 0 (swap16 0x1234); Printf.printf "%x %x %x\n%!" - (swap16 (caml_string_get_16 s 0)) - (swap16 (caml_string_get_16 s 1)) - (swap16 (caml_string_get_16 s 2)); - caml_string_set_16 s 0 (swap16 0xFEDC); + (swap16 (caml_bytes_get_16 s 0)) + (swap16 (caml_bytes_get_16 s 1)) + (swap16 (caml_bytes_get_16 s 2)); + caml_bytes_set_16 s 0 (swap16 0xFEDC); Printf.printf "%x %x %x\n%!" - (swap16 (caml_string_get_16 s 0)) - (swap16 (caml_string_get_16 s 1)) - (swap16 (caml_string_get_16 s 2)) + (swap16 (caml_bytes_get_16 s 0)) + (swap16 (caml_bytes_get_16 s 1)) + (swap16 (caml_bytes_get_16 s 2)) let () = - caml_string_set_32 s 0 (swap32 0x12345678l); + caml_bytes_set_32 s 0 (swap32 0x12345678l); Printf.printf "%lx %lx %lx\n%!" - (swap32 (caml_string_get_32 s 0)) - (swap32 (caml_string_get_32 s 1)) - (swap32 (caml_string_get_32 s 2)); - caml_string_set_32 s 0 (swap32 0xFEDCBA09l); + (swap32 (caml_bytes_get_32 s 0)) + (swap32 (caml_bytes_get_32 s 1)) + (swap32 (caml_bytes_get_32 s 2)); + caml_bytes_set_32 s 0 (swap32 0xFEDCBA09l); Printf.printf "%lx %lx %lx\n%!" - (swap32 (caml_string_get_32 s 0)) - (swap32 (caml_string_get_32 s 1)) - (swap32 (caml_string_get_32 s 2)) + (swap32 (caml_bytes_get_32 s 0)) + (swap32 (caml_bytes_get_32 s 1)) + (swap32 (caml_bytes_get_32 s 2)) let () = - caml_string_set_64 s 0 (swap64 0x1234567890ABCDEFL); + caml_bytes_set_64 s 0 (swap64 0x1234567890ABCDEFL); Printf.printf "%Lx %Lx %Lx\n%!" - (swap64 (caml_string_get_64 s 0)) - (swap64 (caml_string_get_64 s 1)) - (swap64 (caml_string_get_64 s 2)); - caml_string_set_64 s 0 (swap64 0xFEDCBA0987654321L); + (swap64 (caml_bytes_get_64 s 0)) + (swap64 (caml_bytes_get_64 s 1)) + (swap64 (caml_bytes_get_64 s 2)); + caml_bytes_set_64 s 0 (swap64 0xFEDCBA0987654321L); Printf.printf "%Lx %Lx %Lx\n%!" - (swap64 (caml_string_get_64 s 0)) - (swap64 (caml_string_get_64 s 1)) - (swap64 (caml_string_get_64 s 2)) + (swap64 (caml_bytes_get_64 s 0)) + (swap64 (caml_bytes_get_64 s 1)) + (swap64 (caml_bytes_get_64 s 2)) diff --git a/testsuite/tests/prim-bswap/Makefile b/testsuite/tests/prim-bswap/Makefile deleted file mode 100644 index 956ab4a7..00000000 --- a/testsuite/tests/prim-bswap/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -######################################################################### -# # -# OCaml # -# # -# Benedikt Meurer, os-cillation GmbH # -# # -# Copyright 1998 Institut National de Recherche en Informatique # -# et en Automatique. Copyright 2013 Benedikt Meurer. All rights # -# reserved. This file is distributed under the terms of the Q # -# Public License version 1.0. # -# # -######################################################################### - -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/prim-bswap/bswap.ml b/testsuite/tests/prim-bswap/bswap.ml index 9d757335..7ab822c7 100644 --- a/testsuite/tests/prim-bswap/bswap.ml +++ b/testsuite/tests/prim-bswap/bswap.ml @@ -1,3 +1,6 @@ +(* TEST +*) + open Printf external bswap16: int -> int = "%bswap16" diff --git a/testsuite/tests/prim-bswap/ocamltests b/testsuite/tests/prim-bswap/ocamltests new file mode 100644 index 00000000..d5028fc5 --- /dev/null +++ b/testsuite/tests/prim-bswap/ocamltests @@ -0,0 +1 @@ +bswap.ml diff --git a/testsuite/tests/prim-revapply/Makefile b/testsuite/tests/prim-revapply/Makefile deleted file mode 100644 index ef0afea5..00000000 --- a/testsuite/tests/prim-revapply/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/prim-revapply/apply.ml b/testsuite/tests/prim-revapply/apply.ml index 1a169e18..4f947d97 100644 --- a/testsuite/tests/prim-revapply/apply.ml +++ b/testsuite/tests/prim-revapply/apply.ml @@ -1,3 +1,6 @@ +(* TEST +*) + external ( @@ ) : ('a -> 'b) -> 'a -> 'b = "%apply" let f x = x + x diff --git a/testsuite/tests/prim-revapply/ocamltests b/testsuite/tests/prim-revapply/ocamltests new file mode 100644 index 00000000..d0c7d623 --- /dev/null +++ b/testsuite/tests/prim-revapply/ocamltests @@ -0,0 +1,2 @@ +apply.ml +revapply.ml diff --git a/testsuite/tests/prim-revapply/revapply.ml b/testsuite/tests/prim-revapply/revapply.ml index f8b0dc2e..32435562 100644 --- a/testsuite/tests/prim-revapply/revapply.ml +++ b/testsuite/tests/prim-revapply/revapply.ml @@ -1,3 +1,6 @@ +(* TEST +*) + external ( |> ) : 'a -> ('a -> 'b) -> 'b = "%revapply" let f x = x + x diff --git a/testsuite/tests/printing-types/Makefile b/testsuite/tests/printing-types/Makefile deleted file mode 100644 index 9625a3fb..00000000 --- a/testsuite/tests/printing-types/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/printing-types/ocamltests b/testsuite/tests/printing-types/ocamltests new file mode 100644 index 00000000..3a974ca8 --- /dev/null +++ b/testsuite/tests/printing-types/ocamltests @@ -0,0 +1 @@ +pr248.ml diff --git a/testsuite/tests/printing-types/pr248.ml b/testsuite/tests/printing-types/pr248.ml index 6f83e57e..25d39726 100644 --- a/testsuite/tests/printing-types/pr248.ml +++ b/testsuite/tests/printing-types/pr248.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (** Test that weak variables keep their names long enough *) let f y = fun x -> x diff --git a/testsuite/tests/printing-types/pr248.ml.reference b/testsuite/tests/printing-types/pr248.ml.reference deleted file mode 100644 index 44c9fad2..00000000 --- a/testsuite/tests/printing-types/pr248.ml.reference +++ /dev/null @@ -1,10 +0,0 @@ - -# val f : 'a -> 'b -> 'b = -val blah : '_weak1 -> '_weak1 = -val splash : unit -> '_weak1 = -val blurp : '_weak2 -> '_weak2 = -# - : int = 1 -# val g : '_weak3 -> '_weak3 = -# - : '_weak4 -> '_weak4 = -# val h : '_weak4 -> '_weak4 = -# diff --git a/testsuite/tests/printing-types/pr248.ocaml.reference b/testsuite/tests/printing-types/pr248.ocaml.reference new file mode 100644 index 00000000..acae2728 --- /dev/null +++ b/testsuite/tests/printing-types/pr248.ocaml.reference @@ -0,0 +1,9 @@ +val f : 'a -> 'b -> 'b = +val blah : '_weak1 -> '_weak1 = +val splash : unit -> '_weak1 = +val blurp : '_weak2 -> '_weak2 = +- : int = 1 +val g : '_weak3 -> '_weak3 = +- : '_weak4 -> '_weak4 = +val h : '_weak4 -> '_weak4 = + diff --git a/testsuite/tests/regression/gpr1623/gpr1623.ml b/testsuite/tests/regression/gpr1623/gpr1623.ml new file mode 100644 index 00000000..556fe1c4 --- /dev/null +++ b/testsuite/tests/regression/gpr1623/gpr1623.ml @@ -0,0 +1,15 @@ +(* TEST + arguments = "???" + *) + +(* On Windows the runtime expand windows wildcards (asterisks and + * question marks). + * + * This file is a non-regression test for github's PR#1623. + * + * On Windows 64bits, a segfault was triggered when one argument consists + * only of wildcards. + * + * The source code of this test is empty: we just check the arguments + * expansion. + * *) diff --git a/testsuite/tests/lib-threads/token1.reference b/testsuite/tests/regression/gpr1623/gpr1623.reference similarity index 100% rename from testsuite/tests/lib-threads/token1.reference rename to testsuite/tests/regression/gpr1623/gpr1623.reference diff --git a/testsuite/tests/regression/gpr1623/ocamltests b/testsuite/tests/regression/gpr1623/ocamltests new file mode 100644 index 00000000..19223ca2 --- /dev/null +++ b/testsuite/tests/regression/gpr1623/ocamltests @@ -0,0 +1 @@ +gpr1623.ml diff --git a/testsuite/tests/regression/missing_set_of_closures/Makefile b/testsuite/tests/regression/missing_set_of_closures/Makefile deleted file mode 100644 index 9a1ba941..00000000 --- a/testsuite/tests/regression/missing_set_of_closures/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - -.PHONY: default -default: - @if $(BYTECODE_ONLY); then $(MAKE) skip ; else \ - $(MAKE) compile; \ - fi - -.PHONY: skip -skip: - @echo " ... testing 'missing_set_of_closures' => skipped" - -.PHONY: compile -compile: - @$(OCAMLOPT) -c a.ml - @$(OCAMLOPT) -c b.ml - @$(OCAMLOPT) -c b2.ml - @cp b.cmx b.cmi b2.cmx b2.cmi dir/ - @cd dir; printf " ... testing 'missing_set_of_closures'"; \ - $(OCAMLOPT) -w -58 -c c.ml \ - && echo " => passed" || echo " => failed"; \ - -.PHONY: promote -promote: - -.PHONY: clean -clean: defaultclean - @rm -f *.cmi *.cmx *.$(O) dir/*.cmi dir/*.cmx dir/*.$(O) - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/regression/missing_set_of_closures/missing_set_of_closures.ml b/testsuite/tests/regression/missing_set_of_closures/missing_set_of_closures.ml new file mode 100644 index 00000000..70f37e6a --- /dev/null +++ b/testsuite/tests/regression/missing_set_of_closures/missing_set_of_closures.ml @@ -0,0 +1,22 @@ +(* TEST +files = "a.ml b.ml b2.ml" +* setup-ocamlopt.byte-build-env +** script +script = "mkdir -p dir" +*** script +script = "cp ${test_source_directory}/dir/c.ml dir/" +**** ocamlopt.byte +module = "a.ml" +***** ocamlopt.byte +module = "b.ml" +****** ocamlopt.byte +module = "b2.ml" +******* script +script = "cp b.cmx b.cmi b2.cmx b2.cmi dir/" +******** cd +cwd = "dir" +********* ocamlopt.byte +module = "c.ml" +flags = "-w -58" +********** check-ocamlopt.byte-output +*) diff --git a/testsuite/tests/regression/missing_set_of_closures/ocamltests b/testsuite/tests/regression/missing_set_of_closures/ocamltests new file mode 100644 index 00000000..3695f1c8 --- /dev/null +++ b/testsuite/tests/regression/missing_set_of_closures/ocamltests @@ -0,0 +1 @@ +missing_set_of_closures.ml diff --git a/testsuite/tests/regression/pr3612/Makefile b/testsuite/tests/regression/pr3612/Makefile deleted file mode 100644 index 866927b3..00000000 --- a/testsuite/tests/regression/pr3612/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Pierre Chambart, OCamlPro * -#* * -#* Copyright 2014 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr3612 -C_FILES=custom_finalize - -BASEDIR=../../.. -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr3612/ocamltests b/testsuite/tests/regression/pr3612/ocamltests new file mode 100644 index 00000000..69b5ac81 --- /dev/null +++ b/testsuite/tests/regression/pr3612/ocamltests @@ -0,0 +1 @@ +pr3612.ml diff --git a/testsuite/tests/regression/pr3612/pr3612.ml b/testsuite/tests/regression/pr3612/pr3612.ml index 70f42740..7d536318 100644 --- a/testsuite/tests/regression/pr3612/pr3612.ml +++ b/testsuite/tests/regression/pr3612/pr3612.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "custom_finalize.c" +*) + type t external test_alloc : unit -> t = "caml_test_pr3612_alloc" diff --git a/testsuite/tests/regression/pr5080-notes/Makefile b/testsuite/tests/regression/pr5080-notes/Makefile deleted file mode 100644 index 57f971c1..00000000 --- a/testsuite/tests/regression/pr5080-notes/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -ADD_COMPFLAGS = -pp 'camlp4o pa_macro.cmo' -MAIN_MODULE = pr5080_notes_ok - -include ../../../makefiles/Makefile.okbad -include ../../../makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr5080-notes/pr5080_notes_ok.ml b/testsuite/tests/regression/pr5080-notes/pr5080_notes_ok.ml deleted file mode 100644 index 175bc8b7..00000000 --- a/testsuite/tests/regression/pr5080-notes/pr5080_notes_ok.ml +++ /dev/null @@ -1,4 +0,0 @@ -let marshal_int f = - match [] with - | _ :: `INT n :: _ -> f n - | _ -> failwith "marshal_int" diff --git a/testsuite/tests/regression/pr5233/Makefile b/testsuite/tests/regression/pr5233/Makefile deleted file mode 100644 index 46dd3025..00000000 --- a/testsuite/tests/regression/pr5233/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr5233 - -include ../../../makefiles/Makefile.one -include ../../../makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr5233/ocamltests b/testsuite/tests/regression/pr5233/ocamltests new file mode 100644 index 00000000..19c4be2b --- /dev/null +++ b/testsuite/tests/regression/pr5233/ocamltests @@ -0,0 +1 @@ +pr5233.ml diff --git a/testsuite/tests/regression/pr5233/pr5233.ml b/testsuite/tests/regression/pr5233/pr5233.ml index b7fddd7f..05fe6872 100644 --- a/testsuite/tests/regression/pr5233/pr5233.ml +++ b/testsuite/tests/regression/pr5233/pr5233.ml @@ -1,3 +1,5 @@ +(* TEST *) + open Printf;; (* PR#5233: Create a dangling pointer and use it to access random parts diff --git a/testsuite/tests/regression/pr5757/Makefile b/testsuite/tests/regression/pr5757/Makefile deleted file mode 100644 index 7c03bb00..00000000 --- a/testsuite/tests/regression/pr5757/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr5757 - -include ../../../makefiles/Makefile.one -include ../../../makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr5757/ocamltests b/testsuite/tests/regression/pr5757/ocamltests new file mode 100644 index 00000000..c3910e3e --- /dev/null +++ b/testsuite/tests/regression/pr5757/ocamltests @@ -0,0 +1 @@ +pr5757.ml diff --git a/testsuite/tests/regression/pr5757/pr5757.ml b/testsuite/tests/regression/pr5757/pr5757.ml index 4bd8d85f..18cc6db1 100644 --- a/testsuite/tests/regression/pr5757/pr5757.ml +++ b/testsuite/tests/regression/pr5757/pr5757.ml @@ -1,3 +1,5 @@ +(* TEST *) + Random.init 3;; for i = 0 to 100_000 do ignore (Bytes.create (Random.int 1_000_000)) diff --git a/testsuite/tests/regression/pr6024/Makefile b/testsuite/tests/regression/pr6024/Makefile deleted file mode 100644 index c6ff3e5f..00000000 --- a/testsuite/tests/regression/pr6024/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr6024 - -BASEDIR=../../.. -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr6024/ocamltests b/testsuite/tests/regression/pr6024/ocamltests new file mode 100644 index 00000000..fa733320 --- /dev/null +++ b/testsuite/tests/regression/pr6024/ocamltests @@ -0,0 +1 @@ +pr6024.ml diff --git a/testsuite/tests/regression/pr6024/pr6024.ml b/testsuite/tests/regression/pr6024/pr6024.ml index 7798a5ff..2811c84b 100644 --- a/testsuite/tests/regression/pr6024/pr6024.ml +++ b/testsuite/tests/regression/pr6024/pr6024.ml @@ -1 +1,3 @@ +(* TEST *) + Format.printf "@[%@-@@-@]@.";; diff --git a/testsuite/tests/regression/pr7042/Makefile b/testsuite/tests/regression/pr7042/Makefile deleted file mode 100644 index 97995415..00000000 --- a/testsuite/tests/regression/pr7042/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr7042 - -BASEDIR=../../.. -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr7042/ocamltests b/testsuite/tests/regression/pr7042/ocamltests new file mode 100644 index 00000000..6cace61a --- /dev/null +++ b/testsuite/tests/regression/pr7042/ocamltests @@ -0,0 +1 @@ +pr7042.ml diff --git a/testsuite/tests/regression/pr7042/pr7042.ml b/testsuite/tests/regression/pr7042/pr7042.ml index 3fa80abe..ab908e7e 100644 --- a/testsuite/tests/regression/pr7042/pr7042.ml +++ b/testsuite/tests/regression/pr7042/pr7042.ml @@ -1,3 +1,5 @@ +(* TEST *) + let _ = let a = [| 0.0; -. 0.0 |] in Printf.printf "%Lx %Lx\n" diff --git a/testsuite/tests/regression/pr7426/Makefile b/testsuite/tests/regression/pr7426/Makefile deleted file mode 100644 index 8b245519..00000000 --- a/testsuite/tests/regression/pr7426/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -MAIN_MODULE=pr7426 - -BASEDIR=../../.. -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/regression/pr7426/ocamltests b/testsuite/tests/regression/pr7426/ocamltests new file mode 100644 index 00000000..5b4841e4 --- /dev/null +++ b/testsuite/tests/regression/pr7426/ocamltests @@ -0,0 +1 @@ +pr7426.ml diff --git a/testsuite/tests/regression/pr7426/pr7426.ml b/testsuite/tests/regression/pr7426/pr7426.ml index 55aa4bfa..4f0ee318 100644 --- a/testsuite/tests/regression/pr7426/pr7426.ml +++ b/testsuite/tests/regression/pr7426/pr7426.ml @@ -1 +1,3 @@ +(* TEST *) + class some_class = object val some_val = 0.0 end diff --git a/testsuite/tests/required-external/Makefile b/testsuite/tests/required-external/Makefile deleted file mode 100644 index 0285e743..00000000 --- a/testsuite/tests/required-external/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Ensure that calling an external C primite forces linking -# the module that defines it - -MAIN_MODULE = main -LIBRARIES = lib - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common - -main.cmo: lib.cma -main.cmx: lib.cmxa - -lib.cma: file.cmo - @$(OCAMLC) -a -o $@ $< - -lib.cmxa: file.cmx - @$(OCAMLOPT) -a -o $@ $< diff --git a/testsuite/tests/required-external/main.ml b/testsuite/tests/required-external/main.ml index 32d16576..7764b822 100644 --- a/testsuite/tests/required-external/main.ml +++ b/testsuite/tests/required-external/main.ml @@ -1,2 +1,41 @@ +(* TEST +modules = "file.ml" + +* setup-ocamlc.byte-build-env +program = "${test_build_directory}/main.exe" +** ocamlc.byte +module = "file.ml" +*** ocamlc.byte +module = "" +program = "lib.cma" +flags = "-a" +all_modules = "file.cmo" +**** ocamlc.byte +program = "${test_build_directory}/main.exe" +all_modules = "lib.cma main.ml" +flags = "" +***** check-ocamlc.byte-output +****** run +******* check-program-output + +* setup-ocamlopt.byte-build-env +program = "${test_build_directory}/main.exe" +** ocamlopt.byte +module = "file.ml" +*** ocamlopt.byte +module = "" +program = "lib.cmxa" +flags = "-a" +all_modules = "file.cmx" +**** ocamlopt.byte +program = "${test_build_directory}/main.exe" +all_modules = "lib.cmxa main.ml" +flags = "" +***** check-ocamlopt.byte-output +****** run +******* check-program-output + +*) + let () = ignore (File.getcwd ()) diff --git a/testsuite/tests/required-external/ocamltests b/testsuite/tests/required-external/ocamltests new file mode 100644 index 00000000..d389d156 --- /dev/null +++ b/testsuite/tests/required-external/ocamltests @@ -0,0 +1 @@ +main.ml diff --git a/testsuite/tests/runtime-C-exceptions/Makefile b/testsuite/tests/runtime-C-exceptions/Makefile deleted file mode 100644 index da534b75..00000000 --- a/testsuite/tests/runtime-C-exceptions/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -BASEDIR=../.. -#MODULES= -MAIN_MODULE=test -C_FILES=stub_test - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/runtime-C-exceptions/ocamltests b/testsuite/tests/runtime-C-exceptions/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/runtime-C-exceptions/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/runtime-C-exceptions/test.ml b/testsuite/tests/runtime-C-exceptions/test.ml index 794e27cb..17bf4252 100644 --- a/testsuite/tests/runtime-C-exceptions/test.ml +++ b/testsuite/tests/runtime-C-exceptions/test.ml @@ -1,3 +1,7 @@ +(* TEST + modules = "stub_test.c" +*) + external failwith_from_ocaml : string -> 'a = "caml_failwith_value" external dynamic_invalid_argument : unit -> 'a = "dynamic_invalid_argument" diff --git a/testsuite/tests/runtime-errors/Makefile b/testsuite/tests/runtime-errors/Makefile index b7f05895..04ce0695 100644 --- a/testsuite/tests/runtime-errors/Makefile +++ b/testsuite/tests/runtime-errors/Makefile @@ -30,8 +30,8 @@ compile: $(OCAMLOPT) -w a -o $$F.native$(EXE) $$f; \ fi; \ done - $(if $(findstring win32,$(UNIX_OR_WIN32)),:, \ - @grep -q HAS_STACK_OVERFLOW_DETECTION $(TOPDIR)/byterun/caml/s.h \ + @$(if $(findstring win32,$(UNIX_OR_WIN32)),:, \ + grep -q HAS_STACK_OVERFLOW_DETECTION $(TOPDIR)/byterun/caml/s.h \ || rm -f stackoverflow.native$(EXE)) # Cygwin doesn't allow the stack limit to be changed - the 4096 is diff --git a/testsuite/tests/self-contained-toplevel/Makefile b/testsuite/tests/self-contained-toplevel/Makefile deleted file mode 100644 index 5126305b..00000000 --- a/testsuite/tests/self-contained-toplevel/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Jeremie Dimino, Jane Street Europe * -#* * -#* Copyright 2016 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -LIBRARIES=ocaml -MODULES=foo cached_cmi -MAIN_MODULE=main -COMPFLAGS=-I $(OTOPDIR)/typing -I $(OTOPDIR)/toplevel -LIBRARIES=../../../compilerlibs/ocamlcommon \ - ../../../compilerlibs/ocamlbytecomp \ - ../../../compilerlibs/ocamltoplevel - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common - -BYTECODE_ONLY=true -GENERATED_SOURCES+=cached_cmi.ml -EXEC_ARGS=$(OCFLAGS) -noinit input.ml - -cached_cmi.ml: foo.cmi gen_cached_cmi.ml - @$(OCAML) ../../../compilerlibs/ocamlcommon.cma -I $(OTOPDIR)/typing \ - gen_cached_cmi.ml > $@ diff --git a/testsuite/tests/self-contained-toplevel/gen_cached_cmi.ml b/testsuite/tests/self-contained-toplevel/gen_cached_cmi.ml index 176c3b2e..e406423f 100644 --- a/testsuite/tests/self-contained-toplevel/gen_cached_cmi.ml +++ b/testsuite/tests/self-contained-toplevel/gen_cached_cmi.ml @@ -1,4 +1,7 @@ let () = let cmi = Cmi_format.read_cmi "foo.cmi" in let data = Marshal.to_string cmi [] in - Printf.printf "let foo = %S\n" data + let filename = Sys.argv.(1) in + let oc = open_out filename in + Printf.fprintf oc "let foo = %S\n" data; + close_out oc diff --git a/testsuite/tests/self-contained-toplevel/main.ml b/testsuite/tests/self-contained-toplevel/main.ml index 606c4df5..7dd7b5cf 100644 --- a/testsuite/tests/self-contained-toplevel/main.ml +++ b/testsuite/tests/self-contained-toplevel/main.ml @@ -1,3 +1,23 @@ +(* TEST +files = "foo.ml gen_cached_cmi.ml input.ml" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "foo.ml" +*** ocaml with ocamlcommon +ocaml_script_as_argument = "true" +test_file = "gen_cached_cmi.ml" +arguments = "cached_cmi.ml" +**** ocamlc.byte +module = "" +program = "${test_build_directory}/main.exe" +libraries += "ocamlbytecomp ocamltoplevel" +all_modules = "foo.cmo cached_cmi.ml main.ml" +***** run +set OCAMLLIB="${ocamlsrcdir}/stdlib" +arguments = "input.ml" +****** check-program-output +*) + let () = (* Make sure it's no longer available on disk *) if Sys.file_exists "foo.cmi" then Sys.remove "foo.cmi"; diff --git a/testsuite/tests/self-contained-toplevel/ocamltests b/testsuite/tests/self-contained-toplevel/ocamltests new file mode 100644 index 00000000..d389d156 --- /dev/null +++ b/testsuite/tests/self-contained-toplevel/ocamltests @@ -0,0 +1 @@ +main.ml diff --git a/testsuite/tests/tool-command-line/Makefile b/testsuite/tests/tool-command-line/Makefile deleted file mode 100644 index 148dafa2..00000000 --- a/testsuite/tests/tool-command-line/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Bernhard Schommer * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - - -default: - @$(MAKE) byte - @if $(BYTECODE_ONLY); then $(MAKE) opt-skipped ; else \ - $(MAKE) opt; \ - fi - -byte: - @$(OCAMLC) unknown-file 2>&1 | grep "don't know what to do with unknown-file" \ - > unknown-file.byte.result || true - @for file in *.byte.reference; do \ - printf " ... testing '$$file':"; \ - $(DIFF) $$file `basename $$file reference`result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -opt: - @$(OCAMLOPT) unknown-file 2>&1 | grep "don't know what to do with unknown-file"\ - > unknown-file.opt.result || true - @for file in *.opt.reference; do \ - printf " ... testing '$$file':"; \ - $(DIFF) $$file `basename $$file reference`result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -opt-skipped: - @for file in *.opt.reference; do \ - printf " ... testing '$$file':"; \ - echo " => skipped"; \ - done - -promote: defaultpromote - -clean: defaultclean - @rm -f *.result - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-command-line/ocamltests b/testsuite/tests/tool-command-line/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/tool-command-line/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/tool-command-line/test.ml b/testsuite/tests/tool-command-line/test.ml new file mode 100644 index 00000000..e7b7893e --- /dev/null +++ b/testsuite/tests/tool-command-line/test.ml @@ -0,0 +1,26 @@ +(* TEST + +files = "unknown-file" + +* skip (* setup-ocamlc.byte-build-env *) +** ocamlc.byte +all_modules = "" +flags = "unknown-file" +ocamlc_byte_exit_status = "2" +*** check-ocamlc.byte-output + +* skip (* setup-ocamlopt.byte-build-env *) +** ocamlopt.byte +all_modules = "" +flags = "unknown-file" +ocamlopt_byte_exit_status = "2" +*** no-flambda +**** check-ocamlopt.byte-output +*** flambda +**** check-ocamlopt.byte-output +compiler_reference = "${test_source_directory}/test.ocamlopt.byte.flambda.reference" + +*) + +(* this file is just a test driver, the test does not contain real OCamlcode *) + diff --git a/testsuite/tests/tool-command-line/test.ocamlc.byte.reference b/testsuite/tests/tool-command-line/test.ocamlc.byte.reference new file mode 100644 index 00000000..2bcd4b39 --- /dev/null +++ b/testsuite/tests/tool-command-line/test.ocamlc.byte.reference @@ -0,0 +1,130 @@ +don't know what to do with unknown-file +Usage: ocamlc +Options are: + -a Build a library + -absname Show absolute filenames in error messages + -annot Save information in .annot + -bin-annot Save typedtree in .cmt + -c Compile only (do not link) + -cc Use as the C compiler and linker + -cclib Pass option to the C linker + -ccopt Pass option to the C compiler and linker + -color {auto|always|never} Enable or disable colors in compiler messages + The following settings are supported: + auto use heuristics to enable colors only if supported + always enable colors + never disable colors + The default setting is 'auto', and the current heuristic + checks that the TERM environment variable exists and is + not empty or "dumb", and that isatty(stderr) holds. + -compat-32 Check that generated bytecode can run on 32-bit platforms + -config Print configuration values and exit + -custom Link in custom mode + -dllib Use the dynamically-loaded library + -dllpath Add to the run-time search path for shared libraries + -dtypes (deprecated) same as -annot + -for-pack Generate code that can later be `packed' with + ocamlc -pack -o .cmo + -g Save debugging information + -i Print inferred interface + -I Add to the list of include directories + -impl Compile as a .ml file + -intf Compile as a .mli file + -intf-suffix Suffix for interface files (default: .mli) + -intf_suffix (deprecated) same as -intf-suffix + -keep-docs Keep documentation strings in .cmi files + -no-keep-docs Do not keep documentation strings in .cmi files (default) + -keep-locs Keep locations in .cmi files (default) + -no-keep-locs Do not keep locations in .cmi files + -labels Use commuting label mode + -linkall Link all modules, even unused ones + -make-runtime Build a runtime system with given C objects and libraries + -make_runtime (deprecated) same as -make-runtime + -modern (deprecated) same as -labels + -alias-deps Do record dependencies for module aliases + -no-alias-deps Do not record dependencies for module aliases + -app-funct Activate applicative functors + -no-app-funct Deactivate applicative functors + -no-check-prims Do not check runtime for primitives + -noassert Do not compile assertion checks + -noautolink Do not automatically link C libraries specified in .cma files + -nolabels Ignore non-optional labels in types + -nostdlib Do not add default directory to the list of include directories + -o Set output file name to + -opaque Does not generate cross-module optimization information + (reduces necessary recompilation on module change) + -open Opens the module before typing + -output-obj Output an object file instead of an executable + -output-complete-obj Output an object file, including runtime, instead of an executable + -pack Package the given .cmo files into one .cmo + -pp Pipe sources through preprocessor + -ppx Pipe abstract syntax trees through preprocessor + -plugin Load dynamic plugin + -principal Check principality of type inference + -no-principal Do not check principality of type inference (default) + -rectypes Allow arbitrary recursive types + -no-rectypes Do not allow arbitrary recursive types (default) + -runtime-variant Use the variant of the run-time system + -safe-string Make strings immutable (default) + -short-paths Shorten paths in types + -strict-sequence Left-hand part of a sequence must have type unit + -no-strict-sequence Left-hand part of a sequence need not have type unit (default) + -strict-formats Reject invalid formats accepted by legacy implementations + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should always use this flag + to detect invalid formats so you can fix them.) + -no-strict-formats Accept invalid formats accepted by legacy implementations (default) + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should never use this flag + and instead fix invalid formats.) + -thread (deprecated) same as -I +threads + -unboxed-types unannotated unboxable types will be unboxed + -no-unboxed-types unannotated unboxable types will not be unboxed (default) + -unsafe Do not compile bounds checking on array and string access + -unsafe-string Make strings mutable + -use-runtime Generate bytecode for the given runtime system + -use_runtime (deprecated) same as -use-runtime + -v Print compiler version and location of standard library and exit + -verbose Print calls to external commands + -version Print version and exit + --version Print version and exit + -vmthread Generate code that supports the threads library with VM-level + scheduling + -vnum Print version number and exit + -w Enable or disable warnings according to : + + enable warnings in + - disable warnings in + @ enable warnings in and treat them as errors + can be: + a single warning number + .. a range of consecutive warning numbers + a predefined set + default setting is "+a-4-6-7-9-27-29-32..42-44-45-48-50-60" + -warn-error Enable or disable error status for warnings according + to . See option -w for the syntax of . + Default setting is "-a+31" + -warn-help Show description of warning numbers + -where Print location of standard library and exit + - Treat as a file name (even if it starts with `-') + -nopervasives (undocumented) + -use-prims (undocumented) + -dno-unique-ids (undocumented) + -dunique-ids (undocumented) + -dsource (undocumented) + -dparsetree (undocumented) + -dtypedtree (undocumented) + -drawlambda (undocumented) + -dlambda (undocumented) + -dinstr (undocumented) + -dtimings Print timings information for each pass + -dprofile Print performance information for each pass + The columns are: time alloc top-heap absolute-top-heap. + -args Read additional newline-terminated command line arguments + from + -args0 Read additional null character terminated command line arguments +from + -depend Compute dependencies (use 'ocamlc -depend -help' for details) + -help Display this list of options + --help Display this list of options diff --git a/testsuite/tests/tool-command-line/test.ocamlopt.byte.flambda.reference b/testsuite/tests/tool-command-line/test.ocamlopt.byte.flambda.reference new file mode 100644 index 00000000..b2b25085 --- /dev/null +++ b/testsuite/tests/tool-command-line/test.ocamlopt.byte.flambda.reference @@ -0,0 +1,178 @@ +don't know what to do with unknown-file +Usage: ocamlopt +Options are: + -fPIC Generate position-independent machine code (default) + -fno-PIC Generate position-dependent machine code + -a Build a library + -absname Show absolute filenames in error messages + -afl-instrument Enable instrumentation for afl-fuzz + -afl-inst-ratio Configure percentage of branches instrumented + (advanced, see afl-fuzz docs for AFL_INST_RATIO) + -annot Save information in .annot + -bin-annot Save typedtree in .cmt + -inline-branch-factor |=[,...] Estimate the probability of a branch being cold as 1/(1+n) (used for inlining) (default 0.10) + -c Compile only (do not link) + -cc Use as the C compiler and linker + -cclib Pass option to the C linker + -ccopt Pass option to the C compiler and linker + -clambda-checks Instrument clambda code with closure and field access checks (for debugging the compiler) + -Oclassic Make inlining decisions at function definition time rather than at the call site (replicates previous behaviour of the compiler) + -color {auto|always|never} Enable or disable colors in compiler messages + The following settings are supported: + auto use heuristics to enable colors only if supported + always enable colors + never disable colors + The default setting is 'auto', and the current heuristic + checks that the TERM environment variable exists and is + not empty or "dumb", and that isatty(stderr) holds. + -compact Optimize code size rather than speed + -config Print configuration values and exit + -dtypes (deprecated) same as -annot + -for-pack Generate code that can later be `packed' with + ocamlopt -pack -o .cmx + -g Record debugging information for exception backtrace + -i Print inferred interface + -I Add to the list of include directories + -impl Compile as a .ml file + -inline |=[,...] Aggressiveness of inlining (default 10.00, higher numbers mean more aggressive) + -inline-toplevel |=[,...] Aggressiveness of inlining at toplevel (higher numbers mean more aggressive) + -inline-alloc-cost |=[,...] The cost of not removing an allocation during inlining (default 7, higher numbers more costly) + -inline-branch-cost |=[,...] The cost of not removing a conditional during inlining (default 5, higher numbers more costly) + -inline-call-cost |=[,...] The cost of not removing a call during inlining (default 5, higher numbers more costly) + -inline-prim-cost |=[,...] The cost of not removing a primitive during inlining (default 3, higher numbers more costly) + -inline-indirect-cost |=[,...] The cost of not removing an indirect call during inlining (default 4, higher numbers more costly) + -inline-lifting-benefit |=[,...] The benefit of lifting definitions to toplevel during inlining (default 1300, higher numbers more beneficial) + -inlining-report Emit `..inlining' file(s) (one per round) showing the inliner's decisions + -intf Compile as a .mli file + -intf-suffix Suffix for interface files (default: .mli) + -keep-docs Keep documentation strings in .cmi files + -no-keep-docs Do not keep documentation strings in .cmi files (default) + -keep-locs Keep locations in .cmi files (default) + -no-keep-locs Do not keep locations in .cmi files + -labels Use commuting label mode + -linkall Link all modules, even unused ones + -inline-max-depth |=[,...] Maximum depth of search for inlining opportunities inside inlined functions (default 1) + -alias-deps Do record dependencies for module aliases + -no-alias-deps Do not record dependencies for module aliases + -linscan Use the linear scan register allocator + -app-funct Activate applicative functors + -no-app-funct Deactivate applicative functors + -no-float-const-prop Deactivate constant propagation for floating-point operations + -noassert Do not compile assertion checks + -noautolink Do not automatically link C libraries specified in .cmxa files + -nodynlink Enable optimizations for code that will not be dynlinked + -nolabels Ignore non-optional labels in types + -nostdlib Do not add default directory to the list of include directories + -no-unbox-free-vars-of-closures Do not unbox variables that will appear inside function closures + -no-unbox-specialised-args Do not unbox arguments to which functions have been specialised + -o Set output file name to + -O2 Apply increased optimization for speed + -O3 Apply aggressive optimization for speed (may significantly increase code size and compilation time) + -opaque Does not generate cross-module optimization information + (reduces necessary recompilation on module change) + -open Opens the module before typing + -output-obj Output an object file instead of an executable + -output-complete-obj Output an object file, including runtime, instead of an executable + -p Compile and link with profiling support for "gprof" + (not supported on all platforms) + -pack Package the given .cmx files into one .cmx + -plugin Load dynamic plugin + -pp Pipe sources through preprocessor + -ppx Pipe abstract syntax trees through preprocessor + -principal Check principality of type inference + -no-principal Do not check principality of type inference (default) + -rectypes Allow arbitrary recursive types + -no-rectypes Do not allow arbitrary recursive types (default) + -remove-unused-arguments Remove unused function arguments + -rounds Repeat tree optimization and inlining phases this many times (default 1). Rounds are numbered starting from zero. + -runtime-variant Use the variant of the run-time system + -S Keep intermediate assembly file + -safe-string Make strings immutable (default) + -shared Produce a dynlinkable plugin + -short-paths Shorten paths in types + -strict-sequence Left-hand part of a sequence must have type unit + -no-strict-sequence Left-hand part of a sequence need not have type unit (default) + -strict-formats Reject invalid formats accepted by legacy implementations + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should always use this flag + to detect invalid formats so you can fix them.) + -no-strict-formats Accept invalid formats accepted by legacy implementations (default) + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should never use this flag + and instead fix invalid formats.) + -thread (deprecated) same as -I +threads + -unbox-closures Pass free variables via specialised arguments rather than closures + -unbox-closures-factor 0> Scale the size threshold above which unbox-closures will slow down indirect calls rather than duplicating a function (default 10) + -inline-max-unroll |=[,...] Unroll recursive functions at most this many times (default 0) + -unboxed-types unannotated unboxable types will be unboxed + -no-unboxed-types unannotated unboxable types will not be unboxed (default) + -unsafe Do not compile bounds checking on array and string access + -unsafe-string Make strings mutable + -v Print compiler version and location of standard library and exit + -verbose Print calls to external commands + -version Print version and exit + --version Print version and exit + -vnum Print version number and exit + -w Enable or disable warnings according to : + + enable warnings in + - disable warnings in + @ enable warnings in and treat them as errors + can be: + a single warning number + .. a range of consecutive warning numbers + a predefined set + default setting is "+a-4-6-7-9-27-29-32..42-44-45-48-50-60" + -warn-error Enable or disable error status for warnings according + to . See option -w for the syntax of . + Default setting is "-a+31" + -warn-help Show description of warning numbers + -where Print location of standard library and exit + - Treat as a file name (even if it starts with `-') + -nopervasives (undocumented) + -dno-unique-ids (undocumented) + -dunique-ids (undocumented) + -dsource (undocumented) + -dparsetree (undocumented) + -dtypedtree (undocumented) + -drawlambda (undocumented) + -dlambda (undocumented) + -drawclambda (undocumented) + -dclambda (undocumented) + -dflambda Print Flambda terms + -drawflambda Print Flambda terms after closure conversion + -dflambda-invariants Check Flambda invariants around each pass + -dflambda-no-invariants Do not Check Flambda invariants around each pass + -dflambda-let Print when the given Flambda [Let] is created + -dflambda-verbose Print Flambda terms including around each pass + -dcmm (undocumented) + -dsel (undocumented) + -dcombine (undocumented) + -dcse (undocumented) + -dlive (undocumented) + -davail Print register availability info when printing liveness + -drunavail Run register availability pass (for testing only; needs -g) + -dspill (undocumented) + -dsplit (undocumented) + -dinterf (undocumented) + -dprefer (undocumented) + -dalloc (undocumented) + -dreload (undocumented) + -dscheduling (undocumented) + -dlinear (undocumented) + -dinterval (undocumented) + -dstartup (undocumented) + -dtimings Print timings information for each pass + -dprofile Print performance information for each pass + The columns are: time alloc top-heap absolute-top-heap. + -dump-pass Record transformations performed by these passes: + unbox-closures unbox-specialised-args unbox-free-vars-of-closures + remove-free-vars-equal-to-args remove-unused-arguments unused-arguments + -args Read additional newline-terminated command line arguments + from + -args0 Read additional null character terminated command line arguments +from + -depend Compute dependencies (use 'ocamlopt -depend -help' for details) + -help Display this list of options + --help Display this list of options diff --git a/testsuite/tests/tool-command-line/test.ocamlopt.byte.reference b/testsuite/tests/tool-command-line/test.ocamlopt.byte.reference new file mode 100644 index 00000000..829f44c3 --- /dev/null +++ b/testsuite/tests/tool-command-line/test.ocamlopt.byte.reference @@ -0,0 +1,178 @@ +don't know what to do with unknown-file +Usage: ocamlopt +Options are: + -fPIC Generate position-independent machine code (default) + -fno-PIC Generate position-dependent machine code + -a Build a library + -absname Show absolute filenames in error messages + -afl-instrument Enable instrumentation for afl-fuzz + -afl-inst-ratio Configure percentage of branches instrumented + (advanced, see afl-fuzz docs for AFL_INST_RATIO) + -annot Save information in .annot + -bin-annot Save typedtree in .cmt + -inline-branch-factor |=[,...] Estimate the probability of a branch being cold as 1/(1+n) (used for inlining) (default 0.10) + -c Compile only (do not link) + -cc Use as the C compiler and linker + -cclib Pass option to the C linker + -ccopt Pass option to the C compiler and linker + -clambda-checks Instrument clambda code with closure and field access checks (for debugging the compiler) + -Oclassic Make inlining decisions at function definition time rather than at the call site (replicates previous behaviour of the compiler) + -color {auto|always|never} Enable or disable colors in compiler messages + The following settings are supported: + auto use heuristics to enable colors only if supported + always enable colors + never disable colors + The default setting is 'auto', and the current heuristic + checks that the TERM environment variable exists and is + not empty or "dumb", and that isatty(stderr) holds. + -compact Optimize code size rather than speed + -config Print configuration values and exit + -dtypes (deprecated) same as -annot + -for-pack Generate code that can later be `packed' with + ocamlopt -pack -o .cmx + -g Record debugging information for exception backtrace + -i Print inferred interface + -I Add to the list of include directories + -impl Compile as a .ml file + -inline |=[,...] Aggressiveness of inlining (default 1.25, higher numbers mean more aggressive) + -inline-toplevel |=[,...] Aggressiveness of inlining at toplevel (higher numbers mean more aggressive) + -inline-alloc-cost |=[,...] The cost of not removing an allocation during inlining (default 7, higher numbers more costly) + -inline-branch-cost |=[,...] The cost of not removing a conditional during inlining (default 5, higher numbers more costly) + -inline-call-cost |=[,...] The cost of not removing a call during inlining (default 5, higher numbers more costly) + -inline-prim-cost |=[,...] The cost of not removing a primitive during inlining (default 3, higher numbers more costly) + -inline-indirect-cost |=[,...] The cost of not removing an indirect call during inlining (default 4, higher numbers more costly) + -inline-lifting-benefit |=[,...] The benefit of lifting definitions to toplevel during inlining (default 1300, higher numbers more beneficial) + -inlining-report Emit `..inlining' file(s) (one per round) showing the inliner's decisions + -intf Compile as a .mli file + -intf-suffix Suffix for interface files (default: .mli) + -keep-docs Keep documentation strings in .cmi files + -no-keep-docs Do not keep documentation strings in .cmi files (default) + -keep-locs Keep locations in .cmi files (default) + -no-keep-locs Do not keep locations in .cmi files + -labels Use commuting label mode + -linkall Link all modules, even unused ones + -inline-max-depth |=[,...] Maximum depth of search for inlining opportunities inside inlined functions (default 1) + -alias-deps Do record dependencies for module aliases + -no-alias-deps Do not record dependencies for module aliases + -linscan Use the linear scan register allocator + -app-funct Activate applicative functors + -no-app-funct Deactivate applicative functors + -no-float-const-prop Deactivate constant propagation for floating-point operations + -noassert Do not compile assertion checks + -noautolink Do not automatically link C libraries specified in .cmxa files + -nodynlink Enable optimizations for code that will not be dynlinked + -nolabels Ignore non-optional labels in types + -nostdlib Do not add default directory to the list of include directories + -no-unbox-free-vars-of-closures Do not unbox variables that will appear inside function closures + -no-unbox-specialised-args Do not unbox arguments to which functions have been specialised + -o Set output file name to + -O2 Apply increased optimization for speed + -O3 Apply aggressive optimization for speed (may significantly increase code size and compilation time) + -opaque Does not generate cross-module optimization information + (reduces necessary recompilation on module change) + -open Opens the module before typing + -output-obj Output an object file instead of an executable + -output-complete-obj Output an object file, including runtime, instead of an executable + -p Compile and link with profiling support for "gprof" + (not supported on all platforms) + -pack Package the given .cmx files into one .cmx + -plugin Load dynamic plugin + -pp Pipe sources through preprocessor + -ppx Pipe abstract syntax trees through preprocessor + -principal Check principality of type inference + -no-principal Do not check principality of type inference (default) + -rectypes Allow arbitrary recursive types + -no-rectypes Do not allow arbitrary recursive types (default) + -remove-unused-arguments Remove unused function arguments + -rounds Repeat tree optimization and inlining phases this many times (default 1). Rounds are numbered starting from zero. + -runtime-variant Use the variant of the run-time system + -S Keep intermediate assembly file + -safe-string Make strings immutable (default) + -shared Produce a dynlinkable plugin + -short-paths Shorten paths in types + -strict-sequence Left-hand part of a sequence must have type unit + -no-strict-sequence Left-hand part of a sequence need not have type unit (default) + -strict-formats Reject invalid formats accepted by legacy implementations + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should always use this flag + to detect invalid formats so you can fix them.) + -no-strict-formats Accept invalid formats accepted by legacy implementations (default) + (Warning: Invalid formats may behave differently from + previous OCaml versions, and will become always-rejected + in future OCaml versions. You should never use this flag + and instead fix invalid formats.) + -thread (deprecated) same as -I +threads + -unbox-closures Pass free variables via specialised arguments rather than closures + -unbox-closures-factor 0> Scale the size threshold above which unbox-closures will slow down indirect calls rather than duplicating a function (default 10) + -inline-max-unroll |=[,...] Unroll recursive functions at most this many times (default 0) + -unboxed-types unannotated unboxable types will be unboxed + -no-unboxed-types unannotated unboxable types will not be unboxed (default) + -unsafe Do not compile bounds checking on array and string access + -unsafe-string Make strings mutable + -v Print compiler version and location of standard library and exit + -verbose Print calls to external commands + -version Print version and exit + --version Print version and exit + -vnum Print version number and exit + -w Enable or disable warnings according to : + + enable warnings in + - disable warnings in + @ enable warnings in and treat them as errors + can be: + a single warning number + .. a range of consecutive warning numbers + a predefined set + default setting is "+a-4-6-7-9-27-29-32..42-44-45-48-50-60" + -warn-error Enable or disable error status for warnings according + to . See option -w for the syntax of . + Default setting is "-a+31" + -warn-help Show description of warning numbers + -where Print location of standard library and exit + - Treat as a file name (even if it starts with `-') + -nopervasives (undocumented) + -dno-unique-ids (undocumented) + -dunique-ids (undocumented) + -dsource (undocumented) + -dparsetree (undocumented) + -dtypedtree (undocumented) + -drawlambda (undocumented) + -dlambda (undocumented) + -drawclambda (undocumented) + -dclambda (undocumented) + -dflambda Print Flambda terms + -drawflambda Print Flambda terms after closure conversion + -dflambda-invariants Check Flambda invariants around each pass + -dflambda-no-invariants Do not Check Flambda invariants around each pass + -dflambda-let Print when the given Flambda [Let] is created + -dflambda-verbose Print Flambda terms including around each pass + -dcmm (undocumented) + -dsel (undocumented) + -dcombine (undocumented) + -dcse (undocumented) + -dlive (undocumented) + -davail Print register availability info when printing liveness + -drunavail Run register availability pass (for testing only; needs -g) + -dspill (undocumented) + -dsplit (undocumented) + -dinterf (undocumented) + -dprefer (undocumented) + -dalloc (undocumented) + -dreload (undocumented) + -dscheduling (undocumented) + -dlinear (undocumented) + -dinterval (undocumented) + -dstartup (undocumented) + -dtimings Print timings information for each pass + -dprofile Print performance information for each pass + The columns are: time alloc top-heap absolute-top-heap. + -dump-pass Record transformations performed by these passes: + unbox-closures unbox-specialised-args unbox-free-vars-of-closures + remove-free-vars-equal-to-args remove-unused-arguments unused-arguments + -args Read additional newline-terminated command line arguments + from + -args0 Read additional null character terminated command line arguments +from + -depend Compute dependencies (use 'ocamlopt -depend -help' for details) + -help Display this list of options + --help Display this list of options diff --git a/testsuite/tests/tool-command-line/unknown-file.byte.reference b/testsuite/tests/tool-command-line/unknown-file.byte.reference deleted file mode 100644 index 9182c8a7..00000000 --- a/testsuite/tests/tool-command-line/unknown-file.byte.reference +++ /dev/null @@ -1 +0,0 @@ -don't know what to do with unknown-file diff --git a/testsuite/tests/tool-command-line/unknown-file.opt.reference b/testsuite/tests/tool-command-line/unknown-file.opt.reference deleted file mode 100644 index 9182c8a7..00000000 --- a/testsuite/tests/tool-command-line/unknown-file.opt.reference +++ /dev/null @@ -1 +0,0 @@ -don't know what to do with unknown-file diff --git a/testsuite/tests/tool-debugger/basic/Makefile b/testsuite/tests/tool-debugger/basic/Makefile deleted file mode 100644 index d732007a..00000000 --- a/testsuite/tests/tool-debugger/basic/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, EPI Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../../.. -MAIN_MODULE=debuggee -ADD_COMPFLAGS=-g -custom -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(MAKE) compile; \ - $(SET_LD_PATH) OCAMLLIB=. $(MAKE) run; \ - fi - -.PHONY: compile -compile: $(ML_FILES) $(CMO_FILES) $(MAIN_MODULE).cmo - @rm -f program.byte program.byte.exe - @$(OCAMLC) $(ADD_COMPFLAGS) $(ADD_CFLAGS) -o program.byte$(EXE) \ - $(O_FILES) $(CMA_FILES) $(CMO_FILES) $(ADD_CMO_FILES) \ - $(MAIN_MODULE).cmo - @mkdir -p compiler-libs - @cp $(TOPDIR)/toplevel/topdirs.cmi compiler-libs/ - -.PHONY: run -run: - @printf " ... testing with ocamlc" - @rm -f $(MAIN_MODULE).result - @echo 'source input_script' | \ - $(OCAMLRUN) `$(CYGPATH) $(TOPDIR)/debugger/ocamldebug$(EXE)` \ - program.byte$(EXE) >$(MAIN_MODULE).raw.result 2>&1 \ - && sed -e '/Debugger version/d' -e '/^Time:/d' -e '$$d' \ - $(MAIN_MODULE).raw.result >$(MAIN_MODULE).result \ - && $(DIFF) $(MAIN_MODULE).reference $(MAIN_MODULE).result >/dev/null \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result program.byte program.byte.exe \ - program.native program.native.exe \ - $(GENERATED_SOURCES) $(O_FILES) $(TEST_TEMP_FILES) - @rm -rf compiler-libs - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-debugger/basic/debuggee.ml b/testsuite/tests/tool-debugger/basic/debuggee.ml index 341d0b36..6bdac7e7 100644 --- a/testsuite/tests/tool-debugger/basic/debuggee.ml +++ b/testsuite/tests/tool-debugger/basic/debuggee.ml @@ -1,2 +1,14 @@ +(* TEST +set foo = "bar" +flags += " -g " +ocamldebug_script = "${test_source_directory}/input_script" +* shared-libraries +** setup-ocamlc.byte-build-env +*** ocamlc.byte +**** check-ocamlc.byte-output +***** ocamldebug +****** check-program-output +*) + print_endline Sys.argv.(1);; print_endline (Sys.getenv "foo");; diff --git a/testsuite/tests/tool-debugger/basic/debuggee.reference b/testsuite/tests/tool-debugger/basic/debuggee.reference index e998926c..fa9830a6 100644 --- a/testsuite/tests/tool-debugger/basic/debuggee.reference +++ b/testsuite/tests/tool-debugger/basic/debuggee.reference @@ -1,5 +1,4 @@ - -(ocd) Loading program... done. +Loading program... done. arg1 notbar Program exit. diff --git a/testsuite/tests/tool-debugger/basic/input_script b/testsuite/tests/tool-debugger/basic/input_script old mode 100755 new mode 100644 diff --git a/testsuite/tests/tool-debugger/basic/ocamltests b/testsuite/tests/tool-debugger/basic/ocamltests new file mode 100644 index 00000000..4f8025c7 --- /dev/null +++ b/testsuite/tests/tool-debugger/basic/ocamltests @@ -0,0 +1 @@ +debuggee.ml diff --git a/testsuite/tests/tool-debugger/find-artifacts/Makefile b/testsuite/tests/tool-debugger/find-artifacts/Makefile deleted file mode 100644 index 13fe316a..00000000 --- a/testsuite/tests/tool-debugger/find-artifacts/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, EPI Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../../.. -MAIN_MODULE=debuggee -ADD_COMPFLAGS=-g -custom -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(MAKE) compile; \ - $(SET_LD_PATH) OCAMLLIB=. $(MAKE) run; \ - fi - -.PHONY: compile -compile: $(ML_FILES) $(CMO_FILES) - @rm -rf out - @rm -f program.byte program.byte.exe - @mkdir out - @$(OCAMLC) $(ADD_COMPFLAGS) $(ADD_CFLAGS) -o out/blah.cmo -c \ - $(O_FILES) $(CMA_FILES) $(CMO_FILES) $(ADD_CMO_FILES) \ - in/blah.ml - @$(OCAMLC) $(ADD_COMPFLAGS) $(ADD_CFLAGS) -o out/foo.cmo -c \ - $(O_FILES) $(CMA_FILES) $(CMO_FILES) $(ADD_CMO_FILES) \ - -I out in/foo.ml - @$(OCAMLC) $(ADD_COMPFLAGS) $(ADD_CFLAGS) -o program.byte$(EXE) \ - $(O_FILES) $(CMA_FILES) $(CMO_FILES) $(ADD_CMO_FILES) \ - out/blah.cmo out/foo.cmo - @mkdir -p compiler-libs - @cp $(TOPDIR)/toplevel/topdirs.cmi compiler-libs/ - -.PHONY: run -run: - @printf " ... testing with ocamlc" - @rm -f $(MAIN_MODULE).result - @echo 'source input_script' | \ - $(OCAMLRUN) `$(CYGPATH) $(TOPDIR)/debugger/ocamldebug$(EXE)` \ - program.byte$(EXE) >$(MAIN_MODULE).raw.result 2>&1 \ - && sed -e '/Debugger version/d' -e '/^Time:/d' \ - -e '/Breakpoint [0-9]* at [0-9]*:/d' -e '$$d' \ - $(MAIN_MODULE).raw.result | tr -d '\r' >$(MAIN_MODULE).result \ - && $(DIFF) $(MAIN_MODULE).reference $(MAIN_MODULE).result >/dev/null \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result program.byte program.byte.exe \ - program.native program.native.exe \ - $(GENERATED_SOURCES) $(O_FILES) $(TEST_TEMP_FILES) - @rm -rf compiler-libs out - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-debugger/find-artifacts/debuggee.ml b/testsuite/tests/tool-debugger/find-artifacts/debuggee.ml new file mode 100644 index 00000000..c06350ed --- /dev/null +++ b/testsuite/tests/tool-debugger/find-artifacts/debuggee.ml @@ -0,0 +1,24 @@ +(* TEST +ocamldebug_script = "${test_source_directory}/input_script" +* shared-libraries +** setup-ocamlc.byte-build-env +*** script +script = "mkdir out" +**** ocamlc.byte +flags = "-g -c" +all_modules = "${test_source_directory}/in/blah.ml" +program = "out/blah.cmo" +***** ocamlc.byte +program = "out/foo.cmo" +flags = "-I out -g -c" +all_modules = "${test_source_directory}/in/foo.ml" +****** ocamlc.byte +all_modules = "out/blah.cmo out/foo.cmo" +flags = " -g " +program = "debuggee.exe" +******* check-ocamlc.byte-output +******** ocamldebug +********* check-program-output +*) + +(* This file only contains the specification of how to run the test *) diff --git a/testsuite/tests/tool-debugger/find-artifacts/debuggee.reference b/testsuite/tests/tool-debugger/find-artifacts/debuggee.reference index 06564f90..127d6672 100644 --- a/testsuite/tests/tool-debugger/find-artifacts/debuggee.reference +++ b/testsuite/tests/tool-debugger/find-artifacts/debuggee.reference @@ -1,5 +1,4 @@ - -(ocd) Loading program... done. +Loading program... done. Breakpoint: 1 10 <|b|>print x; x: Blah.blah = Foo diff --git a/testsuite/tests/tool-debugger/find-artifacts/ocamltests b/testsuite/tests/tool-debugger/find-artifacts/ocamltests new file mode 100644 index 00000000..4f8025c7 --- /dev/null +++ b/testsuite/tests/tool-debugger/find-artifacts/ocamltests @@ -0,0 +1 @@ +debuggee.ml diff --git a/testsuite/tests/tool-debugger/no_debug_event/Makefile b/testsuite/tests/tool-debugger/no_debug_event/Makefile deleted file mode 100644 index 7ddafa35..00000000 --- a/testsuite/tests/tool-debugger/no_debug_event/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, EPI Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2013 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../../.. -ADD_COMPFLAGS=-g -custom -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(MAKE) compile; \ - $(SET_LD_PATH) OCAMLLIB=. $(MAKE) run; \ - fi - -.PHONY: compile -compile: $(ML_FILES) $(CMO_FILES) - @rm -f c$(EXE) - @$(OCAMLC) $(ADD_COMPFLAGS) -c a.ml -for-pack foo - @$(OCAMLC) $(ADD_COMPFLAGS) a.cmo -pack -o foo.cmo - @$(OCAMLC) $(ADD_COMPFLAGS) -c b.ml - @$(OCAMLC) $(ADD_COMPFLAGS) foo.cmo b.cmo -o c$(EXE) - @mkdir -p compiler-libs - @cp $(TOPDIR)/toplevel/topdirs.cmi compiler-libs/ - -.PHONY: run -run: - @printf " ... testing with ocamlc" - @rm -f noev.result - @echo 'source input_script' | \ - $(OCAMLRUN) `$(CYGPATH) $(TOPDIR)/debugger/ocamldebug$(EXE)` \ - c$(EXE) >noev.raw.result 2>&1 \ - && sed -e '/Debugger version/d' -e '/^Time:/d' \ - -e '/Breakpoint [0-9]* at [0-9]*:/d' -e '$$d' \ - noev.raw.result >noev.result \ - && $(DIFF) noev.reference noev.result >/dev/null \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result *.cm* c$(EXE) - @rm -rf compiler-libs - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-debugger/no_debug_event/noev.ml b/testsuite/tests/tool-debugger/no_debug_event/noev.ml new file mode 100644 index 00000000..92f5b09f --- /dev/null +++ b/testsuite/tests/tool-debugger/no_debug_event/noev.ml @@ -0,0 +1,27 @@ +(* TEST +files = "a.ml b.ml" +ocamldebug_script = "${test_source_directory}/input_script" +* shared-libraries +** setup-ocamlc.byte-build-env +*** ocamlc.byte +module = "a.ml" +flags = "-g -for-pack foo" +**** ocamlc.byte +module = "" +all_modules = "a.cmo" +program = "foo.cmo" +flags = "-g -pack" +***** ocamlc.byte +module = "b.ml" +flags = " -g " +****** ocamlc.byte +module = "" +flags = " -g " +all_modules = "foo.cmo b.cmo" +program = "${test_build_directory}/noev.exe" +******* check-ocamlc.byte-output +******** ocamldebug +********* check-program-output +*) + +(* This file only contains the specification of how to run the test *) diff --git a/testsuite/tests/tool-debugger/no_debug_event/noev.reference b/testsuite/tests/tool-debugger/no_debug_event/noev.reference index d4a69fc9..25598a7e 100644 --- a/testsuite/tests/tool-debugger/no_debug_event/noev.reference +++ b/testsuite/tests/tool-debugger/no_debug_event/noev.reference @@ -1,4 +1,3 @@ - -(ocd) Loading program... done. +Loading program... done. 1 Program exit. diff --git a/testsuite/tests/tool-debugger/no_debug_event/ocamltests b/testsuite/tests/tool-debugger/no_debug_event/ocamltests new file mode 100644 index 00000000..33175c28 --- /dev/null +++ b/testsuite/tests/tool-debugger/no_debug_event/ocamltests @@ -0,0 +1 @@ +noev.ml diff --git a/testsuite/tests/tool-lexyacc/Makefile b/testsuite/tests/tool-lexyacc/Makefile deleted file mode 100644 index 479e8a25..00000000 --- a/testsuite/tests/tool-lexyacc/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=syntax gram_aux grammar scan_aux scanner lexgen output -MAIN_MODULE=main -LEX_MODULES=scanner -YACC_MODULES=grammar -ADD_COMPFLAGS=-w a -EXEC_ARGS=input - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-lexyacc/main.compilers.reference b/testsuite/tests/tool-lexyacc/main.compilers.reference new file mode 100644 index 00000000..a19b8c29 --- /dev/null +++ b/testsuite/tests/tool-lexyacc/main.compilers.reference @@ -0,0 +1 @@ +14 shift/reduce conflicts, 2 reduce/reduce conflicts. diff --git a/testsuite/tests/tool-lexyacc/main.ml b/testsuite/tests/tool-lexyacc/main.ml index 16b9a3a9..4f58b93e 100644 --- a/testsuite/tests/tool-lexyacc/main.ml +++ b/testsuite/tests/tool-lexyacc/main.ml @@ -1,3 +1,12 @@ +(* TEST + modules = "syntax.ml gram_aux.ml grammar.mly scan_aux.ml scanner.mll lexgen.ml output.ml" + files = "input" + arguments = "input" + ocamllex_flags = " -q " + ocamlyacc_flags = " -q " + flags = " -w a " +*) + (* The lexer generator. Command-line parsing. *) open Syntax diff --git a/testsuite/tests/tool-lexyacc/ocamltests b/testsuite/tests/tool-lexyacc/ocamltests new file mode 100644 index 00000000..d389d156 --- /dev/null +++ b/testsuite/tests/tool-lexyacc/ocamltests @@ -0,0 +1 @@ +main.ml diff --git a/testsuite/tests/tool-ocaml/Makefile b/testsuite/tests/tool-ocaml/Makefile deleted file mode 100644 index cd4578d7..00000000 --- a/testsuite/tests/tool-ocaml/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -SHOULD_FAIL=t060-raise.ml - -compile: lib.cmo - @for file in t*.ml; do \ - printf " ... testing '$$file'"; \ - if [ `echo $(SHOULD_FAIL) | grep $$file` ]; then \ - $(OCAML) -w a lib.cmo $$file 2>/dev/null \ - && echo " => failed" || echo " => passed"; \ - else \ - $(OCAML) -w a lib.cmo $$file 2>/dev/null \ - && echo " => passed" || echo " => failed"; \ - fi; \ - done - -promote: - -clean: defaultclean - @rm -f ./a.out - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocaml/ocamltests b/testsuite/tests/tool-ocaml/ocamltests new file mode 100644 index 00000000..de7fc74f --- /dev/null +++ b/testsuite/tests/tool-ocaml/ocamltests @@ -0,0 +1,157 @@ +t000.ml +t010-const0.ml +t010-const1.ml +t010-const2.ml +t010-const3.ml +t011-constint.ml +t020.ml +t021-pushconst1.ml +t021-pushconst2.ml +t021-pushconst3.ml +t022-pushconstint.ml +t040-makeblock1.ml +t040-makeblock2.ml +t040-makeblock3.ml +t041-makeblock.ml +t050-getglobal.ml +t050-pushgetglobal.ml +t051-getglobalfield.ml +t051-pushgetglobalfield.ml +t060-raise.ml +t070-branchif.ml +t070-branchifnot.ml +t070-branch.ml +t071-boolnot.ml +t080-eq.ml +t080-geint.ml +t080-gtint.ml +t080-leint.ml +t080-ltint.ml +t080-neq.ml +t090-acc0.ml +t090-acc1.ml +t090-acc2.ml +t090-acc3.ml +t090-acc4.ml +t090-acc5.ml +t090-acc6.ml +t090-acc7.ml +t091-acc.ml +t092-pushacc0.ml +t092-pushacc1.ml +t092-pushacc2.ml +t092-pushacc3.ml +t092-pushacc4.ml +t092-pushacc5.ml +t092-pushacc6.ml +t092-pushacc7.ml +t092-pushacc.ml +t093-pushacc.ml +t100-pushtrap.ml +t101-poptrap.ml +t110-addint.ml +t110-andint.ml +t110-asrint-1.ml +t110-asrint-2.ml +t110-divint-1.ml +t110-divint-2.ml +t110-divint-3.ml +t110-lslint.ml +t110-lsrint.ml +t110-modint-1.ml +t110-modint-2.ml +t110-mulint.ml +t110-negint.ml +t110-offsetint.ml +t110-orint.ml +t110-subint.ml +t110-xorint.ml +t120-getstringchar.ml +t121-setstringchar.ml +t130-getvectitem.ml +t130-vectlength.ml +t131-setvectitem.ml +t140-switch-1.ml +t140-switch-2.ml +t140-switch-3.ml +t140-switch-4.ml +t141-switch-5.ml +t141-switch-6.ml +t141-switch-7.ml +t142-switch-8.ml +t142-switch-9.ml +t142-switch-A.ml +t150-push-1.ml +t150-push-2.ml +t160-closure.ml +t161-apply1.ml +t162-return.ml +t163.ml +t164-apply2.ml +t164-apply3.ml +t165-apply.ml +t170-envacc2.ml +t170-envacc3.ml +t170-envacc4.ml +t171-envacc.ml +t172-pushenvacc1.ml +t172-pushenvacc2.ml +t172-pushenvacc3.ml +t172-pushenvacc4.ml +t173-pushenvacc.ml +t180-appterm1.ml +t180-appterm2.ml +t180-appterm3.ml +t181-appterm.ml +t190-makefloatblock-1.ml +t190-makefloatblock-2.ml +t190-makefloatblock-3.ml +t191-vectlength.ml +t192-getfloatfield-1.ml +t192-getfloatfield-2.ml +t193-setfloatfield-1.ml +t193-setfloatfield-2.ml +t200-getfield0.ml +t200-getfield1.ml +t200-getfield2.ml +t200-getfield3.ml +t201-getfield.ml +t210-setfield0.ml +t210-setfield1.ml +t210-setfield2.ml +t210-setfield3.ml +t211-setfield.ml +t220-assign.ml +t230-check_signals.ml +t240-c_call1.ml +t240-c_call2.ml +t240-c_call3.ml +t240-c_call4.ml +t240-c_call5.ml +t250-closurerec-1.ml +t250-closurerec-2.ml +t251-pushoffsetclosure0.ml +t251-pushoffsetclosure2.ml +t251-pushoffsetclosurem2.ml +t252-pushoffsetclosure.ml +t253-offsetclosure0.ml +t253-offsetclosure2.ml +t253-offsetclosurem2.ml +t254-offsetclosure.ml +t260-offsetref.ml +t270-push_retaddr.ml +t300-getmethod.ml +t301-object.ml +t310-alloc-1.ml +t310-alloc-2.ml +t320-gc-1.ml +t320-gc-2.ml +t320-gc-3.ml +t330-compact-1.ml +t330-compact-2.ml +t330-compact-3.ml +t330-compact-4.ml +t340-weak.ml +t350-heapcheck.ml +t360-stacks-1.ml +t360-stacks-2.ml diff --git a/testsuite/tests/tool-ocaml/t000.ml b/testsuite/tests/tool-ocaml/t000.ml index 27520c66..87deb62f 100644 --- a/testsuite/tests/tool-ocaml/t000.ml +++ b/testsuite/tests/tool-ocaml/t000.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + (* empty file *) (** diff --git a/testsuite/tests/tool-ocaml/t010-const0.ml b/testsuite/tests/tool-ocaml/t010-const0.ml index 65bb3ded..b1592185 100644 --- a/testsuite/tests/tool-ocaml/t010-const0.ml +++ b/testsuite/tests/tool-ocaml/t010-const0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + 0;; (** diff --git a/testsuite/tests/tool-ocaml/t010-const1.ml b/testsuite/tests/tool-ocaml/t010-const1.ml index 8238b4fc..83629d71 100644 --- a/testsuite/tests/tool-ocaml/t010-const1.ml +++ b/testsuite/tests/tool-ocaml/t010-const1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + 1;; (** diff --git a/testsuite/tests/tool-ocaml/t010-const2.ml b/testsuite/tests/tool-ocaml/t010-const2.ml index 8bbffdbc..8b467ddd 100644 --- a/testsuite/tests/tool-ocaml/t010-const2.ml +++ b/testsuite/tests/tool-ocaml/t010-const2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + 2;; (** diff --git a/testsuite/tests/tool-ocaml/t010-const3.ml b/testsuite/tests/tool-ocaml/t010-const3.ml index e5767ccc..68340da7 100644 --- a/testsuite/tests/tool-ocaml/t010-const3.ml +++ b/testsuite/tests/tool-ocaml/t010-const3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + 3;; (** diff --git a/testsuite/tests/tool-ocaml/t011-constint.ml b/testsuite/tests/tool-ocaml/t011-constint.ml index 104f6050..08dc0802 100644 --- a/testsuite/tests/tool-ocaml/t011-constint.ml +++ b/testsuite/tests/tool-ocaml/t011-constint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + 4;; (** diff --git a/testsuite/tests/tool-ocaml/t020.ml b/testsuite/tests/tool-ocaml/t020.ml index afbce871..3eb1a723 100644 --- a/testsuite/tests/tool-ocaml/t020.ml +++ b/testsuite/tests/tool-ocaml/t020.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in ();; (** diff --git a/testsuite/tests/tool-ocaml/t021-pushconst1.ml b/testsuite/tests/tool-ocaml/t021-pushconst1.ml index 863bd89a..576e9ddd 100644 --- a/testsuite/tests/tool-ocaml/t021-pushconst1.ml +++ b/testsuite/tests/tool-ocaml/t021-pushconst1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in 1;; (** diff --git a/testsuite/tests/tool-ocaml/t021-pushconst2.ml b/testsuite/tests/tool-ocaml/t021-pushconst2.ml index 9e7e42a9..e876901b 100644 --- a/testsuite/tests/tool-ocaml/t021-pushconst2.ml +++ b/testsuite/tests/tool-ocaml/t021-pushconst2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in 2;; (** diff --git a/testsuite/tests/tool-ocaml/t021-pushconst3.ml b/testsuite/tests/tool-ocaml/t021-pushconst3.ml index 5a674f6a..eda9799a 100644 --- a/testsuite/tests/tool-ocaml/t021-pushconst3.ml +++ b/testsuite/tests/tool-ocaml/t021-pushconst3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in 3;; (** diff --git a/testsuite/tests/tool-ocaml/t022-pushconstint.ml b/testsuite/tests/tool-ocaml/t022-pushconstint.ml index f1c71ea5..fc7ac9e1 100644 --- a/testsuite/tests/tool-ocaml/t022-pushconstint.ml +++ b/testsuite/tests/tool-ocaml/t022-pushconstint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in -1;; (** diff --git a/testsuite/tests/tool-ocaml/t040-makeblock1.ml b/testsuite/tests/tool-ocaml/t040-makeblock1.ml index 87458cd9..1fd56689 100644 --- a/testsuite/tests/tool-ocaml/t040-makeblock1.ml +++ b/testsuite/tests/tool-ocaml/t040-makeblock1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + type t = { mutable a : int; };; diff --git a/testsuite/tests/tool-ocaml/t040-makeblock2.ml b/testsuite/tests/tool-ocaml/t040-makeblock2.ml index d64c3401..e33bd036 100644 --- a/testsuite/tests/tool-ocaml/t040-makeblock2.ml +++ b/testsuite/tests/tool-ocaml/t040-makeblock2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + type t = { mutable a : int; mutable b : int; diff --git a/testsuite/tests/tool-ocaml/t040-makeblock3.ml b/testsuite/tests/tool-ocaml/t040-makeblock3.ml index 03c79818..1af62b8e 100644 --- a/testsuite/tests/tool-ocaml/t040-makeblock3.ml +++ b/testsuite/tests/tool-ocaml/t040-makeblock3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + type t = { mutable a : int; mutable b : int; diff --git a/testsuite/tests/tool-ocaml/t041-makeblock.ml b/testsuite/tests/tool-ocaml/t041-makeblock.ml index 4d38eac8..db9004fb 100644 --- a/testsuite/tests/tool-ocaml/t041-makeblock.ml +++ b/testsuite/tests/tool-ocaml/t041-makeblock.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + type t = { mutable a : int; mutable b : int; diff --git a/testsuite/tests/tool-ocaml/t050-getglobal.ml b/testsuite/tests/tool-ocaml/t050-getglobal.ml index 7481ca2a..1dc0f6b3 100644 --- a/testsuite/tests/tool-ocaml/t050-getglobal.ml +++ b/testsuite/tests/tool-ocaml/t050-getglobal.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + [1];; (** diff --git a/testsuite/tests/tool-ocaml/t050-pushgetglobal.ml b/testsuite/tests/tool-ocaml/t050-pushgetglobal.ml index 62be92f0..ddb5858a 100644 --- a/testsuite/tests/tool-ocaml/t050-pushgetglobal.ml +++ b/testsuite/tests/tool-ocaml/t050-pushgetglobal.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in 0.01;; (** diff --git a/testsuite/tests/tool-ocaml/t051-getglobalfield.ml b/testsuite/tests/tool-ocaml/t051-getglobalfield.ml index eb3b6108..afbb1a31 100644 --- a/testsuite/tests/tool-ocaml/t051-getglobalfield.ml +++ b/testsuite/tests/tool-ocaml/t051-getglobalfield.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + Lib.x;; (** diff --git a/testsuite/tests/tool-ocaml/t051-pushgetglobalfield.ml b/testsuite/tests/tool-ocaml/t051-pushgetglobalfield.ml index 3e8a37e6..42681186 100644 --- a/testsuite/tests/tool-ocaml/t051-pushgetglobalfield.ml +++ b/testsuite/tests/tool-ocaml/t051-pushgetglobalfield.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + let _ = () in Lib.x;; (** diff --git a/testsuite/tests/tool-ocaml/t060-raise.ml b/testsuite/tests/tool-ocaml/t060-raise.ml index aff2e387..b212348e 100644 --- a/testsuite/tests/tool-ocaml/t060-raise.ml +++ b/testsuite/tests/tool-ocaml/t060-raise.ml @@ -1,3 +1,12 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +ocaml_exit_status = "2" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; raise End_of_file;; diff --git a/testsuite/tests/tool-ocaml/t070-branch.ml b/testsuite/tests/tool-ocaml/t070-branch.ml index 92e00c09..e2de0da3 100644 --- a/testsuite/tests/tool-ocaml/t070-branch.ml +++ b/testsuite/tests/tool-ocaml/t070-branch.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if true then 0 else raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t070-branchif.ml b/testsuite/tests/tool-ocaml/t070-branchif.ml index 26675771..6e96a036 100644 --- a/testsuite/tests/tool-ocaml/t070-branchif.ml +++ b/testsuite/tests/tool-ocaml/t070-branchif.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if not false then 0 else raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t070-branchifnot.ml b/testsuite/tests/tool-ocaml/t070-branchifnot.ml index d8fa5950..90949503 100644 --- a/testsuite/tests/tool-ocaml/t070-branchifnot.ml +++ b/testsuite/tests/tool-ocaml/t070-branchifnot.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if false then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t071-boolnot.ml b/testsuite/tests/tool-ocaml/t071-boolnot.ml index 8993d134..50e1c737 100644 --- a/testsuite/tests/tool-ocaml/t071-boolnot.ml +++ b/testsuite/tests/tool-ocaml/t071-boolnot.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if not true then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-eq.ml b/testsuite/tests/tool-ocaml/t080-eq.ml index 53d82f2e..d9c335db 100644 --- a/testsuite/tests/tool-ocaml/t080-eq.ml +++ b/testsuite/tests/tool-ocaml/t080-eq.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if not (0 = 0) then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-geint.ml b/testsuite/tests/tool-ocaml/t080-geint.ml index 9da5078f..3eb3d257 100644 --- a/testsuite/tests/tool-ocaml/t080-geint.ml +++ b/testsuite/tests/tool-ocaml/t080-geint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if not (0 >= 0) then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-gtint.ml b/testsuite/tests/tool-ocaml/t080-gtint.ml index dfefd259..5099b21d 100644 --- a/testsuite/tests/tool-ocaml/t080-gtint.ml +++ b/testsuite/tests/tool-ocaml/t080-gtint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 0 > 0 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-leint.ml b/testsuite/tests/tool-ocaml/t080-leint.ml index 04880dc0..b6a88919 100644 --- a/testsuite/tests/tool-ocaml/t080-leint.ml +++ b/testsuite/tests/tool-ocaml/t080-leint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if not (0 <= 0) then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-ltint.ml b/testsuite/tests/tool-ocaml/t080-ltint.ml index 8f23f297..b7f376e6 100644 --- a/testsuite/tests/tool-ocaml/t080-ltint.ml +++ b/testsuite/tests/tool-ocaml/t080-ltint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 0 < 0 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t080-neq.ml b/testsuite/tests/tool-ocaml/t080-neq.ml index a43d84c9..ed219d65 100644 --- a/testsuite/tests/tool-ocaml/t080-neq.ml +++ b/testsuite/tests/tool-ocaml/t080-neq.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 0 <> 0 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t090-acc0.ml b/testsuite/tests/tool-ocaml/t090-acc0.ml index 669249b6..5bbebdd7 100644 --- a/testsuite/tests/tool-ocaml/t090-acc0.ml +++ b/testsuite/tests/tool-ocaml/t090-acc0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in (); diff --git a/testsuite/tests/tool-ocaml/t090-acc1.ml b/testsuite/tests/tool-ocaml/t090-acc1.ml index 33f3e4e3..da9b8772 100644 --- a/testsuite/tests/tool-ocaml/t090-acc1.ml +++ b/testsuite/tests/tool-ocaml/t090-acc1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc2.ml b/testsuite/tests/tool-ocaml/t090-acc2.ml index 415727a1..48ba4d4e 100644 --- a/testsuite/tests/tool-ocaml/t090-acc2.ml +++ b/testsuite/tests/tool-ocaml/t090-acc2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc3.ml b/testsuite/tests/tool-ocaml/t090-acc3.ml index 4faf079c..6d40d557 100644 --- a/testsuite/tests/tool-ocaml/t090-acc3.ml +++ b/testsuite/tests/tool-ocaml/t090-acc3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc4.ml b/testsuite/tests/tool-ocaml/t090-acc4.ml index 0d4bd892..32fd2a1c 100644 --- a/testsuite/tests/tool-ocaml/t090-acc4.ml +++ b/testsuite/tests/tool-ocaml/t090-acc4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc5.ml b/testsuite/tests/tool-ocaml/t090-acc5.ml index a4176c75..657d8701 100644 --- a/testsuite/tests/tool-ocaml/t090-acc5.ml +++ b/testsuite/tests/tool-ocaml/t090-acc5.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc6.ml b/testsuite/tests/tool-ocaml/t090-acc6.ml index db456b38..a6cfd26f 100644 --- a/testsuite/tests/tool-ocaml/t090-acc6.ml +++ b/testsuite/tests/tool-ocaml/t090-acc6.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t090-acc7.ml b/testsuite/tests/tool-ocaml/t090-acc7.ml index c53003c6..03b67ecc 100644 --- a/testsuite/tests/tool-ocaml/t090-acc7.ml +++ b/testsuite/tests/tool-ocaml/t090-acc7.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t091-acc.ml b/testsuite/tests/tool-ocaml/t091-acc.ml index 06c2ad8d..57c17dfc 100644 --- a/testsuite/tests/tool-ocaml/t091-acc.ml +++ b/testsuite/tests/tool-ocaml/t091-acc.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = true in let y = false in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc.ml b/testsuite/tests/tool-ocaml/t092-pushacc.ml index 75eac87f..4cff5cfb 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc0.ml b/testsuite/tests/tool-ocaml/t092-pushacc0.ml index 756304df..3108757a 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc0.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in if x then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t092-pushacc1.ml b/testsuite/tests/tool-ocaml/t092-pushacc1.ml index e5cd00af..5cd5f760 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc1.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc2.ml b/testsuite/tests/tool-ocaml/t092-pushacc2.ml index b1c66c4d..290c8cd6 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc2.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc3.ml b/testsuite/tests/tool-ocaml/t092-pushacc3.ml index 0713c0b6..28309d71 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc3.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc4.ml b/testsuite/tests/tool-ocaml/t092-pushacc4.ml index 9052f7f6..4ea3d847 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc4.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc5.ml b/testsuite/tests/tool-ocaml/t092-pushacc5.ml index 0f5e32e7..f6b063f4 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc5.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc5.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc6.ml b/testsuite/tests/tool-ocaml/t092-pushacc6.ml index a3de52ca..0e1e6368 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc6.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc6.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t092-pushacc7.ml b/testsuite/tests/tool-ocaml/t092-pushacc7.ml index cd1481d2..4c057cc5 100644 --- a/testsuite/tests/tool-ocaml/t092-pushacc7.ml +++ b/testsuite/tests/tool-ocaml/t092-pushacc7.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t093-pushacc.ml b/testsuite/tests/tool-ocaml/t093-pushacc.ml index 8e756b1c..c072dc07 100644 --- a/testsuite/tests/tool-ocaml/t093-pushacc.ml +++ b/testsuite/tests/tool-ocaml/t093-pushacc.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = false in let y = true in diff --git a/testsuite/tests/tool-ocaml/t100-pushtrap.ml b/testsuite/tests/tool-ocaml/t100-pushtrap.ml index 8eae20e5..d5f06b6f 100644 --- a/testsuite/tests/tool-ocaml/t100-pushtrap.ml +++ b/testsuite/tests/tool-ocaml/t100-pushtrap.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; try raise Not_found with _ -> () diff --git a/testsuite/tests/tool-ocaml/t101-poptrap.ml b/testsuite/tests/tool-ocaml/t101-poptrap.ml index cbb5944f..42b84c60 100644 --- a/testsuite/tests/tool-ocaml/t101-poptrap.ml +++ b/testsuite/tests/tool-ocaml/t101-poptrap.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; try () with _ -> () diff --git a/testsuite/tests/tool-ocaml/t110-addint.ml b/testsuite/tests/tool-ocaml/t110-addint.ml index 39aa844d..c3733cb8 100644 --- a/testsuite/tests/tool-ocaml/t110-addint.ml +++ b/testsuite/tests/tool-ocaml/t110-addint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 1 in if 1 + x <> 2 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t110-andint.ml b/testsuite/tests/tool-ocaml/t110-andint.ml index 44017ece..5f92f9a2 100644 --- a/testsuite/tests/tool-ocaml/t110-andint.ml +++ b/testsuite/tests/tool-ocaml/t110-andint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (3 land 6) <> 2 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-asrint-1.ml b/testsuite/tests/tool-ocaml/t110-asrint-1.ml index bab98685..a86d85c4 100644 --- a/testsuite/tests/tool-ocaml/t110-asrint-1.ml +++ b/testsuite/tests/tool-ocaml/t110-asrint-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (-2 asr 1) <> -1 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-asrint-2.ml b/testsuite/tests/tool-ocaml/t110-asrint-2.ml index be714867..a028d36c 100644 --- a/testsuite/tests/tool-ocaml/t110-asrint-2.ml +++ b/testsuite/tests/tool-ocaml/t110-asrint-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (3 asr 1) <> 1 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-divint-1.ml b/testsuite/tests/tool-ocaml/t110-divint-1.ml index 2c1c5b94..3c5cfb64 100644 --- a/testsuite/tests/tool-ocaml/t110-divint-1.ml +++ b/testsuite/tests/tool-ocaml/t110-divint-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 2 / 2 <> 1 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-divint-2.ml b/testsuite/tests/tool-ocaml/t110-divint-2.ml index effdf34b..b2cc2994 100644 --- a/testsuite/tests/tool-ocaml/t110-divint-2.ml +++ b/testsuite/tests/tool-ocaml/t110-divint-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 3 / 2 <> 1 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-divint-3.ml b/testsuite/tests/tool-ocaml/t110-divint-3.ml index 3ccc1512..e6a6913c 100644 --- a/testsuite/tests/tool-ocaml/t110-divint-3.ml +++ b/testsuite/tests/tool-ocaml/t110-divint-3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; try ignore (3 / 0); diff --git a/testsuite/tests/tool-ocaml/t110-lslint.ml b/testsuite/tests/tool-ocaml/t110-lslint.ml index bb25709e..b39a2c92 100644 --- a/testsuite/tests/tool-ocaml/t110-lslint.ml +++ b/testsuite/tests/tool-ocaml/t110-lslint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (3 lsl 2) <> 12 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-lsrint.ml b/testsuite/tests/tool-ocaml/t110-lsrint.ml index 21994a0b..619aedda 100644 --- a/testsuite/tests/tool-ocaml/t110-lsrint.ml +++ b/testsuite/tests/tool-ocaml/t110-lsrint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (14 lsr 2) <> 3 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-modint-1.ml b/testsuite/tests/tool-ocaml/t110-modint-1.ml index 97eaacdd..528ffa54 100644 --- a/testsuite/tests/tool-ocaml/t110-modint-1.ml +++ b/testsuite/tests/tool-ocaml/t110-modint-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 20 mod 3 <> 2 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-modint-2.ml b/testsuite/tests/tool-ocaml/t110-modint-2.ml index edc7ceb0..26141750 100644 --- a/testsuite/tests/tool-ocaml/t110-modint-2.ml +++ b/testsuite/tests/tool-ocaml/t110-modint-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; try ignore (2 mod 0); diff --git a/testsuite/tests/tool-ocaml/t110-mulint.ml b/testsuite/tests/tool-ocaml/t110-mulint.ml index 6c963f6a..d8544c83 100644 --- a/testsuite/tests/tool-ocaml/t110-mulint.ml +++ b/testsuite/tests/tool-ocaml/t110-mulint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 2 * 2 <> 4 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-negint.ml b/testsuite/tests/tool-ocaml/t110-negint.ml index aef6121d..7bff31d4 100644 --- a/testsuite/tests/tool-ocaml/t110-negint.ml +++ b/testsuite/tests/tool-ocaml/t110-negint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 1 in if -x <> -1 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t110-offsetint.ml b/testsuite/tests/tool-ocaml/t110-offsetint.ml index 7793d003..a7ed3970 100644 --- a/testsuite/tests/tool-ocaml/t110-offsetint.ml +++ b/testsuite/tests/tool-ocaml/t110-offsetint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if 2 + 2 <> 4 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-orint.ml b/testsuite/tests/tool-ocaml/t110-orint.ml index bb5e9453..3b77520b 100644 --- a/testsuite/tests/tool-ocaml/t110-orint.ml +++ b/testsuite/tests/tool-ocaml/t110-orint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (3 lor 6) <> 7 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t110-subint.ml b/testsuite/tests/tool-ocaml/t110-subint.ml index 06a23dd6..72ee30f6 100644 --- a/testsuite/tests/tool-ocaml/t110-subint.ml +++ b/testsuite/tests/tool-ocaml/t110-subint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 1 in if 1 - x <> 0 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t110-xorint.ml b/testsuite/tests/tool-ocaml/t110-xorint.ml index ae248d23..d5d3cb5b 100644 --- a/testsuite/tests/tool-ocaml/t110-xorint.ml +++ b/testsuite/tests/tool-ocaml/t110-xorint.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if (3 lxor 6) <> 5 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t120-getstringchar.ml b/testsuite/tests/tool-ocaml/t120-getstringchar.ml index a663ecf4..4988752d 100644 --- a/testsuite/tests/tool-ocaml/t120-getstringchar.ml +++ b/testsuite/tests/tool-ocaml/t120-getstringchar.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if "foo".[2] <> 'o' then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t121-setstringchar.ml b/testsuite/tests/tool-ocaml/t121-setstringchar.ml index ea19572e..f306c755 100644 --- a/testsuite/tests/tool-ocaml/t121-setstringchar.ml +++ b/testsuite/tests/tool-ocaml/t121-setstringchar.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = Bytes.of_string "foo" in x.[2] <- 'x'; diff --git a/testsuite/tests/tool-ocaml/t130-getvectitem.ml b/testsuite/tests/tool-ocaml/t130-getvectitem.ml index 964ebc9f..6cd28413 100644 --- a/testsuite/tests/tool-ocaml/t130-getvectitem.ml +++ b/testsuite/tests/tool-ocaml/t130-getvectitem.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if [| 1; 2 |].(1) <> 2 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t130-vectlength.ml b/testsuite/tests/tool-ocaml/t130-vectlength.ml index aee59441..7e14f3d5 100644 --- a/testsuite/tests/tool-ocaml/t130-vectlength.ml +++ b/testsuite/tests/tool-ocaml/t130-vectlength.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if Array.length [| 1; 2 |] <> 2 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t131-setvectitem.ml b/testsuite/tests/tool-ocaml/t131-setvectitem.ml index b813e91b..b78f51d2 100644 --- a/testsuite/tests/tool-ocaml/t131-setvectitem.ml +++ b/testsuite/tests/tool-ocaml/t131-setvectitem.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = [| 1; 2 |] in x.(0) <- 3; diff --git a/testsuite/tests/tool-ocaml/t140-switch-1.ml b/testsuite/tests/tool-ocaml/t140-switch-1.ml index 9e3eee15..54b3dd7f 100644 --- a/testsuite/tests/tool-ocaml/t140-switch-1.ml +++ b/testsuite/tests/tool-ocaml/t140-switch-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; match 0 with | 0 -> () diff --git a/testsuite/tests/tool-ocaml/t140-switch-2.ml b/testsuite/tests/tool-ocaml/t140-switch-2.ml index ecc5772a..88026c12 100644 --- a/testsuite/tests/tool-ocaml/t140-switch-2.ml +++ b/testsuite/tests/tool-ocaml/t140-switch-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; match 1 with | 0 -> raise Not_found diff --git a/testsuite/tests/tool-ocaml/t140-switch-3.ml b/testsuite/tests/tool-ocaml/t140-switch-3.ml index 316461df..f9b9cd70 100644 --- a/testsuite/tests/tool-ocaml/t140-switch-3.ml +++ b/testsuite/tests/tool-ocaml/t140-switch-3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; match 2 with | 0 -> raise Not_found diff --git a/testsuite/tests/tool-ocaml/t140-switch-4.ml b/testsuite/tests/tool-ocaml/t140-switch-4.ml index 6f72ba35..874a2442 100644 --- a/testsuite/tests/tool-ocaml/t140-switch-4.ml +++ b/testsuite/tests/tool-ocaml/t140-switch-4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; match -1 with | 0 -> raise Not_found diff --git a/testsuite/tests/tool-ocaml/t141-switch-5.ml b/testsuite/tests/tool-ocaml/t141-switch-5.ml index e5b49e6a..454e2b2e 100644 --- a/testsuite/tests/tool-ocaml/t141-switch-5.ml +++ b/testsuite/tests/tool-ocaml/t141-switch-5.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A of int diff --git a/testsuite/tests/tool-ocaml/t141-switch-6.ml b/testsuite/tests/tool-ocaml/t141-switch-6.ml index 5a720327..6bbd6af6 100644 --- a/testsuite/tests/tool-ocaml/t141-switch-6.ml +++ b/testsuite/tests/tool-ocaml/t141-switch-6.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A of int diff --git a/testsuite/tests/tool-ocaml/t141-switch-7.ml b/testsuite/tests/tool-ocaml/t141-switch-7.ml index a7082d08..19425f97 100644 --- a/testsuite/tests/tool-ocaml/t141-switch-7.ml +++ b/testsuite/tests/tool-ocaml/t141-switch-7.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A of int diff --git a/testsuite/tests/tool-ocaml/t142-switch-8.ml b/testsuite/tests/tool-ocaml/t142-switch-8.ml index d32346fc..0de6b8eb 100644 --- a/testsuite/tests/tool-ocaml/t142-switch-8.ml +++ b/testsuite/tests/tool-ocaml/t142-switch-8.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A diff --git a/testsuite/tests/tool-ocaml/t142-switch-9.ml b/testsuite/tests/tool-ocaml/t142-switch-9.ml index 5fbda767..4cdfc1f8 100644 --- a/testsuite/tests/tool-ocaml/t142-switch-9.ml +++ b/testsuite/tests/tool-ocaml/t142-switch-9.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A diff --git a/testsuite/tests/tool-ocaml/t142-switch-A.ml b/testsuite/tests/tool-ocaml/t142-switch-A.ml index fc8aa5c6..0d48e3b5 100644 --- a/testsuite/tests/tool-ocaml/t142-switch-A.ml +++ b/testsuite/tests/tool-ocaml/t142-switch-A.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = | A diff --git a/testsuite/tests/tool-ocaml/t150-push-1.ml b/testsuite/tests/tool-ocaml/t150-push-1.ml index 7319388a..8131d4eb 100644 --- a/testsuite/tests/tool-ocaml/t150-push-1.ml +++ b/testsuite/tests/tool-ocaml/t150-push-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let _ = 0 in try 0 with _ -> 0 diff --git a/testsuite/tests/tool-ocaml/t150-push-2.ml b/testsuite/tests/tool-ocaml/t150-push-2.ml index c0837bf1..49081e6f 100644 --- a/testsuite/tests/tool-ocaml/t150-push-2.ml +++ b/testsuite/tests/tool-ocaml/t150-push-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 1 in try if x <> 1 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t160-closure.ml b/testsuite/tests/tool-ocaml/t160-closure.ml index 2d2f0cce..ea1599b3 100644 --- a/testsuite/tests/tool-ocaml/t160-closure.ml +++ b/testsuite/tests/tool-ocaml/t160-closure.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f () = ();; diff --git a/testsuite/tests/tool-ocaml/t161-apply1.ml b/testsuite/tests/tool-ocaml/t161-apply1.ml index 2892cbe7..e11cba67 100644 --- a/testsuite/tests/tool-ocaml/t161-apply1.ml +++ b/testsuite/tests/tool-ocaml/t161-apply1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ = raise End_of_file in try diff --git a/testsuite/tests/tool-ocaml/t162-return.ml b/testsuite/tests/tool-ocaml/t162-return.ml index 1e08ab4e..63c49697 100644 --- a/testsuite/tests/tool-ocaml/t162-return.ml +++ b/testsuite/tests/tool-ocaml/t162-return.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ = 0 in f 0;; diff --git a/testsuite/tests/tool-ocaml/t163.ml b/testsuite/tests/tool-ocaml/t163.ml index e2760b97..266823a3 100644 --- a/testsuite/tests/tool-ocaml/t163.ml +++ b/testsuite/tests/tool-ocaml/t163.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ = 0 in f 0;; diff --git a/testsuite/tests/tool-ocaml/t164-apply2.ml b/testsuite/tests/tool-ocaml/t164-apply2.ml index ae908538..79ef4136 100644 --- a/testsuite/tests/tool-ocaml/t164-apply2.ml +++ b/testsuite/tests/tool-ocaml/t164-apply2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ = 0 in f 0 0;; diff --git a/testsuite/tests/tool-ocaml/t164-apply3.ml b/testsuite/tests/tool-ocaml/t164-apply3.ml index a05aac2a..1c4f236b 100644 --- a/testsuite/tests/tool-ocaml/t164-apply3.ml +++ b/testsuite/tests/tool-ocaml/t164-apply3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ _ = 0 in f 0 0 0;; diff --git a/testsuite/tests/tool-ocaml/t165-apply.ml b/testsuite/tests/tool-ocaml/t165-apply.ml index e4787321..f71e769c 100644 --- a/testsuite/tests/tool-ocaml/t165-apply.ml +++ b/testsuite/tests/tool-ocaml/t165-apply.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ _ _ = 0 in f 0 0 0 0;; diff --git a/testsuite/tests/tool-ocaml/t170-envacc2.ml b/testsuite/tests/tool-ocaml/t170-envacc2.ml index 8e9a0219..c09a08ce 100644 --- a/testsuite/tests/tool-ocaml/t170-envacc2.ml +++ b/testsuite/tests/tool-ocaml/t170-envacc2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 2 in diff --git a/testsuite/tests/tool-ocaml/t170-envacc3.ml b/testsuite/tests/tool-ocaml/t170-envacc3.ml index d0be88ce..d70a9124 100644 --- a/testsuite/tests/tool-ocaml/t170-envacc3.ml +++ b/testsuite/tests/tool-ocaml/t170-envacc3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 2 in diff --git a/testsuite/tests/tool-ocaml/t170-envacc4.ml b/testsuite/tests/tool-ocaml/t170-envacc4.ml index 9764c3b2..73a95a52 100644 --- a/testsuite/tests/tool-ocaml/t170-envacc4.ml +++ b/testsuite/tests/tool-ocaml/t170-envacc4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 2 in diff --git a/testsuite/tests/tool-ocaml/t171-envacc.ml b/testsuite/tests/tool-ocaml/t171-envacc.ml index a83295b8..f39b5b85 100644 --- a/testsuite/tests/tool-ocaml/t171-envacc.ml +++ b/testsuite/tests/tool-ocaml/t171-envacc.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 2 in diff --git a/testsuite/tests/tool-ocaml/t172-pushenvacc1.ml b/testsuite/tests/tool-ocaml/t172-pushenvacc1.ml index ba615ba7..1465bdb3 100644 --- a/testsuite/tests/tool-ocaml/t172-pushenvacc1.ml +++ b/testsuite/tests/tool-ocaml/t172-pushenvacc1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let f _ = x + x in diff --git a/testsuite/tests/tool-ocaml/t172-pushenvacc2.ml b/testsuite/tests/tool-ocaml/t172-pushenvacc2.ml index afdbcc5d..72e86be7 100644 --- a/testsuite/tests/tool-ocaml/t172-pushenvacc2.ml +++ b/testsuite/tests/tool-ocaml/t172-pushenvacc2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 4 in diff --git a/testsuite/tests/tool-ocaml/t172-pushenvacc3.ml b/testsuite/tests/tool-ocaml/t172-pushenvacc3.ml index 308fd5ed..013b03d8 100644 --- a/testsuite/tests/tool-ocaml/t172-pushenvacc3.ml +++ b/testsuite/tests/tool-ocaml/t172-pushenvacc3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 4 in diff --git a/testsuite/tests/tool-ocaml/t172-pushenvacc4.ml b/testsuite/tests/tool-ocaml/t172-pushenvacc4.ml index feba1281..45ab2925 100644 --- a/testsuite/tests/tool-ocaml/t172-pushenvacc4.ml +++ b/testsuite/tests/tool-ocaml/t172-pushenvacc4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 4 in diff --git a/testsuite/tests/tool-ocaml/t173-pushenvacc.ml b/testsuite/tests/tool-ocaml/t173-pushenvacc.ml index ffddf8d7..4c869587 100644 --- a/testsuite/tests/tool-ocaml/t173-pushenvacc.ml +++ b/testsuite/tests/tool-ocaml/t173-pushenvacc.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 5 in let y = 4 in diff --git a/testsuite/tests/tool-ocaml/t180-appterm1.ml b/testsuite/tests/tool-ocaml/t180-appterm1.ml index a0006caf..70cac0d9 100644 --- a/testsuite/tests/tool-ocaml/t180-appterm1.ml +++ b/testsuite/tests/tool-ocaml/t180-appterm1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ = 12 in let g _ = f 0 in diff --git a/testsuite/tests/tool-ocaml/t180-appterm2.ml b/testsuite/tests/tool-ocaml/t180-appterm2.ml index 850301d0..e3b9d62a 100644 --- a/testsuite/tests/tool-ocaml/t180-appterm2.ml +++ b/testsuite/tests/tool-ocaml/t180-appterm2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ = 12 in let g _ = f 0 0 in diff --git a/testsuite/tests/tool-ocaml/t180-appterm3.ml b/testsuite/tests/tool-ocaml/t180-appterm3.ml index eedc52e5..2e4949bb 100644 --- a/testsuite/tests/tool-ocaml/t180-appterm3.ml +++ b/testsuite/tests/tool-ocaml/t180-appterm3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ _ = 13 in let g _ = f 0 0 0 in diff --git a/testsuite/tests/tool-ocaml/t181-appterm.ml b/testsuite/tests/tool-ocaml/t181-appterm.ml index 2222bc40..d6d179ca 100644 --- a/testsuite/tests/tool-ocaml/t181-appterm.ml +++ b/testsuite/tests/tool-ocaml/t181-appterm.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f _ _ _ _ = -10 in let g _ = f 0 0 0 0 in diff --git a/testsuite/tests/tool-ocaml/t190-makefloatblock-1.ml b/testsuite/tests/tool-ocaml/t190-makefloatblock-1.ml index 1d906c9c..6263bf3d 100644 --- a/testsuite/tests/tool-ocaml/t190-makefloatblock-1.ml +++ b/testsuite/tests/tool-ocaml/t190-makefloatblock-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 0.0 in [| x |];; diff --git a/testsuite/tests/tool-ocaml/t190-makefloatblock-2.ml b/testsuite/tests/tool-ocaml/t190-makefloatblock-2.ml index bb06aba8..1a650c54 100644 --- a/testsuite/tests/tool-ocaml/t190-makefloatblock-2.ml +++ b/testsuite/tests/tool-ocaml/t190-makefloatblock-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 0.0 in [| x; x |];; diff --git a/testsuite/tests/tool-ocaml/t190-makefloatblock-3.ml b/testsuite/tests/tool-ocaml/t190-makefloatblock-3.ml index 581439df..fb53a4c9 100644 --- a/testsuite/tests/tool-ocaml/t190-makefloatblock-3.ml +++ b/testsuite/tests/tool-ocaml/t190-makefloatblock-3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 0.0 in [| x; x; x |];; diff --git a/testsuite/tests/tool-ocaml/t191-vectlength.ml b/testsuite/tests/tool-ocaml/t191-vectlength.ml index 6cd19667..b2f5a66b 100644 --- a/testsuite/tests/tool-ocaml/t191-vectlength.ml +++ b/testsuite/tests/tool-ocaml/t191-vectlength.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = 0.0 in if Array.length [| x |] <> 1 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t192-getfloatfield-1.ml b/testsuite/tests/tool-ocaml/t192-getfloatfield-1.ml index bd8109f4..30f29106 100644 --- a/testsuite/tests/tool-ocaml/t192-getfloatfield-1.ml +++ b/testsuite/tests/tool-ocaml/t192-getfloatfield-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : float; b : float };; diff --git a/testsuite/tests/tool-ocaml/t192-getfloatfield-2.ml b/testsuite/tests/tool-ocaml/t192-getfloatfield-2.ml index 0c62a4b0..c32b858b 100644 --- a/testsuite/tests/tool-ocaml/t192-getfloatfield-2.ml +++ b/testsuite/tests/tool-ocaml/t192-getfloatfield-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : float; b : float };; diff --git a/testsuite/tests/tool-ocaml/t193-setfloatfield-1.ml b/testsuite/tests/tool-ocaml/t193-setfloatfield-1.ml index c679c43a..6ce6578e 100644 --- a/testsuite/tests/tool-ocaml/t193-setfloatfield-1.ml +++ b/testsuite/tests/tool-ocaml/t193-setfloatfield-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : float; diff --git a/testsuite/tests/tool-ocaml/t193-setfloatfield-2.ml b/testsuite/tests/tool-ocaml/t193-setfloatfield-2.ml index 2088257a..49390a31 100644 --- a/testsuite/tests/tool-ocaml/t193-setfloatfield-2.ml +++ b/testsuite/tests/tool-ocaml/t193-setfloatfield-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : float; diff --git a/testsuite/tests/tool-ocaml/t200-getfield0.ml b/testsuite/tests/tool-ocaml/t200-getfield0.ml index b3f59fe5..5681ab7d 100644 --- a/testsuite/tests/tool-ocaml/t200-getfield0.ml +++ b/testsuite/tests/tool-ocaml/t200-getfield0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : int; diff --git a/testsuite/tests/tool-ocaml/t200-getfield1.ml b/testsuite/tests/tool-ocaml/t200-getfield1.ml index 4dcb2f7c..8e2f1dfe 100644 --- a/testsuite/tests/tool-ocaml/t200-getfield1.ml +++ b/testsuite/tests/tool-ocaml/t200-getfield1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : int; diff --git a/testsuite/tests/tool-ocaml/t200-getfield2.ml b/testsuite/tests/tool-ocaml/t200-getfield2.ml index 02f3234f..ebddd527 100644 --- a/testsuite/tests/tool-ocaml/t200-getfield2.ml +++ b/testsuite/tests/tool-ocaml/t200-getfield2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : int; diff --git a/testsuite/tests/tool-ocaml/t200-getfield3.ml b/testsuite/tests/tool-ocaml/t200-getfield3.ml index b8ba042e..487d8f2f 100644 --- a/testsuite/tests/tool-ocaml/t200-getfield3.ml +++ b/testsuite/tests/tool-ocaml/t200-getfield3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : int; diff --git a/testsuite/tests/tool-ocaml/t201-getfield.ml b/testsuite/tests/tool-ocaml/t201-getfield.ml index 91f86fb7..a0d81c89 100644 --- a/testsuite/tests/tool-ocaml/t201-getfield.ml +++ b/testsuite/tests/tool-ocaml/t201-getfield.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { a : int; diff --git a/testsuite/tests/tool-ocaml/t210-setfield0.ml b/testsuite/tests/tool-ocaml/t210-setfield0.ml index b7fce85a..4376f1df 100644 --- a/testsuite/tests/tool-ocaml/t210-setfield0.ml +++ b/testsuite/tests/tool-ocaml/t210-setfield0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : int; diff --git a/testsuite/tests/tool-ocaml/t210-setfield1.ml b/testsuite/tests/tool-ocaml/t210-setfield1.ml index 7bb65c55..c5de35c9 100644 --- a/testsuite/tests/tool-ocaml/t210-setfield1.ml +++ b/testsuite/tests/tool-ocaml/t210-setfield1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : int; diff --git a/testsuite/tests/tool-ocaml/t210-setfield2.ml b/testsuite/tests/tool-ocaml/t210-setfield2.ml index 4cd42ecf..ef8218f9 100644 --- a/testsuite/tests/tool-ocaml/t210-setfield2.ml +++ b/testsuite/tests/tool-ocaml/t210-setfield2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : int; diff --git a/testsuite/tests/tool-ocaml/t210-setfield3.ml b/testsuite/tests/tool-ocaml/t210-setfield3.ml index 7df75362..531d4e8e 100644 --- a/testsuite/tests/tool-ocaml/t210-setfield3.ml +++ b/testsuite/tests/tool-ocaml/t210-setfield3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : int; diff --git a/testsuite/tests/tool-ocaml/t211-setfield.ml b/testsuite/tests/tool-ocaml/t211-setfield.ml index 47e3b7db..4183cd69 100644 --- a/testsuite/tests/tool-ocaml/t211-setfield.ml +++ b/testsuite/tests/tool-ocaml/t211-setfield.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; type t = { mutable a : int; diff --git a/testsuite/tests/tool-ocaml/t220-assign.ml b/testsuite/tests/tool-ocaml/t220-assign.ml index ecb57e60..ef8e5725 100644 --- a/testsuite/tests/tool-ocaml/t220-assign.ml +++ b/testsuite/tests/tool-ocaml/t220-assign.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = ref 1 in x := 3; diff --git a/testsuite/tests/tool-ocaml/t230-check_signals.ml b/testsuite/tests/tool-ocaml/t230-check_signals.ml index 41e82d8c..924a649b 100644 --- a/testsuite/tests/tool-ocaml/t230-check_signals.ml +++ b/testsuite/tests/tool-ocaml/t230-check_signals.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; for i = 0 to 0 do () done;; diff --git a/testsuite/tests/tool-ocaml/t240-c_call1.ml b/testsuite/tests/tool-ocaml/t240-c_call1.ml index 70809c75..0b0bfd41 100644 --- a/testsuite/tests/tool-ocaml/t240-c_call1.ml +++ b/testsuite/tests/tool-ocaml/t240-c_call1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if Pervasives.int_of_string "123" <> 123 then raise Not_found;; (** test for fix of bug 6649: http://caml.inria.fr/mantis/view.php?id=6649 *) diff --git a/testsuite/tests/tool-ocaml/t240-c_call2.ml b/testsuite/tests/tool-ocaml/t240-c_call2.ml index 733b3412..d4a10a70 100644 --- a/testsuite/tests/tool-ocaml/t240-c_call2.ml +++ b/testsuite/tests/tool-ocaml/t240-c_call2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if Pervasives.compare 1 2 <> -1 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t240-c_call3.ml b/testsuite/tests/tool-ocaml/t240-c_call3.ml index 4e91c3fd..5306aa22 100644 --- a/testsuite/tests/tool-ocaml/t240-c_call3.ml +++ b/testsuite/tests/tool-ocaml/t240-c_call3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; if Hashtbl.hash_param 5 6 [1;2;3] <> 697606130 then raise Not_found;; diff --git a/testsuite/tests/tool-ocaml/t240-c_call4.ml b/testsuite/tests/tool-ocaml/t240-c_call4.ml index 8297eb14..ba3a2ce7 100644 --- a/testsuite/tests/tool-ocaml/t240-c_call4.ml +++ b/testsuite/tests/tool-ocaml/t240-c_call4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let s = Bytes.of_string "abcdefgh" in Bytes.unsafe_fill s 0 6 'x'; diff --git a/testsuite/tests/tool-ocaml/t240-c_call5.ml b/testsuite/tests/tool-ocaml/t240-c_call5.ml index 535bb377..8be199c7 100644 --- a/testsuite/tests/tool-ocaml/t240-c_call5.ml +++ b/testsuite/tests/tool-ocaml/t240-c_call5.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let s = Bytes.of_string "abcdefgh" in Bytes.unsafe_blit s 3 s 0 3; diff --git a/testsuite/tests/tool-ocaml/t250-closurerec-1.ml b/testsuite/tests/tool-ocaml/t250-closurerec-1.ml index 283b17a3..a8f02b34 100644 --- a/testsuite/tests/tool-ocaml/t250-closurerec-1.ml +++ b/testsuite/tests/tool-ocaml/t250-closurerec-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = 0;; diff --git a/testsuite/tests/tool-ocaml/t250-closurerec-2.ml b/testsuite/tests/tool-ocaml/t250-closurerec-2.ml index ffe3d481..4d973b36 100644 --- a/testsuite/tests/tool-ocaml/t250-closurerec-2.ml +++ b/testsuite/tests/tool-ocaml/t250-closurerec-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = 23 in if f 0 <> 23 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t251-pushoffsetclosure0.ml b/testsuite/tests/tool-ocaml/t251-pushoffsetclosure0.ml index 1ea295a3..6a2fe2c2 100644 --- a/testsuite/tests/tool-ocaml/t251-pushoffsetclosure0.ml +++ b/testsuite/tests/tool-ocaml/t251-pushoffsetclosure0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f = function | 0 -> 13 diff --git a/testsuite/tests/tool-ocaml/t251-pushoffsetclosure2.ml b/testsuite/tests/tool-ocaml/t251-pushoffsetclosure2.ml index 8634f29e..10a16d71 100644 --- a/testsuite/tests/tool-ocaml/t251-pushoffsetclosure2.ml +++ b/testsuite/tests/tool-ocaml/t251-pushoffsetclosure2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = g 0 and g _ = 4 diff --git a/testsuite/tests/tool-ocaml/t251-pushoffsetclosurem2.ml b/testsuite/tests/tool-ocaml/t251-pushoffsetclosurem2.ml index 65267e5b..b0cd3227 100644 --- a/testsuite/tests/tool-ocaml/t251-pushoffsetclosurem2.ml +++ b/testsuite/tests/tool-ocaml/t251-pushoffsetclosurem2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = 4 and g _ = f 2 diff --git a/testsuite/tests/tool-ocaml/t252-pushoffsetclosure.ml b/testsuite/tests/tool-ocaml/t252-pushoffsetclosure.ml index dccce95a..d4d01bdc 100644 --- a/testsuite/tests/tool-ocaml/t252-pushoffsetclosure.ml +++ b/testsuite/tests/tool-ocaml/t252-pushoffsetclosure.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f x = x and g _ = f 4 diff --git a/testsuite/tests/tool-ocaml/t253-offsetclosure0.ml b/testsuite/tests/tool-ocaml/t253-offsetclosure0.ml index 35d66ba3..0f56a0a2 100644 --- a/testsuite/tests/tool-ocaml/t253-offsetclosure0.ml +++ b/testsuite/tests/tool-ocaml/t253-offsetclosure0.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = g f and g _ = 10 diff --git a/testsuite/tests/tool-ocaml/t253-offsetclosure2.ml b/testsuite/tests/tool-ocaml/t253-offsetclosure2.ml index 55adf632..e383b8cc 100644 --- a/testsuite/tests/tool-ocaml/t253-offsetclosure2.ml +++ b/testsuite/tests/tool-ocaml/t253-offsetclosure2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = g and g _ = 10 diff --git a/testsuite/tests/tool-ocaml/t253-offsetclosurem2.ml b/testsuite/tests/tool-ocaml/t253-offsetclosurem2.ml index e61e0c22..d131d892 100644 --- a/testsuite/tests/tool-ocaml/t253-offsetclosurem2.ml +++ b/testsuite/tests/tool-ocaml/t253-offsetclosurem2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = 11 and g _ = f diff --git a/testsuite/tests/tool-ocaml/t254-offsetclosure.ml b/testsuite/tests/tool-ocaml/t254-offsetclosure.ml index 95eb1b0c..de58828c 100644 --- a/testsuite/tests/tool-ocaml/t254-offsetclosure.ml +++ b/testsuite/tests/tool-ocaml/t254-offsetclosure.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f _ = 11 and g _ = 0 diff --git a/testsuite/tests/tool-ocaml/t260-offsetref.ml b/testsuite/tests/tool-ocaml/t260-offsetref.ml index 20dbf2c0..9803cbe9 100644 --- a/testsuite/tests/tool-ocaml/t260-offsetref.ml +++ b/testsuite/tests/tool-ocaml/t260-offsetref.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = ref 32 in incr x; diff --git a/testsuite/tests/tool-ocaml/t270-push_retaddr.ml b/testsuite/tests/tool-ocaml/t270-push_retaddr.ml index 2c13f225..1bfffbc5 100644 --- a/testsuite/tests/tool-ocaml/t270-push_retaddr.ml +++ b/testsuite/tests/tool-ocaml/t270-push_retaddr.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let f a b c d = 123 in if f 0 1 2 3 <> 123 then raise Not_found diff --git a/testsuite/tests/tool-ocaml/t300-getmethod.ml b/testsuite/tests/tool-ocaml/t300-getmethod.ml index 8108e801..13dae267 100644 --- a/testsuite/tests/tool-ocaml/t300-getmethod.ml +++ b/testsuite/tests/tool-ocaml/t300-getmethod.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; class c = object diff --git a/testsuite/tests/tool-ocaml/t301-object.ml b/testsuite/tests/tool-ocaml/t301-object.ml index 6b33f827..8b822439 100644 --- a/testsuite/tests/tool-ocaml/t301-object.ml +++ b/testsuite/tests/tool-ocaml/t301-object.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + (**** file testinterp/t301-object.ml suggested by Jacques Garrigue to Basile Starynkevitch diff --git a/testsuite/tests/tool-ocaml/t310-alloc-1.ml b/testsuite/tests/tool-ocaml/t310-alloc-1.ml index 9e0ff1a2..4a3b0092 100644 --- a/testsuite/tests/tool-ocaml/t310-alloc-1.ml +++ b/testsuite/tests/tool-ocaml/t310-alloc-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f a n = if n <= 0 then a diff --git a/testsuite/tests/tool-ocaml/t310-alloc-2.ml b/testsuite/tests/tool-ocaml/t310-alloc-2.ml index efdc399b..10a8d753 100644 --- a/testsuite/tests/tool-ocaml/t310-alloc-2.ml +++ b/testsuite/tests/tool-ocaml/t310-alloc-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let v = Array.make 200000 2 in let t = ref 0 in diff --git a/testsuite/tests/tool-ocaml/t320-gc-1.ml b/testsuite/tests/tool-ocaml/t320-gc-1.ml index dde4e0b6..98986b2f 100644 --- a/testsuite/tests/tool-ocaml/t320-gc-1.ml +++ b/testsuite/tests/tool-ocaml/t320-gc-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then [] diff --git a/testsuite/tests/tool-ocaml/t320-gc-2.ml b/testsuite/tests/tool-ocaml/t320-gc-2.ml index 39ec57c4..cc04f0bb 100644 --- a/testsuite/tests/tool-ocaml/t320-gc-2.ml +++ b/testsuite/tests/tool-ocaml/t320-gc-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then [] diff --git a/testsuite/tests/tool-ocaml/t320-gc-3.ml b/testsuite/tests/tool-ocaml/t320-gc-3.ml index 69a63682..bf59bf40 100644 --- a/testsuite/tests/tool-ocaml/t320-gc-3.ml +++ b/testsuite/tests/tool-ocaml/t320-gc-3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then [] diff --git a/testsuite/tests/tool-ocaml/t330-compact-1.ml b/testsuite/tests/tool-ocaml/t330-compact-1.ml index aaa80f0f..b19fd3a5 100644 --- a/testsuite/tests/tool-ocaml/t330-compact-1.ml +++ b/testsuite/tests/tool-ocaml/t330-compact-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; Gc.compact ();; diff --git a/testsuite/tests/tool-ocaml/t330-compact-2.ml b/testsuite/tests/tool-ocaml/t330-compact-2.ml index fa91834e..3640d8ad 100644 --- a/testsuite/tests/tool-ocaml/t330-compact-2.ml +++ b/testsuite/tests/tool-ocaml/t330-compact-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; Gc.compact ();; let _ = Pervasives.do_at_exit();; diff --git a/testsuite/tests/tool-ocaml/t330-compact-3.ml b/testsuite/tests/tool-ocaml/t330-compact-3.ml index 44d80a7d..17cf1fdc 100644 --- a/testsuite/tests/tool-ocaml/t330-compact-3.ml +++ b/testsuite/tests/tool-ocaml/t330-compact-3.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then [] diff --git a/testsuite/tests/tool-ocaml/t330-compact-4.ml b/testsuite/tests/tool-ocaml/t330-compact-4.ml index 60161a5f..a3cc2080 100644 --- a/testsuite/tests/tool-ocaml/t330-compact-4.ml +++ b/testsuite/tests/tool-ocaml/t330-compact-4.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then [] diff --git a/testsuite/tests/tool-ocaml/t340-weak.ml b/testsuite/tests/tool-ocaml/t340-weak.ml index 7ced585d..7478483f 100644 --- a/testsuite/tests/tool-ocaml/t340-weak.ml +++ b/testsuite/tests/tool-ocaml/t340-weak.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let x = Array.make 20 "" in let w = weak_create 20 in diff --git a/testsuite/tests/tool-ocaml/t350-heapcheck.ml b/testsuite/tests/tool-ocaml/t350-heapcheck.ml index 45295eaa..6eca59a5 100644 --- a/testsuite/tests/tool-ocaml/t350-heapcheck.ml +++ b/testsuite/tests/tool-ocaml/t350-heapcheck.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; ignore (Gc.stat ()); let x = Array.make 20 "" in diff --git a/testsuite/tests/tool-ocaml/t360-stacks-1.ml b/testsuite/tests/tool-ocaml/t360-stacks-1.ml index 2c257a79..965f4992 100644 --- a/testsuite/tests/tool-ocaml/t360-stacks-1.ml +++ b/testsuite/tests/tool-ocaml/t360-stacks-1.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then 12 diff --git a/testsuite/tests/tool-ocaml/t360-stacks-2.ml b/testsuite/tests/tool-ocaml/t360-stacks-2.ml index 88a884c7..016cc0db 100644 --- a/testsuite/tests/tool-ocaml/t360-stacks-2.ml +++ b/testsuite/tests/tool-ocaml/t360-stacks-2.ml @@ -1,3 +1,11 @@ +(* TEST +include tool-ocaml-lib +flags = "-w a" +ocaml_script_as_argument = "true" +* setup-ocaml-build-env +** ocaml +*) + open Lib;; let rec f n = if n <= 0 then 12 diff --git a/testsuite/tests/tool-ocamlc-compat32/Makefile b/testsuite/tests/tool-ocamlc-compat32/Makefile deleted file mode 100644 index 938f0253..00000000 --- a/testsuite/tests/tool-ocamlc-compat32/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -BASEDIR=../.. - -.PHONY: default -default: - @printf " ... testing -compat-32" - @if ($(OCAMLC) -config | grep "word_size: *64") \ - then $(MAKE) run; \ - else echo ' => skipped (not compiled in 64bit)'; \ - fi - -.PHONY: run -run: - @$(OCAMLC) -compat-32 -c a.ml > test.result 2>&1 || true - @$(OCAMLC) -c a.ml - @$(OCAMLC) -compat-32 -a a.cmo -o a.cma >> test.result 2>&1 || true - @$(OCAMLC) -a a.cmo -o a.cma - @$(OCAMLC) -compat-32 a.cma -o a.byte -linkall >> test.result 2>&1 || true - @$(DIFF) test.reference test.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - -promote: defaultpromote - -clean: defaultclean - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamlc-compat32/a.ml b/testsuite/tests/tool-ocamlc-compat32/a.ml deleted file mode 100644 index 81fdd458..00000000 --- a/testsuite/tests/tool-ocamlc-compat32/a.ml +++ /dev/null @@ -1 +0,0 @@ -let a = 0xffffffffffff diff --git a/testsuite/tests/tool-ocamlc-compat32/compat32.compilers.reference b/testsuite/tests/tool-ocamlc-compat32/compat32.compilers.reference new file mode 100644 index 00000000..0f74c728 --- /dev/null +++ b/testsuite/tests/tool-ocamlc-compat32/compat32.compilers.reference @@ -0,0 +1,6 @@ +File "compat32.ml", line 1: +Error: Generated bytecode unit "compat32.cmo" cannot be used on a 32-bit platform +File "_none_", line 1: +Error: Generated bytecode library "compat32.cma" cannot be used on a 32-bit platform +File "_none_", line 1: +Error: Generated bytecode executable "compat32.byte" cannot be used on a 32-bit platform diff --git a/testsuite/tests/tool-ocamlc-compat32/compat32.ml b/testsuite/tests/tool-ocamlc-compat32/compat32.ml new file mode 100644 index 00000000..8b09d8ab --- /dev/null +++ b/testsuite/tests/tool-ocamlc-compat32/compat32.ml @@ -0,0 +1,29 @@ +(* TEST + * arch64 + ** setup-ocamlc.byte-build-env + *** ocamlc.byte + compile_only = "true" + flags = "-compat-32" + ocamlc_byte_exit_status = "2" + **** ocamlc.byte + ocamlc_byte_exit_status = "0" + flags = "" + ***** ocamlc.byte + compile_only = "false" + all_modules = "compat32.cmo" + flags = "-compat-32 -a" + program = "compat32.cma" + ocamlc_byte_exit_status = "2" + ****** ocamlc.byte + flags = "-a" + program = "compat32.cma" + ocamlc_byte_exit_status = "0" + ******* ocamlc.byte + all_modules = "compat32.cma" + flags = "-compat-32 -linkall" + program = "compat32.byte" + ocamlc_byte_exit_status = "2" + ******** check-ocamlc.byte-output +*) + +let a = 0xffffffffffff diff --git a/testsuite/tests/tool-ocamlc-compat32/ocamltests b/testsuite/tests/tool-ocamlc-compat32/ocamltests new file mode 100644 index 00000000..3f712ba6 --- /dev/null +++ b/testsuite/tests/tool-ocamlc-compat32/ocamltests @@ -0,0 +1 @@ +compat32.ml diff --git a/testsuite/tests/tool-ocamlc-compat32/test.reference b/testsuite/tests/tool-ocamlc-compat32/test.reference deleted file mode 100644 index 8ef25626..00000000 --- a/testsuite/tests/tool-ocamlc-compat32/test.reference +++ /dev/null @@ -1,6 +0,0 @@ -File "a.ml", line 1: -Error: Generated bytecode unit "a.cmo" cannot be used on a 32-bit platform -File "_none_", line 1: -Error: Generated bytecode library "a.cma" cannot be used on a 32-bit platform -File "_none_", line 1: -Error: Generated bytecode executable "a.byte" cannot be used on a 32-bit platform diff --git a/testsuite/tests/tool-ocamlc-open/Makefile b/testsuite/tests/tool-ocamlc-open/Makefile deleted file mode 100644 index 4e2c52d3..00000000 --- a/testsuite/tests/tool-ocamlc-open/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -BASEDIR=../.. - -compile: - @printf " ... testing 'foo.ml'" - @$(OCAMLC) -c a.ml - @$(OCAMLC) -open A.M -c b.ml \ - && echo " => passed" || echo " => failed" - -promote: - -clean: - @rm -f a.cmi a.cmo b.cmi b.cmo - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamlc-open/ocamltests b/testsuite/tests/tool-ocamlc-open/ocamltests new file mode 100644 index 00000000..8f3a918d --- /dev/null +++ b/testsuite/tests/tool-ocamlc-open/ocamltests @@ -0,0 +1 @@ +tool-ocamlc-open.ml diff --git a/testsuite/tests/tool-ocamlc-open/tool-ocamlc-open.ml b/testsuite/tests/tool-ocamlc-open/tool-ocamlc-open.ml new file mode 100644 index 00000000..56d818e0 --- /dev/null +++ b/testsuite/tests/tool-ocamlc-open/tool-ocamlc-open.ml @@ -0,0 +1,10 @@ +(* TEST +files = "a.ml b.ml" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "a.ml" +*** ocamlc.byte +module = "b.ml" +flags = "-open A.M" +**** check-ocamlc.byte-output +*) diff --git a/testsuite/tests/tool-ocamldoc-2/Makefile b/testsuite/tests/tool-ocamldoc-2/Makefile deleted file mode 100644 index 18ba07db..00000000 --- a/testsuite/tests/tool-ocamldoc-2/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/ocamldoc -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/str -DOCFLAGS=-I $(OTOPDIR)/stdlib $(COMPFLAGS)\ - -latextitle "1,subsection*" \ - -latextitle "2,subsubsection*" \ - -latextitle "6,subsection*" \ - -latextitle "7,subsubsection*" \ - -latex-type-prefix "TYP" \ - -latex-module-prefix "" \ - -latex-module-type-prefix "" \ - -latex-value-prefix "" - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(SET_LD_PATH) $(MAKE) run; \ - fi - -.PHONY: run -run: *.ml *.mli *.txt - @for file in *.mli *.ml *.txt; do \ - printf " ... testing '$$file'"; \ - F="`basename $$file .mli`"; \ - F="`basename $$F .ml`"; \ - F="`basename $$F .txt`"; \ - $(OCAMLDOC) $(DOCFLAGS) -hide-warnings -latex $ \ - -o $$F.result $$file; \ - $(DIFF) $$F.reference $$F.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result *.html *.tex *.log *.out *.sty *.toc *.css *.aux - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamldoc-2/extensible_variant.ml b/testsuite/tests/tool-ocamldoc-2/extensible_variant.ml deleted file mode 100644 index 324a48d8..00000000 --- a/testsuite/tests/tool-ocamldoc-2/extensible_variant.ml +++ /dev/null @@ -1,25 +0,0 @@ -(** Testing display of extensible variant types and exceptions. - - @test_types_display - *) - -(** Also check reference for {!M.A}, {!M.B}, {!M.C} and {!E} *) - -(** Extensible type *) -type e = .. - -module M = struct - type e += - | A (** A doc *) - | B (** B doc *) - | C (** C doc *) -end - -module type MT = sig - type e += - | A (** A doc *) - | B (** B doc *) - | C (** C doc *) -end - -exception E diff --git a/testsuite/tests/tool-ocamldoc-2/inline_records.mli b/testsuite/tests/tool-ocamldoc-2/inline_records.mli deleted file mode 100644 index ee5f14d7..00000000 --- a/testsuite/tests/tool-ocamldoc-2/inline_records.mli +++ /dev/null @@ -1,48 +0,0 @@ -(** - This test focuses on the printing of documentation for inline record - within the latex generator. -*) - - -(** A nice exception *) -exception Simple - -(** A less simple exception *) -exception Less of int - -(** An open sum type *) -type ext = .. - -(** A simple record type for reference *) -type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); - more:int list (** More documentation for r, [more : int list] *) } - - -(** A sum type with one inline record *) -type t = A of {lbl: int (** [A] field documentation *) - ; more:int list (** More [A] field documentation *) } -(** Constructor documentation *) - -(** A sum type with two inline records *) -type s = - | B of { a_label_for_B : int (** [B] field documentation *); - more_label_for_B:int list (** More [B] field documentation *) } - (** Constructor B documentation *) - | C of { c_has_label_too: float (** [C] field documentation*); - more_than_one: unit (** ... documentations *) } - (** Constructor C documentation *) - -(** A gadt constructor *) -type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any -(** Constructor D documentation *) - -exception Error of {name:string (** Error field documentation [name:string] *) } - -type ext += - | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } - (** Constructor E documentation *) - | F of { even_more: int -> int (** Some field documentations for [F] *) } - (** Constructor F documentation *) - | G of { last: int -> int (** The last and least field documentation *) } - (** Constructor G documentation *) -(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc-2/inline_records_bis.ml b/testsuite/tests/tool-ocamldoc-2/inline_records_bis.ml deleted file mode 100644 index ee5f14d7..00000000 --- a/testsuite/tests/tool-ocamldoc-2/inline_records_bis.ml +++ /dev/null @@ -1,48 +0,0 @@ -(** - This test focuses on the printing of documentation for inline record - within the latex generator. -*) - - -(** A nice exception *) -exception Simple - -(** A less simple exception *) -exception Less of int - -(** An open sum type *) -type ext = .. - -(** A simple record type for reference *) -type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); - more:int list (** More documentation for r, [more : int list] *) } - - -(** A sum type with one inline record *) -type t = A of {lbl: int (** [A] field documentation *) - ; more:int list (** More [A] field documentation *) } -(** Constructor documentation *) - -(** A sum type with two inline records *) -type s = - | B of { a_label_for_B : int (** [B] field documentation *); - more_label_for_B:int list (** More [B] field documentation *) } - (** Constructor B documentation *) - | C of { c_has_label_too: float (** [C] field documentation*); - more_than_one: unit (** ... documentations *) } - (** Constructor C documentation *) - -(** A gadt constructor *) -type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any -(** Constructor D documentation *) - -exception Error of {name:string (** Error field documentation [name:string] *) } - -type ext += - | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } - (** Constructor E documentation *) - | F of { even_more: int -> int (** Some field documentations for [F] *) } - (** Constructor F documentation *) - | G of { last: int -> int (** The last and least field documentation *) } - (** Constructor G documentation *) -(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc-2/level_0.mli b/testsuite/tests/tool-ocamldoc-2/level_0.mli deleted file mode 100644 index 22c4665d..00000000 --- a/testsuite/tests/tool-ocamldoc-2/level_0.mli +++ /dev/null @@ -1,15 +0,0 @@ -(** Test for level 0 headings - - {1 Level 1} - - Standard heading levels start at 1. - - {0 Level 0} - A level 0 heading is guaranted to be at the same level that - the main heading of the module. - - This setup allows users to start their standard heading at level 1 rather - than 2, without losing the ability to add global level heading, - when, if ever, such heading is warranted - - *) diff --git a/testsuite/tests/tool-ocamldoc-2/loop.ml b/testsuite/tests/tool-ocamldoc-2/loop.ml deleted file mode 100644 index b0306b76..00000000 --- a/testsuite/tests/tool-ocamldoc-2/loop.ml +++ /dev/null @@ -1,3 +0,0 @@ - -module rec A : sig type t end = B and B : sig type t = A.t end = A;; - diff --git a/testsuite/tests/tool-ocamldoc-2/short_description.reference b/testsuite/tests/tool-ocamldoc-2/short_description.reference deleted file mode 100644 index 9cc843fc..00000000 --- a/testsuite/tests/tool-ocamldoc-2/short_description.reference +++ /dev/null @@ -1,21 +0,0 @@ -\documentclass[11pt]{article} -\usepackage[latin1]{inputenc} -\usepackage[T1]{fontenc} -\usepackage{textcomp} -\usepackage{fullpage} -\usepackage{url} -\usepackage{ocamldoc} -\begin{document} -\tableofcontents -\section{Short\_description : Short global description in text mode} -\label{Short-underscoredescription}\index{Short-underscoredescription@\verb`Short_description`} - - - -This file tests that documentation in text mode are given -a short description in the global description of modules. - - - - -\end{document} diff --git a/testsuite/tests/tool-ocamldoc-2/short_description.txt b/testsuite/tests/tool-ocamldoc-2/short_description.txt deleted file mode 100644 index 7241f875..00000000 --- a/testsuite/tests/tool-ocamldoc-2/short_description.txt +++ /dev/null @@ -1,4 +0,0 @@ -Short global description in text mode - -This file tests that documentation in text mode are given -a short description in the global description of modules. diff --git a/testsuite/tests/tool-ocamldoc-2/test.mli b/testsuite/tests/tool-ocamldoc-2/test.mli deleted file mode 100644 index 3c4ec154..00000000 --- a/testsuite/tests/tool-ocamldoc-2/test.mli +++ /dev/null @@ -1,30 +0,0 @@ - -(** Ten comments for tests *) - -(** {6 A first comments for title } *) - -(** {7 A subsection for ocamldoc *} *) - -(** {7 Bis } *) - -(** {7 Ter } *) - -(** {6 A new section } *) - -(** {7 And its subsection } *) - -(** {7 Encore } *) - -(** Encore! Encore! *) - - -(**/**) -module Silence : sig - (** At last *) -end - -(**/**) - -(** {7 With strange aeons } *) - -module End : sig end diff --git a/testsuite/tests/tool-ocamldoc-2/variants.mli b/testsuite/tests/tool-ocamldoc-2/variants.mli deleted file mode 100644 index 7562a0b8..00000000 --- a/testsuite/tests/tool-ocamldoc-2/variants.mli +++ /dev/null @@ -1,38 +0,0 @@ -(** This test is here to check the latex code generated for variants *) - -type s = A | B (** only B is documented here *) | C - -type t = - | A - (** doc for A *) - | B - (** doc for B *) - -(** Some documentation for u*) -type u = -| A (** doc for A *) | B of unit (** doc for B *) - - -(** With records *) -type w = -| A of { x: int } - (** doc for A *) -| B of { y:int } - (** doc for B *) - -(** With args *) -type z = -| A of int - (** doc for A *) -| B of int - (** doc for B *) - -(** Gadt notation *) -type a = - A: a (** doc for A*) - -(** Lonely constructor *) -type b = - B (** doc for B *) - -type no_documentation = A | B | C diff --git a/testsuite/tests/tool-ocamldoc-2/variants.reference b/testsuite/tests/tool-ocamldoc-2/variants.reference deleted file mode 100644 index 4d1753c7..00000000 --- a/testsuite/tests/tool-ocamldoc-2/variants.reference +++ /dev/null @@ -1,190 +0,0 @@ -\documentclass[11pt]{article} -\usepackage[latin1]{inputenc} -\usepackage[T1]{fontenc} -\usepackage{textcomp} -\usepackage{fullpage} -\usepackage{url} -\usepackage{ocamldoc} -\begin{document} -\tableofcontents -\section{Module {\tt{Variants}} : This test is here to check the latex code generated for variants} -\label{Variants}\index{Variants@\verb`Variants`} - - - - -\ocamldocvspace{0.5cm} - - - -\label{TYPVariants.s}\begin{ocamldoccode} -type s = - | A - | B -\end{ocamldoccode} -\begin{ocamldoccomment} -only B is documented here - - -\end{ocamldoccomment} -\begin{ocamldoccode} - | C -\end{ocamldoccode} -\index{s@\verb`s`} - - - - -\label{TYPVariants.t}\begin{ocamldoccode} -type t = - | A -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for A - - -\end{ocamldoccomment} -\begin{ocamldoccode} - | B -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for B - - -\end{ocamldoccomment} -\index{t@\verb`t`} - - - - -\label{TYPVariants.u}\begin{ocamldoccode} -type u = - | A -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for A - - -\end{ocamldoccomment} -\begin{ocamldoccode} - | B of unit -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for B - - -\end{ocamldoccomment} -\index{u@\verb`u`} -\begin{ocamldocdescription} -Some documentation for u - - -\end{ocamldocdescription} - - - - -\label{TYPVariants.w}\begin{ocamldoccode} -type w = - | A of {\char123} x : int ; -{\char125} -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for A - - -\end{ocamldoccomment} -\begin{ocamldoccode} - | B of {\char123} y : int ; -{\char125} -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for B - - -\end{ocamldoccomment} -\index{w@\verb`w`} -\begin{ocamldocdescription} -With records - - -\end{ocamldocdescription} - - - - -\label{TYPVariants.z}\begin{ocamldoccode} -type z = - | A of int -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for A - - -\end{ocamldoccomment} -\begin{ocamldoccode} - | B of int -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for B - - -\end{ocamldoccomment} -\index{z@\verb`z`} -\begin{ocamldocdescription} -With args - - -\end{ocamldocdescription} - - - - -\label{TYPVariants.a}\begin{ocamldoccode} -type a = - | A : a -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for A - - -\end{ocamldoccomment} -\index{a@\verb`a`} -\begin{ocamldocdescription} -Gadt notation - - -\end{ocamldocdescription} - - - - -\label{TYPVariants.b}\begin{ocamldoccode} -type b = - | B -\end{ocamldoccode} -\begin{ocamldoccomment} -doc for B - - -\end{ocamldoccomment} -\index{b@\verb`b`} -\begin{ocamldocdescription} -Lonely constructor - - -\end{ocamldocdescription} - - - - -\label{TYPVariants.no-underscoredocumentation}\begin{ocamldoccode} -type no_documentation = - | A - | B - | C -\end{ocamldoccode} -\index{no-underscoredocumentation@\verb`no_documentation`} - - -\end{document} diff --git a/testsuite/tests/tool-ocamldoc-html/Documentation_tags.mli b/testsuite/tests/tool-ocamldoc-html/Documentation_tags.mli deleted file mode 100644 index bac254ab..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Documentation_tags.mli +++ /dev/null @@ -1,19 +0,0 @@ -(** Test the html rendering of ocamldoc documentation tags *) - -val heterological: unit -(** - @author yes - @param no No description - @param neither see no description - @deprecated since the start of time - @return () - @see "Documentation_tags.mli" Self reference - @since Now - @before Time not implemented -*) - -val noop: unit -(** - @raise Not_found Never - @raise Invalid_argument Never -*) diff --git a/testsuite/tests/tool-ocamldoc-html/Documentation_tags.reference b/testsuite/tests/tool-ocamldoc-html/Documentation_tags.reference deleted file mode 100644 index 53f9d79e..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Documentation_tags.reference +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - -Documentation_tags - - - -

      Module Documentation_tags

      - -
      module Documentation_tags: sig .. end
      -
      -

      Test the html rendering of ocamldoc documentation tags

      -
      -
      -
      - -
      val heterological : unit
      -
      -Deprecated.since the start of time
      -
        -
      • Author(s): yes
      • -
      • Before Time not implemented
      • -
      • Since Now
      • -
      • Returns ()
      • -
      • See also Documentation_tags.mli Self reference
      • -
      -
      - -
      val noop : unit
      -
        -
      • Raises
        • Not_found Never
        • -
        • Invalid_argument Never
        • -
      • -
      -
      - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Inline_records.mli b/testsuite/tests/tool-ocamldoc-html/Inline_records.mli deleted file mode 100644 index f80cd2bd..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Inline_records.mli +++ /dev/null @@ -1,45 +0,0 @@ -(** - This test focuses on the printing of documentation for inline record - within the latex generator. -*) - - -(** A nice exception *) -exception Simple - -(** An open sum type *) -type ext = .. - -(** A simple record type for reference *) -type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); - more:int list (** More documentation for r, [more : int list] *) } - - -(** A sum type with one inline record *) -type t = A of {lbl: int (** [A] field documentation *) - ; more:int list (** More [A] field documentation *) } -(** Constructor documentation *) - -(** A sum type with two inline records *) -type s = - | B of { a_label_for_B : int (** [B] field documentation *); - more_label_for_B:int list (** More [B] field documentation *) } - (** Constructor B documentation *) - | C of { c_has_label_too: float (** [C] field documentation*); - more_than_one: unit (** ... documentations *) } - (** Constructor C documentation *) - -(** A gadt constructor *) -type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any -(** Constructor D documentation *) - -exception Error of {name:string (** Error field documentation [name:string] *) } - -type ext += - | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } - (** Constructor E documentation *) - | F of { even_more: int -> int (** Some field documentations for [F] *) } - (** Constructor F documentation *) - | G of { last: int -> int (** The last and least field documentation *) } - (** Constructor G documentation *) -(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc-html/Inline_records.reference b/testsuite/tests/tool-ocamldoc-html/Inline_records.reference deleted file mode 100644 index 92d9e79d..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Inline_records.reference +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - -Inline_records - - - -

      Module Inline_records

      - -
      module Inline_records: sig .. end
      -
      -

      This test focuses on the printing of documentation for inline record - within the latex generator.

      -
      -
      -
      - -
      exception Simple
      -
      -
      -

      A nice exception

      -
      -
      - -
      type ext = ..
      -
      -
      -

      An open sum type

      -
      -
      - - -
      type r = {
      - - - - - - - - - -
      -   -lbl : int;(*
      -
      -

      Field documentation for non-inline, lbl : int

      -
      -
      -
      *)
      -   -more : int list;(*
      -
      -

      More documentation for r, more : int list

      -
      -
      -
      *)
      -} - -
      -
      -

      A simple record type for reference

      -
      -
      - - -
      type t = 
      - - - - -
      -| -A of { - - - - - - - - - -
      -   -lbl : int;(*
      -
      -

      A field documentation

      -
      -
      -
      *)
      -   -more : int list;(*
      -
      -

      More A field documentation

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor documentation

      -
      -
      -
      *)
      - -
      -
      -

      A sum type with one inline record

      -
      -
      - - -
      type s = 
      - - - - - - - - - -
      -| -B of { - - - - - - - - - -
      -   -a_label_for_B : int;(*
      -
      -

      B field documentation

      -
      -
      -
      *)
      -   -more_label_for_B : int list;(*
      -
      -

      More B field documentation

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor B documentation

      -
      -
      -
      *)
      -| -C of { - - - - - - - - - -
      -   -c_has_label_too : float;(*
      -
      -

      C field documentation

      -
      -
      -
      *)
      -   -more_than_one : unit;(*
      -
      -

      ... documentations

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor C documentation

      -
      -
      -
      *)
      - -
      -
      -

      A sum type with two inline records

      -
      -
      - - -
      type any = 
      - - - - -
      -| -D : { - - - - -
      -   -any : 'a;(*
      -
      -

      A field any:'a for D in any.

      -
      -
      -
      *)
      -} - -> any
      (*
      -
      -

      Constructor D documentation

      -
      -
      -
      *)
      - -
      -
      -

      A gadt constructor

      -
      -
      - - -
      exception Error of {
      -
      -
      -
      -
      -
      -   -name : string;(*
      -
      -

      Error field documentation name:string

      -
      -
      -
      *)
      -} -
      -
      type ext += 
      - - - - - - - - - - - - - - -
      -| -E of { - - - - -
      -   -yet_another_field : unit;(*
      -
      -

      Field documentation for E in ext

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor E documentation

      -
      -
      -
      *)
      -| -F of { - - - - -
      -   -even_more : int -> int;(*
      -
      -

      Some field documentations for F

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor F documentation

      -
      -
      -
      *)
      -| -G of { - - - - -
      -   -last : int -> int;(*
      -
      -

      The last and least field documentation

      -
      -
      -
      *)
      -} -
      (*
      -
      -

      Constructor G documentation

      -
      -
      -
      *)
      - -
      -
      -

      Two new constructors for ext

      -
      -
      - - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Item_ids.mli b/testsuite/tests/tool-ocamldoc-html/Item_ids.mli deleted file mode 100644 index 9001d3a1..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Item_ids.mli +++ /dev/null @@ -1,13 +0,0 @@ -(** Check that all toplevel items are given a unique id. *) - -exception Ex -type t -val x: t -type ext = .. -type ext += A -class c: object end -class type ct= object end -[@@@attribute] -module M: sig end -module type s = sig end - diff --git a/testsuite/tests/tool-ocamldoc-html/Item_ids.reference b/testsuite/tests/tool-ocamldoc-html/Item_ids.reference deleted file mode 100644 index 94eddefc..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Item_ids.reference +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - -Item_ids - - - -

      Module Item_ids

      - -
      module Item_ids: sig .. end
      -
      -

      Check that all toplevel items are given a unique id.

      -
      -
      -
      - -
      exception Ex
      - -
      type t 
      - - -
      val x : t
      -
      type ext = ..
      - -
      type ext += 
      - - - - -
      -| -A
      - - - -
      class c : object .. end
      -
      class type ct = object .. end
      -
      module M: sig .. end
      -
      module type s = sig .. end
      \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Linebreaks.mli b/testsuite/tests/tool-ocamldoc-html/Linebreaks.mli deleted file mode 100644 index cca816f3..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Linebreaks.mli +++ /dev/null @@ -1,68 +0,0 @@ -(** - This file tests the encoding of linebreak inside OCaml code by the - ocamldoc html backend. - - Two slightly different aspects are tested in this very file. - - - First, inside a "pre" tags, blanks character should not be escaped. - For instance, the generated html code for this test fragment should not - contain any
      tag: - {[ - let f x = - let g x = - let h x = x in - h x in - g x - ]} - See {{:http://caml.inria.fr/mantis/view.php?id=6341} MPR#6341} for more - details or the file Linebreaks.html generated by ocamldoc from this file. - - Second, outside of a "pre" tags, blank characters in embedded code - should be escaped, in order to make them render in a "pre"-like fashion. - A good example should be the files type_{i Modulename}.html generated by - ocamldoc that should contains the signature of the module [Modulename] in - a "code" tags. - For instance with the following type definitions, -*) - -type a = A -type 'a b = {field:'a} -type c = C: 'a -> c - -type s = .. -type s += B - -val x : a - -module S: sig module I:sig end end -module type s = sig end - -class type d = object end - -exception E of {inline:int} - - -(** type_Linebreaks.html should contain - -{[ -sig - type a = A - type 'a b = { field : 'a; } - type c = C : 'a -> Linebreaks.c - type s = .. - type s += B - val x : Linebreaks.a - module S : sig module I : sig end end - module type s = sig end - class type d = object end - exception E of { inline : int; } -end -]} - -with
      tags used for linebreaks. -Another example would be [ let f x = -x] which is rendered with a
      linebreak inside Linebreaks.html. - -See {{:http://caml.inria.fr/mantis/view.php?id=7272}MPR#7272} for more -information. - -*) diff --git a/testsuite/tests/tool-ocamldoc-html/Linebreaks.reference b/testsuite/tests/tool-ocamldoc-html/Linebreaks.reference deleted file mode 100644 index 8abb6dc9..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Linebreaks.reference +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - -Linebreaks - - - -

      Module Linebreaks

      - -
      module Linebreaks: sig .. end
      -
      -

      This file tests the encoding of linebreak inside OCaml code by the - ocamldoc html backend.

      - -

      Two slightly different aspects are tested in this very file.

      - -
        -
      • First, inside a "pre" tags, blanks character should not be escaped. - For instance, the generated html code for this test fragment should not - contain any <br> tag: -
             let f x =
        -       let g x =
        -         let h x = x in
        -         h x in
        -       g x
        -   
        - See MPR#6341 for more - details or the file Linebreaks.html generated by ocamldoc from this file.
      • -
      • Second, outside of a "pre" tags, blank characters in embedded code - should be escaped, in order to make them render in a "pre"-like fashion. - A good example should be the files type_Modulename.html generated by - ocamldoc that should contains the signature of the module Modulename in - a "code" tags. - For instance with the following type definitions,
      • -
      -
      -
      -
      - -
      type a = 
      - - - - -
      -| -A
      - - - -
      type 'a b = {
      - - - - -
      -   -field : 'a;
      -} - - - -
      type c = 
      - - - - -
      -| -C : 'a -> c
      - - - -
      type s = ..
      - -
      type s += 
      - - - - -
      -| -B
      - - - -
      val x : a
      -
      module S: sig .. end
      -
      module type s = sig .. end
      -
      class type d = object .. end
      -
      exception E of {
      -
      -
      -
      -
      -
      -   -inline : int;
      -} -
      -

      type_Linebreaks.html should contain

      - -
      sig
      -  type a = A
      -  type 'a b = { field : 'a; }
      -  type c = C : 'a -> Linebreaks.c
      -  type s = ..
      -  type s += B
      -  val x : Linebreaks.a
      -  module S : sig module I : sig  end end
      -  module type s = sig  end
      -  class type d = object  end
      -  exception E of { inline : int; }
      -end
      -
      -

      with <br> tags used for linebreaks. -Another example would be  let f x =
      -x
      which is rendered with a <br> linebreak inside Linebreaks.html.

      - -

      See MPR#7272 for more -information.

      - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Loop.ml b/testsuite/tests/tool-ocamldoc-html/Loop.ml deleted file mode 100644 index b0306b76..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Loop.ml +++ /dev/null @@ -1,3 +0,0 @@ - -module rec A : sig type t end = B and B : sig type t = A.t end = A;; - diff --git a/testsuite/tests/tool-ocamldoc-html/Loop.reference b/testsuite/tests/tool-ocamldoc-html/Loop.reference deleted file mode 100644 index 2025479d..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Loop.reference +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - -Loop - - - -

      Module Loop

      - -
      module Loop: sig .. end

      - -
      module A: B
      -
      module B: A
      \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Makefile b/testsuite/tests/tool-ocamldoc-html/Makefile deleted file mode 100644 index 116b580b..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/ocamldoc -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/str -DOCFLAGS=-I $(OTOPDIR)/stdlib $(COMPFLAGS)\ - -latextitle "6,subsection*" \ - -latextitle "7,subsubsection*" \ - -latex-type-prefix "TYP" \ - -latex-module-prefix "" \ - -latex-module-type-prefix "" \ - -latex-value-prefix "" - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(SET_LD_PATH) $(MAKE) run; \ - fi - -.PHONY: run -run: *.mli *.ml -# Note that we strip both .ml and .mli extensions - @for file in *.ml *.mli; do \ - printf " ... testing '$$file'"; \ - F="`basename $$file .mli`"; \ - F="`basename $$F .ml`"; \ - $(OCAMLDOC) $(DOCFLAGS) -colorize-code -hide-warnings -html $ \ - -o index $$file; \ - cp $$F.html $$F.result; \ - $(DIFF) $$F.reference $$F.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done;\ -# For linebreaks.mli, we also compare type_Linebreaks.html and not only -# the main html file - @cp type_Linebreaks.html type_Linebreaks.result;\ - printf " ... testing 'type_Linebreak.html'";\ - $(DIFF) type_Linebreaks.reference type_Linebreaks.result\ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result *.html *.tex *.log *.out *.sty *.toc *.css *.aux - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamldoc-html/Module_whitespace.ml b/testsuite/tests/tool-ocamldoc-html/Module_whitespace.ml deleted file mode 100644 index d9ddee7b..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Module_whitespace.ml +++ /dev/null @@ -1,4 +0,0 @@ -module M = Set.Make(struct - type t = int - let compare = compare -end) diff --git a/testsuite/tests/tool-ocamldoc-html/Module_whitespace.reference b/testsuite/tests/tool-ocamldoc-html/Module_whitespace.reference deleted file mode 100644 index fc98a0bb..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Module_whitespace.reference +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - -Module_whitespace - - - -

      Module Module_whitespace

      - -
      module Module_whitespace: sig .. end

      - -
      module M: Set.Make(sig
      -
      type t = int 
      - - -
      val compare : 'a -> 'a -> int
      -
      end)
      \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/No_preamble.mli b/testsuite/tests/tool-ocamldoc-html/No_preamble.mli deleted file mode 100644 index 2760e266..00000000 --- a/testsuite/tests/tool-ocamldoc-html/No_preamble.mli +++ /dev/null @@ -1,5 +0,0 @@ - -open String - -(** This is a documentation comment for [x], not a module preamble. *) -val x: unit diff --git a/testsuite/tests/tool-ocamldoc-html/No_preamble.reference b/testsuite/tests/tool-ocamldoc-html/No_preamble.reference deleted file mode 100644 index f34662e8..00000000 --- a/testsuite/tests/tool-ocamldoc-html/No_preamble.reference +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - -No_preamble - - - -

      Module No_preamble

      - -
      module No_preamble: sig .. end

      - -
      val x : unit
      -
      -

      This is a documentation comment for x, not a module preamble.

      -
      -
      - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Paragraph.mli b/testsuite/tests/tool-ocamldoc-html/Paragraph.mli deleted file mode 100644 index 7081da1d..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Paragraph.mli +++ /dev/null @@ -1,50 +0,0 @@ -(** This file tests the generation of paragraph within module comments. - - - At least three points should be exercised in this tests - - - First, all text should be tagged - - Second, no paragraph should contain only spaces characters - - Third, the mixing of different text style should not create - invalid p tags - - - See also {{: http://caml.inria.fr/mantis/view.php?id=7352} MPR:7352}, - {{: http://caml.inria.fr/mantis/view.php?id=7353} MPR:7353} - - {2:here Testing non-text elements } - - [code x ] {i should } be inside a p. - - - {e But} {b not} - {[ - let complex_code = () - ]} - here. - - + An enumerated list first element - + second element - - {L Alignement test: left} - {R Right} - {C Center} - - - Other complex text{_ in subscript }{^ and superscript} - {V Verbatim V} - - There is also {%html: html specific %} elements. - - @author: Florian Angeletti - @version: 1 -*) - -(** *) - -type t -(** - And cross-reference {! t}. - {!modules: Paragraph} - {!indexlist} -*) diff --git a/testsuite/tests/tool-ocamldoc-html/Paragraph.reference b/testsuite/tests/tool-ocamldoc-html/Paragraph.reference deleted file mode 100644 index 84dee74c..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Paragraph.reference +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - -Paragraph - - - -

      Module Paragraph

      - -
      module Paragraph: sig .. end
      -
      -

      This file tests the generation of paragraph within module comments.

      - -

      At least three points should be exercised in this tests

      - -
        -
      • First, all text should be tagged
      • -
      • Second, no paragraph should contain only spaces characters
      • -
      • Third, the mixing of different text style should not create - invalid p tags
      • -
      -

      See also MPR:7352, - MPR:7353

      - -

      Testing non-text elements

      -

      code x  should be inside a p.

      - -

      But not

      -
            let complex_code = ()
      -    

      here.

      - -
        -
      1. An enumerated list first element
      2. -
      3. second element
      4. -
      -
      Alignement test: left
      Right
      Center
      -

      Other complex textin subscript and superscript

      - -

      There is also html specific elements.

      -
      -
        -
      • Author(s): : Florian Angeletti
      • -
      • Version: : 1
      • -
      -
      -
      - -
      type t 
      -
      -
      -

      And cross-reference Paragraph.t. - - - -
      Paragraph
      -

      This file tests the generation of paragraph within module comments.

      - -
      -

      - -
      -
      - - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/Variants.mli b/testsuite/tests/tool-ocamldoc-html/Variants.mli deleted file mode 100644 index f60c267e..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Variants.mli +++ /dev/null @@ -1,43 +0,0 @@ -(** This test is here to check the latex code generated for variants *) - -type s = A | B (** only B is documented here *) | C - -type t = - | A - (** doc for A. - {[0]} - With three paragraphs. - {[1]} - To check styling - *) - | B - (** doc for B *) - -(** Some documentation for u*) -type u = -| A (** doc for A *) | B of unit (** doc for B *) - - -(** With records *) -type w = -| A of { x: int } - (** doc for A *) -| B of { y:int } - (** doc for B *) - -(** With args *) -type z = -| A of int - (** doc for A *) -| B of int - (** doc for B *) - -(** Gadt notation *) -type a = - A: a (** doc for A*) - -(** Lonely constructor *) -type b = - B (** doc for B *) - -type no_documentation = A | B | C diff --git a/testsuite/tests/tool-ocamldoc-html/Variants.reference b/testsuite/tests/tool-ocamldoc-html/Variants.reference deleted file mode 100644 index d5aa791d..00000000 --- a/testsuite/tests/tool-ocamldoc-html/Variants.reference +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - - - - -Variants - - - -

      Module Variants

      - -
      module Variants: sig .. end
      -
      -

      This test is here to check the latex code generated for variants

      -
      -
      -
      - -
      type s = 
      - - - - - - - - - - - - - - -
      -| -A
      -| -B(*
      -
      -

      only B is documented here

      -
      -
      -
      *)
      -| -C
      - - - -
      type t = 
      - - - - - - - - - -
      -| -A(*
      -
      -

      doc for A.

      -
      0

      With three paragraphs.

      -
      1

      To check styling

      -
      -
      -
      *)
      -| -B(*
      -
      -

      doc for B

      -
      -
      -
      *)
      - - - -
      type u = 
      - - - - - - - - - -
      -| -A(*
      -
      -

      doc for A

      -
      -
      -
      *)
      -| -B of unit(*
      -
      -

      doc for B

      -
      -
      -
      *)
      - -
      -
      -

      Some documentation for u

      -
      -
      - - -
      type w = 
      - - - - - - - - - -
      -| -A of { - - - - -
      -   -x : int;
      -} -
      (*
      -
      -

      doc for A

      -
      -
      -
      *)
      -| -B of { - - - - -
      -   -y : int;
      -} -
      (*
      -
      -

      doc for B

      -
      -
      -
      *)
      - -
      -
      -

      With records

      -
      -
      - - -
      type z = 
      - - - - - - - - - -
      -| -A of int(*
      -
      -

      doc for A

      -
      -
      -
      *)
      -| -B of int(*
      -
      -

      doc for B

      -
      -
      -
      *)
      - -
      -
      -

      With args

      -
      -
      - - -
      type a = 
      - - - - -
      -| -A : a(*
      -
      -

      doc for A

      -
      -
      -
      *)
      - -
      -
      -

      Gadt notation

      -
      -
      - - -
      type b = 
      - - - - -
      -| -B(*
      -
      -

      doc for B

      -
      -
      -
      *)
      - -
      -
      -

      Lonely constructor

      -
      -
      - - -
      type no_documentation = 
      - - - - - - - - - - - - - - -
      -| -A
      -| -B
      -| -C
      - - - \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-html/type_Linebreaks.reference b/testsuite/tests/tool-ocamldoc-html/type_Linebreaks.reference deleted file mode 100644 index ad097f11..00000000 --- a/testsuite/tests/tool-ocamldoc-html/type_Linebreaks.reference +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - -Linebreaks - - -sig
      -  type a = A
      -  type 'a b = { field : 'a; }
      -  type c = C : '-> Linebreaks.c
      -  type s = ..
      -  type s += B
      -  val x : Linebreaks.a
      -  module S : sig module I : sig  end end
      -  module type s = sig  end
      -  class type d = object  end
      -  exception E of { inline : int; }
      -end
      \ No newline at end of file diff --git a/testsuite/tests/tool-ocamldoc-man/Inline_records.mli b/testsuite/tests/tool-ocamldoc-man/Inline_records.mli deleted file mode 100644 index f80cd2bd..00000000 --- a/testsuite/tests/tool-ocamldoc-man/Inline_records.mli +++ /dev/null @@ -1,45 +0,0 @@ -(** - This test focuses on the printing of documentation for inline record - within the latex generator. -*) - - -(** A nice exception *) -exception Simple - -(** An open sum type *) -type ext = .. - -(** A simple record type for reference *) -type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); - more:int list (** More documentation for r, [more : int list] *) } - - -(** A sum type with one inline record *) -type t = A of {lbl: int (** [A] field documentation *) - ; more:int list (** More [A] field documentation *) } -(** Constructor documentation *) - -(** A sum type with two inline records *) -type s = - | B of { a_label_for_B : int (** [B] field documentation *); - more_label_for_B:int list (** More [B] field documentation *) } - (** Constructor B documentation *) - | C of { c_has_label_too: float (** [C] field documentation*); - more_than_one: unit (** ... documentations *) } - (** Constructor C documentation *) - -(** A gadt constructor *) -type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any -(** Constructor D documentation *) - -exception Error of {name:string (** Error field documentation [name:string] *) } - -type ext += - | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } - (** Constructor E documentation *) - | F of { even_more: int -> int (** Some field documentations for [F] *) } - (** Constructor F documentation *) - | G of { last: int -> int (** The last and least field documentation *) } - (** Constructor G documentation *) -(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc-man/Inline_records.reference b/testsuite/tests/tool-ocamldoc-man/Inline_records.reference deleted file mode 100644 index 7184b971..00000000 --- a/testsuite/tests/tool-ocamldoc-man/Inline_records.reference +++ /dev/null @@ -1,201 +0,0 @@ -.SH NAME -Inline_records \- This test focuses on the printing of documentation for inline record within the latex generator. -.SH Module -Module Inline_records -.SH Documentation -.sp -Module -.BI "Inline_records" - : -.B sig end - -.sp -This test focuses on the printing of documentation for inline record -within the latex generator\&. - -.sp - -.sp -.sp - -.I exception Simple - -.sp -A nice exception - -.sp -.I type ext -= .. - -.sp -An open sum type - -.sp -.I type r -= { - lbl : -.B int -; (* Field documentation for non\-inline, -.B lbl : int - - *) - more : -.B int list -; (* More documentation for r, -.B more : int list - - *) - } - -.sp -A simple record type for reference - -.sp -.I type t -= - | A -.B of { - lbl : -.B int -; (* -.B A -field documentation - *) - more : -.B int list -; (* More -.B A -field documentation - *) - } -.I " " - (* Constructor documentation - *) - -.sp -A sum type with one inline record - -.sp -.I type s -= - | B -.B of { - a_label_for_B : -.B int -; (* -.B B -field documentation - *) - more_label_for_B : -.B int list -; (* More -.B B -field documentation - *) - } -.I " " - (* Constructor B documentation - *) - | C -.B of { - c_has_label_too : -.B float -; (* -.B C -field documentation - *) - more_than_one : -.B unit -; (* \&.\&.\&. documentations - *) - } -.I " " - (* Constructor C documentation - *) - -.sp -A sum type with two inline records - -.sp -.I type any -= - | D -.B of { - any : -.B 'a -; (* -.B A -field -.B any:\&'a -for -.B D -in -.B any -\&. - *) - } -.B -> -.B any -.I " " - (* Constructor D documentation - *) - -.sp -A gadt constructor - -.sp - -.I exception Error -.B of { - name : -.B string -; (* Error field documentation -.B name:string - - *) - } - -.sp - -.sp -.I type ext -+= - | E -.B of { - yet_another_field : -.B unit -; (* Field documentation for -.B E -in ext - *) - } -.I " " -(* Constructor E documentation - *) - | F -.B of { - even_more : -.B int -> int -; (* Some field documentations for -.B F - - *) - } -.I " " -(* Constructor F documentation - *) - | G -.B of { - last : -.B int -> int -; (* The last and least field documentation - *) - } -.I " " -(* Constructor G documentation - *) - -.sp -Two new constructors for ext - -.sp diff --git a/testsuite/tests/tool-ocamldoc-man/Makefile b/testsuite/tests/tool-ocamldoc-man/Makefile deleted file mode 100644 index a3c272a1..00000000 --- a/testsuite/tests/tool-ocamldoc-man/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/ocamldoc -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/str -DOCFLAGS=-I $(OTOPDIR)/stdlib $(COMPFLAGS)\ - -latextitle "6,subsection*" \ - -latextitle "7,subsubsection*" \ - -latex-type-prefix "TYP" \ - -latex-module-prefix "" \ - -latex-module-type-prefix "" \ - -latex-value-prefix "" - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(SET_LD_PATH) $(MAKE) run; \ - fi - -.PHONY: run -run: *.mli - @for file in *.mli; do \ - printf " ... testing '$$file'"; \ - F="`basename $$file .mli`"; \ - $(OCAMLDOC) $(DOCFLAGS) -hide-warnings -man $ \ - -o index $$file; \ - tail -n +2 $$F.3o > $$F.result; \ - $(DIFF) $$F.reference $$F.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result *.html *.tex *.log *.out *.sty *.toc *.css *.aux *.3o - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamldoc-open/Makefile b/testsuite/tests/tool-ocamldoc-open/Makefile deleted file mode 100644 index 92f09a1d..00000000 --- a/testsuite/tests/tool-ocamldoc-open/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -BASEDIR=../.. -COMPFLAGS=-I $(OTOPDIR)/ocamldoc -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/str -DOCFLAGS=-I $(OTOPDIR)/stdlib $(COMPFLAGS) - -SRC= main.ml alias.ml inner.ml -ODOCS=$(SRC:%.ml=%.odoc) - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(SET_LD_PATH) $(MAKE) doc; \ - fi - -.PHONY: doc -doc: $(ODOCS) - @printf " ... testing ocamldoc '-open' option";\ - $(OCAMLDOC) $(DOCFLAGS) -hide-warnings \ - -load alias.odoc -load inner.odoc \ - -load main.odoc -latex -o doc.result ;\ - $(DIFF) doc.result doc.reference > /dev/null \ - && echo " => passed" || echo " => failed"; - -inner.odoc: inner.ml - @$(OCAMLDOC) $(DOCFLAGS) -hide-warnings \ - -dump inner.odoc inner.ml - -alias.odoc: inner.cmi alias.ml - @$(OCAMLDOC) $(DOCFLAGS) -hide-warnings \ - -dump alias.odoc alias.ml - -main.odoc: alias.cmi main.ml - @$(OCAMLDOC) $(DOCFLAGS) -hide-warnings \ - -open Alias.Container -open Aliased_inner -dump main.odoc main.ml - -alias.cmi:inner.cmi - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.odoc *.toc *.sty *.aux *.log *.result - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamldoc-open/doc.reference b/testsuite/tests/tool-ocamldoc-open/main.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-open/doc.reference rename to testsuite/tests/tool-ocamldoc-open/main.latex.reference diff --git a/testsuite/tests/tool-ocamldoc-open/main.ml b/testsuite/tests/tool-ocamldoc-open/main.ml index abc1f818..4dca4e54 100644 --- a/testsuite/tests/tool-ocamldoc-open/main.ml +++ b/testsuite/tests/tool-ocamldoc-open/main.ml @@ -1,3 +1,9 @@ +(* TEST + modules = "inner.ml alias.ml" + * ocamldoc + ocamldoc_backend="latex" + ocamldoc_flags=" -open Alias.Container -open Aliased_inner " +*) (** Documentation test *) diff --git a/testsuite/tests/tool-ocamldoc-open/main.ocamldoc.latex.reference b/testsuite/tests/tool-ocamldoc-open/main.ocamldoc.latex.reference new file mode 100644 index 00000000..930579ee --- /dev/null +++ b/testsuite/tests/tool-ocamldoc-open/main.ocamldoc.latex.reference @@ -0,0 +1,3 @@ +Warning: Module or module type Inner not found +Warning: Module or module type Inner not found +Warning: Module or module type Inner not found diff --git a/testsuite/tests/tool-ocamldoc-open/ocamltests b/testsuite/tests/tool-ocamldoc-open/ocamltests new file mode 100644 index 00000000..d389d156 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc-open/ocamltests @@ -0,0 +1 @@ +main.ml diff --git a/testsuite/tests/tool-ocamldoc/Documentation_tags.html.reference b/testsuite/tests/tool-ocamldoc/Documentation_tags.html.reference new file mode 100644 index 00000000..f646c4c1 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Documentation_tags.html.reference @@ -0,0 +1,44 @@ + + + + + + + + + + +Documentation_tags + + + +

      Module Documentation_tags

      + +
      module Documentation_tags: sig .. end
      +
      +

      Test the html rendering of ocamldoc documentation tags

      +
      +
      +
      + +
      val heterological : unit
      +
      +Deprecated.since the start of time
      +
        +
      • Author(s): yes
      • +
      • Before Time not implemented
      • +
      • Since Now
      • +
      • Returns ()
      • +
      • See also Documentation_tags.mli Self reference
      • +
      +
      + +
      val noop : unit
      +
        +
      • Raises
        • Not_found Never
        • +
        • Invalid_argument Never
        • +
      • +
      +
      + diff --git a/testsuite/tests/tool-ocamldoc/Documentation_tags.mli b/testsuite/tests/tool-ocamldoc/Documentation_tags.mli new file mode 100644 index 00000000..413a4ca0 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Documentation_tags.mli @@ -0,0 +1,23 @@ +(* TEST + * ocamldoc with html +*) + +(** Test the html rendering of ocamldoc documentation tags *) + +val heterological: unit +(** + @author yes + @param no No description + @param neither see no description + @deprecated since the start of time + @return () + @see "Documentation_tags.mli" Self reference + @since Now + @before Time not implemented +*) + +val noop: unit +(** + @raise Not_found Never + @raise Invalid_argument Never +*) diff --git a/testsuite/tests/tool-ocamldoc-2/extensible_variant.reference b/testsuite/tests/tool-ocamldoc/Extensible_variant.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/extensible_variant.reference rename to testsuite/tests/tool-ocamldoc/Extensible_variant.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Extensible_variant.ml b/testsuite/tests/tool-ocamldoc/Extensible_variant.ml new file mode 100644 index 00000000..f459fa27 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Extensible_variant.ml @@ -0,0 +1,29 @@ +(* TEST + * ocamldoc with latex +*) + +(** Testing display of extensible variant types and exceptions. + + @test_types_display + *) + +(** Also check reference for {!M.A}, {!M.B}, {!M.C} and {!E} *) + +(** Extensible type *) +type e = .. + +module M = struct + type e += + | A (** A doc *) + | B (** B doc *) + | C (** C doc *) +end + +module type MT = sig + type e += + | A (** A doc *) + | B (** B doc *) + | C (** C doc *) +end + +exception E diff --git a/testsuite/tests/tool-ocamldoc/Extensible_variant.ocamldoc.latex.reference b/testsuite/tests/tool-ocamldoc/Extensible_variant.ocamldoc.latex.reference new file mode 100644 index 00000000..c80cf142 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Extensible_variant.ocamldoc.latex.reference @@ -0,0 +1 @@ +Warning: Tag @test_types_display not handled by this generator diff --git a/testsuite/tests/tool-ocamldoc/Inline_records.html.reference b/testsuite/tests/tool-ocamldoc/Inline_records.html.reference new file mode 100644 index 00000000..d41a6676 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Inline_records.html.reference @@ -0,0 +1,352 @@ + + + + + + + + + + + + +Inline_records + + + +

      Module Inline_records

      + +
      module Inline_records: sig .. end
      +
      +

      This test focuses on the printing of documentation for inline record + within the latex generator.

      +
      +
      +
      + +
      exception Simple
      +
      +
      +

      A nice exception

      +
      +
      + +
      exception Less of int
      +
      +
      +

      A less simple exception

      +
      +
      + +
      type ext = ..
      +
      +
      +

      An open sum type

      +
      +
      + + +
      type r = {
      + + + + + + + + + +
      +   +lbl : int;(*
      +
      +

      Field documentation for non-inline, lbl : int

      +
      +
      +
      *)
      +   +more : int list;(*
      +
      +

      More documentation for r, more : int list

      +
      +
      +
      *)
      +} + +
      +
      +

      A simple record type for reference

      +
      +
      + + +
      type t = 
      + + + + +
      +| +A of { + + + + + + + + + +
      +   +lbl : int;(*
      +
      +

      A field documentation

      +
      +
      +
      *)
      +   +more : int list;(*
      +
      +

      More A field documentation

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor documentation

      +
      +
      +
      *)
      + +
      +
      +

      A sum type with one inline record

      +
      +
      + + +
      type s = 
      + + + + + + + + + +
      +| +B of { + + + + + + + + + +
      +   +a_label_for_B : int;(*
      +
      +

      B field documentation

      +
      +
      +
      *)
      +   +more_label_for_B : int list;(*
      +
      +

      More B field documentation

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor B documentation

      +
      +
      +
      *)
      +| +C of { + + + + + + + + + +
      +   +c_has_label_too : float;(*
      +
      +

      C field documentation

      +
      +
      +
      *)
      +   +more_than_one : unit;(*
      +
      +

      ... documentations

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor C documentation

      +
      +
      +
      *)
      + +
      +
      +

      A sum type with two inline records

      +
      +
      + + +
      type any = 
      + + + + +
      +| +D : { + + + + +
      +   +any : 'a;(*
      +
      +

      A field any:'a for D in any.

      +
      +
      +
      *)
      +} + -> any
      (*
      +
      +

      Constructor D documentation

      +
      +
      +
      *)
      + +
      +
      +

      A gadt constructor

      +
      +
      + + +
      exception Error of {
      +
      +
      +
      +
      +
      +   +name : string;(*
      +
      +

      Error field documentation name:string

      +
      +
      +
      *)
      +} +
      +
      type ext += 
      + + + + + + + + + + + + + + +
      +| +E of { + + + + +
      +   +yet_another_field : unit;(*
      +
      +

      Field documentation for E in ext

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor E documentation

      +
      +
      +
      *)
      +| +F of { + + + + +
      +   +even_more : int -> int;(*
      +
      +

      Some field documentations for F

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor F documentation

      +
      +
      +
      *)
      +| +G of { + + + + +
      +   +last : int -> int;(*
      +
      +

      The last and least field documentation

      +
      +
      +
      *)
      +} +
      (*
      +
      +

      Constructor G documentation

      +
      +
      +
      *)
      + +
      +
      +

      Two new constructors for ext

      +
      +
      + + diff --git a/testsuite/tests/tool-ocamldoc-2/inline_records.reference b/testsuite/tests/tool-ocamldoc/Inline_records.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/inline_records.reference rename to testsuite/tests/tool-ocamldoc/Inline_records.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Inline_records.man.reference b/testsuite/tests/tool-ocamldoc/Inline_records.man.reference new file mode 100644 index 00000000..a2890e40 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Inline_records.man.reference @@ -0,0 +1,210 @@ +.SH NAME +Inline_records \- This test focuses on the printing of documentation for inline record within the latex generator. +.SH Module +Module Inline_records +.SH Documentation +.sp +Module +.BI "Inline_records" + : +.B sig end + +.sp +This test focuses on the printing of documentation for inline record +within the latex generator\&. + +.sp + +.sp +.sp + +.I exception Simple + +.sp +A nice exception + +.sp + +.I exception Less +.B of +.B int + +.sp +A less simple exception + +.sp +.I type ext += .. + +.sp +An open sum type + +.sp +.I type r += { + lbl : +.B int +; (* Field documentation for non\-inline, +.B lbl : int + + *) + more : +.B int list +; (* More documentation for r, +.B more : int list + + *) + } + +.sp +A simple record type for reference + +.sp +.I type t += + | A +.B of { + lbl : +.B int +; (* +.B A +field documentation + *) + more : +.B int list +; (* More +.B A +field documentation + *) + } +.I " " + (* Constructor documentation + *) + +.sp +A sum type with one inline record + +.sp +.I type s += + | B +.B of { + a_label_for_B : +.B int +; (* +.B B +field documentation + *) + more_label_for_B : +.B int list +; (* More +.B B +field documentation + *) + } +.I " " + (* Constructor B documentation + *) + | C +.B of { + c_has_label_too : +.B float +; (* +.B C +field documentation + *) + more_than_one : +.B unit +; (* \&.\&.\&. documentations + *) + } +.I " " + (* Constructor C documentation + *) + +.sp +A sum type with two inline records + +.sp +.I type any += + | D +.B of { + any : +.B 'a +; (* +.B A +field +.B any:\&'a +for +.B D +in +.B any +\&. + *) + } +.B -> +.B any +.I " " + (* Constructor D documentation + *) + +.sp +A gadt constructor + +.sp + +.I exception Error +.B of { + name : +.B string +; (* Error field documentation +.B name:string + + *) + } + +.sp + +.sp +.I type ext ++= + | E +.B of { + yet_another_field : +.B unit +; (* Field documentation for +.B E +in ext + *) + } +.I " " +(* Constructor E documentation + *) + | F +.B of { + even_more : +.B int -> int +; (* Some field documentations for +.B F + + *) + } +.I " " +(* Constructor F documentation + *) + | G +.B of { + last : +.B int -> int +; (* The last and least field documentation + *) + } +.I " " +(* Constructor G documentation + *) + +.sp +Two new constructors for ext + +.sp diff --git a/testsuite/tests/tool-ocamldoc/Inline_records.mli b/testsuite/tests/tool-ocamldoc/Inline_records.mli new file mode 100644 index 00000000..5b4646d9 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Inline_records.mli @@ -0,0 +1,54 @@ +(* TEST + * ocamldoc with html + * ocamldoc with latex + * ocamldoc with man +*) + +(** + This test focuses on the printing of documentation for inline record + within the latex generator. +*) + + +(** A nice exception *) +exception Simple + +(** A less simple exception *) +exception Less of int + +(** An open sum type *) +type ext = .. + +(** A simple record type for reference *) +type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); + more:int list (** More documentation for r, [more : int list] *) } + + +(** A sum type with one inline record *) +type t = A of {lbl: int (** [A] field documentation *) + ; more:int list (** More [A] field documentation *) } +(** Constructor documentation *) + +(** A sum type with two inline records *) +type s = + | B of { a_label_for_B : int (** [B] field documentation *); + more_label_for_B:int list (** More [B] field documentation *) } + (** Constructor B documentation *) + | C of { c_has_label_too: float (** [C] field documentation*); + more_than_one: unit (** ... documentations *) } + (** Constructor C documentation *) + +(** A gadt constructor *) +type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any +(** Constructor D documentation *) + +exception Error of {name:string (** Error field documentation [name:string] *) } + +type ext += + | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } + (** Constructor E documentation *) + | F of { even_more: int -> int (** Some field documentations for [F] *) } + (** Constructor F documentation *) + | G of { last: int -> int (** The last and least field documentation *) } + (** Constructor G documentation *) +(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc-2/inline_records_bis.reference b/testsuite/tests/tool-ocamldoc/Inline_records_bis.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/inline_records_bis.reference rename to testsuite/tests/tool-ocamldoc/Inline_records_bis.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Inline_records_bis.ml b/testsuite/tests/tool-ocamldoc/Inline_records_bis.ml new file mode 100644 index 00000000..4844aaf2 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Inline_records_bis.ml @@ -0,0 +1,52 @@ +(* TEST + * ocamldoc with latex +*) + +(** + This test focuses on the printing of documentation for inline record + within the latex generator. +*) + + +(** A nice exception *) +exception Simple + +(** A less simple exception *) +exception Less of int + +(** An open sum type *) +type ext = .. + +(** A simple record type for reference *) +type r = { lbl: int (** Field documentation for non-inline, [lbl : int] *); + more:int list (** More documentation for r, [more : int list] *) } + + +(** A sum type with one inline record *) +type t = A of {lbl: int (** [A] field documentation *) + ; more:int list (** More [A] field documentation *) } +(** Constructor documentation *) + +(** A sum type with two inline records *) +type s = + | B of { a_label_for_B : int (** [B] field documentation *); + more_label_for_B:int list (** More [B] field documentation *) } + (** Constructor B documentation *) + | C of { c_has_label_too: float (** [C] field documentation*); + more_than_one: unit (** ... documentations *) } + (** Constructor C documentation *) + +(** A gadt constructor *) +type any = D: { any:'a (** [A] field [any:'a] for [D] in [any]. *) } -> any +(** Constructor D documentation *) + +exception Error of {name:string (** Error field documentation [name:string] *) } + +type ext += + | E of { yet_another_field: unit (** Field documentation for [E] in ext *) } + (** Constructor E documentation *) + | F of { even_more: int -> int (** Some field documentations for [F] *) } + (** Constructor F documentation *) + | G of { last: int -> int (** The last and least field documentation *) } + (** Constructor G documentation *) +(** Two new constructors for ext *) diff --git a/testsuite/tests/tool-ocamldoc/Item_ids.html.reference b/testsuite/tests/tool-ocamldoc/Item_ids.html.reference new file mode 100644 index 00000000..c3b66f3e --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Item_ids.html.reference @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + +Item_ids + + + +

      Module Item_ids

      + +
      module Item_ids: sig .. end
      +
      +

      Check that all toplevel items are given a unique id.

      +
      +
      +
      + +
      exception Ex
      + +
      type t 
      + + +
      val x : t
      +
      type ext = ..
      + +
      type ext += 
      + + + + +
      +| +A
      + + + +
      class c : object .. end
      +
      class type ct = object .. end
      +
      module M: sig .. end
      +
      module type s = sig .. end
      diff --git a/testsuite/tests/tool-ocamldoc/Item_ids.mli b/testsuite/tests/tool-ocamldoc/Item_ids.mli new file mode 100644 index 00000000..878c6fef --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Item_ids.mli @@ -0,0 +1,16 @@ +(* TEST + * ocamldoc with html +*) + +(** Check that all toplevel items are given a unique id. *) + +exception Ex +type t +val x: t +type ext = .. +type ext += A +class c: object end +class type ct= object end +[@@@attribute] +module M: sig end +module type s = sig end diff --git a/testsuite/tests/tool-ocamldoc-2/level_0.reference b/testsuite/tests/tool-ocamldoc/Level_0.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/level_0.reference rename to testsuite/tests/tool-ocamldoc/Level_0.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Level_0.mli b/testsuite/tests/tool-ocamldoc/Level_0.mli new file mode 100644 index 00000000..d9458572 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Level_0.mli @@ -0,0 +1,19 @@ +(* TEST + * ocamldoc with latex +*) + +(** Test for level 0 headings + + {1 Level 1} + + Standard heading levels start at 1. + + {0 Level 0} + A level 0 heading is guaranted to be at the same level that + the main heading of the module. + + This setup allows users to start their standard heading at level 1 rather + than 2, without losing the ability to add global level heading, + when, if ever, such heading is warranted + + *) diff --git a/testsuite/tests/tool-ocamldoc/Linebreaks.html.reference b/testsuite/tests/tool-ocamldoc/Linebreaks.html.reference new file mode 100644 index 00000000..026e26df --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Linebreaks.html.reference @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + +Linebreaks + + + +

      Module Linebreaks

      + +
      module Linebreaks: sig .. end
      +
      +

      This file tests the encoding of linebreak inside OCaml code by the + ocamldoc html backend.

      + +

      Two slightly different aspects are tested in this very file.

      + +
        +
      • First, inside a "pre" tags, blanks character should not be escaped. + For instance, the generated html code for this test fragment should not + contain any <br> tag: +
             let f x =
        +       let g x =
        +         let h x = x in
        +         h x in
        +       g x
        +   
        + See MPR#6341 for more + details or the file Linebreaks.html generated by ocamldoc from this file.
      • +
      • Second, outside of a "pre" tags, blank characters in embedded code + should be escaped, in order to make them render in a "pre"-like fashion. + A good example should be the files type_Modulename.html generated by + ocamldoc that should contains the signature of the module Modulename in + a "code" tags. + For instance with the following type definitions,
      • +
      +
      +
      +
      + +
      type a = 
      + + + + +
      +| +A
      + + + +
      type 'a b = {
      + + + + +
      +   +field : 'a;
      +} + + + +
      type c = 
      + + + + +
      +| +C : 'a -> c
      + + + +
      type s = ..
      + +
      type s += 
      + + + + +
      +| +B
      + + + +
      val x : a
      +
      module S: sig .. end
      +
      module type s = sig .. end
      +
      class type d = object .. end
      +
      exception E of {
      +
      +
      +
      +
      +
      +   +inline : int;
      +} +
      +

      type_Linebreaks.html should contain

      + +
      sig
      +  type a = A
      +  type 'a b = { field : 'a; }
      +  type c = C : 'a -> Linebreaks.c
      +  type s = ..
      +  type s += B
      +  val x : Linebreaks.a
      +  module S : sig module I : sig  end end
      +  module type s = sig  end
      +  class type d = object  end
      +  exception E of { inline : int; }
      +end
      +
      +

      with <br> tags used for linebreaks. +Another example would be  let f x =
      +x
      which is rendered with a <br> linebreak inside Linebreaks.html.

      + +

      See MPR#7272 for more +information.

      + diff --git a/testsuite/tests/tool-ocamldoc/Linebreaks.mli b/testsuite/tests/tool-ocamldoc/Linebreaks.mli new file mode 100644 index 00000000..1dce3838 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Linebreaks.mli @@ -0,0 +1,75 @@ +(* TEST + * ocamldoc with html + ** check-program-output + output="type_Linebreaks.html" + reference="${test_source_directory}/type_Linebreaks.reference" +*) + +(** + This file tests the encoding of linebreak inside OCaml code by the + ocamldoc html backend. + + Two slightly different aspects are tested in this very file. + + - First, inside a "pre" tags, blanks character should not be escaped. + For instance, the generated html code for this test fragment should not + contain any
      tag: + {[ + let f x = + let g x = + let h x = x in + h x in + g x + ]} + See {{:http://caml.inria.fr/mantis/view.php?id=6341} MPR#6341} for more + details or the file Linebreaks.html generated by ocamldoc from this file. + - Second, outside of a "pre" tags, blank characters in embedded code + should be escaped, in order to make them render in a "pre"-like fashion. + A good example should be the files type_{i Modulename}.html generated by + ocamldoc that should contains the signature of the module [Modulename] in + a "code" tags. + For instance with the following type definitions, +*) + +type a = A +type 'a b = {field:'a} +type c = C: 'a -> c + +type s = .. +type s += B + +val x : a + +module S: sig module I:sig end end +module type s = sig end + +class type d = object end + +exception E of {inline:int} + + +(** type_Linebreaks.html should contain + +{[ +sig + type a = A + type 'a b = { field : 'a; } + type c = C : 'a -> Linebreaks.c + type s = .. + type s += B + val x : Linebreaks.a + module S : sig module I : sig end end + module type s = sig end + class type d = object end + exception E of { inline : int; } +end +]} + +with
      tags used for linebreaks. +Another example would be [ let f x = +x] which is rendered with a
      linebreak inside Linebreaks.html. + +See {{:http://caml.inria.fr/mantis/view.php?id=7272}MPR#7272} for more +information. + +*) diff --git a/testsuite/tests/tool-ocamldoc/Loop.html.reference b/testsuite/tests/tool-ocamldoc/Loop.html.reference new file mode 100644 index 00000000..74ad9a7e --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Loop.html.reference @@ -0,0 +1,20 @@ + + + + + + + + + +Loop + + + +

      Module Loop

      + +
      module Loop: sig .. end

      + +
      module A: B
      +
      module B: A
      diff --git a/testsuite/tests/tool-ocamldoc-2/loop.reference b/testsuite/tests/tool-ocamldoc/Loop.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/loop.reference rename to testsuite/tests/tool-ocamldoc/Loop.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Loop.ml b/testsuite/tests/tool-ocamldoc/Loop.ml new file mode 100644 index 00000000..8428f9fc --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Loop.ml @@ -0,0 +1,5 @@ +(* TEST + * ocamldoc with html + * ocamldoc with latex +*) +module rec A : sig type t end = B and B : sig type t = A.t end = A;; diff --git a/testsuite/tests/tool-ocamldoc/Makefile b/testsuite/tests/tool-ocamldoc/Makefile deleted file mode 100644 index e28c62f1..00000000 --- a/testsuite/tests/tool-ocamldoc/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -CUSTOM_MODULE=odoc_test -COMPFLAGS=-I $(OTOPDIR)/ocamldoc -LD_PATH=$(TOPDIR)/otherlibs/$(UNIXLIBVAR)unix:$(TOPDIR)/otherlibs/str -DOCFLAGS=-I $(OTOPDIR)/stdlib $(COMPFLAGS) - -.PHONY: default -default: - @if ! $(SUPPORTS_SHARED_LIBRARIES); then \ - echo 'skipped (shared libraries not available)'; \ - else \ - $(SET_LD_PATH) $(MAKE) run; \ - fi - -.PHONY: run -run: $(CUSTOM_MODULE).cmo - @for file in t*.ml; do \ - printf " ... testing '$$file'"; \ - F="`basename $$file .ml`"; \ - $(OCAMLDOC) $(DOCFLAGS) -hide-warnings -g $(CUSTOM_MODULE).cmo \ - -o $$F.result $$file; \ - $(DIFF) $$F.reference $$F.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; - @$(OCAMLDOC) $(DOCFLAGS) -hide-warnings -html t*.ml 2>&1 \ - | grep -v test_types_display || true - @$(OCAMLDOC) $(DOCFLAGS) -hide-warnings -latex t*.ml 2>&1 \ - | grep -v test_types_display || true - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result *.html *.tex *.log *.out *.sty *.toc *.css *.aux - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamldoc/Module_whitespace.html.reference b/testsuite/tests/tool-ocamldoc/Module_whitespace.html.reference new file mode 100644 index 00000000..c31de5be --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Module_whitespace.html.reference @@ -0,0 +1,24 @@ + + + + + + + + + +Module_whitespace + + + +

      Module Module_whitespace

      + +
      module Module_whitespace: sig .. end

      + +
      module M: Stdlib.Set.Make(sig
      +
      type t = int 
      + + +
      val compare : 'a -> 'a -> int
      +
      end)
      diff --git a/testsuite/tests/tool-ocamldoc/Module_whitespace.ml b/testsuite/tests/tool-ocamldoc/Module_whitespace.ml new file mode 100644 index 00000000..75c6c292 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Module_whitespace.ml @@ -0,0 +1,8 @@ +(* TEST + * ocamldoc with html +*) + +module M = Set.Make(struct + type t = int + let compare = compare +end) diff --git a/testsuite/tests/tool-ocamldoc/Module_whitespace.ocamldoc.html.reference b/testsuite/tests/tool-ocamldoc/Module_whitespace.ocamldoc.html.reference new file mode 100644 index 00000000..515605c3 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Module_whitespace.ocamldoc.html.reference @@ -0,0 +1,2 @@ +Warning: Module or module type Stdlib.Set.Make not found +Warning: Module or module type Stdlib.Set.Make not found diff --git a/testsuite/tests/tool-ocamldoc/No_preamble.html.reference b/testsuite/tests/tool-ocamldoc/No_preamble.html.reference new file mode 100644 index 00000000..0f386701 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/No_preamble.html.reference @@ -0,0 +1,25 @@ + + + + + + + + + + +No_preamble + + + +

      Module No_preamble

      + +
      module No_preamble: sig .. end

      + +
      val x : unit
      +
      +

      This is a documentation comment for x, not a module preamble.

      +
      +
      + diff --git a/testsuite/tests/tool-ocamldoc/No_preamble.mli b/testsuite/tests/tool-ocamldoc/No_preamble.mli new file mode 100644 index 00000000..7d016dda --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/No_preamble.mli @@ -0,0 +1,8 @@ +(* TEST + * ocamldoc with html +*) + +open String + +(** This is a documentation comment for [x], not a module preamble. *) +val x: unit diff --git a/testsuite/tests/tool-ocamldoc/Paragraph.html.reference b/testsuite/tests/tool-ocamldoc/Paragraph.html.reference new file mode 100644 index 00000000..2672a5f6 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Paragraph.html.reference @@ -0,0 +1,75 @@ + + + + + + + + + + +Paragraph + + + +

      Module Paragraph

      + +
      module Paragraph: sig .. end
      +
      +

      This file tests the generation of paragraph within module comments.

      + +

      At least three points should be exercised in this tests

      + +
        +
      • First, all text should be tagged
      • +
      • Second, no paragraph should contain only spaces characters
      • +
      • Third, the mixing of different text style should not create + invalid p tags
      • +
      +

      See also MPR:7352, + MPR:7353

      + +

      Testing non-text elements

      +

      code x  should be inside a p.

      + +

      But not

      +
            let complex_code = ()
      +    

      here.

      + +
        +
      1. An enumerated list first element
      2. +
      3. second element
      4. +
      +
      Alignement test: left
      Right
      Center
      +

      Other complex textin subscript and superscript

      + +

      There is also html specific elements.

      +
      +
        +
      • Author(s): : Florian Angeletti
      • +
      • Version: : 1
      • +
      +
      +
      + +
      type t 
      +
      +
      +

      And cross-reference Paragraph.t. + + + +
      Paragraph
      +

      This file tests the generation of paragraph within module comments.

      + +
      +

      + +
      +
      + + diff --git a/testsuite/tests/tool-ocamldoc/Paragraph.mli b/testsuite/tests/tool-ocamldoc/Paragraph.mli new file mode 100644 index 00000000..5e94589c --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Paragraph.mli @@ -0,0 +1,54 @@ +(* TEST + * ocamldoc with html +*) + +(** This file tests the generation of paragraph within module comments. + + + At least three points should be exercised in this tests + + - First, all text should be tagged + - Second, no paragraph should contain only spaces characters + - Third, the mixing of different text style should not create + invalid p tags + + + See also {{: http://caml.inria.fr/mantis/view.php?id=7352} MPR:7352}, + {{: http://caml.inria.fr/mantis/view.php?id=7353} MPR:7353} + + {2:here Testing non-text elements } + + [code x ] {i should } be inside a p. + + + {e But} {b not} + {[ + let complex_code = () + ]} + here. + + + An enumerated list first element + + second element + + {L Alignement test: left} + {R Right} + {C Center} + + + Other complex text{_ in subscript }{^ and superscript} + {V Verbatim V} + + There is also {%html: html specific %} elements. + + @author: Florian Angeletti + @version: 1 +*) + +(** *) + +type t +(** + And cross-reference {! t}. + {!modules: Paragraph} + {!indexlist} +*) diff --git a/testsuite/tests/tool-ocamldoc/Short_description.latex.reference b/testsuite/tests/tool-ocamldoc/Short_description.latex.reference new file mode 100644 index 00000000..4a938e41 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Short_description.latex.reference @@ -0,0 +1,26 @@ +\documentclass[11pt]{article} +\usepackage[latin1]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{textcomp} +\usepackage{fullpage} +\usepackage{url} +\usepackage{ocamldoc} +\begin{document} +\tableofcontents +\section{Short\_description : (* TEST + * ocamldoc with latex +*)} +\label{Short-underscoredescription}\index{Short-underscoredescription@\verb`Short_description`} + + + +Short global description in text mode + + +This file tests that documentation in text mode are given +a short description in the global description of modules. + + + + +\end{document} diff --git a/testsuite/tests/tool-ocamldoc/Short_description.txt b/testsuite/tests/tool-ocamldoc/Short_description.txt new file mode 100644 index 00000000..e0021ea6 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Short_description.txt @@ -0,0 +1,8 @@ +(* TEST + * ocamldoc with latex +*) + +Short global description in text mode + +This file tests that documentation in text mode are given +a short description in the global description of modules. diff --git a/testsuite/tests/tool-ocamldoc-2/test.reference b/testsuite/tests/tool-ocamldoc/Test.latex.reference similarity index 100% rename from testsuite/tests/tool-ocamldoc-2/test.reference rename to testsuite/tests/tool-ocamldoc/Test.latex.reference diff --git a/testsuite/tests/tool-ocamldoc/Test.mli b/testsuite/tests/tool-ocamldoc/Test.mli new file mode 100644 index 00000000..b28c8e73 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Test.mli @@ -0,0 +1,33 @@ +(* TEST + * ocamldoc with latex +*) + +(** Ten comments for tests *) + +(** {6 A first comments for title } *) + +(** {7 A subsection for ocamldoc *} *) + +(** {7 Bis } *) + +(** {7 Ter } *) + +(** {6 A new section } *) + +(** {7 And its subsection } *) + +(** {7 Encore } *) + +(** Encore! Encore! *) + + +(**/**) +module Silence : sig + (** At last *) +end + +(**/**) + +(** {7 With strange aeons } *) + +module End : sig end diff --git a/testsuite/tests/tool-ocamldoc/Variants.html.reference b/testsuite/tests/tool-ocamldoc/Variants.html.reference new file mode 100644 index 00000000..38e3ebf7 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Variants.html.reference @@ -0,0 +1,282 @@ + + + + + + + + + + +Variants + + + +

      Module Variants

      + +
      module Variants: sig .. end
      +
      +

      This test is here to check the latex code generated for variants

      +
      +
      +
      + +
      type s = 
      + + + + + + + + + + + + + + +
      +| +A
      +| +B(*
      +
      +

      only B is documented here

      +
      +
      +
      *)
      +| +C
      + + + +
      type t = 
      + + + + + + + + + +
      +| +A(*
      +
      +

      doc for A.

      +
      0

      With three paragraphs.

      +
      1

      To check styling

      +
      +
      +
      *)
      +| +B(*
      +
      +

      doc for B

      +
      +
      +
      *)
      + + + +
      type u = 
      + + + + + + + + + +
      +| +A(*
      +
      +

      doc for A

      +
      +
      +
      *)
      +| +B of unit(*
      +
      +

      doc for B

      +
      +
      +
      *)
      + +
      +
      +

      Some documentation for u

      +
      +
      + + +
      type w = 
      + + + + + + + + + +
      +| +A of { + + + + +
      +   +x : int;
      +} +
      (*
      +
      +

      doc for A

      +
      +
      +
      *)
      +| +B of { + + + + +
      +   +y : int;
      +} +
      (*
      +
      +

      doc for B

      +
      +
      +
      *)
      + +
      +
      +

      With records

      +
      +
      + + +
      type z = 
      + + + + + + + + + +
      +| +A of int(*
      +
      +

      doc for A

      +
      +
      +
      *)
      +| +B of int(*
      +
      +

      doc for B

      +
      +
      +
      *)
      + +
      +
      +

      With args

      +
      +
      + + +
      type a = 
      + + + + +
      +| +A : a(*
      +
      +

      doc for A

      +
      +
      +
      *)
      + +
      +
      +

      Gadt notation

      +
      +
      + + +
      type b = 
      + + + + +
      +| +B(*
      +
      +

      doc for B

      +
      +
      +
      *)
      + +
      +
      +

      Lonely constructor

      +
      +
      + + +
      type no_documentation = 
      + + + + + + + + + + + + + + +
      +| +A
      +| +B
      +| +C
      + + + +
      type e = 
      + + +
      +| +
      + +
      +
      +

      Empty variant

      +
      +
      + + diff --git a/testsuite/tests/tool-ocamldoc/Variants.latex.reference b/testsuite/tests/tool-ocamldoc/Variants.latex.reference new file mode 100644 index 00000000..bc618391 --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Variants.latex.reference @@ -0,0 +1,214 @@ +\documentclass[11pt]{article} +\usepackage[latin1]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{textcomp} +\usepackage{fullpage} +\usepackage{url} +\usepackage{ocamldoc} +\begin{document} +\tableofcontents +\section{Module {\tt{Variants}} : This test is here to check the latex code generated for variants} +\label{Variants}\index{Variants@\verb`Variants`} + + + + +\ocamldocvspace{0.5cm} + + + +\label{TYPVariants.s}\begin{ocamldoccode} +type s = + | A + | B +\end{ocamldoccode} +\begin{ocamldoccomment} +only B is documented here + + +\end{ocamldoccomment} +\begin{ocamldoccode} + | C +\end{ocamldoccode} +\index{s@\verb`s`} + + + + +\label{TYPVariants.t}\begin{ocamldoccode} +type t = + | A +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for A. + \begin{ocamldoccode} +0 +\end{ocamldoccode} + + With three paragraphs. + \begin{ocamldoccode} +1 +\end{ocamldoccode} + + To check styling + + +\end{ocamldoccomment} +\begin{ocamldoccode} + | B +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for B + + +\end{ocamldoccomment} +\index{t@\verb`t`} + + + + +\label{TYPVariants.u}\begin{ocamldoccode} +type u = + | A +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for A + + +\end{ocamldoccomment} +\begin{ocamldoccode} + | B of unit +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for B + + +\end{ocamldoccomment} +\index{u@\verb`u`} +\begin{ocamldocdescription} +Some documentation for u + + +\end{ocamldocdescription} + + + + +\label{TYPVariants.w}\begin{ocamldoccode} +type w = + | A of {\char123} x : int ; +{\char125} +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for A + + +\end{ocamldoccomment} +\begin{ocamldoccode} + | B of {\char123} y : int ; +{\char125} +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for B + + +\end{ocamldoccomment} +\index{w@\verb`w`} +\begin{ocamldocdescription} +With records + + +\end{ocamldocdescription} + + + + +\label{TYPVariants.z}\begin{ocamldoccode} +type z = + | A of int +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for A + + +\end{ocamldoccomment} +\begin{ocamldoccode} + | B of int +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for B + + +\end{ocamldoccomment} +\index{z@\verb`z`} +\begin{ocamldocdescription} +With args + + +\end{ocamldocdescription} + + + + +\label{TYPVariants.a}\begin{ocamldoccode} +type a = + | A : a +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for A + + +\end{ocamldoccomment} +\index{a@\verb`a`} +\begin{ocamldocdescription} +Gadt notation + + +\end{ocamldocdescription} + + + + +\label{TYPVariants.b}\begin{ocamldoccode} +type b = + | B +\end{ocamldoccode} +\begin{ocamldoccomment} +doc for B + + +\end{ocamldoccomment} +\index{b@\verb`b`} +\begin{ocamldocdescription} +Lonely constructor + + +\end{ocamldocdescription} + + + + +\label{TYPVariants.no-underscoredocumentation}\begin{ocamldoccode} +type no_documentation = + | A + | B + | C +\end{ocamldoccode} +\index{no-underscoredocumentation@\verb`no_documentation`} + + + + +\label{TYPVariants.e}\begin{ocamldoccode} +type e = + | +\end{ocamldoccode} +\index{e@\verb`e`} +\begin{ocamldocdescription} +Empty variant + + +\end{ocamldocdescription} + + +\end{document} diff --git a/testsuite/tests/tool-ocamldoc/Variants.mli b/testsuite/tests/tool-ocamldoc/Variants.mli new file mode 100644 index 00000000..137a42ce --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/Variants.mli @@ -0,0 +1,51 @@ +(* TEST + * ocamldoc with html + * ocamldoc with latex +*) + +(** This test is here to check the latex code generated for variants *) + +type s = A | B (** only B is documented here *) | C + +type t = + | A + (** doc for A. + {[0]} + With three paragraphs. + {[1]} + To check styling + *) + | B + (** doc for B *) + +(** Some documentation for u*) +type u = +| A (** doc for A *) | B of unit (** doc for B *) + + +(** With records *) +type w = +| A of { x: int } + (** doc for A *) +| B of { y:int } + (** doc for B *) + +(** With args *) +type z = +| A of int + (** doc for A *) +| B of int + (** doc for B *) + +(** Gadt notation *) +type a = + A: a (** doc for A*) + +(** Lonely constructor *) +type b = + B (** doc for B *) + +type no_documentation = A | B | C + +(** Empty variant *) +type e = | diff --git a/testsuite/tests/tool-ocamldoc/ocamltests b/testsuite/tests/tool-ocamldoc/ocamltests new file mode 100644 index 00000000..0d05eb3d --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/ocamltests @@ -0,0 +1,19 @@ +Documentation_tags.mli +Extensible_variant.ml +Inline_records.mli +Inline_records_bis.ml +Item_ids.mli +Paragraph.mli +Module_whitespace.ml +No_preamble.mli +Level_0.mli +Linebreaks.mli +Loop.ml +Short_description.txt +t01.ml +t02.ml +t03.ml +t04.ml +t05.ml +Test.mli +Variants.mli diff --git a/testsuite/tests/tool-ocamldoc/t01.ml b/testsuite/tests/tool-ocamldoc/t01.ml index b1db38ea..1003b47f 100644 --- a/testsuite/tests/tool-ocamldoc/t01.ml +++ b/testsuite/tests/tool-ocamldoc/t01.ml @@ -1,3 +1,9 @@ +(* TEST + plugins="odoc_test.ml" + * ocamldoc + flags="-I ${ocamlsrcdir}/ocamldoc" +*) + (** Testing display of types. @test_types_display diff --git a/testsuite/tests/tool-ocamldoc/t02.ml b/testsuite/tests/tool-ocamldoc/t02.ml index d7c97421..a2280cf8 100644 --- a/testsuite/tests/tool-ocamldoc/t02.ml +++ b/testsuite/tests/tool-ocamldoc/t02.ml @@ -1,3 +1,9 @@ +(* TEST + plugins="odoc_test.ml" + * ocamldoc + flags="-I ${ocamlsrcdir}/ocamldoc" +*) + module Foo = struct type u type t = int let x = 1 end;; module type TFoo = module type of Foo;; diff --git a/testsuite/tests/tool-ocamldoc/t03.ml b/testsuite/tests/tool-ocamldoc/t03.ml index 9d9e1593..3ee319ba 100644 --- a/testsuite/tests/tool-ocamldoc/t03.ml +++ b/testsuite/tests/tool-ocamldoc/t03.ml @@ -1,3 +1,9 @@ +(* TEST + plugins="odoc_test.ml" + * ocamldoc + flags="-I ${ocamlsrcdir}/ocamldoc" +*) + module Foo = struct type t = int let x = 1 end;; module type MT = module type of Foo;; module Bar = struct type t = int let x = 2 end;; diff --git a/testsuite/tests/tool-ocamldoc/t03.ocamldoc.reference b/testsuite/tests/tool-ocamldoc/t03.ocamldoc.reference new file mode 100644 index 00000000..cbf7ddcc --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/t03.ocamldoc.reference @@ -0,0 +1 @@ +Warning: Module type not found diff --git a/testsuite/tests/tool-ocamldoc/t04.ml b/testsuite/tests/tool-ocamldoc/t04.ml index 97782ae6..d815b4cc 100644 --- a/testsuite/tests/tool-ocamldoc/t04.ml +++ b/testsuite/tests/tool-ocamldoc/t04.ml @@ -1,3 +1,9 @@ +(* TEST + plugins="odoc_test.ml" + * ocamldoc + flags="-I ${ocamlsrcdir}/ocamldoc" +*) + (** Testing display of inline record. @test_types_display diff --git a/testsuite/tests/tool-ocamldoc/t05.ml b/testsuite/tests/tool-ocamldoc/t05.ml index b0306b76..885dc90a 100644 --- a/testsuite/tests/tool-ocamldoc/t05.ml +++ b/testsuite/tests/tool-ocamldoc/t05.ml @@ -1,3 +1,7 @@ +(* TEST + plugins="odoc_test.ml" + * ocamldoc + flags="-I ${ocamlsrcdir}/ocamldoc" +*) module rec A : sig type t end = B and B : sig type t = A.t end = A;; - diff --git a/testsuite/tests/tool-ocamldoc/type_Linebreaks.reference b/testsuite/tests/tool-ocamldoc/type_Linebreaks.reference new file mode 100644 index 00000000..f3df279a --- /dev/null +++ b/testsuite/tests/tool-ocamldoc/type_Linebreaks.reference @@ -0,0 +1,27 @@ + + + + + + + + + + + + +Linebreaks + + +sig
      +  type a = A
      +  type 'a b = { field : 'a; }
      +  type c = C : '-> Linebreaks.c
      +  type s = ..
      +  type s += B
      +  val x : Linebreaks.a
      +  module S : sig module I : sig  end end
      +  module type s = sig  end
      +  class type d = object  end
      +  exception E of { inline : int; }
      +end
      diff --git a/testsuite/tests/tool-ocamlobjinfo/Makefile b/testsuite/tests/tool-ocamlobjinfo/Makefile deleted file mode 100644 index 19a745c7..00000000 --- a/testsuite/tests/tool-ocamlobjinfo/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -BASEDIR=../.. - -LD_PATH= - -# This test ensures that ocamlobjinfo is behaving as the configuration -# expects and is a guard against the breakage fixed in 17fc532 - -.PHONY: default -default: - @printf " ... testing 'ocamlobjinfo'" - @if ! $(SUPPORTS_SHARED_LIBRARIES) || $(BYTECODE_ONLY) ; then \ - echo ' => skipped (.cmxs not built)'; \ - elif ! grep -q HAS_LIBBFD $(TOPDIR)/byterun/caml/s.h ; then \ - echo ' => skipped (BFD library not available)'; \ - else \ - $(SET_LD_PATH) OCAMLLIB=$(TOPDIR)/tools $(MAKE) run; \ - fi - -.PHONY: run -run: - @rm -f $(MAIN_MODULE).result - @$(OCAMLOPT) -shared -o question.cmxs question.ml - @$(OCAMLRUN) `$(CYGPATH) $(TOPDIR)/tools/ocamlobjinfo` \ - question.cmxs \ - > test.raw.result 2>&1 \ - && sed -e 's/\([^0-9a-z]\)[0-9a-z]\{32\}\([^0-9a-z]\|$$\)/\1\2/' \ - test.raw.result > test.result \ - && $(DIFF) test.reference test.result > /dev/null \ - && echo " => passed" || echo " => failed" - -.PHONY: promote -promote: defaultpromote - -.PHONY: clean -clean: defaultclean - @rm -f *.result - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-ocamlobjinfo/has-lib-bfd.sh b/testsuite/tests/tool-ocamlobjinfo/has-lib-bfd.sh new file mode 100644 index 00000000..4074d6da --- /dev/null +++ b/testsuite/tests/tool-ocamlobjinfo/has-lib-bfd.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if grep -q HAS_LIBBFD ${ocamlsrcdir}/byterun/caml/s.h; then + exit ${TEST_PASS}; +fi +echo libbfd not available > ${ocamltest_response} +exit ${TEST_SKIP} diff --git a/testsuite/tests/tool-ocamlobjinfo/ocamltests b/testsuite/tests/tool-ocamlobjinfo/ocamltests new file mode 100644 index 00000000..ccd381fe --- /dev/null +++ b/testsuite/tests/tool-ocamlobjinfo/ocamltests @@ -0,0 +1 @@ +question.ml diff --git a/testsuite/tests/tool-ocamlobjinfo/question.ml b/testsuite/tests/tool-ocamlobjinfo/question.ml index cd298427..b8848e68 100644 --- a/testsuite/tests/tool-ocamlobjinfo/question.ml +++ b/testsuite/tests/tool-ocamlobjinfo/question.ml @@ -1 +1,15 @@ +(* TEST +script = "sh ${test_source_directory}/has-lib-bfd.sh" +* shared-libraries +** script +*** setup-ocamlopt.byte-build-env +**** ocamlopt.byte +flags = "-shared" +all_modules = "question.ml" +program = "question.cmxs" +***** check-ocamlopt.byte-output +****** ocamlobjinfo +******* check-program-output +*) + let answer = 42 diff --git a/testsuite/tests/tool-ocamlobjinfo/question.reference b/testsuite/tests/tool-ocamlobjinfo/question.reference new file mode 100644 index 00000000..513bf9c1 --- /dev/null +++ b/testsuite/tests/tool-ocamlobjinfo/question.reference @@ -0,0 +1,10 @@ +File question.cmxs +Name: Question +CRC of implementation: 00000000000000000000000000000000 +Globals defined: + Question +Interfaces imported: + 00000000000000000000000000000000 Stdlib + 00000000000000000000000000000000 Question + 00000000000000000000000000000000 CamlinternalFormatBasics +Implementations imported: diff --git a/testsuite/tests/tool-ocamlobjinfo/test.reference b/testsuite/tests/tool-ocamlobjinfo/test.reference deleted file mode 100644 index dab40e8c..00000000 --- a/testsuite/tests/tool-ocamlobjinfo/test.reference +++ /dev/null @@ -1,10 +0,0 @@ -File question.cmxs -Name: Question -CRC of implementation: -Globals defined: - Question -Interfaces imported: - Question - Pervasives - CamlinternalFormatBasics -Implementations imported: diff --git a/testsuite/tests/tool-toplevel-invocation/Makefile b/testsuite/tests/tool-toplevel-invocation/Makefile deleted file mode 100644 index 31db2c3f..00000000 --- a/testsuite/tests/tool-toplevel-invocation/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Bernhard Schommer * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. - - -default: - @for file in *.txt; do \ - TERM=dumb $(OCAML) -args $$file < test.ml 2>&1 \ - | grep -v '^ OCaml version' > $$file.result; \ - done - @for file in *.reference; do \ - printf " ... testing '$$file':"; \ - $(DIFF) $$file `basename $$file reference`result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done - - -promote: defaultpromote - -clean: defaultclean - @rm -f *.result - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/tool-toplevel-invocation/ocamltests b/testsuite/tests/tool-toplevel-invocation/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/tool-toplevel-invocation/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/tool-toplevel-invocation/test.ml b/testsuite/tests/tool-toplevel-invocation/test.ml index 03b03d71..3932035c 100644 --- a/testsuite/tests/tool-toplevel-invocation/test.ml +++ b/testsuite/tests/tool-toplevel-invocation/test.ml @@ -1 +1,43 @@ +(* TEST + +files = "first_arg_fail.txt last_arg_fail.txt" + +* setup-ocaml-build-env + +** ocaml +flags = "-args ${test_source_directory}/first_arg_fail.txt" +compiler_reference = "${test_source_directory}/first_arg_fail.txt.reference" +compiler_output = "${test_build_directory}/first_arg_fail.output" +ocaml_exit_status = "2" +*** check-ocaml-output + +** ocaml +flags = "-args ${test_source_directory}/indirect_first_arg_fail.txt" +compiler_reference = "${test_source_directory}/indirect_first_arg_fail.txt.reference" +compiler_output = "${test_build_directory}/indirect_first_arg_fail.output" +ocaml_exit_status = "2" +*** check-ocaml-output + +** ocaml +flags = "-args ${test_source_directory}/indirect_last_arg_fail.txt" +compiler_reference = "${test_source_directory}/indirect_last_arg_fail.txt.reference" +compiler_output = "${test_build_directory}/indirect_last_arg_fail.output" +ocaml_exit_status = "2" +*** check-ocaml-output + +** ocaml +flags = "-args ${test_source_directory}/last_arg_fail.txt" +compiler_reference = "${test_source_directory}/last_arg_fail.txt.reference" +compiler_output = "${test_build_directory}/last_arg_fail.output" +ocaml_exit_status = "2" +*** check-ocaml-output + +** ocaml +flags = "-args ${test_source_directory}/working_arg.txt" +compiler_reference = "${test_source_directory}/working_arg.txt.reference" +compiler_output = "${test_build_directory}/working_arg.output" +*** check-ocaml-output + +*) + printf "Test succeeds\n";; diff --git a/testsuite/tests/tool-toplevel-invocation/working_arg.txt.reference b/testsuite/tests/tool-toplevel-invocation/working_arg.txt.reference index 2438811a..1b6c345f 100644 --- a/testsuite/tests/tool-toplevel-invocation/working_arg.txt.reference +++ b/testsuite/tests/tool-toplevel-invocation/working_arg.txt.reference @@ -1,4 +1,3 @@ - -# Test succeeds +Test succeeds - : unit = () -# + diff --git a/testsuite/tests/tool-toplevel/Makefile b/testsuite/tests/tool-toplevel/Makefile deleted file mode 100644 index 17a9c8e3..00000000 --- a/testsuite/tests/tool-toplevel/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common -TOPFLAGS+=-I $(OTOPDIR)/toplevel diff --git a/testsuite/tests/tool-toplevel/exotic_lists.compilers.reference b/testsuite/tests/tool-toplevel/exotic_lists.compilers.reference new file mode 100644 index 00000000..957052ba --- /dev/null +++ b/testsuite/tests/tool-toplevel/exotic_lists.compilers.reference @@ -0,0 +1,14 @@ +module L : sig type ('a, 'b) t = [] | (::) of 'a * ('b, 'a) t end +- : (int list, string) L.t = +L.(::) ([1; 2], + L.(::) ("2", L.(::) ([3; 4], L.(::) ("4", L.(::) ([5], L.[]))))) +- : (int, string) L.t = +(::) (1, (::) ("2", (::) (3, (::) ("4", (::) (5, []))))) +module L : sig type 'a t = 'a list = [] | (::) of 'a * 'a t end +- : int L.t L.t = +L.(::) (L.(::) (1, L.[]), + L.(::) (L.(::) (2, L.[]), + L.(::) (L.(::) (3, L.[]), + L.(::) (L.(::) (4, L.[]), L.(::) (L.(::) (5, L.[]), L.[]))))) +- : int L.t = (::) (1, (::) (2, (::) (3, (::) (4, (::) (5, []))))) + diff --git a/testsuite/tests/tool-toplevel/exotic_lists.ml b/testsuite/tests/tool-toplevel/exotic_lists.ml index ae42ec8f..1f068cd2 100644 --- a/testsuite/tests/tool-toplevel/exotic_lists.ml +++ b/testsuite/tests/tool-toplevel/exotic_lists.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + module L = struct type ('a,'b) t = [] | (::) of 'a * ('b,'a) t end;; diff --git a/testsuite/tests/tool-toplevel/exotic_lists.ml.reference b/testsuite/tests/tool-toplevel/exotic_lists.ml.reference deleted file mode 100644 index e064340d..00000000 --- a/testsuite/tests/tool-toplevel/exotic_lists.ml.reference +++ /dev/null @@ -1,15 +0,0 @@ - -# module L : sig type ('a, 'b) t = [] | (::) of 'a * ('b, 'a) t end -# - : (int list, string) L.t = -L.(::) ([1; 2], - L.(::) ("2", L.(::) ([3; 4], L.(::) ("4", L.(::) ([5], L.[]))))) -# # - : (int, string) L.t = -(::) (1, (::) ("2", (::) (3, (::) ("4", (::) (5, []))))) -# module L : sig type 'a t = 'a list = [] | (::) of 'a * 'a t end -# - : int L.t L.t = -L.(::) (L.(::) (1, L.[]), - L.(::) (L.(::) (2, L.[]), - L.(::) (L.(::) (3, L.[]), - L.(::) (L.(::) (4, L.[]), L.(::) (L.(::) (5, L.[]), L.[]))))) -# # - : int L.t = (::) (1, (::) (2, (::) (3, (::) (4, (::) (5, []))))) -# diff --git a/testsuite/tests/tool-toplevel/ocamltests b/testsuite/tests/tool-toplevel/ocamltests new file mode 100644 index 00000000..81e8f0f0 --- /dev/null +++ b/testsuite/tests/tool-toplevel/ocamltests @@ -0,0 +1,5 @@ +exotic_lists.ml +pr7060.ml +pr7751.ml +strings.ml +tracing.ml diff --git a/testsuite/tests/tool-toplevel/pr7060.compilers.reference b/testsuite/tests/tool-toplevel/pr7060.compilers.reference new file mode 100644 index 00000000..6b142def --- /dev/null +++ b/testsuite/tests/tool-toplevel/pr7060.compilers.reference @@ -0,0 +1,15 @@ +type t = A | B +type u = C of t +Characters 18-54: + let print_t out = function A -> Format.fprintf out "A";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +B +val print_t : Format.formatter -> t -> unit = +- : t = + +- : u = +C + + diff --git a/testsuite/tests/tool-toplevel/pr7060.ml b/testsuite/tests/tool-toplevel/pr7060.ml index 67c11a47..e6ad7408 100644 --- a/testsuite/tests/tool-toplevel/pr7060.ml +++ b/testsuite/tests/tool-toplevel/pr7060.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + type t = A | B;; type u = C of t;; let print_t out = function A -> Format.fprintf out "A";; diff --git a/testsuite/tests/tool-toplevel/pr7060.ml.reference b/testsuite/tests/tool-toplevel/pr7060.ml.reference deleted file mode 100644 index bdfca395..00000000 --- a/testsuite/tests/tool-toplevel/pr7060.ml.reference +++ /dev/null @@ -1,16 +0,0 @@ - -# type t = A | B -# type u = C of t -# Characters 18-54: - let print_t out = function A -> Format.fprintf out "A";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -B -val print_t : Format.formatter -> t -> unit = -# # - : t = - -# - : u = -C - -# diff --git a/testsuite/tests/tool-toplevel/pr7751.compilers.reference b/testsuite/tests/tool-toplevel/pr7751.compilers.reference new file mode 100644 index 00000000..ec948bdc --- /dev/null +++ b/testsuite/tests/tool-toplevel/pr7751.compilers.reference @@ -0,0 +1,10 @@ +- : Parsetree.expression = +{Parsetree.pexp_desc = + Parsetree.Pexp_constant (Parsetree.Pconst_integer ("1", None)); + pexp_loc = + {Location.loc_start = + {Lexing.pos_fname = ""; pos_lnum = 1; pos_bol = 0; pos_cnum = 0}; + loc_end = {Lexing.pos_fname = ""; pos_lnum = 1; pos_bol = 0; pos_cnum = 1}; + loc_ghost = false}; + pexp_attributes = []} + diff --git a/testsuite/tests/tool-toplevel/pr7751.ml b/testsuite/tests/tool-toplevel/pr7751.ml new file mode 100644 index 00000000..40ce9ffd --- /dev/null +++ b/testsuite/tests/tool-toplevel/pr7751.ml @@ -0,0 +1,6 @@ +(* TEST + include ocamlcommon + * toplevel +*) + +Parse.expression (Lexing.from_string "1");; diff --git a/testsuite/tests/tool-toplevel/strings.compilers.reference b/testsuite/tests/tool-toplevel/strings.compilers.reference new file mode 100644 index 00000000..cbc727fd --- /dev/null +++ b/testsuite/tests/tool-toplevel/strings.compilers.reference @@ -0,0 +1,10 @@ +- : string = "\n\t\r\b" +- : string = "\"\\'" +- : string = +" !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" +- : string = +"\000\001\002\003\004\005\006\007\011\012\014\015\016\017\018\019\020\021\022\023\024\025\026\027\028\029\030\031\127" +- : string = +"\"Ἀχιλλεύς\r\n天照\tब्रह्मन्\t𒄑 𒂆 𒈦 𒄑 𒂆 𒈦\\" +- : string = "ایدهآل" + diff --git a/testsuite/tests/tool-toplevel/strings.ml b/testsuite/tests/tool-toplevel/strings.ml index 14a5d2e7..07e86f42 100644 --- a/testsuite/tests/tool-toplevel/strings.ml +++ b/testsuite/tests/tool-toplevel/strings.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Test the printing of strings in the terminal *) "\n\t\r\b";; diff --git a/testsuite/tests/tool-toplevel/strings.ml.reference b/testsuite/tests/tool-toplevel/strings.ml.reference deleted file mode 100644 index 10673d4d..00000000 --- a/testsuite/tests/tool-toplevel/strings.ml.reference +++ /dev/null @@ -1,11 +0,0 @@ - -# - : string = "\n\t\r\b" -# - : string = "\"\\'" -# - : string = -" !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" -# - : string = -"\000\001\002\003\004\005\006\007\011\012\014\015\016\017\018\019\020\021\022\023\024\025\026\027\028\029\030\031\127" -# - : string = -"\"Ἀχιλλεύς\r\n天照\tब्रह्मन्\t𒄑 𒂆 𒈦 𒄑 𒂆 𒈦\\" -# - : string = "ایدهآل" -# diff --git a/testsuite/tests/tool-toplevel/tracing.compilers.reference b/testsuite/tests/tool-toplevel/tracing.compilers.reference new file mode 100644 index 00000000..3cdb4826 --- /dev/null +++ b/testsuite/tests/tool-toplevel/tracing.compilers.reference @@ -0,0 +1,29 @@ +- : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = +List.fold_left is now traced. +- : int = 0 +List.fold_left <-- +List.fold_left --> +List.fold_left* <-- +List.fold_left* --> +List.fold_left** <-- [; ; ] +List.fold_left <-- +List.fold_left --> +List.fold_left* <-- +List.fold_left* --> +List.fold_left** <-- [; ] +List.fold_left <-- +List.fold_left --> +List.fold_left* <-- +List.fold_left* --> +List.fold_left** <-- [] +List.fold_left <-- +List.fold_left --> +List.fold_left* <-- +List.fold_left* --> +List.fold_left** <-- [] +List.fold_left** --> +List.fold_left** --> +List.fold_left** --> +List.fold_left** --> +- : int = 6 + diff --git a/testsuite/tests/tool-toplevel/tracing.ml b/testsuite/tests/tool-toplevel/tracing.ml index 5acaff23..8a1221f6 100644 --- a/testsuite/tests/tool-toplevel/tracing.ml +++ b/testsuite/tests/tool-toplevel/tracing.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + List.fold_left;; #trace List.fold_left;; 0;; diff --git a/testsuite/tests/tool-toplevel/tracing.ml.reference b/testsuite/tests/tool-toplevel/tracing.ml.reference deleted file mode 100644 index e6eda8d7..00000000 --- a/testsuite/tests/tool-toplevel/tracing.ml.reference +++ /dev/null @@ -1,30 +0,0 @@ - -# - : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = -# List.fold_left is now traced. -# - : int = 0 -# List.fold_left <-- -List.fold_left --> -List.fold_left* <-- -List.fold_left* --> -List.fold_left** <-- [; ; ] -List.fold_left <-- -List.fold_left --> -List.fold_left* <-- -List.fold_left* --> -List.fold_left** <-- [; ] -List.fold_left <-- -List.fold_left --> -List.fold_left* <-- -List.fold_left* --> -List.fold_left** <-- [] -List.fold_left <-- -List.fold_left --> -List.fold_left* <-- -List.fold_left* --> -List.fold_left** <-- [] -List.fold_left** --> -List.fold_left** --> -List.fold_left** --> -List.fold_left** --> -- : int = 6 -# diff --git a/testsuite/tests/translprim/Makefile b/testsuite/tests/translprim/Makefile deleted file mode 100644 index cdfef9a2..00000000 --- a/testsuite/tests/translprim/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -newdefault: array_spec.ml.reference module_coercion.ml.reference - $(MAKE) default - -BASEDIR=../.. -TOPFLAGS+=-dlambda -include $(BASEDIR)/makefiles/Makefile.dlambda -include $(BASEDIR)/makefiles/Makefile.common - -GENERATED_SOURCES = array_spec.ml.reference module_coercion.ml.reference \ - *.flat-float - -ifeq "$(FLAT_FLOAT_ARRAY)" "true" -suffix = -flat -else -suffix = -noflat -endif - -array_spec.ml.reference: array_spec.ml.reference$(suffix) \ - $(FLAT_FLOAT_ARRAY).flat-float - cp $< $@ - -module_coercion.ml.reference: module_coercion.ml.reference$(suffix) \ - $(FLAT_FLOAT_ARRAY).flat-float - cp $< $@ - -%.flat-float: - @rm -f $(GENERATED_SOURCES) - @touch $@ diff --git a/testsuite/tests/translprim/array_spec.compilers.reference.flat b/testsuite/tests/translprim/array_spec.compilers.reference.flat new file mode 100644 index 00000000..c692c8a9 --- /dev/null +++ b/testsuite/tests/translprim/array_spec.compilers.reference.flat @@ -0,0 +1,65 @@ +(setglobal Array_spec! + (let + (int_a = (makearray[int] 1 2 3) + float_a = (makearray[float] 1. 2. 3.) + addr_a = (makearray[addr] "a" "b" "c")) + (seq (array.length[int] int_a) (array.length[float] float_a) + (array.length[addr] addr_a) (function a (array.length[gen] a)) + (array.get[int] int_a 0) (array.get[float] float_a 0) + (array.get[addr] addr_a 0) (function a (array.get[gen] a 0)) + (array.unsafe_get[int] int_a 0) (array.unsafe_get[float] float_a 0) + (array.unsafe_get[addr] addr_a 0) + (function a (array.unsafe_get[gen] a 0)) (array.set[int] int_a 0 1) + (array.set[float] float_a 0 1.) (array.set[addr] addr_a 0 "a") + (function a x (array.set[gen] a 0 x)) (array.unsafe_set[int] int_a 0 1) + (array.unsafe_set[float] float_a 0 1.) + (array.unsafe_set[addr] addr_a 0 "a") + (function a x (array.unsafe_set[gen] a 0 x)) + (let + (eta_gen_len = (function prim stub (array.length[gen] prim)) + eta_gen_safe_get = + (function prim prim stub (array.get[gen] prim prim)) + eta_gen_unsafe_get = + (function prim prim stub (array.unsafe_get[gen] prim prim)) + eta_gen_safe_set = + (function prim prim prim stub (array.set[gen] prim prim prim)) + eta_gen_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[gen] prim prim prim)) + eta_int_len = (function prim stub (array.length[int] prim)) + eta_int_safe_get = + (function prim prim stub (array.get[int] prim prim)) + eta_int_unsafe_get = + (function prim prim stub (array.unsafe_get[int] prim prim)) + eta_int_safe_set = + (function prim prim prim stub (array.set[int] prim prim prim)) + eta_int_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[int] prim prim prim)) + eta_float_len = (function prim stub (array.length[float] prim)) + eta_float_safe_get = + (function prim prim stub (array.get[float] prim prim)) + eta_float_unsafe_get = + (function prim prim stub (array.unsafe_get[float] prim prim)) + eta_float_safe_set = + (function prim prim prim stub (array.set[float] prim prim prim)) + eta_float_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[float] prim prim prim)) + eta_addr_len = (function prim stub (array.length[addr] prim)) + eta_addr_safe_get = + (function prim prim stub (array.get[addr] prim prim)) + eta_addr_unsafe_get = + (function prim prim stub (array.unsafe_get[addr] prim prim)) + eta_addr_safe_set = + (function prim prim prim stub (array.set[addr] prim prim prim)) + eta_addr_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim))) + (makeblock 0 int_a float_a addr_a eta_gen_len eta_gen_safe_get + eta_gen_unsafe_get eta_gen_safe_set eta_gen_unsafe_set eta_int_len + eta_int_safe_get eta_int_unsafe_get eta_int_safe_set + eta_int_unsafe_set eta_float_len eta_float_safe_get + eta_float_unsafe_get eta_float_safe_set eta_float_unsafe_set + eta_addr_len eta_addr_safe_get eta_addr_unsafe_get + eta_addr_safe_set eta_addr_unsafe_set))))) diff --git a/testsuite/tests/translprim/array_spec.compilers.reference.no-flat b/testsuite/tests/translprim/array_spec.compilers.reference.no-flat new file mode 100644 index 00000000..b6538050 --- /dev/null +++ b/testsuite/tests/translprim/array_spec.compilers.reference.no-flat @@ -0,0 +1,65 @@ +(setglobal Array_spec! + (let + (int_a = (makearray[int] 1 2 3) + float_a = (makearray[addr] 1. 2. 3.) + addr_a = (makearray[addr] "a" "b" "c")) + (seq (array.length[int] int_a) (array.length[addr] float_a) + (array.length[addr] addr_a) (function a (array.length[addr] a)) + (array.get[int] int_a 0) (array.get[addr] float_a 0) + (array.get[addr] addr_a 0) (function a (array.get[addr] a 0)) + (array.unsafe_get[int] int_a 0) (array.unsafe_get[addr] float_a 0) + (array.unsafe_get[addr] addr_a 0) + (function a (array.unsafe_get[addr] a 0)) (array.set[int] int_a 0 1) + (array.set[addr] float_a 0 1.) (array.set[addr] addr_a 0 "a") + (function a x (array.set[addr] a 0 x)) + (array.unsafe_set[int] int_a 0 1) (array.unsafe_set[addr] float_a 0 1.) + (array.unsafe_set[addr] addr_a 0 "a") + (function a x (array.unsafe_set[addr] a 0 x)) + (let + (eta_gen_len = (function prim stub (array.length[addr] prim)) + eta_gen_safe_get = + (function prim prim stub (array.get[addr] prim prim)) + eta_gen_unsafe_get = + (function prim prim stub (array.unsafe_get[addr] prim prim)) + eta_gen_safe_set = + (function prim prim prim stub (array.set[addr] prim prim prim)) + eta_gen_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + eta_int_len = (function prim stub (array.length[int] prim)) + eta_int_safe_get = + (function prim prim stub (array.get[int] prim prim)) + eta_int_unsafe_get = + (function prim prim stub (array.unsafe_get[int] prim prim)) + eta_int_safe_set = + (function prim prim prim stub (array.set[int] prim prim prim)) + eta_int_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[int] prim prim prim)) + eta_float_len = (function prim stub (array.length[addr] prim)) + eta_float_safe_get = + (function prim prim stub (array.get[addr] prim prim)) + eta_float_unsafe_get = + (function prim prim stub (array.unsafe_get[addr] prim prim)) + eta_float_safe_set = + (function prim prim prim stub (array.set[addr] prim prim prim)) + eta_float_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + eta_addr_len = (function prim stub (array.length[addr] prim)) + eta_addr_safe_get = + (function prim prim stub (array.get[addr] prim prim)) + eta_addr_unsafe_get = + (function prim prim stub (array.unsafe_get[addr] prim prim)) + eta_addr_safe_set = + (function prim prim prim stub (array.set[addr] prim prim prim)) + eta_addr_unsafe_set = + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim))) + (makeblock 0 int_a float_a addr_a eta_gen_len eta_gen_safe_get + eta_gen_unsafe_get eta_gen_safe_set eta_gen_unsafe_set eta_int_len + eta_int_safe_get eta_int_unsafe_get eta_int_safe_set + eta_int_unsafe_set eta_float_len eta_float_safe_get + eta_float_unsafe_get eta_float_safe_set eta_float_unsafe_set + eta_addr_len eta_addr_safe_get eta_addr_unsafe_get + eta_addr_safe_set eta_addr_unsafe_set))))) diff --git a/testsuite/tests/translprim/array_spec.ml b/testsuite/tests/translprim/array_spec.ml index e78c9634..d84979d4 100644 --- a/testsuite/tests/translprim/array_spec.ml +++ b/testsuite/tests/translprim/array_spec.ml @@ -1,3 +1,15 @@ +(* TEST + * setup-ocamlc.byte-build-env + ** ocamlc.byte + flags = "-dlambda -dno-unique-ids" + *** flat-float-array + **** check-ocamlc.byte-output + compiler_reference = "${test_source_directory}/array_spec.compilers.reference.flat" + *** no-flat-float-array + **** check-ocamlc.byte-output + compiler_reference = "${test_source_directory}/array_spec.compilers.reference.no-flat" +*) + external len : 'a array -> int = "%array_length" external safe_get : 'a array -> int -> 'a = "%array_safe_get" external unsafe_get : 'a array -> int -> 'a = "%array_unsafe_get" diff --git a/testsuite/tests/translprim/array_spec.ml.reference-flat b/testsuite/tests/translprim/array_spec.ml.reference-flat deleted file mode 100644 index 83fe0c4c..00000000 --- a/testsuite/tests/translprim/array_spec.ml.reference-flat +++ /dev/null @@ -1,88 +0,0 @@ -(setglobal Array_spec! - (let - (int_a = (makearray[int] 1 2 3) - float_a = (makearray[float] 1. 2. 3.) - addr_a = (makearray[addr] "a" "b" "c")) - (seq (array.length[int] int_a) (array.length[float] float_a) - (array.length[addr] addr_a) - (function a (array.length[gen] a)) - (array.get[int] int_a 0) (array.get[float] float_a 0) - (array.get[addr] addr_a 0) - (function a (array.get[gen] a 0)) - (array.unsafe_get[int] int_a 0) - (array.unsafe_get[float] float_a 0) - (array.unsafe_get[addr] addr_a 0) - (function a (array.unsafe_get[gen] a 0)) - (array.set[int] int_a 0 1) (array.set[float] float_a 0 1.) - (array.set[addr] addr_a 0 "a") - (function a x (array.set[gen] a 0 x)) - (array.unsafe_set[int] int_a 0 1) - (array.unsafe_set[float] float_a 0 1.) - (array.unsafe_set[addr] addr_a 0 "a") - (function a x (array.unsafe_set[gen] a 0 x)) - (let - (eta_gen_len = - (function prim stub (array.length[gen] prim)) - eta_gen_safe_get = - (function prim prim stub - (array.get[gen] prim prim)) - eta_gen_unsafe_get = - (function prim prim stub - (array.unsafe_get[gen] prim prim)) - eta_gen_safe_set = - (function prim prim prim stub - (array.set[gen] prim prim prim)) - eta_gen_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[gen] prim prim prim)) - eta_int_len = - (function prim stub (array.length[int] prim)) - eta_int_safe_get = - (function prim prim stub - (array.get[int] prim prim)) - eta_int_unsafe_get = - (function prim prim stub - (array.unsafe_get[int] prim prim)) - eta_int_safe_set = - (function prim prim prim stub - (array.set[int] prim prim prim)) - eta_int_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[int] prim prim prim)) - eta_float_len = - (function prim stub (array.length[float] prim)) - eta_float_safe_get = - (function prim prim stub - (array.get[float] prim prim)) - eta_float_unsafe_get = - (function prim prim stub - (array.unsafe_get[float] prim prim)) - eta_float_safe_set = - (function prim prim prim stub - (array.set[float] prim prim prim)) - eta_float_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[float] prim prim prim)) - eta_addr_len = - (function prim stub (array.length[addr] prim)) - eta_addr_safe_get = - (function prim prim stub - (array.get[addr] prim prim)) - eta_addr_unsafe_get = - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - eta_addr_safe_set = - (function prim prim prim stub - (array.set[addr] prim prim prim)) - eta_addr_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim))) - (makeblock 0 int_a float_a addr_a eta_gen_len - eta_gen_safe_get eta_gen_unsafe_get eta_gen_safe_set - eta_gen_unsafe_set eta_int_len eta_int_safe_get - eta_int_unsafe_get eta_int_safe_set - eta_int_unsafe_set eta_float_len eta_float_safe_get - eta_float_unsafe_get eta_float_safe_set - eta_float_unsafe_set eta_addr_len eta_addr_safe_get - eta_addr_unsafe_get eta_addr_safe_set - eta_addr_unsafe_set))))) diff --git a/testsuite/tests/translprim/array_spec.ml.reference-noflat b/testsuite/tests/translprim/array_spec.ml.reference-noflat deleted file mode 100644 index ba90062d..00000000 --- a/testsuite/tests/translprim/array_spec.ml.reference-noflat +++ /dev/null @@ -1,88 +0,0 @@ -(setglobal Array_spec! - (let - (int_a = (makearray[int] 1 2 3) - float_a = (makearray[addr] 1. 2. 3.) - addr_a = (makearray[addr] "a" "b" "c")) - (seq (array.length[int] int_a) (array.length[addr] float_a) - (array.length[addr] addr_a) - (function a (array.length[addr] a)) - (array.get[int] int_a 0) (array.get[addr] float_a 0) - (array.get[addr] addr_a 0) - (function a (array.get[addr] a 0)) - (array.unsafe_get[int] int_a 0) - (array.unsafe_get[addr] float_a 0) - (array.unsafe_get[addr] addr_a 0) - (function a (array.unsafe_get[addr] a 0)) - (array.set[int] int_a 0 1) (array.set[addr] float_a 0 1.) - (array.set[addr] addr_a 0 "a") - (function a x (array.set[addr] a 0 x)) - (array.unsafe_set[int] int_a 0 1) - (array.unsafe_set[addr] float_a 0 1.) - (array.unsafe_set[addr] addr_a 0 "a") - (function a x (array.unsafe_set[addr] a 0 x)) - (let - (eta_gen_len = - (function prim stub (array.length[addr] prim)) - eta_gen_safe_get = - (function prim prim stub - (array.get[addr] prim prim)) - eta_gen_unsafe_get = - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - eta_gen_safe_set = - (function prim prim prim stub - (array.set[addr] prim prim prim)) - eta_gen_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - eta_int_len = - (function prim stub (array.length[int] prim)) - eta_int_safe_get = - (function prim prim stub - (array.get[int] prim prim)) - eta_int_unsafe_get = - (function prim prim stub - (array.unsafe_get[int] prim prim)) - eta_int_safe_set = - (function prim prim prim stub - (array.set[int] prim prim prim)) - eta_int_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[int] prim prim prim)) - eta_float_len = - (function prim stub (array.length[addr] prim)) - eta_float_safe_get = - (function prim prim stub - (array.get[addr] prim prim)) - eta_float_unsafe_get = - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - eta_float_safe_set = - (function prim prim prim stub - (array.set[addr] prim prim prim)) - eta_float_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - eta_addr_len = - (function prim stub (array.length[addr] prim)) - eta_addr_safe_get = - (function prim prim stub - (array.get[addr] prim prim)) - eta_addr_unsafe_get = - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - eta_addr_safe_set = - (function prim prim prim stub - (array.set[addr] prim prim prim)) - eta_addr_unsafe_set = - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim))) - (makeblock 0 int_a float_a addr_a eta_gen_len - eta_gen_safe_get eta_gen_unsafe_get eta_gen_safe_set - eta_gen_unsafe_set eta_int_len eta_int_safe_get - eta_int_unsafe_get eta_int_safe_set - eta_int_unsafe_set eta_float_len eta_float_safe_get - eta_float_unsafe_get eta_float_safe_set - eta_float_unsafe_set eta_addr_len eta_addr_safe_get - eta_addr_unsafe_get eta_addr_safe_set - eta_addr_unsafe_set))))) diff --git a/testsuite/tests/translprim/comparison_table.compilers.reference b/testsuite/tests/translprim/comparison_table.compilers.reference new file mode 100644 index 00000000..b3c439fe --- /dev/null +++ b/testsuite/tests/translprim/comparison_table.compilers.reference @@ -0,0 +1,248 @@ +(setglobal Comparison_table! + (let + (gen_cmp = (function x y (caml_compare x y)) + int_cmp = (function x y (caml_int_compare x y)) + bool_cmp = (function x y (caml_int_compare x y)) + intlike_cmp = (function x y (caml_int_compare x y)) + float_cmp = (function x y (caml_float_compare x y)) + string_cmp = (function x y (caml_string_compare x y)) + int32_cmp = (function x y (caml_int32_compare x y)) + int64_cmp = (function x y (caml_int64_compare x y)) + nativeint_cmp = (function x y (caml_nativeint_compare x y)) + gen_eq = (function x y (caml_equal x y)) + int_eq = (function x y (== x y)) + bool_eq = (function x y (== x y)) + intlike_eq = (function x y (== x y)) + float_eq = (function x y (==. x y)) + string_eq = (function x y (caml_string_equal x y)) + int32_eq = (function x y (Int32.== x y)) + int64_eq = (function x y (Int64.== x y)) + nativeint_eq = (function x y (Nativeint.== x y)) + gen_ne = (function x y (caml_notequal x y)) + int_ne = (function x y (!= x y)) + bool_ne = (function x y (!= x y)) + intlike_ne = (function x y (!= x y)) + float_ne = (function x y (!=. x y)) + string_ne = (function x y (caml_string_notequal x y)) + int32_ne = (function x y (Int32.!= x y)) + int64_ne = (function x y (Int64.!= x y)) + nativeint_ne = (function x y (Nativeint.!= x y)) + gen_lt = (function x y (caml_lessthan x y)) + int_lt = (function x y (< x y)) + bool_lt = (function x y (< x y)) + intlike_lt = (function x y (< x y)) + float_lt = (function x y (<. x y)) + string_lt = (function x y (caml_string_lessthan x y)) + int32_lt = (function x y (Int32.< x y)) + int64_lt = (function x y (Int64.< x y)) + nativeint_lt = (function x y (Nativeint.< x y)) + gen_gt = (function x y (caml_greaterthan x y)) + int_gt = (function x y (> x y)) + bool_gt = (function x y (> x y)) + intlike_gt = (function x y (> x y)) + float_gt = (function x y (>. x y)) + string_gt = (function x y (caml_string_greaterthan x y)) + int32_gt = (function x y (Int32.> x y)) + int64_gt = (function x y (Int64.> x y)) + nativeint_gt = (function x y (Nativeint.> x y)) + gen_le = (function x y (caml_lessequal x y)) + int_le = (function x y (<= x y)) + bool_le = (function x y (<= x y)) + intlike_le = (function x y (<= x y)) + float_le = (function x y (<=. x y)) + string_le = (function x y (caml_string_lessequal x y)) + int32_le = (function x y (Int32.<= x y)) + int64_le = (function x y (Int64.<= x y)) + nativeint_le = (function x y (Nativeint.<= x y)) + gen_ge = (function x y (caml_greaterequal x y)) + int_ge = (function x y (>= x y)) + bool_ge = (function x y (>= x y)) + intlike_ge = (function x y (>= x y)) + float_ge = (function x y (>=. x y)) + string_ge = (function x y (caml_string_greaterequal x y)) + int32_ge = (function x y (Int32.>= x y)) + int64_ge = (function x y (Int64.>= x y)) + nativeint_ge = (function x y (Nativeint.>= x y)) + eta_gen_cmp = (function prim prim stub (caml_compare prim prim)) + eta_int_cmp = (function prim prim stub (caml_int_compare prim prim)) + eta_bool_cmp = (function prim prim stub (caml_int_compare prim prim)) + eta_intlike_cmp = (function prim prim stub (caml_int_compare prim prim)) + eta_float_cmp = (function prim prim stub (caml_float_compare prim prim)) + eta_string_cmp = + (function prim prim stub (caml_string_compare prim prim)) + eta_int32_cmp = (function prim prim stub (caml_int32_compare prim prim)) + eta_int64_cmp = (function prim prim stub (caml_int64_compare prim prim)) + eta_nativeint_cmp = + (function prim prim stub (caml_nativeint_compare prim prim)) + eta_gen_eq = (function prim prim stub (caml_equal prim prim)) + eta_int_eq = (function prim prim stub (== prim prim)) + eta_bool_eq = (function prim prim stub (== prim prim)) + eta_intlike_eq = (function prim prim stub (== prim prim)) + eta_float_eq = (function prim prim stub (==. prim prim)) + eta_string_eq = (function prim prim stub (caml_string_equal prim prim)) + eta_int32_eq = (function prim prim stub (Int32.== prim prim)) + eta_int64_eq = (function prim prim stub (Int64.== prim prim)) + eta_nativeint_eq = (function prim prim stub (Nativeint.== prim prim)) + eta_gen_ne = (function prim prim stub (caml_notequal prim prim)) + eta_int_ne = (function prim prim stub (!= prim prim)) + eta_bool_ne = (function prim prim stub (!= prim prim)) + eta_intlike_ne = (function prim prim stub (!= prim prim)) + eta_float_ne = (function prim prim stub (!=. prim prim)) + eta_string_ne = + (function prim prim stub (caml_string_notequal prim prim)) + eta_int32_ne = (function prim prim stub (Int32.!= prim prim)) + eta_int64_ne = (function prim prim stub (Int64.!= prim prim)) + eta_nativeint_ne = (function prim prim stub (Nativeint.!= prim prim)) + eta_gen_lt = (function prim prim stub (caml_lessthan prim prim)) + eta_int_lt = (function prim prim stub (< prim prim)) + eta_bool_lt = (function prim prim stub (< prim prim)) + eta_intlike_lt = (function prim prim stub (< prim prim)) + eta_float_lt = (function prim prim stub (<. prim prim)) + eta_string_lt = + (function prim prim stub (caml_string_lessthan prim prim)) + eta_int32_lt = (function prim prim stub (Int32.< prim prim)) + eta_int64_lt = (function prim prim stub (Int64.< prim prim)) + eta_nativeint_lt = (function prim prim stub (Nativeint.< prim prim)) + eta_gen_gt = (function prim prim stub (caml_greaterthan prim prim)) + eta_int_gt = (function prim prim stub (> prim prim)) + eta_bool_gt = (function prim prim stub (> prim prim)) + eta_intlike_gt = (function prim prim stub (> prim prim)) + eta_float_gt = (function prim prim stub (>. prim prim)) + eta_string_gt = + (function prim prim stub (caml_string_greaterthan prim prim)) + eta_int32_gt = (function prim prim stub (Int32.> prim prim)) + eta_int64_gt = (function prim prim stub (Int64.> prim prim)) + eta_nativeint_gt = (function prim prim stub (Nativeint.> prim prim)) + eta_gen_le = (function prim prim stub (caml_lessequal prim prim)) + eta_int_le = (function prim prim stub (<= prim prim)) + eta_bool_le = (function prim prim stub (<= prim prim)) + eta_intlike_le = (function prim prim stub (<= prim prim)) + eta_float_le = (function prim prim stub (<=. prim prim)) + eta_string_le = + (function prim prim stub (caml_string_lessequal prim prim)) + eta_int32_le = (function prim prim stub (Int32.<= prim prim)) + eta_int64_le = (function prim prim stub (Int64.<= prim prim)) + eta_nativeint_le = (function prim prim stub (Nativeint.<= prim prim)) + eta_gen_ge = (function prim prim stub (caml_greaterequal prim prim)) + eta_int_ge = (function prim prim stub (>= prim prim)) + eta_bool_ge = (function prim prim stub (>= prim prim)) + eta_intlike_ge = (function prim prim stub (>= prim prim)) + eta_float_ge = (function prim prim stub (>=. prim prim)) + eta_string_ge = + (function prim prim stub (caml_string_greaterequal prim prim)) + eta_int32_ge = (function prim prim stub (Int32.>= prim prim)) + eta_int64_ge = (function prim prim stub (Int64.>= prim prim)) + eta_nativeint_ge = (function prim prim stub (Nativeint.>= prim prim)) + int_vec = [0: [0: 1 1] [0: [0: 1 2] [0: [0: 2 1] 0a]]] + bool_vec = [0: [0: 0a 0a] [0: [0: 0a 1a] [0: [0: 1a 0a] 0a]]] + intlike_vec = [0: [0: 0a 0a] [0: [0: 0a 1a] [0: [0: 1a 0a] 0a]]] + float_vec = [0: [0: 1. 1.] [0: [0: 1. 2.] [0: [0: 2. 1.] 0a]]] + string_vec = [0: [0: "1" "1"] [0: [0: "1" "2"] [0: [0: "2" "1"] 0a]]] + int32_vec = [0: [0: 1l 1l] [0: [0: 1l 2l] [0: [0: 2l 1l] 0a]]] + int64_vec = [0: [0: 1L 1L] [0: [0: 1L 2L] [0: [0: 2L 1L] 0a]]] + nativeint_vec = [0: [0: 1n 1n] [0: [0: 1n 2n] [0: [0: 2n 1n] 0a]]] + test_vec = + (function cmp eq ne lt gt le ge vec + (let + (uncurry = + (function f param (apply f (field 0 param) (field 1 param))) + map = + (function f l + (apply (field 16 (global Stdlib__list!)) (apply uncurry f) l))) + (makeblock 0 + (makeblock 0 (apply map gen_cmp vec) (apply map cmp vec)) + (apply map + (function gen spec + (makeblock 0 (apply map gen vec) (apply map spec vec))) + (makeblock 0 (makeblock 0 gen_eq eq) + (makeblock 0 (makeblock 0 gen_ne ne) + (makeblock 0 (makeblock 0 gen_lt lt) + (makeblock 0 (makeblock 0 gen_gt gt) + (makeblock 0 (makeblock 0 gen_le le) + (makeblock 0 (makeblock 0 gen_ge ge) 0a))))))))))) + (seq + (apply test_vec int_cmp int_eq int_ne int_lt int_gt int_le int_ge + int_vec) + (apply test_vec bool_cmp bool_eq bool_ne bool_lt bool_gt bool_le + bool_ge bool_vec) + (apply test_vec intlike_cmp intlike_eq intlike_ne intlike_lt intlike_gt + intlike_le intlike_ge intlike_vec) + (apply test_vec float_cmp float_eq float_ne float_lt float_gt float_le + float_ge float_vec) + (apply test_vec string_cmp string_eq string_ne string_lt string_gt + string_le string_ge string_vec) + (apply test_vec int32_cmp int32_eq int32_ne int32_lt int32_gt int32_le + int32_ge int32_vec) + (apply test_vec int64_cmp int64_eq int64_ne int64_lt int64_gt int64_le + int64_ge int64_vec) + (apply test_vec nativeint_cmp nativeint_eq nativeint_ne nativeint_lt + nativeint_gt nativeint_le nativeint_ge nativeint_vec) + (let + (eta_test_vec = + (function cmp eq ne lt gt le ge vec + (let + (uncurry = + (function f param + (apply f (field 0 param) (field 1 param))) + map = + (function f l + (apply (field 16 (global Stdlib__list!)) + (apply uncurry f) l))) + (makeblock 0 + (makeblock 0 (apply map eta_gen_cmp vec) + (apply map cmp vec)) + (apply map + (function gen spec + (makeblock 0 (apply map gen vec) (apply map spec vec))) + (makeblock 0 (makeblock 0 eta_gen_eq eq) + (makeblock 0 (makeblock 0 eta_gen_ne ne) + (makeblock 0 (makeblock 0 eta_gen_lt lt) + (makeblock 0 (makeblock 0 eta_gen_gt gt) + (makeblock 0 (makeblock 0 eta_gen_le le) + (makeblock 0 (makeblock 0 eta_gen_ge ge) 0a))))))))))) + (seq + (apply eta_test_vec eta_int_cmp eta_int_eq eta_int_ne eta_int_lt + eta_int_gt eta_int_le eta_int_ge int_vec) + (apply eta_test_vec eta_bool_cmp eta_bool_eq eta_bool_ne + eta_bool_lt eta_bool_gt eta_bool_le eta_bool_ge bool_vec) + (apply eta_test_vec eta_intlike_cmp eta_intlike_eq eta_intlike_ne + eta_intlike_lt eta_intlike_gt eta_intlike_le eta_intlike_ge + intlike_vec) + (apply eta_test_vec eta_float_cmp eta_float_eq eta_float_ne + eta_float_lt eta_float_gt eta_float_le eta_float_ge float_vec) + (apply eta_test_vec eta_string_cmp eta_string_eq eta_string_ne + eta_string_lt eta_string_gt eta_string_le eta_string_ge + string_vec) + (apply eta_test_vec eta_int32_cmp eta_int32_eq eta_int32_ne + eta_int32_lt eta_int32_gt eta_int32_le eta_int32_ge int32_vec) + (apply eta_test_vec eta_int64_cmp eta_int64_eq eta_int64_ne + eta_int64_lt eta_int64_gt eta_int64_le eta_int64_ge int64_vec) + (apply eta_test_vec eta_nativeint_cmp eta_nativeint_eq + eta_nativeint_ne eta_nativeint_lt eta_nativeint_gt + eta_nativeint_le eta_nativeint_ge nativeint_vec) + (makeblock 0 gen_cmp int_cmp bool_cmp intlike_cmp float_cmp + string_cmp int32_cmp int64_cmp nativeint_cmp gen_eq int_eq + bool_eq intlike_eq float_eq string_eq int32_eq int64_eq + nativeint_eq gen_ne int_ne bool_ne intlike_ne float_ne string_ne + int32_ne int64_ne nativeint_ne gen_lt int_lt bool_lt intlike_lt + float_lt string_lt int32_lt int64_lt nativeint_lt gen_gt int_gt + bool_gt intlike_gt float_gt string_gt int32_gt int64_gt + nativeint_gt gen_le int_le bool_le intlike_le float_le string_le + int32_le int64_le nativeint_le gen_ge int_ge bool_ge intlike_ge + float_ge string_ge int32_ge int64_ge nativeint_ge eta_gen_cmp + eta_int_cmp eta_bool_cmp eta_intlike_cmp eta_float_cmp + eta_string_cmp eta_int32_cmp eta_int64_cmp eta_nativeint_cmp + eta_gen_eq eta_int_eq eta_bool_eq eta_intlike_eq eta_float_eq + eta_string_eq eta_int32_eq eta_int64_eq eta_nativeint_eq + eta_gen_ne eta_int_ne eta_bool_ne eta_intlike_ne eta_float_ne + eta_string_ne eta_int32_ne eta_int64_ne eta_nativeint_ne + eta_gen_lt eta_int_lt eta_bool_lt eta_intlike_lt eta_float_lt + eta_string_lt eta_int32_lt eta_int64_lt eta_nativeint_lt + eta_gen_gt eta_int_gt eta_bool_gt eta_intlike_gt eta_float_gt + eta_string_gt eta_int32_gt eta_int64_gt eta_nativeint_gt + eta_gen_le eta_int_le eta_bool_le eta_intlike_le eta_float_le + eta_string_le eta_int32_le eta_int64_le eta_nativeint_le + eta_gen_ge eta_int_ge eta_bool_ge eta_intlike_ge eta_float_ge + eta_string_ge eta_int32_ge eta_int64_ge eta_nativeint_ge int_vec + bool_vec intlike_vec float_vec string_vec int32_vec int64_vec + nativeint_vec test_vec eta_test_vec)))))) diff --git a/testsuite/tests/translprim/comparison_table.ml b/testsuite/tests/translprim/comparison_table.ml index 129ea5c5..1a914306 100644 --- a/testsuite/tests/translprim/comparison_table.ml +++ b/testsuite/tests/translprim/comparison_table.ml @@ -1,3 +1,10 @@ +(* TEST + * setup-ocamlc.byte-build-env + ** ocamlc.byte + flags = "-dlambda -dno-unique-ids" + *** check-ocamlc.byte-output +*) + external cmp : 'a -> 'a -> int = "%compare";; external eq : 'a -> 'a -> bool = "%equal";; external ne : 'a -> 'a -> bool = "%notequal";; diff --git a/testsuite/tests/translprim/comparison_table.ml.reference b/testsuite/tests/translprim/comparison_table.ml.reference deleted file mode 100644 index 635b05a2..00000000 --- a/testsuite/tests/translprim/comparison_table.ml.reference +++ /dev/null @@ -1,375 +0,0 @@ -(setglobal Comparison_table! - (let - (gen_cmp = (function x y (caml_compare x y)) - int_cmp = (function x y (caml_int_compare x y)) - bool_cmp = - (function x y (caml_int_compare x y)) - intlike_cmp = - (function x y (caml_int_compare x y)) - float_cmp = - (function x y (caml_float_compare x y)) - string_cmp = - (function x y (caml_string_compare x y)) - int32_cmp = - (function x y (caml_int32_compare x y)) - int64_cmp = - (function x y (caml_int64_compare x y)) - nativeint_cmp = - (function x y (caml_nativeint_compare x y)) - gen_eq = (function x y (caml_equal x y)) - int_eq = (function x y (== x y)) - bool_eq = (function x y (== x y)) - intlike_eq = (function x y (== x y)) - float_eq = (function x y (==. x y)) - string_eq = - (function x y (caml_string_equal x y)) - int32_eq = (function x y (Int32.== x y)) - int64_eq = (function x y (Int64.== x y)) - nativeint_eq = - (function x y (Nativeint.== x y)) - gen_ne = (function x y (caml_notequal x y)) - int_ne = (function x y (!= x y)) - bool_ne = (function x y (!= x y)) - intlike_ne = (function x y (!= x y)) - float_ne = (function x y (!=. x y)) - string_ne = - (function x y (caml_string_notequal x y)) - int32_ne = (function x y (Int32.!= x y)) - int64_ne = (function x y (Int64.!= x y)) - nativeint_ne = - (function x y (Nativeint.!= x y)) - gen_lt = (function x y (caml_lessthan x y)) - int_lt = (function x y (< x y)) - bool_lt = (function x y (< x y)) - intlike_lt = (function x y (< x y)) - float_lt = (function x y (<. x y)) - string_lt = - (function x y (caml_string_lessthan x y)) - int32_lt = (function x y (Int32.< x y)) - int64_lt = (function x y (Int64.< x y)) - nativeint_lt = (function x y (Nativeint.< x y)) - gen_gt = (function x y (caml_greaterthan x y)) - int_gt = (function x y (> x y)) - bool_gt = (function x y (> x y)) - intlike_gt = (function x y (> x y)) - float_gt = (function x y (>. x y)) - string_gt = - (function x y (caml_string_greaterthan x y)) - int32_gt = (function x y (Int32.> x y)) - int64_gt = (function x y (Int64.> x y)) - nativeint_gt = (function x y (Nativeint.> x y)) - gen_le = (function x y (caml_lessequal x y)) - int_le = (function x y (<= x y)) - bool_le = (function x y (<= x y)) - intlike_le = (function x y (<= x y)) - float_le = (function x y (<=. x y)) - string_le = - (function x y (caml_string_lessequal x y)) - int32_le = (function x y (Int32.<= x y)) - int64_le = (function x y (Int64.<= x y)) - nativeint_le = - (function x y (Nativeint.<= x y)) - gen_ge = (function x y (caml_greaterequal x y)) - int_ge = (function x y (>= x y)) - bool_ge = (function x y (>= x y)) - intlike_ge = (function x y (>= x y)) - float_ge = (function x y (>=. x y)) - string_ge = - (function x y (caml_string_greaterequal x y)) - int32_ge = (function x y (Int32.>= x y)) - int64_ge = (function x y (Int64.>= x y)) - nativeint_ge = - (function x y (Nativeint.>= x y)) - eta_gen_cmp = - (function prim prim stub (caml_compare prim prim)) - eta_int_cmp = - (function prim prim stub - (caml_int_compare prim prim)) - eta_bool_cmp = - (function prim prim stub - (caml_int_compare prim prim)) - eta_intlike_cmp = - (function prim prim stub - (caml_int_compare prim prim)) - eta_float_cmp = - (function prim prim stub - (caml_float_compare prim prim)) - eta_string_cmp = - (function prim prim stub - (caml_string_compare prim prim)) - eta_int32_cmp = - (function prim prim stub - (caml_int32_compare prim prim)) - eta_int64_cmp = - (function prim prim stub - (caml_int64_compare prim prim)) - eta_nativeint_cmp = - (function prim prim stub - (caml_nativeint_compare prim prim)) - eta_gen_eq = - (function prim prim stub (caml_equal prim prim)) - eta_int_eq = - (function prim prim stub (== prim prim)) - eta_bool_eq = - (function prim prim stub (== prim prim)) - eta_intlike_eq = - (function prim prim stub (== prim prim)) - eta_float_eq = - (function prim prim stub (==. prim prim)) - eta_string_eq = - (function prim prim stub - (caml_string_equal prim prim)) - eta_int32_eq = - (function prim prim stub (Int32.== prim prim)) - eta_int64_eq = - (function prim prim stub (Int64.== prim prim)) - eta_nativeint_eq = - (function prim prim stub (Nativeint.== prim prim)) - eta_gen_ne = - (function prim prim stub - (caml_notequal prim prim)) - eta_int_ne = - (function prim prim stub (!= prim prim)) - eta_bool_ne = - (function prim prim stub (!= prim prim)) - eta_intlike_ne = - (function prim prim stub (!= prim prim)) - eta_float_ne = - (function prim prim stub (!=. prim prim)) - eta_string_ne = - (function prim prim stub - (caml_string_notequal prim prim)) - eta_int32_ne = - (function prim prim stub (Int32.!= prim prim)) - eta_int64_ne = - (function prim prim stub (Int64.!= prim prim)) - eta_nativeint_ne = - (function prim prim stub (Nativeint.!= prim prim)) - eta_gen_lt = - (function prim prim stub - (caml_lessthan prim prim)) - eta_int_lt = - (function prim prim stub (< prim prim)) - eta_bool_lt = - (function prim prim stub (< prim prim)) - eta_intlike_lt = - (function prim prim stub (< prim prim)) - eta_float_lt = - (function prim prim stub (<. prim prim)) - eta_string_lt = - (function prim prim stub - (caml_string_lessthan prim prim)) - eta_int32_lt = - (function prim prim stub (Int32.< prim prim)) - eta_int64_lt = - (function prim prim stub (Int64.< prim prim)) - eta_nativeint_lt = - (function prim prim stub (Nativeint.< prim prim)) - eta_gen_gt = - (function prim prim stub - (caml_greaterthan prim prim)) - eta_int_gt = - (function prim prim stub (> prim prim)) - eta_bool_gt = - (function prim prim stub (> prim prim)) - eta_intlike_gt = - (function prim prim stub (> prim prim)) - eta_float_gt = - (function prim prim stub (>. prim prim)) - eta_string_gt = - (function prim prim stub - (caml_string_greaterthan prim prim)) - eta_int32_gt = - (function prim prim stub (Int32.> prim prim)) - eta_int64_gt = - (function prim prim stub (Int64.> prim prim)) - eta_nativeint_gt = - (function prim prim stub (Nativeint.> prim prim)) - eta_gen_le = - (function prim prim stub - (caml_lessequal prim prim)) - eta_int_le = - (function prim prim stub (<= prim prim)) - eta_bool_le = - (function prim prim stub (<= prim prim)) - eta_intlike_le = - (function prim prim stub (<= prim prim)) - eta_float_le = - (function prim prim stub (<=. prim prim)) - eta_string_le = - (function prim prim stub - (caml_string_lessequal prim prim)) - eta_int32_le = - (function prim prim stub (Int32.<= prim prim)) - eta_int64_le = - (function prim prim stub (Int64.<= prim prim)) - eta_nativeint_le = - (function prim prim stub (Nativeint.<= prim prim)) - eta_gen_ge = - (function prim prim stub - (caml_greaterequal prim prim)) - eta_int_ge = - (function prim prim stub (>= prim prim)) - eta_bool_ge = - (function prim prim stub (>= prim prim)) - eta_intlike_ge = - (function prim prim stub (>= prim prim)) - eta_float_ge = - (function prim prim stub (>=. prim prim)) - eta_string_ge = - (function prim prim stub - (caml_string_greaterequal prim prim)) - eta_int32_ge = - (function prim prim stub (Int32.>= prim prim)) - eta_int64_ge = - (function prim prim stub (Int64.>= prim prim)) - eta_nativeint_ge = - (function prim prim stub (Nativeint.>= prim prim)) - int_vec = [0: [0: 1 1] [0: [0: 1 2] [0: [0: 2 1] 0a]]] - bool_vec = [0: [0: 0a 0a] [0: [0: 0a 1a] [0: [0: 1a 0a] 0a]]] - intlike_vec = [0: [0: 0a 0a] [0: [0: 0a 1a] [0: [0: 1a 0a] 0a]]] - float_vec = [0: [0: 1. 1.] [0: [0: 1. 2.] [0: [0: 2. 1.] 0a]]] - string_vec = - [0: [0: "1" "1"] [0: [0: "1" "2"] [0: [0: "2" "1"] 0a]]] - int32_vec = [0: [0: 1l 1l] [0: [0: 1l 2l] [0: [0: 2l 1l] 0a]]] - int64_vec = [0: [0: 1L 1L] [0: [0: 1L 2L] [0: [0: 2L 1L] 0a]]] - nativeint_vec = [0: [0: 1n 1n] [0: [0: 1n 2n] [0: [0: 2n 1n] 0a]]] - test_vec = - (function cmp eq ne lt gt le ge - vec - (let - (uncurry = - (function f param - (apply f (field 0 param) (field 1 param))) - map = - (function f l - (apply (field 16 (global List!)) (apply uncurry f) - l))) - (makeblock 0 - (makeblock 0 (apply map gen_cmp vec) - (apply map cmp vec)) - (apply map - (function gen spec - (makeblock 0 (apply map gen vec) - (apply map spec vec))) - (makeblock 0 (makeblock 0 gen_eq eq) - (makeblock 0 (makeblock 0 gen_ne ne) - (makeblock 0 (makeblock 0 gen_lt lt) - (makeblock 0 (makeblock 0 gen_gt gt) - (makeblock 0 (makeblock 0 gen_le le) - (makeblock 0 (makeblock 0 gen_ge ge) 0a))))))))))) - (seq - (apply test_vec int_cmp int_eq int_ne int_lt - int_gt int_le int_ge int_vec) - (apply test_vec bool_cmp bool_eq bool_ne - bool_lt bool_gt bool_le bool_ge bool_vec) - (apply test_vec intlike_cmp intlike_eq intlike_ne - intlike_lt intlike_gt intlike_le intlike_ge - intlike_vec) - (apply test_vec float_cmp float_eq float_ne - float_lt float_gt float_le float_ge - float_vec) - (apply test_vec string_cmp string_eq string_ne - string_lt string_gt string_le string_ge - string_vec) - (apply test_vec int32_cmp int32_eq int32_ne - int32_lt int32_gt int32_le int32_ge - int32_vec) - (apply test_vec int64_cmp int64_eq int64_ne - int64_lt int64_gt int64_le int64_ge - int64_vec) - (apply test_vec nativeint_cmp nativeint_eq - nativeint_ne nativeint_lt nativeint_gt - nativeint_le nativeint_ge nativeint_vec) - (let - (eta_test_vec = - (function cmp eq ne lt gt le ge - vec - (let - (uncurry = - (function f param - (apply f (field 0 param) (field 1 param))) - map = - (function f l - (apply (field 16 (global List!)) - (apply uncurry f) l))) - (makeblock 0 - (makeblock 0 (apply map eta_gen_cmp vec) - (apply map cmp vec)) - (apply map - (function gen spec - (makeblock 0 (apply map gen vec) - (apply map spec vec))) - (makeblock 0 (makeblock 0 eta_gen_eq eq) - (makeblock 0 (makeblock 0 eta_gen_ne ne) - (makeblock 0 (makeblock 0 eta_gen_lt lt) - (makeblock 0 (makeblock 0 eta_gen_gt gt) - (makeblock 0 (makeblock 0 eta_gen_le le) - (makeblock 0 - (makeblock 0 eta_gen_ge ge) 0a))))))))))) - (seq - (apply eta_test_vec eta_int_cmp eta_int_eq - eta_int_ne eta_int_lt eta_int_gt eta_int_le - eta_int_ge int_vec) - (apply eta_test_vec eta_bool_cmp eta_bool_eq - eta_bool_ne eta_bool_lt eta_bool_gt - eta_bool_le eta_bool_ge bool_vec) - (apply eta_test_vec eta_intlike_cmp eta_intlike_eq - eta_intlike_ne eta_intlike_lt eta_intlike_gt - eta_intlike_le eta_intlike_ge intlike_vec) - (apply eta_test_vec eta_float_cmp eta_float_eq - eta_float_ne eta_float_lt eta_float_gt - eta_float_le eta_float_ge float_vec) - (apply eta_test_vec eta_string_cmp eta_string_eq - eta_string_ne eta_string_lt eta_string_gt - eta_string_le eta_string_ge string_vec) - (apply eta_test_vec eta_int32_cmp eta_int32_eq - eta_int32_ne eta_int32_lt eta_int32_gt - eta_int32_le eta_int32_ge int32_vec) - (apply eta_test_vec eta_int64_cmp eta_int64_eq - eta_int64_ne eta_int64_lt eta_int64_gt - eta_int64_le eta_int64_ge int64_vec) - (apply eta_test_vec eta_nativeint_cmp - eta_nativeint_eq eta_nativeint_ne eta_nativeint_lt - eta_nativeint_gt eta_nativeint_le eta_nativeint_ge - nativeint_vec) - (makeblock 0 gen_cmp int_cmp bool_cmp - intlike_cmp float_cmp string_cmp int32_cmp - int64_cmp nativeint_cmp gen_eq int_eq - bool_eq intlike_eq float_eq string_eq - int32_eq int64_eq nativeint_eq gen_ne - int_ne bool_ne intlike_ne float_ne - string_ne int32_ne int64_ne nativeint_ne - gen_lt int_lt bool_lt intlike_lt - float_lt string_lt int32_lt int64_lt - nativeint_lt gen_gt int_gt bool_gt - intlike_gt float_gt string_gt int32_gt - int64_gt nativeint_gt gen_le int_le - bool_le intlike_le float_le string_le - int32_le int64_le nativeint_le gen_ge - int_ge bool_ge intlike_ge float_ge - string_ge int32_ge int64_ge nativeint_ge - eta_gen_cmp eta_int_cmp eta_bool_cmp - eta_intlike_cmp eta_float_cmp eta_string_cmp - eta_int32_cmp eta_int64_cmp eta_nativeint_cmp - eta_gen_eq eta_int_eq eta_bool_eq - eta_intlike_eq eta_float_eq eta_string_eq - eta_int32_eq eta_int64_eq eta_nativeint_eq - eta_gen_ne eta_int_ne eta_bool_ne - eta_intlike_ne eta_float_ne eta_string_ne - eta_int32_ne eta_int64_ne eta_nativeint_ne - eta_gen_lt eta_int_lt eta_bool_lt - eta_intlike_lt eta_float_lt eta_string_lt - eta_int32_lt eta_int64_lt eta_nativeint_lt - eta_gen_gt eta_int_gt eta_bool_gt - eta_intlike_gt eta_float_gt eta_string_gt - eta_int32_gt eta_int64_gt eta_nativeint_gt - eta_gen_le eta_int_le eta_bool_le - eta_intlike_le eta_float_le eta_string_le - eta_int32_le eta_int64_le eta_nativeint_le - eta_gen_ge eta_int_ge eta_bool_ge - eta_intlike_ge eta_float_ge eta_string_ge - eta_int32_ge eta_int64_ge eta_nativeint_ge - int_vec bool_vec intlike_vec float_vec - string_vec int32_vec int64_vec nativeint_vec - test_vec eta_test_vec)))))) diff --git a/testsuite/tests/translprim/locs.ml b/testsuite/tests/translprim/locs.ml new file mode 100644 index 00000000..dbdcb733 --- /dev/null +++ b/testsuite/tests/translprim/locs.ml @@ -0,0 +1,44 @@ +(* TEST *) + +let print_loc loc = + print_endline loc + +let print_file file = + print_endline file + +let print_line line = + print_endline (string_of_int line) + +let print_module md = + print_endline md + +let print_pos (file, line, col1, col2) = + Printf.printf "%s, %d, %d, %d\n" file line col1 col2 + +let () = print_loc __LOC__ + +let () = print_file __FILE__ + +let () = print_line __LINE__ + +let () = print_module __MODULE__ + +let () = print_pos __POS__ + +let loc, s1 = __LOC_OF__ "an expression" + +let () = print_loc loc + +let () = print_endline s1 + +let line, s2 = __LINE_OF__ "another expression" + +let () = print_line line + +let () = print_endline s2 + +let pos, s3 = __POS_OF__ "yet another expression" + +let () = print_pos pos + +let () = print_endline s3 diff --git a/testsuite/tests/translprim/locs.reference b/testsuite/tests/translprim/locs.reference new file mode 100644 index 00000000..abb22875 --- /dev/null +++ b/testsuite/tests/translprim/locs.reference @@ -0,0 +1,11 @@ +File "locs.ml", line 18, characters 19-26 +locs.ml +22 +Locs +locs.ml, 26, 19, 26 +File "locs.ml", line 28, characters 14-40 +an expression +34 +another expression +locs.ml, 40, 14, 49 +yet another expression diff --git a/testsuite/tests/translprim/module_coercion.compilers.reference.flat b/testsuite/tests/translprim/module_coercion.compilers.reference.flat new file mode 100644 index 00000000..b70909ee --- /dev/null +++ b/testsuite/tests/translprim/module_coercion.compilers.reference.flat @@ -0,0 +1,87 @@ +(setglobal Module_coercion! + (let (M = (module-defn(M) module_coercion.ml(13):417-1116 (makeblock 0))) + (makeblock 0 M + (module-defn(M_int) module_coercion.ml(44):1533-1572 + (makeblock 0 (function prim stub (array.length[int] prim)) + (function prim prim stub (array.get[int] prim prim)) + (function prim prim stub (array.unsafe_get[int] prim prim)) + (function prim prim prim stub (array.set[int] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[int] prim prim prim)) + (function prim prim stub (caml_int_compare prim prim)) + (function prim prim stub (== prim prim)) + (function prim prim stub (!= prim prim)) + (function prim prim stub (< prim prim)) + (function prim prim stub (> prim prim)) + (function prim prim stub (<= prim prim)) + (function prim prim stub (>= prim prim)))) + (module-defn(M_float) module_coercion.ml(45):1575-1618 + (makeblock 0 (function prim stub (array.length[float] prim)) + (function prim prim stub (array.get[float] prim prim)) + (function prim prim stub (array.unsafe_get[float] prim prim)) + (function prim prim prim stub (array.set[float] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[float] prim prim prim)) + (function prim prim stub (caml_float_compare prim prim)) + (function prim prim stub (==. prim prim)) + (function prim prim stub (!=. prim prim)) + (function prim prim stub (<. prim prim)) + (function prim prim stub (>. prim prim)) + (function prim prim stub (<=. prim prim)) + (function prim prim stub (>=. prim prim)))) + (module-defn(M_string) module_coercion.ml(46):1621-1666 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_string_compare prim prim)) + (function prim prim stub (caml_string_equal prim prim)) + (function prim prim stub (caml_string_notequal prim prim)) + (function prim prim stub (caml_string_lessthan prim prim)) + (function prim prim stub (caml_string_greaterthan prim prim)) + (function prim prim stub (caml_string_lessequal prim prim)) + (function prim prim stub (caml_string_greaterequal prim prim)))) + (module-defn(M_int32) module_coercion.ml(47):1669-1712 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_int32_compare prim prim)) + (function prim prim stub (Int32.== prim prim)) + (function prim prim stub (Int32.!= prim prim)) + (function prim prim stub (Int32.< prim prim)) + (function prim prim stub (Int32.> prim prim)) + (function prim prim stub (Int32.<= prim prim)) + (function prim prim stub (Int32.>= prim prim)))) + (module-defn(M_int64) module_coercion.ml(48):1715-1758 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_int64_compare prim prim)) + (function prim prim stub (Int64.== prim prim)) + (function prim prim stub (Int64.!= prim prim)) + (function prim prim stub (Int64.< prim prim)) + (function prim prim stub (Int64.> prim prim)) + (function prim prim stub (Int64.<= prim prim)) + (function prim prim stub (Int64.>= prim prim)))) + (module-defn(M_nativeint) module_coercion.ml(49):1761-1812 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_nativeint_compare prim prim)) + (function prim prim stub (Nativeint.== prim prim)) + (function prim prim stub (Nativeint.!= prim prim)) + (function prim prim stub (Nativeint.< prim prim)) + (function prim prim stub (Nativeint.> prim prim)) + (function prim prim stub (Nativeint.<= prim prim)) + (function prim prim stub (Nativeint.>= prim prim))))))) diff --git a/testsuite/tests/translprim/module_coercion.compilers.reference.no-flat b/testsuite/tests/translprim/module_coercion.compilers.reference.no-flat new file mode 100644 index 00000000..3a9503ee --- /dev/null +++ b/testsuite/tests/translprim/module_coercion.compilers.reference.no-flat @@ -0,0 +1,87 @@ +(setglobal Module_coercion! + (let (M = (module-defn(M) module_coercion.ml(13):417-1116 (makeblock 0))) + (makeblock 0 M + (module-defn(M_int) module_coercion.ml(44):1533-1572 + (makeblock 0 (function prim stub (array.length[int] prim)) + (function prim prim stub (array.get[int] prim prim)) + (function prim prim stub (array.unsafe_get[int] prim prim)) + (function prim prim prim stub (array.set[int] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[int] prim prim prim)) + (function prim prim stub (caml_int_compare prim prim)) + (function prim prim stub (== prim prim)) + (function prim prim stub (!= prim prim)) + (function prim prim stub (< prim prim)) + (function prim prim stub (> prim prim)) + (function prim prim stub (<= prim prim)) + (function prim prim stub (>= prim prim)))) + (module-defn(M_float) module_coercion.ml(45):1575-1618 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_float_compare prim prim)) + (function prim prim stub (==. prim prim)) + (function prim prim stub (!=. prim prim)) + (function prim prim stub (<. prim prim)) + (function prim prim stub (>. prim prim)) + (function prim prim stub (<=. prim prim)) + (function prim prim stub (>=. prim prim)))) + (module-defn(M_string) module_coercion.ml(46):1621-1666 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_string_compare prim prim)) + (function prim prim stub (caml_string_equal prim prim)) + (function prim prim stub (caml_string_notequal prim prim)) + (function prim prim stub (caml_string_lessthan prim prim)) + (function prim prim stub (caml_string_greaterthan prim prim)) + (function prim prim stub (caml_string_lessequal prim prim)) + (function prim prim stub (caml_string_greaterequal prim prim)))) + (module-defn(M_int32) module_coercion.ml(47):1669-1712 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_int32_compare prim prim)) + (function prim prim stub (Int32.== prim prim)) + (function prim prim stub (Int32.!= prim prim)) + (function prim prim stub (Int32.< prim prim)) + (function prim prim stub (Int32.> prim prim)) + (function prim prim stub (Int32.<= prim prim)) + (function prim prim stub (Int32.>= prim prim)))) + (module-defn(M_int64) module_coercion.ml(48):1715-1758 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_int64_compare prim prim)) + (function prim prim stub (Int64.== prim prim)) + (function prim prim stub (Int64.!= prim prim)) + (function prim prim stub (Int64.< prim prim)) + (function prim prim stub (Int64.> prim prim)) + (function prim prim stub (Int64.<= prim prim)) + (function prim prim stub (Int64.>= prim prim)))) + (module-defn(M_nativeint) module_coercion.ml(49):1761-1812 + (makeblock 0 (function prim stub (array.length[addr] prim)) + (function prim prim stub (array.get[addr] prim prim)) + (function prim prim stub (array.unsafe_get[addr] prim prim)) + (function prim prim prim stub (array.set[addr] prim prim prim)) + (function prim prim prim stub + (array.unsafe_set[addr] prim prim prim)) + (function prim prim stub (caml_nativeint_compare prim prim)) + (function prim prim stub (Nativeint.== prim prim)) + (function prim prim stub (Nativeint.!= prim prim)) + (function prim prim stub (Nativeint.< prim prim)) + (function prim prim stub (Nativeint.> prim prim)) + (function prim prim stub (Nativeint.<= prim prim)) + (function prim prim stub (Nativeint.>= prim prim))))))) diff --git a/testsuite/tests/translprim/module_coercion.ml b/testsuite/tests/translprim/module_coercion.ml index 041b3034..86f2ae95 100644 --- a/testsuite/tests/translprim/module_coercion.ml +++ b/testsuite/tests/translprim/module_coercion.ml @@ -1,3 +1,15 @@ +(* TEST + * setup-ocamlc.byte-build-env + ** ocamlc.byte + flags = "-dlambda -dno-unique-ids" + *** flat-float-array + **** check-ocamlc.byte-output + compiler_reference = "${test_source_directory}/module_coercion.compilers.reference.flat" + *** no-flat-float-array + **** check-ocamlc.byte-output + compiler_reference = "${test_source_directory}/module_coercion.compilers.reference.no-flat" +*) + module M = struct external len : 'a array -> int = "%array_length" external safe_get : 'a array -> int -> 'a = "%array_safe_get" diff --git a/testsuite/tests/translprim/module_coercion.ml.reference-flat b/testsuite/tests/translprim/module_coercion.ml.reference-flat deleted file mode 100644 index 27cd3f73..00000000 --- a/testsuite/tests/translprim/module_coercion.ml.reference-flat +++ /dev/null @@ -1,125 +0,0 @@ -(setglobal Module_coercion! - (let - (M = (module-defn(M) module_coercion.ml(1):0-699 (makeblock 0))) - (makeblock 0 M - (module-defn(M_int) module_coercion.ml(32):1116-1155 - (makeblock 0 (function prim stub (array.length[int] prim)) - (function prim prim stub - (array.get[int] prim prim)) - (function prim prim stub - (array.unsafe_get[int] prim prim)) - (function prim prim prim stub - (array.set[int] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[int] prim prim prim)) - (function prim prim stub - (caml_int_compare prim prim)) - (function prim prim stub (== prim prim)) - (function prim prim stub (!= prim prim)) - (function prim prim stub (< prim prim)) - (function prim prim stub (> prim prim)) - (function prim prim stub (<= prim prim)) - (function prim prim stub (>= prim prim)))) - (module-defn(M_float) module_coercion.ml(33):1158-1201 - (makeblock 0 - (function prim stub (array.length[float] prim)) - (function prim prim stub - (array.get[float] prim prim)) - (function prim prim stub - (array.unsafe_get[float] prim prim)) - (function prim prim prim stub - (array.set[float] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[float] prim prim prim)) - (function prim prim stub - (caml_float_compare prim prim)) - (function prim prim stub (==. prim prim)) - (function prim prim stub (!=. prim prim)) - (function prim prim stub (<. prim prim)) - (function prim prim stub (>. prim prim)) - (function prim prim stub (<=. prim prim)) - (function prim prim stub (>=. prim prim)))) - (module-defn(M_string) module_coercion.ml(34):1204-1249 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_string_compare prim prim)) - (function prim prim stub - (caml_string_equal prim prim)) - (function prim prim stub - (caml_string_notequal prim prim)) - (function prim prim stub - (caml_string_lessthan prim prim)) - (function prim prim stub - (caml_string_greaterthan prim prim)) - (function prim prim stub - (caml_string_lessequal prim prim)) - (function prim prim stub - (caml_string_greaterequal prim prim)))) - (module-defn(M_int32/1104) module_coercion.ml(35):1252-1295 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_int32_compare prim prim)) - (function prim prim stub (Int32.== prim prim)) - (function prim prim stub (Int32.!= prim prim)) - (function prim prim stub (Int32.< prim prim)) - (function prim prim stub (Int32.> prim prim)) - (function prim prim stub (Int32.<= prim prim)) - (function prim prim stub (Int32.>= prim prim)))) - (module-defn(M_int64/1129) module_coercion.ml(36):1298-1341 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_int64_compare prim prim)) - (function prim prim stub (Int64.== prim prim)) - (function prim prim stub (Int64.!= prim prim)) - (function prim prim stub (Int64.< prim prim)) - (function prim prim stub (Int64.> prim prim)) - (function prim prim stub (Int64.<= prim prim)) - (function prim prim stub (Int64.>= prim prim)))) - (module-defn(M_nativeint) module_coercion.ml(37):1344-1395 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_nativeint_compare prim prim)) - (function prim prim stub - (Nativeint.== prim prim)) - (function prim prim stub - (Nativeint.!= prim prim)) - (function prim prim stub - (Nativeint.< prim prim)) - (function prim prim stub - (Nativeint.> prim prim)) - (function prim prim stub - (Nativeint.<= prim prim)) - (function prim prim stub - (Nativeint.>= prim prim))))))) diff --git a/testsuite/tests/translprim/module_coercion.ml.reference-noflat b/testsuite/tests/translprim/module_coercion.ml.reference-noflat deleted file mode 100644 index b3cc51bc..00000000 --- a/testsuite/tests/translprim/module_coercion.ml.reference-noflat +++ /dev/null @@ -1,124 +0,0 @@ -(setglobal Module_coercion! - (let - (M = (module-defn(M) module_coercion.ml(1):0-699 (makeblock 0))) - (makeblock 0 M - (module-defn(M_int) module_coercion.ml(32):1116-1155 - (makeblock 0 (function prim stub (array.length[int] prim)) - (function prim prim stub - (array.get[int] prim prim)) - (function prim prim stub - (array.unsafe_get[int] prim prim)) - (function prim prim prim stub - (array.set[int] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[int] prim prim prim)) - (function prim prim stub - (caml_int_compare prim prim)) - (function prim prim stub (== prim prim)) - (function prim prim stub (!= prim prim)) - (function prim prim stub (< prim prim)) - (function prim prim stub (> prim prim)) - (function prim prim stub (<= prim prim)) - (function prim prim stub (>= prim prim)))) - (module-defn(M_float) module_coercion.ml(33):1158-1201 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_float_compare prim prim)) - (function prim prim stub (==. prim prim)) - (function prim prim stub (!=. prim prim)) - (function prim prim stub (<. prim prim)) - (function prim prim stub (>. prim prim)) - (function prim prim stub (<=. prim prim)) - (function prim prim stub (>=. prim prim)))) - (module-defn(M_string) module_coercion.ml(34):1204-1249 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_string_compare prim prim)) - (function prim prim stub - (caml_string_equal prim prim)) - (function prim prim stub - (caml_string_notequal prim prim)) - (function prim prim stub - (caml_string_lessthan prim prim)) - (function prim prim stub - (caml_string_greaterthan prim prim)) - (function prim prim stub - (caml_string_lessequal prim prim)) - (function prim prim stub - (caml_string_greaterequal prim prim)))) - (module-defn(M_int32/1104) module_coercion.ml(35):1252-1295 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_int32_compare prim prim)) - (function prim prim stub (Int32.== prim prim)) - (function prim prim stub (Int32.!= prim prim)) - (function prim prim stub (Int32.< prim prim)) - (function prim prim stub (Int32.> prim prim)) - (function prim prim stub (Int32.<= prim prim)) - (function prim prim stub (Int32.>= prim prim)))) - (module-defn(M_int64/1129) module_coercion.ml(36):1298-1341 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_int64_compare prim prim)) - (function prim prim stub (Int64.== prim prim)) - (function prim prim stub (Int64.!= prim prim)) - (function prim prim stub (Int64.< prim prim)) - (function prim prim stub (Int64.> prim prim)) - (function prim prim stub (Int64.<= prim prim)) - (function prim prim stub (Int64.>= prim prim)))) - (module-defn(M_nativeint) module_coercion.ml(37):1344-1395 - (makeblock 0 (function prim stub (array.length[addr] prim)) - (function prim prim stub - (array.get[addr] prim prim)) - (function prim prim stub - (array.unsafe_get[addr] prim prim)) - (function prim prim prim stub - (array.set[addr] prim prim prim)) - (function prim prim prim stub - (array.unsafe_set[addr] prim prim prim)) - (function prim prim stub - (caml_nativeint_compare prim prim)) - (function prim prim stub - (Nativeint.== prim prim)) - (function prim prim stub - (Nativeint.!= prim prim)) - (function prim prim stub - (Nativeint.< prim prim)) - (function prim prim stub - (Nativeint.> prim prim)) - (function prim prim stub - (Nativeint.<= prim prim)) - (function prim prim stub - (Nativeint.>= prim prim))))))) diff --git a/testsuite/tests/translprim/ocamltests b/testsuite/tests/translprim/ocamltests new file mode 100644 index 00000000..2c3151aa --- /dev/null +++ b/testsuite/tests/translprim/ocamltests @@ -0,0 +1,5 @@ +array_spec.ml +comparison_table.ml +module_coercion.ml +ref_spec.ml +locs.ml diff --git a/testsuite/tests/translprim/ref_spec.compilers.reference b/testsuite/tests/translprim/ref_spec.compilers.reference new file mode 100644 index 00000000..72b48d4f --- /dev/null +++ b/testsuite/tests/translprim/ref_spec.compilers.reference @@ -0,0 +1,37 @@ +(setglobal Ref_spec! + (let + (int_ref = (makemutable 0 (int) 1) + var_ref = (makemutable 0 65a) + vargen_ref = (makemutable 0 65a) + cst_ref = (makemutable 0 0a) + gen_ref = (makemutable 0 0a) + flt_ref = (makemutable 0 (float) 0.)) + (seq (setfield_imm 0 int_ref 2) (setfield_imm 0 var_ref 66a) + (setfield_ptr 0 vargen_ref [0: 66 0]) (setfield_ptr 0 vargen_ref 67a) + (setfield_imm 0 cst_ref 1a) (setfield_ptr 0 gen_ref [0: "foo"]) + (setfield_ptr 0 gen_ref 0a) (setfield_ptr 0 flt_ref 1.) + (let + (int_rec = (makemutable 0 (*,int) 0a 1) + var_rec = (makemutable 0 0a 65a) + vargen_rec = (makemutable 0 0a 65a) + cst_rec = (makemutable 0 0a 0a) + gen_rec = (makemutable 0 0a 0a) + flt_rec = (makemutable 0 (*,float) 0a 0.) + flt_rec' = (makearray[float] 0. 0.)) + (seq (setfield_imm 1 int_rec 2) (setfield_imm 1 var_rec 66a) + (setfield_ptr 1 vargen_rec [0: 66 0]) + (setfield_ptr 1 vargen_rec 67a) (setfield_imm 1 cst_rec 1a) + (setfield_ptr 1 gen_rec [0: "foo"]) (setfield_ptr 1 gen_rec 0a) + (setfield_ptr 1 flt_rec 1.) (setfloatfield 1 flt_rec' 1.) + (let + (set_open_poly = (function r y (setfield_ptr 0 r y)) + set_open_poly = (function r y (setfield_imm 0 r y)) + set_open_poly = (function r y (setfield_imm 0 r y)) + set_open_poly = (function r y (setfield_imm 0 r y)) + set_open_poly = (function r y (setfield_ptr 0 r y)) + set_open_poly = (function r y (setfield_ptr 0 r y)) + set_open_poly = (function r y (setfield_ptr 0 r y)) + set_open_poly = (function r y (setfield_ptr 0 r y))) + (makeblock 0 int_ref var_ref vargen_ref cst_ref gen_ref flt_ref + int_rec var_rec vargen_rec cst_rec gen_rec flt_rec flt_rec' + set_open_poly))))))) diff --git a/testsuite/tests/translprim/ref_spec.ml b/testsuite/tests/translprim/ref_spec.ml index 068fa884..82cbd1ee 100644 --- a/testsuite/tests/translprim/ref_spec.ml +++ b/testsuite/tests/translprim/ref_spec.ml @@ -1,3 +1,10 @@ +(* TEST + * setup-ocamlc.byte-build-env + ** ocamlc.byte + flags = "-dlambda -dno-unique-ids" + *** check-ocamlc.byte-output +*) + type 'a custom_rec = { x : unit; mutable y : 'a } type float_rec = { w : float; mutable z : float } diff --git a/testsuite/tests/translprim/ref_spec.ml.reference b/testsuite/tests/translprim/ref_spec.ml.reference deleted file mode 100644 index c21b100b..00000000 --- a/testsuite/tests/translprim/ref_spec.ml.reference +++ /dev/null @@ -1,50 +0,0 @@ -(setglobal Ref_spec! - (let - (int_ref = (makemutable 0 (int) 1) - var_ref = (makemutable 0 65a) - vargen_ref = (makemutable 0 65a) - cst_ref = (makemutable 0 0a) - gen_ref = (makemutable 0 0a) - flt_ref = (makemutable 0 (float) 0.)) - (seq (setfield_imm 0 int_ref 2) (setfield_imm 0 var_ref 66a) - (setfield_ptr 0 vargen_ref [0: 66 0]) - (setfield_ptr 0 vargen_ref 67a) (setfield_imm 0 cst_ref 1a) - (setfield_ptr 0 gen_ref [0: "foo"]) - (setfield_ptr 0 gen_ref 0a) (setfield_ptr 0 flt_ref 1.) - (let - (int_rec = (makemutable 0 (*,int) 0a 1) - var_rec = (makemutable 0 0a 65a) - vargen_rec = (makemutable 0 0a 65a) - cst_rec = (makemutable 0 0a 0a) - gen_rec = (makemutable 0 0a 0a) - flt_rec = (makemutable 0 (*,float) 0a 0.) - flt_rec' = (makearray[float] 0. 0.)) - (seq (setfield_imm 1 int_rec 2) - (setfield_imm 1 var_rec 66a) - (setfield_ptr 1 vargen_rec [0: 66 0]) - (setfield_ptr 1 vargen_rec 67a) - (setfield_imm 1 cst_rec 1a) - (setfield_ptr 1 gen_rec [0: "foo"]) - (setfield_ptr 1 gen_rec 0a) (setfield_ptr 1 flt_rec 1.) - (setfloatfield 1 flt_rec' 1.) - (let - (set_open_poly = - (function r y (setfield_ptr 0 r y)) - set_open_poly = - (function r y (setfield_imm 0 r y)) - set_open_poly = - (function r y (setfield_imm 0 r y)) - set_open_poly = - (function r y (setfield_imm 0 r y)) - set_open_poly = - (function r y (setfield_ptr 0 r y)) - set_open_poly = - (function r y (setfield_ptr 0 r y)) - set_open_poly = - (function r y (setfield_ptr 0 r y)) - set_open_poly = - (function r y (setfield_ptr 0 r y))) - (makeblock 0 int_ref var_ref vargen_ref - cst_ref gen_ref flt_ref int_rec - var_rec vargen_rec cst_rec gen_rec - flt_rec flt_rec' set_open_poly))))))) diff --git a/testsuite/tests/typing-core-bugs/ocamltests b/testsuite/tests/typing-core-bugs/ocamltests new file mode 100644 index 00000000..498d4c3d --- /dev/null +++ b/testsuite/tests/typing-core-bugs/ocamltests @@ -0,0 +1,2 @@ +unit_fun_hints.ml +type_expected_explanation.ml diff --git a/testsuite/tests/typing-core-bugs/type_expected_explanation.ml b/testsuite/tests/typing-core-bugs/type_expected_explanation.ml new file mode 100644 index 00000000..97143f90 --- /dev/null +++ b/testsuite/tests/typing-core-bugs/type_expected_explanation.ml @@ -0,0 +1,177 @@ +(* TEST + flags = "-strict-sequence" + * expect +*) + +if 3 then ();; + +[%%expect{| +Line _, characters 3-4: + if 3 then ();; + ^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of an if-statement +|}];; + +fun b -> if true then (print_int b) else (if b then ());; + +[%%expect{| +Line _, characters 45-46: + fun b -> if true then (print_int b) else (if b then ());; + ^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of an if-statement +|}];; + +(* Left-to-right bias is still there: if we swap the branches, the new error + message does not show up because of propagation order. *) +fun b -> if true then (if b then ()) else (print_int b);; + +[%%expect{| +Line _, characters 53-54: + fun b -> if true then (if b then ()) else (print_int b);; + ^ +Error: This expression has type bool but an expression was expected of type + int +|}];; + +if (let x = 3 in x) then ();; + +[%%expect{| +Line _, characters 17-18: + if (let x = 3 in x) then ();; + ^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of an if-statement +|}];; + +if (if true then 3 else 4) then ();; + +[%%expect{| +Line _, characters 17-18: + if (if true then 3 else 4) then ();; + ^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of an if-statement +|}];; + +if true then 3;; + +[%%expect{| +Line _, characters 13-14: + if true then 3;; + ^ +Error: This expression has type int but an expression was expected of type + unit + because it is in the result of a conditional with no else branch +|}];; + +if (fun x -> x) then ();; + +[%%expect{| +Line _, characters 3-15: + if (fun x -> x) then ();; + ^^^^^^^^^^^^ +Error: This expression should not be a function, the expected type is +bool +because it is in the condition of an if-statement +|}];; + +while 42 do () done;; + +[%%expect{| +Line _, characters 6-8: + while 42 do () done;; + ^^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of a while-loop +|}];; + +(* -strict-sequence is required for this test to fail, otherwise only a warning + is produced *) +while true do (if true then 3 else 4) done;; + +[%%expect{| +Line _, characters 14-37: + while true do (if true then 3 else 4) done;; + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type int but an expression was expected of type + unit + because it is in the body of a while-loop +|}];; + +for i = 3. to 4 do () done;; + +[%%expect{| +Line _, characters 8-10: + for i = 3. to 4 do () done;; + ^^ +Error: This expression has type float but an expression was expected of type + int + because it is in a for-loop start index +|}];; + +for i = 3 to 4. do () done;; + +[%%expect{| +Line _, characters 13-15: + for i = 3 to 4. do () done;; + ^^ +Error: This expression has type float but an expression was expected of type + int + because it is in a for-loop stop index +|}];; + +(* -strict-sequence is required for this test to fail, otherwise only a warning + is produced *) +for i = 0 to 0 do (if true then 3 else 4) done;; + +[%%expect{| +Line _, characters 18-41: + for i = 0 to 0 do (if true then 3 else 4) done;; + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type int but an expression was expected of type + unit + because it is in the body of a for-loop +|}];; + +assert 12;; + +[%%expect{| +Line _, characters 7-9: + assert 12;; + ^^ +Error: This expression has type int but an expression was expected of type + bool + because it is in the condition of an assertion +|}];; + +(* -strict-sequence is also required for this test to fail *) +(let x = 3 in x+1); ();; + +[%%expect{| +Line _, characters 0-18: + (let x = 3 in x+1); ();; + ^^^^^^^^^^^^^^^^^^ +Error: This expression has type int but an expression was expected of type + unit + because it is in the left-hand side of a sequence +|}];; + +let ordered_list_with x y = + if x <= y then [x;y] + else if x > y then [y;x] + +[%%expect{| +Line _, characters 22-26: + else if x > y then [y;x] + ^^^^ +Error: This variant expression is expected to have type unit + because it is in the result of a conditional with no else branch + The constructor :: does not belong to type unit +|}];; diff --git a/testsuite/tests/typing-core-bugs/unit_fun_hints.ml b/testsuite/tests/typing-core-bugs/unit_fun_hints.ml new file mode 100644 index 00000000..ae7135d3 --- /dev/null +++ b/testsuite/tests/typing-core-bugs/unit_fun_hints.ml @@ -0,0 +1,73 @@ +(* TEST + flags = "-strict-sequence" + * expect +*) + +let g f = f () +let _ = g 3;; (* missing `fun () ->' *) + +[%%expect{| +val g : (unit -> 'a) -> 'a = +Line _, characters 10-11: + let _ = g 3;; (* missing `fun () ->' *) + ^ +Error: This expression has type int but an expression was expected of type + unit -> 'a + Hint: Did you forget to wrap the expression using `fun () ->'? +|}];; + + +let _ = + print_int 3; + print_newline; (* missing unit argument *) + print_int 5;; + +(* We use -strict-sequence for this test: otherwise only a warning is produced + about print_newline not being of type unit *) +[%%expect{| +Line _, characters 3-16: + print_newline; (* missing unit argument *) + ^^^^^^^^^^^^^ +Error: This expression has type unit -> unit + but an expression was expected of type unit + because it is in the left-hand side of a sequence + Hint: Did you forget to provide `()' as argument? +|}];; + +let x = read_int in (* missing unit argument *) +print_int x;; + +[%%expect{| +Line _, characters 10-11: + print_int x;; + ^ +Error: This expression has type unit -> int + but an expression was expected of type int + Hint: Did you forget to provide `()' as argument? +|}];; + +let g f = + let _ = f () in + f = 3;; + +[%%expect{| +Line _, characters 6-7: + f = 3;; + ^ +Error: This expression has type int but an expression was expected of type + unit -> 'a + Hint: Did you forget to wrap the expression using `fun () ->'? +|}];; + +let g f = + let _ = f () in + 3 = f;; + +[%%expect{| +Line _, characters 6-7: + 3 = f;; + ^ +Error: This expression has type unit -> 'a + but an expression was expected of type int + Hint: Did you forget to provide `()' as argument? +|}] diff --git a/testsuite/tests/typing-deprecated/Makefile b/testsuite/tests/typing-deprecated/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-deprecated/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-deprecated/deprecated.ml b/testsuite/tests/typing-deprecated/deprecated.ml old mode 100755 new mode 100644 index da515558..902483d7 --- a/testsuite/tests/typing-deprecated/deprecated.ml +++ b/testsuite/tests/typing-deprecated/deprecated.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + [@@@ocaml.warning "+3"];; module X: sig @@ -13,6 +17,8 @@ end = struct end;; [%%expect{| Line _, characters 9-10: + val x: t [@@ocaml.deprecated] + ^ Warning 3: deprecated: t module X : sig type t type s type u val x : t end |}] @@ -21,6 +27,8 @@ type t = X.t ;; [%%expect{| Line _, characters 9-12: + type t = X.t + ^^^ Warning 3: deprecated: X.t type t = X.t |}] @@ -29,6 +37,8 @@ let x = X.x ;; [%%expect{| Line _, characters 8-11: + let x = X.x + ^^^ Warning 3: deprecated: X.x val x : X.t = |}] @@ -39,8 +49,12 @@ type t = X.t * X.s ;; [%%expect{| Line _, characters 9-12: + type t = X.t * X.s + ^^^ Warning 3: deprecated: X.t Line _, characters 15-18: + type t = X.t * X.s + ^^^ Warning 3: deprecated: X.s type t = X.t * X.s |}] @@ -56,6 +70,8 @@ and t2 = X.s ;; [%%expect{| Line _, characters 9-12: + and t2 = X.s + ^^^ Warning 3: deprecated: X.s type t1 = X.t and t2 = X.s @@ -65,6 +81,8 @@ type t = A of t [@@ocaml.deprecated] ;; [%%expect{| Line _, characters 14-15: + type t = A of t [@@ocaml.deprecated] + ^ Warning 3: deprecated: t type t = A of t |}] @@ -89,6 +107,8 @@ type t = (X.t [@ocaml.warning "-3"]) * X.s ;; [%%expect{| Line _, characters 39-42: + type t = (X.t [@ocaml.warning "-3"]) * X.s + ^^^ Warning 3: deprecated: X.s type t = X.t * X.s |}] @@ -107,6 +127,8 @@ let _ = function (_ : X.t) -> () ;; [%%expect{| Line _, characters 22-25: + let _ = function (_ : X.t) -> () + ^^^ Warning 3: deprecated: X.t - : X.t -> unit = |}] @@ -124,6 +146,8 @@ module M = struct let x = X.x end ;; [%%expect{| Line _, characters 26-29: + module M = struct let x = X.x end + ^^^ Warning 3: deprecated: X.x module M : sig val x : X.t end |}] @@ -144,8 +168,12 @@ module M : sig val x : X.t end module rec M : sig val x: X.t end = struct let x = X.x end [%%expect{| Line _, characters 26-29: + module rec M : sig val x: X.t end = struct let x = X.x end + ^^^ Warning 3: deprecated: X.t Line _, characters 51-54: + module rec M : sig val x: X.t end = struct let x = X.x end + ^^^ Warning 3: deprecated: X.x module rec M : sig val x : X.t end |}] @@ -167,6 +195,8 @@ module rec M : struct let x = X.x end [%%expect{| Line _, characters 17-20: + struct let x = X.x end + ^^^ Warning 3: deprecated: X.x module rec M : sig val x : X.t end |}] @@ -177,6 +207,8 @@ module type S = sig type t = X.t end ;; [%%expect{| Line _, characters 29-32: + module type S = sig type t = X.t end + ^^^ Warning 3: deprecated: X.t module type S = sig type t = X.t end |}] @@ -200,6 +232,8 @@ class c = object method x = X.x end ;; [%%expect{| Line _, characters 28-31: + class c = object method x = X.x end + ^^^ Warning 3: deprecated: X.x class c : object method x : X.t end |}] @@ -229,6 +263,8 @@ class type c = object method x : X.t end ;; [%%expect{| Line _, characters 33-36: + class type c = object method x : X.t end + ^^^ Warning 3: deprecated: X.t class type c = object method x : X.t end |}] @@ -259,6 +295,8 @@ external foo: unit -> X.t = "foo" ;; [%%expect{| Line _, characters 22-25: + external foo: unit -> X.t = "foo" + ^^^ Warning 3: deprecated: X.t external foo : unit -> X.t = "foo" |}] @@ -276,6 +314,8 @@ X.x ;; [%%expect{| Line _, characters 0-3: + X.x + ^^^ Warning 3: deprecated: X.x - : X.t = |}] @@ -296,6 +336,8 @@ open D [%%expect{| module D : sig end Line _, characters 5-6: + open D + ^ Warning 3: deprecated: module D |}] @@ -308,6 +350,8 @@ include D ;; [%%expect{| Line _, characters 8-9: + include D + ^ Warning 3: deprecated: module D |}] @@ -332,6 +376,8 @@ type ext += ;; [%%expect{| Line _, characters 9-12: + | A of X.t + ^^^ Warning 3: deprecated: X.t type ext += A of X.t | B of X.s | C of X.u |}] @@ -349,6 +395,8 @@ exception Foo of X.t ;; [%%expect{| Line _, characters 17-20: + exception Foo of X.t + ^^^ Warning 3: deprecated: X.t exception Foo of X.t |}] @@ -369,6 +417,8 @@ type t = ;; [%%expect{| Line _, characters 9-12: + | A of X.t + ^^^ Warning 3: deprecated: X.t type t = A of X.t | B of X.s | C of X.u |}] @@ -382,6 +432,8 @@ type t = ;; [%%expect{| Line _, characters 7-10: + a: X.t; + ^^^ Warning 3: deprecated: X.t type t = { a : X.t; b : X.s; c : X.u; } |}] @@ -396,6 +448,8 @@ type t = ;; [%%expect{| Line _, characters 7-10: + a: X.t; + ^^^ Warning 3: deprecated: X.t type t = < a : X.t; b : X.s; c : X.u > |}] @@ -410,6 +464,8 @@ type t = ;; [%%expect{| Line _, characters 10-13: + | `A of X.t + ^^^ Warning 3: deprecated: X.t type t = [ `A of X.t | `B of X.s | `C of X.u ] |}] @@ -422,6 +478,8 @@ type t = [ `A of X.t | `B of X.s | `C of X.u ] ;; [%%expect{| Line _, characters 20-33: + [@@@ocaml.ppwarning "Pp warning!"] + ^^^^^^^^^^^^^ Warning 22: Pp warning! |}] @@ -431,8 +489,12 @@ let x = () [@ocaml.ppwarning "Pp warning 1!"] ;; [%%expect{| Line _, characters 24-39: + [@@ocaml.ppwarning "Pp warning 2!"] + ^^^^^^^^^^^^^^^ Warning 22: Pp warning 2! Line _, characters 29-44: + let x = () [@ocaml.ppwarning "Pp warning 1!"] + ^^^^^^^^^^^^^^^ Warning 22: Pp warning 1! val x : unit = () |}] @@ -442,6 +504,8 @@ type t = unit ;; [%%expect{| Line _, characters 22-35: + [@ocaml.ppwarning "Pp warning!"] + ^^^^^^^^^^^^^ Warning 22: Pp warning! type t = unit |}] @@ -458,6 +522,8 @@ end ;; [%%expect{| Line _, characters 22-36: + [@@@ocaml.ppwarning "Pp warning2!"] + ^^^^^^^^^^^^^^ Warning 22: Pp warning2! module X : sig end |}] @@ -466,6 +532,8 @@ let x = ((() [@ocaml.ppwarning "Pp warning 1!"]) [@ocaml.warning "-22"]) [@ocam ;; [%%expect{| Line _, characters 93-108: + let x = ((() [@ocaml.ppwarning "Pp warning 1!"]) [@ocaml.warning "-22"]) [@ocaml.ppwarning "Pp warning 2!"] + ^^^^^^^^^^^^^^^ Warning 22: Pp warning 2! val x : unit = () |}] @@ -475,8 +543,12 @@ type t = ((unit [@ocaml.ppwarning "Pp warning 1!"]) [@ocaml.warning "-22"]) [@o ;; [%%expect{| Line _, characters 21-36: + [@@ocaml.ppwarning "Pp warning 3!"] + ^^^^^^^^^^^^^^^ Warning 22: Pp warning 3! Line _, characters 96-111: + type t = ((unit [@ocaml.ppwarning "Pp warning 1!"]) [@ocaml.warning "-22"]) [@ocaml.ppwarning "Pp warning 2!"] + ^^^^^^^^^^^^^^^ Warning 22: Pp warning 2! type t = unit |}] @@ -485,8 +557,12 @@ let ([][@ocaml.ppwarning "XX"]) = [] ;; [%%expect{| Line _, characters 25-29: + let ([][@ocaml.ppwarning "XX"]) = [] + ^^^^ Warning 22: XX Line _, characters 4-31: + let ([][@ocaml.ppwarning "XX"]) = [] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: _::_ diff --git a/testsuite/tests/typing-deprecated/ocamltests b/testsuite/tests/typing-deprecated/ocamltests new file mode 100644 index 00000000..b8c7cb45 --- /dev/null +++ b/testsuite/tests/typing-deprecated/ocamltests @@ -0,0 +1 @@ +deprecated.ml diff --git a/testsuite/tests/typing-extension-constructor/Makefile b/testsuite/tests/typing-extension-constructor/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-extension-constructor/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-extension-constructor/ocamltests b/testsuite/tests/typing-extension-constructor/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/typing-extension-constructor/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/typing-extension-constructor/test.ml b/testsuite/tests/typing-extension-constructor/test.ml index 4c73807f..d18777c7 100644 --- a/testsuite/tests/typing-extension-constructor/test.ml +++ b/testsuite/tests/typing-extension-constructor/test.ml @@ -1,3 +1,6 @@ +(* TEST + * toplevel +*) type t = ..;; type t += A;; diff --git a/testsuite/tests/typing-extension-constructor/test.ml.reference b/testsuite/tests/typing-extension-constructor/test.ml.reference deleted file mode 100644 index 5fc7ac41..00000000 --- a/testsuite/tests/typing-extension-constructor/test.ml.reference +++ /dev/null @@ -1,12 +0,0 @@ - -# type t = .. -# type t += A -# - : extension_constructor = -# - : extension_constructor = -# module M : sig type extension_constructor = int end -# # Characters 2-28: - ([%extension_constructor A] : extension_constructor);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This expression has type extension_constructor - but an expression was expected of type M.extension_constructor = int -# diff --git a/testsuite/tests/typing-extension-constructor/test.ocaml.reference b/testsuite/tests/typing-extension-constructor/test.ocaml.reference new file mode 100644 index 00000000..f116fd3c --- /dev/null +++ b/testsuite/tests/typing-extension-constructor/test.ocaml.reference @@ -0,0 +1,11 @@ +type t = .. +type t += A +- : extension_constructor = +- : extension_constructor = +module M : sig type extension_constructor = int end +Characters 2-28: + ([%extension_constructor A] : extension_constructor);; + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type extension_constructor + but an expression was expected of type M.extension_constructor = int + diff --git a/testsuite/tests/typing-extensions/Makefile b/testsuite/tests/typing-extensions/Makefile deleted file mode 100644 index 9625a3fb..00000000 --- a/testsuite/tests/typing-extensions/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-extensions/cast.ml b/testsuite/tests/typing-extensions/cast.ml index 1efcfd50..713d86d8 100644 --- a/testsuite/tests/typing-extensions/cast.ml +++ b/testsuite/tests/typing-extensions/cast.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; diff --git a/testsuite/tests/typing-extensions/cast.ml.reference b/testsuite/tests/typing-extensions/cast.ml.reference deleted file mode 100644 index 3478d60f..00000000 --- a/testsuite/tests/typing-extensions/cast.ml.reference +++ /dev/null @@ -1,34 +0,0 @@ - -# - : unit = () -# type 'b class_name = .. constraint 'b = < cast : 'a. 'a name -> 'a; .. > -and 'a name = - Class : 'a class_name -> (< cast : 'a0. 'a0 name -> 'a0; .. > as 'a) name -# exception Bad_cast -# class type castable = object method cast : 'a name -> 'a end -# class type foo_t = object method cast : 'a name -> 'a method foo : string end -# type 'b class_name += Foo : foo_t class_name -# class foo : foo_t -# class type bar_t = - object - method bar : string - method cast : 'a name -> 'a - method foo : string - end -# type 'b class_name += Bar : bar_t class_name -# class bar : bar_t -# val clist : castable list ref = {contents = []} -# val push_castable : #castable -> unit = -# val pop_castable : unit -> castable = -# - : unit = () -# - : unit = () -# - : unit = () -# val c1 : castable = -# val c2 : castable = -# val c3 : castable = -# val f1 : foo = -# val f2 : foo = -# val f3 : foo = -# Exception: Bad_cast. -# val b2 : bar = -# Exception: Bad_cast. -# diff --git a/testsuite/tests/typing-extensions/cast.ocaml.reference b/testsuite/tests/typing-extensions/cast.ocaml.reference new file mode 100644 index 00000000..8ba5e321 --- /dev/null +++ b/testsuite/tests/typing-extensions/cast.ocaml.reference @@ -0,0 +1,33 @@ +- : unit = () +type 'b class_name = .. constraint 'b = < cast : 'a. 'a name -> 'a; .. > +and 'a name = + Class : 'a class_name -> (< cast : 'a0. 'a0 name -> 'a0; .. > as 'a) name +exception Bad_cast +class type castable = object method cast : 'a name -> 'a end +class type foo_t = object method cast : 'a name -> 'a method foo : string end +type 'b class_name += Foo : foo_t class_name +class foo : foo_t +class type bar_t = + object + method bar : string + method cast : 'a name -> 'a + method foo : string + end +type 'b class_name += Bar : bar_t class_name +class bar : bar_t +val clist : castable list ref = {contents = []} +val push_castable : #castable -> unit = +val pop_castable : unit -> castable = +- : unit = () +- : unit = () +- : unit = () +val c1 : castable = +val c2 : castable = +val c3 : castable = +val f1 : foo = +val f2 : foo = +val f3 : foo = +Exception: Bad_cast. +val b2 : bar = +Exception: Bad_cast. + diff --git a/testsuite/tests/typing-extensions/extensions.ml b/testsuite/tests/typing-extensions/extensions.ml index c921ecf2..59ea0305 100644 --- a/testsuite/tests/typing-extensions/extensions.ml +++ b/testsuite/tests/typing-extensions/extensions.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; diff --git a/testsuite/tests/typing-extensions/extensions.ml.reference b/testsuite/tests/typing-extensions/extensions.ml.reference deleted file mode 100644 index a71a8187..00000000 --- a/testsuite/tests/typing-extensions/extensions.ml.reference +++ /dev/null @@ -1,139 +0,0 @@ - -# - : unit = () -# type foo = .. -# type foo += A | B of int -# val is_a : foo -> bool = -# type foo -# Characters 1-21: - type foo += A of int (* Error type is not open *) - ^^^^^^^^^^^^^^^^^^^^ -Error: Type definition foo is not extensible -# type foo = private .. -# Characters 13-21: - type foo += A of int (* Error type is private *) - ^^^^^^^^ -Error: Cannot extend private type definition foo -# type 'a foo = .. -# Characters 1-30: - type ('a, 'b) foo += A of int (* Error: type parameter mismatch *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This extension does not match the definition of type foo - They have different arities. -# module type S = sig type foo = private .. type foo += A of float end -# Characters 73-95: - type foo += B of float (* Error: foo does not have an extensible type *) - ^^^^^^^^^^^^^^^^^^^^^^ -Error: Type definition foo is not extensible -# type foo = .. -# module M : - sig - type foo += A of int | B of string - type foo += C of int | D of float - - end -# module type S = - sig - type foo += B of string | C of int - type foo += D of float - type foo += A of int - end -# module M_S : S -# type 'a foo = .. -# type _ foo += A : int -> int foo | B : int foo -# val get_num : 'a foo -> 'a -> 'a option = -# type 'a foo = .. constraint 'a = [> `Var ] -# type 'a foo += A of 'a -# Characters 11-12: - let a = A 9 (* ERROR: Constraints not met *) - ^ -Error: This expression has type int but an expression was expected of type - [> `Var ] -# Characters 20-23: - type 'a foo += B : int foo (* ERROR: Constraints not met *) - ^^^ -Error: This type int should be an instance of type [> `Var ] -# type foo = .. -# module M : sig type foo += A of int end -# val a1 : foo = M.A 10 -# module type S = sig type foo += private A of int end -# module M_S : S -# val is_s : foo -> bool = -# Characters 10-18: - let a2 = M_S.A 20 (* ERROR: Cannot create a value using a private constructor *) - ^^^^^^^^ -Error: Cannot create values of the private type foo -# type foo = .. -# module M : sig type foo += A1 of int end -# type foo += A2 of int -# type bar = .. -# Characters 18-22: - type bar += A3 = M.A1 (* Error: rebind wrong type *) - ^^^^ -Error: The constructor M.A1 has type foo but was expected to be of type bar -# module M : sig type foo += private B1 of int end -# type foo += private B2 of int -# Characters 18-22: - type foo += B3 = M.B1 (* Error: rebind private extension *) - ^^^^ -Error: The constructor M.B1 is private -# Characters 17-24: - type foo += C = Unknown (* Error: unbound extension *) - ^^^^^^^ -Error: Unbound constructor Unknown -# module M : sig type foo = private .. type foo += A1 of int end -type M.foo += A2 of int -type 'a foo = .. -# type 'a foo1 = 'a foo = .. -# type 'a foo2 = 'a foo = .. -# type 'a foo1 += A of int | B of 'a | C : int foo1 -# type 'a foo2 += D of int | E of 'a | F : int foo2 -# type +'a foo = .. -# type 'a foo += A of (int -> 'a) -# Characters 1-32: - type 'a foo += B of ('a -> int) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: In this definition, expected parameter variances are not satisfied. - The 1st type parameter was expected to be covariant, - but it is injective contravariant. -# Characters 1-40: - type _ foo += C : ('a -> int) -> 'a foo - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: In this definition, expected parameter variances are not satisfied. - The 1st type parameter was expected to be covariant, - but it is injective contravariant. -# type 'a bar = .. -# Characters 1-33: - type +'a bar += D of (int -> 'a) (* ERROR: type variances do not match *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This extension does not match the definition of type bar - Their variances do not agree. -# module M : sig type exn += Foo of int * float | Bar : 'a list -> exn end -# module M : - sig exception Bar : 'a list -> exn exception Foo of int * float end -# exception Foo of int * float -# exception Bar : 'a list -> exn -# module M : sig type exn += Foo of int * float | Bar : 'a list -> exn end -# type foo = .. -# type foo += Foo of int * int option | Bar of int option -# val x : foo * foo = (Foo (3, Some 4), Bar (Some 5)) -# type foo += Foo of string -# val y : foo * foo = (, Bar (Some 5)) -# exception Foo of int * int option -# exception Bar of int option -# val x : exn * exn = (Foo (3, Some 4), Bar (Some 5)) -# type foo += Foo of string -# val y : exn * exn = (Foo (3, _), Bar (Some 5)) -# type foo = .. -# type foo += Foo | Bar of int -# val extension_name : 'a -> string = -# val extension_id : 'a -> int = -# val n1 : string = "Foo" -# val n2 : string = "Bar" -# val t : bool = true -# val f : bool = false -# val is_foo : 'a -> bool = -type foo += Foo -# val f : bool = false -# Exception: Invalid_argument "Obj.extension_constructor". -# Exception: Invalid_argument "Obj.extension_constructor". -# diff --git a/testsuite/tests/typing-extensions/extensions.ocaml.reference b/testsuite/tests/typing-extensions/extensions.ocaml.reference new file mode 100644 index 00000000..6d55712e --- /dev/null +++ b/testsuite/tests/typing-extensions/extensions.ocaml.reference @@ -0,0 +1,138 @@ +- : unit = () +type foo = .. +type foo += A | B of int +val is_a : foo -> bool = +type foo +Characters 1-21: + type foo += A of int (* Error type is not open *) + ^^^^^^^^^^^^^^^^^^^^ +Error: Type definition foo is not extensible +type foo = private .. +Characters 13-21: + type foo += A of int (* Error type is private *) + ^^^^^^^^ +Error: Cannot extend private type definition foo +type 'a foo = .. +Characters 1-30: + type ('a, 'b) foo += A of int (* Error: type parameter mismatch *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This extension does not match the definition of type foo + They have different arities. +module type S = sig type foo = private .. type foo += A of float end +Characters 73-95: + type foo += B of float (* Error: foo does not have an extensible type *) + ^^^^^^^^^^^^^^^^^^^^^^ +Error: Type definition foo is not extensible +type foo = .. +module M : + sig + type foo += A of int | B of string + type foo += C of int | D of float + + end +module type S = + sig + type foo += B of string | C of int + type foo += D of float + type foo += A of int + end +module M_S : S +type 'a foo = .. +type _ foo += A : int -> int foo | B : int foo +val get_num : 'a foo -> 'a -> 'a option = +type 'a foo = .. constraint 'a = [> `Var ] +type 'a foo += A of 'a +Characters 11-12: + let a = A 9 (* ERROR: Constraints not met *) + ^ +Error: This expression has type int but an expression was expected of type + [> `Var ] +Characters 20-23: + type 'a foo += B : int foo (* ERROR: Constraints not met *) + ^^^ +Error: This type int should be an instance of type [> `Var ] +type foo = .. +module M : sig type foo += A of int end +val a1 : foo = M.A 10 +module type S = sig type foo += private A of int end +module M_S : S +val is_s : foo -> bool = +Characters 10-18: + let a2 = M_S.A 20 (* ERROR: Cannot create a value using a private constructor *) + ^^^^^^^^ +Error: Cannot create values of the private type foo +type foo = .. +module M : sig type foo += A1 of int end +type foo += A2 of int +type bar = .. +Characters 18-22: + type bar += A3 = M.A1 (* Error: rebind wrong type *) + ^^^^ +Error: The constructor M.A1 has type foo but was expected to be of type bar +module M : sig type foo += private B1 of int end +type foo += private B2 of int +Characters 18-22: + type foo += B3 = M.B1 (* Error: rebind private extension *) + ^^^^ +Error: The constructor M.B1 is private +Characters 17-24: + type foo += C = Unknown (* Error: unbound extension *) + ^^^^^^^ +Error: Unbound constructor Unknown +module M : sig type foo = private .. type foo += A1 of int end +type M.foo += A2 of int +type 'a foo = .. +type 'a foo1 = 'a foo = .. +type 'a foo2 = 'a foo = .. +type 'a foo1 += A of int | B of 'a | C : int foo1 +type 'a foo2 += D of int | E of 'a | F : int foo2 +type +'a foo = .. +type 'a foo += A of (int -> 'a) +Characters 1-32: + type 'a foo += B of ('a -> int) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: In this definition, expected parameter variances are not satisfied. + The 1st type parameter was expected to be covariant, + but it is injective contravariant. +Characters 1-40: + type _ foo += C : ('a -> int) -> 'a foo + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: In this definition, expected parameter variances are not satisfied. + The 1st type parameter was expected to be covariant, + but it is injective contravariant. +type 'a bar = .. +Characters 1-33: + type +'a bar += D of (int -> 'a) (* ERROR: type variances do not match *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This extension does not match the definition of type bar + Their variances do not agree. +module M : sig type exn += Foo of int * float | Bar : 'a list -> exn end +module M : + sig exception Bar : 'a list -> exn exception Foo of int * float end +exception Foo of int * float +exception Bar : 'a list -> exn +module M : sig type exn += Foo of int * float | Bar : 'a list -> exn end +type foo = .. +type foo += Foo of int * int option | Bar of int option +val x : foo * foo = (Foo (3, Some 4), Bar (Some 5)) +type foo += Foo of string +val y : foo * foo = (, Bar (Some 5)) +exception Foo of int * int option +exception Bar of int option +val x : exn * exn = (Foo (3, Some 4), Bar (Some 5)) +type foo += Foo of string +val y : exn * exn = (Foo (3, _), Bar (Some 5)) +type foo = .. +type foo += Foo | Bar of int +val extension_name : 'a -> string = +val extension_id : 'a -> int = +val n1 : string = "Foo" +val n2 : string = "Bar" +val t : bool = true +val f : bool = false +val is_foo : 'a -> bool = +type foo += Foo +val f : bool = false +Exception: Invalid_argument "Obj.extension_constructor". +Exception: Invalid_argument "Obj.extension_constructor". + diff --git a/testsuite/tests/typing-extensions/msg.ml b/testsuite/tests/typing-extensions/msg.ml index c8453351..da50613c 100644 --- a/testsuite/tests/typing-extensions/msg.ml +++ b/testsuite/tests/typing-extensions/msg.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Typed names *) module Msg : sig diff --git a/testsuite/tests/typing-extensions/msg.ml.reference b/testsuite/tests/typing-extensions/msg.ml.reference deleted file mode 100644 index 27f15ea7..00000000 --- a/testsuite/tests/typing-extensions/msg.ml.reference +++ /dev/null @@ -1,23 +0,0 @@ - -# module Msg : - sig - type 'a tag = private .. - type result = Result : 'a tag * 'a -> result - val write : 'a tag -> 'a -> unit - val read : unit -> result - type 'a tag += Int : int tag - module type Desc = - sig - type t - val label : string - val write : t -> string - val read : string -> t - end - module Define : functor (D : Desc) -> sig type 'a tag += C : D.t tag end - end -# val write_int : int -> unit = -# module StrM : sig type 'a Msg.tag += C : string Msg.tag end -# type 'a Msg.tag += String : string Msg.tag -# val write_string : string -> unit = -# val read_one : unit -> unit = -# diff --git a/testsuite/tests/typing-extensions/msg.ocaml.reference b/testsuite/tests/typing-extensions/msg.ocaml.reference new file mode 100644 index 00000000..c5ed56b3 --- /dev/null +++ b/testsuite/tests/typing-extensions/msg.ocaml.reference @@ -0,0 +1,22 @@ +module Msg : + sig + type 'a tag = private .. + type result = Result : 'a tag * 'a -> result + val write : 'a tag -> 'a -> unit + val read : unit -> result + type 'a tag += Int : int tag + module type Desc = + sig + type t + val label : string + val write : t -> string + val read : string -> t + end + module Define : functor (D : Desc) -> sig type 'a tag += C : D.t tag end + end +val write_int : int -> unit = +module StrM : sig type 'a Msg.tag += C : string Msg.tag end +type 'a Msg.tag += String : string Msg.tag +val write_string : string -> unit = +val read_one : unit -> unit = + diff --git a/testsuite/tests/typing-extensions/ocamltests b/testsuite/tests/typing-extensions/ocamltests new file mode 100644 index 00000000..24414ead --- /dev/null +++ b/testsuite/tests/typing-extensions/ocamltests @@ -0,0 +1,4 @@ +cast.ml +extensions.ml +msg.ml +open_types.ml diff --git a/testsuite/tests/typing-extensions/open_types.ml b/testsuite/tests/typing-extensions/open_types.ml index 0f9038d1..d1129878 100644 --- a/testsuite/tests/typing-extensions/open_types.ml +++ b/testsuite/tests/typing-extensions/open_types.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + type foo = .. ;; diff --git a/testsuite/tests/typing-extensions/open_types.ml.reference b/testsuite/tests/typing-extensions/open_types.ml.reference deleted file mode 100644 index 4b9e8f6f..00000000 --- a/testsuite/tests/typing-extensions/open_types.ml.reference +++ /dev/null @@ -1,124 +0,0 @@ - -# type foo = .. -# type bar = foo = .. -# type baz = foo = .. -# type bar += Bar1 of int -# type baz += Bar2 of int -# module M : sig type bar += Foo of float end -# module type S = sig type baz += Foo of float end -# module M_S : S -# type foo = .. -# type bar = foo -# Characters 1-23: - type bar += Bar of int (* Error: type is not open *) - ^^^^^^^^^^^^^^^^^^^^^^ -Error: Type definition bar is not extensible -# Characters 1-20: - type baz = bar = .. (* Error: type kinds don't match *) - ^^^^^^^^^^^^^^^^^^^ -Error: This variant or record definition does not match that of type bar - Their kinds differ. -# type 'a foo = .. -# Characters 1-32: - type ('a, 'b) bar = 'a foo = .. (* Error: arrities do not match *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This variant or record definition does not match that of type 'a foo - They have different arities. -# type ('a, 'b) foo = .. -# Characters 1-38: - type ('a, 'b) bar = ('a, 'a) foo = .. (* Error: constraints do not match *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This variant or record definition does not match that of type - ('a, 'a) foo - Their constraints differ. -# module M : sig type foo = .. end -# module type S = sig type foo end -# module M_S : S -# Characters 1-20: - type M_S.foo += Foo (* ERROR: Cannot extend a type that isn't "open" *) - ^^^^^^^^^^^^^^^^^^^ -Error: Type definition M_S.foo is not extensible -# module M : sig type foo end -# module type S = sig type foo = .. end -# Characters 15-16: - module M_S = (M : S) (* ERROR: Signatures are not compatible *) - ^ -Error: Signature mismatch: - Modules do not match: sig type foo = M.foo end is not included in S - Type declarations do not match: - type foo = M.foo - is not included in - type foo = .. - Their kinds differ. -# module M : sig type foo = .. end -# module type S = sig type foo = private .. end -# module M_S : S -# Characters 17-20: - type M_S.foo += Foo (* ERROR: Cannot extend a private extensible type *) - ^^^ -Error: Cannot extend private type definition M_S.foo -# module M : sig type foo = private .. end -# module type S = sig type foo = .. end -# Characters 15-16: - module M_S = (M : S) (* ERROR: Signatures are not compatible *) - ^ -Error: Signature mismatch: - Modules do not match: - sig type foo = M.foo = private .. end - is not included in - S - Type declarations do not match: - type foo = M.foo = private .. - is not included in - type foo = .. - A private type would be revealed. -# module M : sig type +'a foo = .. type 'a bar = 'a foo = .. end -# module type S = sig type 'a foo = .. type 'a bar = 'a foo = .. end -# Characters 15-16: - module M_S = (M : S) (* ERROR: Signatures are not compatible *) - ^ -Error: Signature mismatch: - Modules do not match: - sig type 'a foo = 'a M.foo = .. type 'a bar = 'a foo = .. end - is not included in - S - Type declarations do not match: - type 'a foo = 'a M.foo = .. - is not included in - type 'a foo = .. - Their variances do not agree. -# type exn2 = exn = .. -# Characters 61-79: - let f = function Foo -> () - ^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -*extension* -Matching over values of extensible variant types (the *extension* above) -must include a wild card pattern in order to be exhaustive. -type foo = .. -type foo += Foo -val f : foo -> unit = -# Characters 44-96: - ........function - | [Foo] -> 1 - | _::_::_ -> 3 - | [] -> 2 -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -*extension*::[] -Matching over values of extensible variant types (the *extension* above) -must include a wild card pattern in order to be exhaustive. -val f : foo list -> int = -# type t = .. -type t += IPair : (int * int) -> t -# Characters 9-63: - let f = function IPair (i, j) -> Format.sprintf "(%d, %d)" i j ;; (* warn *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -*extension* -Matching over values of extensible variant types (the *extension* above) -must include a wild card pattern in order to be exhaustive. -val f : t -> string = -# diff --git a/testsuite/tests/typing-extensions/open_types.ocaml.reference b/testsuite/tests/typing-extensions/open_types.ocaml.reference new file mode 100644 index 00000000..fc44f884 --- /dev/null +++ b/testsuite/tests/typing-extensions/open_types.ocaml.reference @@ -0,0 +1,123 @@ +type foo = .. +type bar = foo = .. +type baz = foo = .. +type bar += Bar1 of int +type baz += Bar2 of int +module M : sig type bar += Foo of float end +module type S = sig type baz += Foo of float end +module M_S : S +type foo = .. +type bar = foo +Characters 1-23: + type bar += Bar of int (* Error: type is not open *) + ^^^^^^^^^^^^^^^^^^^^^^ +Error: Type definition bar is not extensible +Characters 1-20: + type baz = bar = .. (* Error: type kinds don't match *) + ^^^^^^^^^^^^^^^^^^^ +Error: This variant or record definition does not match that of type bar + Their kinds differ. +type 'a foo = .. +Characters 1-32: + type ('a, 'b) bar = 'a foo = .. (* Error: arrities do not match *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This variant or record definition does not match that of type 'a foo + They have different arities. +type ('a, 'b) foo = .. +Characters 1-38: + type ('a, 'b) bar = ('a, 'a) foo = .. (* Error: constraints do not match *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This variant or record definition does not match that of type + ('a, 'a) foo + Their constraints differ. +module M : sig type foo = .. end +module type S = sig type foo end +module M_S : S +Characters 1-20: + type M_S.foo += Foo (* ERROR: Cannot extend a type that isn't "open" *) + ^^^^^^^^^^^^^^^^^^^ +Error: Type definition M_S.foo is not extensible +module M : sig type foo end +module type S = sig type foo = .. end +Characters 15-16: + module M_S = (M : S) (* ERROR: Signatures are not compatible *) + ^ +Error: Signature mismatch: + Modules do not match: sig type foo = M.foo end is not included in S + Type declarations do not match: + type foo = M.foo + is not included in + type foo = .. + Their kinds differ. +module M : sig type foo = .. end +module type S = sig type foo = private .. end +module M_S : S +Characters 17-20: + type M_S.foo += Foo (* ERROR: Cannot extend a private extensible type *) + ^^^ +Error: Cannot extend private type definition M_S.foo +module M : sig type foo = private .. end +module type S = sig type foo = .. end +Characters 15-16: + module M_S = (M : S) (* ERROR: Signatures are not compatible *) + ^ +Error: Signature mismatch: + Modules do not match: + sig type foo = M.foo = private .. end + is not included in + S + Type declarations do not match: + type foo = M.foo = private .. + is not included in + type foo = .. + A private type would be revealed. +module M : sig type +'a foo = .. type 'a bar = 'a foo = .. end +module type S = sig type 'a foo = .. type 'a bar = 'a foo = .. end +Characters 15-16: + module M_S = (M : S) (* ERROR: Signatures are not compatible *) + ^ +Error: Signature mismatch: + Modules do not match: + sig type 'a foo = 'a M.foo = .. type 'a bar = 'a foo = .. end + is not included in + S + Type declarations do not match: + type 'a foo = 'a M.foo = .. + is not included in + type 'a foo = .. + Their variances do not agree. +type exn2 = exn = .. +Characters 61-79: + let f = function Foo -> () + ^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +*extension* +Matching over values of extensible variant types (the *extension* above) +must include a wild card pattern in order to be exhaustive. +type foo = .. +type foo += Foo +val f : foo -> unit = +Characters 44-96: + ........function + | [Foo] -> 1 + | _::_::_ -> 3 + | [] -> 2 +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +*extension*::[] +Matching over values of extensible variant types (the *extension* above) +must include a wild card pattern in order to be exhaustive. +val f : foo list -> int = +type t = .. +type t += IPair : (int * int) -> t +Characters 9-63: + let f = function IPair (i, j) -> Format.sprintf "(%d, %d)" i j ;; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +*extension* +Matching over values of extensible variant types (the *extension* above) +must include a wild card pattern in order to be exhaustive. +val f : t -> string = + diff --git a/testsuite/tests/typing-fstclassmod/Makefile b/testsuite/tests/typing-fstclassmod/Makefile deleted file mode 100644 index 3f32b3dc..00000000 --- a/testsuite/tests/typing-fstclassmod/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -#MODULES= -MAIN_MODULE=fstclassmod -ADD_COMPFLAGS=-w A -warn-error A - -include $(BASEDIR)/makefiles/Makefile.one -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-fstclassmod/fstclassmod.ml b/testsuite/tests/typing-fstclassmod/fstclassmod.ml index a291a4c7..1e5c531c 100644 --- a/testsuite/tests/typing-fstclassmod/fstclassmod.ml +++ b/testsuite/tests/typing-fstclassmod/fstclassmod.ml @@ -1,3 +1,7 @@ +(* TEST + flags = "-w A -warn-error A" +*) + (* Example of algorithm parametrized with modules *) let sort (type s) set l = diff --git a/testsuite/tests/typing-fstclassmod/ocamltests b/testsuite/tests/typing-fstclassmod/ocamltests new file mode 100644 index 00000000..c5ee22bd --- /dev/null +++ b/testsuite/tests/typing-fstclassmod/ocamltests @@ -0,0 +1 @@ +fstclassmod.ml diff --git a/testsuite/tests/typing-gadts/Makefile b/testsuite/tests/typing-gadts/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-gadts/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-gadts/ambiguity.ml b/testsuite/tests/typing-gadts/ambiguity.ml new file mode 100644 index 00000000..20e923a0 --- /dev/null +++ b/testsuite/tests/typing-gadts/ambiguity.ml @@ -0,0 +1,198 @@ +(* TEST + * expect +*) + +[@@@warning "-8-11-12"] (* reduce the noise. *) + +type ('a, 'b) eq = Refl : ('a, 'a) eq;; +[%%expect{| +type ('a, 'b) eq = Refl : ('a, 'a) eq +|}];; + +let ret_e1 (type a b) (b : bool) (wit : (a, b) eq) (x : a) (y : b) = + match wit with + | Refl -> if b then x else y + | _ -> x +;; +[%%expect{| +Line _, characters 29-30: + | Refl -> if b then x else y + ^ +Error: This expression has type b = a but an expression was expected of type + a + This instance of a is ambiguous: + it would escape the scope of its equation +|}] + +let ret_e2 (type a b) (b : bool) (wit : (a, b) eq) (x : a) (y : b) = + match wit with + | Refl -> if b then x else y + | _ -> y +;; +[%%expect{| +Line _, characters 29-30: + | Refl -> if b then x else y + ^ +Error: This expression has type b = a but an expression was expected of type + a + This instance of a is ambiguous: + it would escape the scope of its equation +|}] + +let ret_ei1 (type a) (b : bool) (wit : (a, int) eq) (x : a) = + match wit with + | Refl -> if b then x else 0 + | _ -> x +;; +[%%expect{| +Line _, characters 29-30: + | Refl -> if b then x else 0 + ^ +Error: This expression has type int but an expression was expected of type + a = int + This instance of int is ambiguous: + it would escape the scope of its equation +|}] + +let ret_ei2 (type a) (b : bool) (wit : (a, int) eq) (x : a) = + match wit with + | Refl -> if b then x else 0 + | _ -> x +;; +[%%expect{| +Line _, characters 29-30: + | Refl -> if b then x else 0 + ^ +Error: This expression has type int but an expression was expected of type + a = int + This instance of int is ambiguous: + it would escape the scope of its equation +|}] + + +let ret_f (type a b) (wit : (a, b) eq) (x : a) (y : b) = + match wit with + | Refl -> [x; y] + | _ -> [x] +;; +[%%expect{| +Line _, characters 16-17: + | Refl -> [x; y] + ^ +Error: This expression has type b = a but an expression was expected of type + a + This instance of a is ambiguous: + it would escape the scope of its equation +|}] + +let ret_g1 (type a b) (wit : (a, b) eq) (x : a) (y : b) = + match wit with + | Refl -> [x; y] + | _ -> [y] +;; +[%%expect{| +Line _, characters 16-17: + | Refl -> [x; y] + ^ +Error: This expression has type b = a but an expression was expected of type + a + This instance of a is ambiguous: + it would escape the scope of its equation +|}] + +(* First reported in MPR#7617: the typechecker arbitrarily picks a + representative for an ambivalent type escaping its scope. + The commit that was implemented poses problems of its own: we are now + unifying the type of the patterns in the environment of each pattern, instead + of the outter one. The code discussed in PR#7617 passes because each branch + contains the same equation, but consider the following cases: *) + +let f (type a b) (x : (a, b) eq) = + match x, [] with + | Refl, [(_ : a) | (_ : b)] -> [] + | _, [(_ : a)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +let g1 (type a b) (x : (a, b) eq) = + match x, [] with + | Refl, [(_ : a) | (_ : b)] -> [] + | _, [(_ : b)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +let g2 (type a b) (x : (a, b) eq) = + match x, [] with + | Refl, [(_ : b) | (_ : a)] -> [] + | _, [(_ : a)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : b) | (_ : a)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +let h1 (type a b) (x : (a, b) eq) = + match x, [] with + | _, [(_ : a)] -> [] + | Refl, [(_ : a) | (_ : b)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +let h2 (type a b) (x : (a, b) eq) = + match x, [] with + | _, [(_ : b)] -> [] + | Refl, [(_ : a) | (_ : b)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +let h3 (type a b) (x : (a, b) eq) = + match x, [] with + | _, [(_ : a)] -> [] + | Refl, [(_ : b) | (_ : a)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : b) | (_ : a)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] diff --git a/testsuite/tests/typing-gadts/didier.ml b/testsuite/tests/typing-gadts/didier.ml index cab57d2b..749ae667 100644 --- a/testsuite/tests/typing-gadts/didier.ml +++ b/testsuite/tests/typing-gadts/didier.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type 'a ty = | Int : int ty | Bool : bool ty @@ -9,6 +13,8 @@ let fbool (type t) (x : t) (tag : t ty) = [%%expect{| type 'a ty = Int : int ty | Bool : bool ty Line _, characters 2-30: + ..match tag with + | Bool -> x Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Int @@ -23,6 +29,8 @@ let fint (type t) (x : t) (tag : t ty) = ;; [%%expect{| Line _, characters 2-33: + ..match tag with + | Int -> x > 0 Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Bool @@ -42,6 +50,8 @@ let f (type t) (x : t) (tag : t ty) = val f : 'a -> 'a ty -> bool = |}, Principal{| Line _, characters 12-13: + | Bool -> x + ^ Error: This expression has type t but an expression was expected of type bool |}];; (* val f : 'a -> 'a ty -> bool = *) @@ -54,10 +64,14 @@ let g (type t) (x : t) (tag : t ty) = ;; [%%expect{| Line _, characters 11-16: + | Int -> x > 0 + ^^^^^ Error: This expression has type bool but an expression was expected of type t = int |}, Principal{| Line _, characters 11-16: + | Int -> x > 0 + ^^^^^ Error: This expression has type bool but an expression was expected of type t |}];; (* Error: This expression has type bool but an expression was expected of type diff --git a/testsuite/tests/typing-gadts/dynamic_frisch.ml b/testsuite/tests/typing-gadts/dynamic_frisch.ml index 112c161b..7af47672 100644 --- a/testsuite/tests/typing-gadts/dynamic_frisch.ml +++ b/testsuite/tests/typing-gadts/dynamic_frisch.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Encoding generics using GADTs *) (* (c) Alain Frisch / Lexifi *) (* cf. http://www.lexifi.com/blog/dynamic-types *) @@ -598,6 +602,8 @@ let ty_list : type a e. (a,e) ty -> (a vlist,e) ty = fun t -> ;; [%%expect{| Line _, characters 41-58: + | "Cons", Some (Tdyn (Pair (_, Var), (p : a * a vlist))) -> `Cons p))) + ^^^^^^^^^^^^^^^^^ Error: This pattern matches values of type a * a vlist but a pattern was expected which matches values of type $Tdyn_'a = $0 * $1 diff --git a/testsuite/tests/typing-gadts/nested_equations.ml b/testsuite/tests/typing-gadts/nested_equations.ml index 4039e358..ffb7084c 100644 --- a/testsuite/tests/typing-gadts/nested_equations.ml +++ b/testsuite/tests/typing-gadts/nested_equations.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Tests for nested equations (bind abstract types from other modules) *) type _ t = Int : int t;; @@ -13,6 +17,8 @@ let f_bool (x : bool) : int = let Int = w_bool in x;; (* fail *) [%%expect{| val w_bool : bool t = Int Line _, characters 34-37: + let f_bool (x : bool) : int = let Int = w_bool in x;; (* fail *) + ^^^ Error: This pattern matches values of type int t but a pattern was expected which matches values of type bool t Type int is not compatible with type bool @@ -30,6 +36,8 @@ let f_spec (x : Arg.spec) : int = let Int = w_spec in x;; (* fail *) [%%expect{| val w_spec : Arg.spec t = Int Line _, characters 38-41: + let f_spec (x : Arg.spec) : int = let Int = w_spec in x;; (* fail *) + ^^^ Error: This pattern matches values of type int t but a pattern was expected which matches values of type Arg.spec t Type int is not compatible with type Arg.spec diff --git a/testsuite/tests/typing-gadts/ocamltests b/testsuite/tests/typing-gadts/ocamltests new file mode 100644 index 00000000..ace6ac47 --- /dev/null +++ b/testsuite/tests/typing-gadts/ocamltests @@ -0,0 +1,48 @@ +ambiguity.ml +didier.ml +dynamic_frisch.ml +nested_equations.ml +omega07.ml +pr5332.ml +pr5689.ml +pr5785.ml +pr5848.ml +pr5906.ml +pr5948.ml +pr5981.ml +pr5985.ml +pr5989.ml +pr5997.ml +pr6158.ml +pr6163.ml +pr6174.ml +pr6241.ml +pr6690.ml +pr6817.ml +pr6934.ml +pr6980.ml +pr6993_bad.ml +pr7016.ml +pr7160.ml +pr7214.ml +pr7222.ml +pr7230.ml +pr7234.ml +pr7260.ml +pr7269.ml +pr7298.ml +pr7374.ml +pr7378.ml +pr7381.ml +pr7390.ml +pr7391.ml +pr7397.ml +pr7421.ml +pr7432.ml +pr7618.ml +pr7747.ml +term-conv.ml +test.ml +unify_mb.ml +variables_in_mcomp.ml +yallop_bugs.ml diff --git a/testsuite/tests/typing-gadts/omega07.ml b/testsuite/tests/typing-gadts/omega07.ml index 5fd175c3..a8a78b17 100644 --- a/testsuite/tests/typing-gadts/omega07.ml +++ b/testsuite/tests/typing-gadts/omega07.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* An attempt at encoding omega examples from the 2nd Central European Functional Programming School: diff --git a/testsuite/tests/typing-gadts/pr5332.ml b/testsuite/tests/typing-gadts/pr5332.ml index e0c77acd..9747cb9b 100644 --- a/testsuite/tests/typing-gadts/pr5332.ml +++ b/testsuite/tests/typing-gadts/pr5332.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type ('env, 'a) var = | Zero : ('a * 'env, 'a) var | Succ : ('env, 'a) var -> ('b * 'env, 'a) var @@ -23,6 +27,8 @@ type ('env, 'a) typ = | Tbool : ('env, bool) typ | Tvar : ('env, 'a) var -> ('env, 'a) typ Line _, characters 5-6: + | _ -> . (* error *) + ^ Error: This match case could not be refuted. Here is an example of a value that would reach it: (Tint, Tvar Zero) |}];; diff --git a/testsuite/tests/typing-gadts/pr5689.ml b/testsuite/tests/typing-gadts/pr5689.ml index 748212d4..49375c0f 100644 --- a/testsuite/tests/typing-gadts/pr5689.ml +++ b/testsuite/tests/typing-gadts/pr5689.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type inkind = [ `Link | `Nonlink ] type _ inline_t = @@ -97,6 +101,8 @@ let rec process : type a. a linkp2 -> ast_t -> a inline_t = [%%expect{| type _ linkp2 = Kind : 'a linkp -> ([< inkind ] as 'a) linkp2 Line _, characters 35-43: + | (Kind _, Ast_Text txt) -> Text txt + ^^^^^^^^ Error: This expression has type ([< inkind > `Nonlink ] as 'a) inline_t but an expression was expected of type a inline_t Type 'a = [< `Link | `Nonlink > `Nonlink ] is not compatible with type diff --git a/testsuite/tests/typing-gadts/pr5785.ml b/testsuite/tests/typing-gadts/pr5785.ml index 9624adcd..671f88cc 100644 --- a/testsuite/tests/typing-gadts/pr5785.ml +++ b/testsuite/tests/typing-gadts/pr5785.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module Add (T : sig type two end) = struct type _ t = @@ -10,6 +14,9 @@ struct end;; [%%expect{| Line _, characters 43-100: + ...........................................function + | One, One -> "two" + | Two, Two -> "four" Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Two, One) diff --git a/testsuite/tests/typing-gadts/pr5848.ml b/testsuite/tests/typing-gadts/pr5848.ml index d1ebbdf5..1c908d78 100644 --- a/testsuite/tests/typing-gadts/pr5848.ml +++ b/testsuite/tests/typing-gadts/pr5848.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module B : sig type (_, _) t = Eq: ('a, 'a) t val f: 'a -> 'b -> ('a, 'b) t @@ -15,6 +19,5 @@ let of_type: type a. a -> a = fun x -> [%%expect{| module B : sig type (_, _) t = Eq : ('a, 'a) t val f : 'a -> 'b -> ('a, 'b) t end -Line _, characters 4-6: -Error: The GADT constructor Eq of type B.t must be qualified in this pattern. +val of_type : 'a -> 'a = |}];; diff --git a/testsuite/tests/typing-gadts/pr5906.ml b/testsuite/tests/typing-gadts/pr5906.ml index a9541265..b3c19827 100644 --- a/testsuite/tests/typing-gadts/pr5906.ml +++ b/testsuite/tests/typing-gadts/pr5906.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type _ constant = | Int: int -> int constant | Bool: bool -> bool constant @@ -24,6 +28,11 @@ type (_, _, _) binop = | Leq : ('a, 'a, bool) binop | Add : (int, int, int) binop Line _, characters 2-195: + ..match bop, x, y with + | Eq, Bool x, Bool y -> Bool (if x then y else not y) + | Leq, Int x, Int y -> Bool (x <= y) + | Leq, Bool x, Bool y -> Bool (x <= y) + | Add, Int x, Int y -> Int (x + y) Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Eq, Int _, _) diff --git a/testsuite/tests/typing-gadts/pr5948.ml b/testsuite/tests/typing-gadts/pr5948.ml index 52477628..59852564 100644 --- a/testsuite/tests/typing-gadts/pr5948.ml +++ b/testsuite/tests/typing-gadts/pr5948.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type tag = [`TagA | `TagB | `TagC];; type 'a poly = @@ -36,6 +40,8 @@ val intAorB : [< `TagA of int | `TagB ] -> int = type _ wrapPoly = WrapPoly : 'a poly -> ([< `TagA of int | `TagB ] as 'a) wrapPoly Line _, characters 23-27: + | WrapPoly ATag -> intA + ^^^^ Error: This expression has type ([< `TagA of 'b ] as 'a) -> 'b but an expression was expected of type a -> int Type [< `TagA of 'b ] as 'a is not compatible with type @@ -47,5 +53,7 @@ let _ = example6 (WrapPoly AandBTags) `TagB (* This causes a seg fault *) ;; [%%expect{| Line _, characters 9-17: + let _ = example6 (WrapPoly AandBTags) `TagB (* This causes a seg fault *) + ^^^^^^^^ Error: Unbound value example6 |}];; diff --git a/testsuite/tests/typing-gadts/pr5981.ml b/testsuite/tests/typing-gadts/pr5981.ml index bda9a883..4d6d69e9 100644 --- a/testsuite/tests/typing-gadts/pr5981.ml +++ b/testsuite/tests/typing-gadts/pr5981.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module F(S : sig type 'a t end) = struct type _ ab = A : int S.t ab @@ -9,6 +13,8 @@ module F(S : sig type 'a t end) = struct end;; [%%expect{| Line _, characters 47-84: + ...............................................match l, r with + | A, B -> "f A B" Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (A, A) @@ -34,6 +40,8 @@ module F(S : sig type 'a t end) = struct end;; [%%expect{| Line _, characters 15-52: + ...............match l, r with + | A, B -> "f A B" Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (A, A) diff --git a/testsuite/tests/typing-gadts/pr5985.ml b/testsuite/tests/typing-gadts/pr5985.ml index 0243887f..06c5125b 100644 --- a/testsuite/tests/typing-gadts/pr5985.ml +++ b/testsuite/tests/typing-gadts/pr5985.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Report from Jeremy Yallop *) module F (S : sig type 'a s end) = struct include S @@ -5,6 +9,8 @@ module F (S : sig type 'a s end) = struct end;; (* fail *) [%%expect{| Line _, characters 2-29: + type _ t = T : 'a -> 'a s t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -32,6 +38,8 @@ module F(T:sig type 'a t end) = struct end;; (* fail *) [%%expect{| Line _, characters 2-86: + ..class ['a] c x = + object constraint 'a = 'b T.t val x' : 'b = x method x = x' end Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -44,6 +52,8 @@ let magic (x : int) : bool = x;; (* fail *) [%%expect{| Line _, characters 0-49: + type 'x t = A of 'a constraint 'x = [< `X of 'a ] ;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -51,6 +61,8 @@ Error: In this definition, a type variable cannot be deduced type 'a t = A : 'a -> [< `X of 'a ] t;; (* fail *) [%%expect{| Line _, characters 0-37: + type 'a t = A : 'a -> [< `X of 'a ] t;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -66,6 +78,8 @@ type (_, _) eq = Eq : ('a, 'a) eq val eq : 'a = val eq : ('a Queue.t, 'b Queue.t) eq = Eq Line _, characters 0-33: + type _ t = T : 'a -> 'a Queue.t t;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -82,6 +96,8 @@ module type S = sig end;; (* fail *) [%%expect{| Line _, characters 2-29: + type _ t = T : 'a -> 'a s t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; @@ -89,6 +105,8 @@ Error: In this definition, a type variable cannot be deduced module rec M : (S with type 'a s = unit) = M;; [%%expect{| Line _, characters 16-17: + module rec M : (S with type 'a s = unit) = M;; + ^ Error: Unbound module type S |}];; (* For the above reason, we cannot allow the abstract declaration @@ -112,6 +130,8 @@ type +'a t = 'b constraint 'a = 'b q;; [%%expect{| type 'a q = Q Line _, characters 0-36: + type +'a t = 'b constraint 'a = 'b q;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable has a variance that cannot be deduced from the type parameters. It was expected to be unrestricted, but it is covariant. @@ -127,6 +147,8 @@ type +'a s = 'b constraint 'a = 'b t type -'a s = 'b constraint 'a = 'b t;; (* fail *) [%%expect{| Line _, characters 0-36: + type -'a s = 'b constraint 'a = 'b t;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable has a variance that is not reflected by its occurrence in type parameters. It was expected to be contravariant, but it is covariant. @@ -146,6 +168,8 @@ type +'a s = 'b constraint 'a = 'b q t type +'a s = 'b constraint 'a = 'b t q;; (* fail *) [%%expect{| Line _, characters 0-38: + type +'a s = 'b constraint 'a = 'b t q;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable has a variance that cannot be deduced from the type parameters. It was expected to be unrestricted, but it is covariant. @@ -172,6 +196,8 @@ type _ g = G : 'a -> 'a t g;; (* fail *) [%%expect{| type +'a t = unit constraint 'a = 'b list Line _, characters 0-27: + type _ g = G : 'a -> 'a t g;; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this definition, a type variable cannot be deduced from the type parameters. |}];; diff --git a/testsuite/tests/typing-gadts/pr5989.ml b/testsuite/tests/typing-gadts/pr5989.ml index 0abf7cb3..3b51c9cd 100644 --- a/testsuite/tests/typing-gadts/pr5989.ml +++ b/testsuite/tests/typing-gadts/pr5989.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) t = Any : ('a, 'b) t | Eq : ('a, 'a) t @@ -22,6 +26,8 @@ let () = print_endline (f M.eq) ;; type (_, _) t = Any : ('a, 'b) t | Eq : ('a, 'a) t module M : sig type s = private [> `A ] val eq : (s, [ `A | `B ]) t end Line _, characters 39-64: + .......................................function + | Any -> "Any" Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq @@ -50,6 +56,8 @@ module N : val eq : (s, < a : int; b : bool >) t end Line _, characters 49-74: + .................................................function + | Any -> "Any" Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq diff --git a/testsuite/tests/typing-gadts/pr5997.ml b/testsuite/tests/typing-gadts/pr5997.ml index 1e293ef0..f9ca2cf8 100644 --- a/testsuite/tests/typing-gadts/pr5997.ml +++ b/testsuite/tests/typing-gadts/pr5997.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) comp = | Eq : ('a, 'a) comp | Diff : ('a, 'b) comp @@ -19,6 +23,8 @@ type (_, _) comp = Eq : ('a, 'a) comp | Diff : ('a, 'b) comp module U : sig type t = T end module M : sig type t = T val comp : (U.t, t) comp end Line _, characters 0-33: + match M.comp with | Diff -> false;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq @@ -40,6 +46,8 @@ match M.comp with | Diff -> false;; module U : sig type t = { x : int; } end module M : sig type t = { x : int; } val comp : (U.t, t) comp end Line _, characters 0-33: + match M.comp with | Diff -> false;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq diff --git a/testsuite/tests/typing-gadts/pr6158.ml b/testsuite/tests/typing-gadts/pr6158.ml index 5a115b7b..c52fa026 100644 --- a/testsuite/tests/typing-gadts/pr6158.ml +++ b/testsuite/tests/typing-gadts/pr6158.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type 'a t = T of 'a type 'a s = S of 'a @@ -12,6 +16,8 @@ type 'a t = T of 'a type 'a s = S of 'a type (_, _) eq = Refl : ('a, 'a) eq Line _, characters 45-49: + let f : (int s, int t) eq -> unit = function Refl -> ();; + ^^^^ Error: This pattern matches values of type (int s, int s) eq but a pattern was expected which matches values of type (int s, int t) eq diff --git a/testsuite/tests/typing-gadts/pr6163.ml b/testsuite/tests/typing-gadts/pr6163.ml index bfb644ad..38642f32 100644 --- a/testsuite/tests/typing-gadts/pr6163.ml +++ b/testsuite/tests/typing-gadts/pr6163.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type _ nat = Zero : [`Zero] nat | Succ : 'a nat -> [`Succ of 'a] nat;; @@ -21,6 +25,8 @@ type aux = [ `Succ of [< [< [< [ `Zero ] pre_nat ] pre_nat ] pre_nat ] ] nat -> aux Line _, characters 4-5: + | _ -> . (* error *) + ^ Error: This match case could not be refuted. Here is an example of a value that would reach it: Succ (Succ (Succ (Succ (Succ Zero)))) diff --git a/testsuite/tests/typing-gadts/pr6174.ml b/testsuite/tests/typing-gadts/pr6174.ml index fcf5c633..fbf799a6 100644 --- a/testsuite/tests/typing-gadts/pr6174.ml +++ b/testsuite/tests/typing-gadts/pr6174.ml @@ -1,9 +1,15 @@ +(* TEST + * expect +*) + type _ t = C : ((('a -> 'o) -> 'o) -> ('b -> 'o) -> 'o) t let f : type a o. ((a -> o) -> o) t -> (a -> o) -> o = fun C k -> k (fun x -> x);; [%%expect{| type _ t = C : ((('a -> 'o) -> 'o) -> ('b -> 'o) -> 'o) t Line _, characters 24-25: + fun C k -> k (fun x -> x);; + ^ Error: This expression has type $0 but an expression was expected of type $1 = ($2 -> $1) -> $1 |}];; diff --git a/testsuite/tests/typing-gadts/pr6241.ml b/testsuite/tests/typing-gadts/pr6241.ml index ebda191c..77f0bdff 100644 --- a/testsuite/tests/typing-gadts/pr6241.ml +++ b/testsuite/tests/typing-gadts/pr6241.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) t = A : ('a, 'a) t | B : string -> ('a, 'b) t @@ -18,6 +22,8 @@ let x = N.f A;; [%%expect{| type (_, _) t = A : ('a, 'a) t | B : string -> ('a, 'b) t Line _, characters 52-74: + ....................................................function + | B s -> s Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: A diff --git a/testsuite/tests/typing-gadts/pr6690.ml b/testsuite/tests/typing-gadts/pr6690.ml index b9466f68..bfe6a353 100644 --- a/testsuite/tests/typing-gadts/pr6690.ml +++ b/testsuite/tests/typing-gadts/pr6690.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type 'a visit_action type insert @@ -23,6 +27,8 @@ type ('a, 'result, 'visit_action) context = Local : ('a, 'a * insert, 'a local_visit_action) context | Global : ('a, 'a, 'a visit_action) context Line _, characters 4-9: + | Local -> fun _ -> raise Exit + ^^^^^ Error: This pattern matches values of type ($0, $0 * insert, $0 local_visit_action) context but a pattern was expected which matches values of type @@ -36,6 +42,8 @@ type ('a, 'result, 'visit_action) context = Local : ('a, 'a * insert, 'a local_visit_action) context | Global : ('a, 'a, 'a visit_action) context Line _, characters 4-10: + | Global -> fun _ -> raise Exit + ^^^^^^ Error: This pattern matches values of type ($1, $1, visit_action) context but a pattern was expected which matches values of type ($0, $0 * insert, visit_action) context @@ -50,6 +58,8 @@ let vexpr (type visit_action) ;; [%%expect{| Line _, characters 4-9: + | Local -> fun _ -> raise Exit + ^^^^^ Error: This pattern matches values of type ($'a, $'a * insert, $'a local_visit_action) context but a pattern was expected which matches values of type @@ -57,6 +67,8 @@ Error: This pattern matches values of type The type constructor $'a would escape its scope |}, Principal{| Line _, characters 4-10: + | Global -> fun _ -> raise Exit + ^^^^^^ Error: This pattern matches values of type ($1, $1, visit_action) context but a pattern was expected which matches values of type ($0, $0 * insert, visit_action) context diff --git a/testsuite/tests/typing-gadts/pr6817.ml b/testsuite/tests/typing-gadts/pr6817.ml index c31f975b..64621436 100644 --- a/testsuite/tests/typing-gadts/pr6817.ml +++ b/testsuite/tests/typing-gadts/pr6817.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module A = struct type nil = Cstr end diff --git a/testsuite/tests/typing-gadts/pr6934.ml b/testsuite/tests/typing-gadts/pr6934.ml index 37170d2c..789a0ebc 100644 --- a/testsuite/tests/typing-gadts/pr6934.ml +++ b/testsuite/tests/typing-gadts/pr6934.ml @@ -1,6 +1,12 @@ +(* TEST + * expect +*) + type nonrec t = A : t;; [%%expect{| Line _, characters 16-21: + type nonrec t = A : t;; + ^^^^^ Error: GADT case syntax cannot be used in a 'nonrec' block. |}] diff --git a/testsuite/tests/typing-gadts/pr6980.ml b/testsuite/tests/typing-gadts/pr6980.ml index 85b35d8f..b2321edf 100644 --- a/testsuite/tests/typing-gadts/pr6980.ml +++ b/testsuite/tests/typing-gadts/pr6980.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type 'a t = [< `Foo | `Bar] as 'a;; type 'a s = [< `Foo | `Bar | `Baz > `Bar] as 'a;; @@ -18,6 +22,8 @@ and 'a second = Second : [< `Bar | `Baz | `Foo > `Bar ] s second type aux = Aux : ([< `Bar | `Foo ] as 'a) t second * ('a -> int) -> aux val it : [< `Bar | `Foo > `Bar ] = `Bar Line _, characters 27-29: + let g (Aux(Second, f)) = f it;; + ^^ Error: This expression has type [< `Bar | `Foo > `Bar ] but an expression was expected of type [< `Bar | `Foo ] Types for tag `Bar are incompatible diff --git a/testsuite/tests/typing-gadts/pr6993_bad.ml b/testsuite/tests/typing-gadts/pr6993_bad.ml index 65a312ba..d480ee89 100644 --- a/testsuite/tests/typing-gadts/pr6993_bad.ml +++ b/testsuite/tests/typing-gadts/pr6993_bad.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) eqp = Y : ('a, 'a) eqp | N : string -> ('a, 'b) eqp let f : ('a list, 'a) eqp -> unit = function N s -> print_string s;; @@ -14,6 +18,8 @@ f B.eq;; [%%expect{| type (_, _) eqp = Y : ('a, 'a) eqp | N : string -> ('a, 'b) eqp Line _, characters 36-66: + let f : ('a list, 'a) eqp -> unit = function N s -> print_string s;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Y diff --git a/testsuite/tests/typing-gadts/pr7016.ml b/testsuite/tests/typing-gadts/pr7016.ml index 2dff639e..cb618cc7 100644 --- a/testsuite/tests/typing-gadts/pr7016.ml +++ b/testsuite/tests/typing-gadts/pr7016.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) t = | Nil : ('tl, 'tl) t | Cons : 'a * ('b, 'tl) t -> ('a * 'b, 'tl) t;; @@ -8,6 +12,8 @@ type (_, _) t = Nil : ('tl, 'tl) t | Cons : 'a * ('b, 'tl) t -> ('a * 'b, 'tl) t Line _, characters 9-43: + let get1 (Cons (x, _) : (_ * 'a, 'a) t) = x ;; (* warn, cf PR#6993 *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Nil @@ -21,6 +27,8 @@ let get1' = function val get1' : ('b * 'a as 'a, 'a) t -> 'b = |}, Principal{| Line _, characters 4-7: + | Nil -> assert false ;; (* ok *) + ^^^ Error: This pattern matches values of type ('b * 'a, 'b * 'a) t but a pattern was expected which matches values of type ('b * 'a, 'a) t diff --git a/testsuite/tests/typing-gadts/pr7160.ml b/testsuite/tests/typing-gadts/pr7160.ml index 38254892..1c7633ba 100644 --- a/testsuite/tests/typing-gadts/pr7160.ml +++ b/testsuite/tests/typing-gadts/pr7160.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type _ t = Int : int -> int t | String : string -> string t | Same : 'l t -> 'l t;; let rec f = function Int x -> x | Same s -> f s;; @@ -11,6 +15,8 @@ type _ t = | Same : 'l t -> 'l t val f : int t -> int = Line _, characters 0-97: + type 'a tt = 'a t = + Int : int -> int tt | String : string -> string tt | Same : 'l1 t -> 'l2 tt.. Error: This variant or record definition does not match that of type 'a t The types for field Same are not equal. |}];; diff --git a/testsuite/tests/typing-gadts/pr7214.ml b/testsuite/tests/typing-gadts/pr7214.ml index 736b353e..8a589ee8 100644 --- a/testsuite/tests/typing-gadts/pr7214.ml +++ b/testsuite/tests/typing-gadts/pr7214.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type _ t = I : int t;; let f (type a) (x : a t) = @@ -9,6 +13,8 @@ let f (type a) (x : a t) = [%%expect{| type _ t = I : int t Line _, characters 9-10: + let (I : a t) = x (* fail because of toplevel let *) + ^ Error: This pattern matches values of type int t but a pattern was expected which matches values of type a t Type int is not compatible with type a @@ -31,6 +37,8 @@ let bad (type a) = [%%expect{| type (_, _) eq = Refl : ('a, 'a) eq Line _, characters 10-14: + let (Refl : (int, a) eq) = M.e (* must fail for soundness *) + ^^^^ Error: This pattern matches values of type (int, int) eq but a pattern was expected which matches values of type (int, a) eq Type int is not compatible with type a diff --git a/testsuite/tests/typing-gadts/pr7222.ml b/testsuite/tests/typing-gadts/pr7222.ml index d26539de..290f4448 100644 --- a/testsuite/tests/typing-gadts/pr7222.ml +++ b/testsuite/tests/typing-gadts/pr7222.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type +'a n = private int type nil = private Nil_type type (_,_) elt = @@ -17,6 +21,8 @@ type (_, _) elt = | Elt : 'nat n -> ('l, 'nat -> 'l) elt type _ t = Nil : nil t | Cons : ('x, 'fx) elt * 'x t -> 'fx t Line _, characters 11-18: + let Cons(Elt dim, _) = sh in () + ^^^^^^^ Error: This pattern matches values of type ($Cons_'x, 'a -> $Cons_'x) elt but a pattern was expected which matches values of type ($Cons_'x, 'a -> $'b -> nil) elt @@ -29,6 +35,8 @@ type (_, _) elt = | Elt : 'nat n -> ('l, 'nat -> 'l) elt type _ t = Nil : nil t | Cons : ('x, 'fx) elt * 'x t -> 'fx t Line _, characters 6-22: + let Cons(Elt dim, _) = sh in () + ^^^^^^^^^^^^^^^^ Error: This pattern matches values of type ('a -> $0 -> nil) t but a pattern was expected which matches values of type ('a -> 'b -> nil) t diff --git a/testsuite/tests/typing-gadts/pr7230.ml b/testsuite/tests/typing-gadts/pr7230.ml index 16f652ce..1c29f5e4 100644 --- a/testsuite/tests/typing-gadts/pr7230.ml +++ b/testsuite/tests/typing-gadts/pr7230.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type _ t = T : int t;; (* Should raise Not_found *) diff --git a/testsuite/tests/typing-gadts/pr7234.ml b/testsuite/tests/typing-gadts/pr7234.ml index 622aef90..49c040ed 100644 --- a/testsuite/tests/typing-gadts/pr7234.ml +++ b/testsuite/tests/typing-gadts/pr7234.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) eq = Eq : ('a, 'a) eq | Neq : int -> ('a, 'b) eq;; type 'a t;; let f (type a) (Neq n : (a, a t) eq) = n;; (* warn! *) @@ -5,6 +9,8 @@ let f (type a) (Neq n : (a, a t) eq) = n;; (* warn! *) type (_, _) eq = Eq : ('a, 'a) eq | Neq : int -> ('a, 'b) eq type 'a t Line _, characters 15-40: + let f (type a) (Neq n : (a, a t) eq) = n;; (* warn! *) + ^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq @@ -16,6 +22,8 @@ module F (T : sig type _ t end) = struct end;; [%%expect{| Line _, characters 16-43: + let f (type a) (Neq n : (a, a T.t) eq) = n (* warn! *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Eq diff --git a/testsuite/tests/typing-gadts/pr7260.ml b/testsuite/tests/typing-gadts/pr7260.ml index 77daa1f2..d5a15673 100644 --- a/testsuite/tests/typing-gadts/pr7260.ml +++ b/testsuite/tests/typing-gadts/pr7260.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type bar = < bar: unit > type _ ty = Int : int ty @@ -16,6 +20,12 @@ type bar = < bar : unit > type _ ty = Int : int ty type dyn = Dyn : 'a ty -> dyn Line _, characters 0-108: + class foo = + object (this) + method foo (Dyn ty) = + match ty with + | Int -> (this :> bar) + end................................. Error: This class should be virtual. The following methods are undefined : bar |}];; diff --git a/testsuite/tests/typing-gadts/pr7269.ml b/testsuite/tests/typing-gadts/pr7269.ml index 051b4dc5..2a07e8b5 100644 --- a/testsuite/tests/typing-gadts/pr7269.ml +++ b/testsuite/tests/typing-gadts/pr7269.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type s = [`A | `B] and sub = [`B];; type +'a t = T : [< `Conj of 'a & sub | `Other of string] -> 'a t;; (* ok *) @@ -8,6 +12,8 @@ type s = [ `A | `B ] and sub = [ `B ] type +'a t = T : [< `Conj of 'a & sub | `Other of string ] -> 'a t Line _, characters 6-47: + let f (T (`Other msg) : s t) = print_string msg;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: T (`Conj _) @@ -34,6 +40,8 @@ module M : val x : t end Line _, characters 12-59: + let () = M.(match x with T (`Other msg) -> print_string msg);; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: T (`Conj _) @@ -64,6 +72,8 @@ module M : val e : elim -> unit end Line _, characters 21-57: + let () = M.(e { ex = fun (`Other msg) -> print_string msg });; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: `Conj _ diff --git a/testsuite/tests/typing-gadts/pr7298.ml b/testsuite/tests/typing-gadts/pr7298.ml index 695fc3c4..931d9612 100644 --- a/testsuite/tests/typing-gadts/pr7298.ml +++ b/testsuite/tests/typing-gadts/pr7298.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type t = T : t;; module M : sig diff --git a/testsuite/tests/typing-gadts/pr7374.ml b/testsuite/tests/typing-gadts/pr7374.ml index b7243fb3..f682807b 100644 --- a/testsuite/tests/typing-gadts/pr7374.ml +++ b/testsuite/tests/typing-gadts/pr7374.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type ('a, 'b) eq = Refl : ('a, 'a) eq module type S = sig @@ -18,6 +22,8 @@ end = struct end;; (* should fail *) [%%expect{| Line _, characters 16-20: + fun Refl -> Refl + ^^^^ Error: This expression has type (a, a) eq but an expression was expected of type (a, t) eq Type a is not compatible with type t = [ `Rec of 'a ] X.t as 'a @@ -42,6 +48,8 @@ module F (X : sig type 'a t end) = struct end;; (* should fail *) [%%expect{| Line _, characters 21-25: + fun Refl Refl -> Refl;; + ^^^^ Error: This expression has type (a, a) eq but an expression was expected of type (a, a X.t X.t) eq Type a = b X.t is not compatible with type a X.t X.t diff --git a/testsuite/tests/typing-gadts/pr7378.ml b/testsuite/tests/typing-gadts/pr7378.ml index 3d8a2924..190fbfdc 100644 --- a/testsuite/tests/typing-gadts/pr7378.ml +++ b/testsuite/tests/typing-gadts/pr7378.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module X = struct type t = | A : 'a * 'b * ('a -> unit) -> t @@ -12,6 +16,8 @@ module Y = struct end;; (* should fail *) [%%expect{| Line _, characters 2-54: + ..type t = X.t = + | A : 'a * 'b * ('b -> unit) -> t Error: This variant or record definition does not match that of type X.t The types for field A are not equal. |}] diff --git a/testsuite/tests/typing-gadts/pr7381.ml b/testsuite/tests/typing-gadts/pr7381.ml index 79cc245c..7609cce7 100644 --- a/testsuite/tests/typing-gadts/pr7381.ml +++ b/testsuite/tests/typing-gadts/pr7381.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_,_) eql = Refl : ('a, 'a) eql;; [%%expect{| type (_, _) eql = Refl : ('a, 'a) eql diff --git a/testsuite/tests/typing-gadts/pr7390.ml b/testsuite/tests/typing-gadts/pr7390.ml index b421ec57..29e23ae7 100644 --- a/testsuite/tests/typing-gadts/pr7390.ml +++ b/testsuite/tests/typing-gadts/pr7390.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type empty = Empty and filled = Filled type ('a,'fout,'fin) opt = | N : ('a, 'f, 'f) opt @@ -18,6 +22,8 @@ let f (* : filled either -> string *) = fun (Either (Y a, N)) -> a;; [%%expect{| Line _, characters 2-28: + fun (Either (Y a, N)) -> a;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Either (N, Y _) diff --git a/testsuite/tests/typing-gadts/pr7391.ml b/testsuite/tests/typing-gadts/pr7391.ml index ace84b5d..f5ffc205 100644 --- a/testsuite/tests/typing-gadts/pr7391.ml +++ b/testsuite/tests/typing-gadts/pr7391.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + class virtual child1 parent = object method private parent = parent @@ -56,7 +60,7 @@ let _ = - : < child : unit -> child2; previous : child2 option > = |}] -(* Didn't work in 4.03 *) +(* Didn't work in 4.03, but works in 4.07 *) let _ = object(self) method previous = None @@ -69,8 +73,23 @@ let _ = in o end;; [%%expect{| -Line _, characters 16-22: -Error: The method parent has type < child : 'a; previous : 'b option > - but is expected to have type < previous : < .. > option; .. > - Self type cannot escape its class +- : < child : child2; previous : child2 option > = +|}] + +(* Also didn't work in 4.03 *) + +type gadt = Not_really_though : gadt + +let _ = + object(self) + method previous = None + method child Not_really_though = + object + inherit child1 self + inherit child2 + end + end;; +[%%expect{| +type gadt = Not_really_though : gadt +- : < child : gadt -> child2; previous : child2 option > = |}] diff --git a/testsuite/tests/typing-gadts/pr7397.ml b/testsuite/tests/typing-gadts/pr7397.ml index 3960514b..8a85eaff 100644 --- a/testsuite/tests/typing-gadts/pr7397.ml +++ b/testsuite/tests/typing-gadts/pr7397.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type +'a t class type a = object diff --git a/testsuite/tests/typing-gadts/pr7421.ml b/testsuite/tests/typing-gadts/pr7421.ml index 5bee9bc1..a17a774e 100644 --- a/testsuite/tests/typing-gadts/pr7421.ml +++ b/testsuite/tests/typing-gadts/pr7421.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type (_, _) eq = Refl : ('a, 'a) eq;; type empty = (int, unit) eq;; [%%expect{| @@ -10,6 +14,8 @@ let f (x : ('a, empty Lazy.t) result) = | Error (lazy _) -> .;; [%%expect{| Line _, characters 4-18: + | Error (lazy _) -> .;; + ^^^^^^^^^^^^^^ Error: This match case could not be refuted. Here is an example of a value that would reach it: Error lazy _ |}] @@ -19,6 +25,8 @@ let f (x : ('a, empty Lazy.t) result) = | Error (lazy Refl) -> .;; [%%expect{| Line _, characters 16-20: + | Error (lazy Refl) -> .;; + ^^^^ Error: This pattern matches values of type (int, int) eq but a pattern was expected which matches values of type empty = (int, unit) eq diff --git a/testsuite/tests/typing-gadts/pr7432.ml b/testsuite/tests/typing-gadts/pr7432.ml index 6b83f48e..0eb9b601 100644 --- a/testsuite/tests/typing-gadts/pr7432.ml +++ b/testsuite/tests/typing-gadts/pr7432.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + #labels false;; type (_,_) eql = Refl : ('a, 'a) eql type s = x:int -> y:float -> unit @@ -18,6 +22,8 @@ let f : [`L of (s, t) eql | `R of silly] -> 'a = ;; [%%expect{| Line _, characters 2-30: + function `R {silly} -> silly + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: `L Refl diff --git a/testsuite/tests/typing-gadts/pr7518.ml b/testsuite/tests/typing-gadts/pr7518.ml deleted file mode 100644 index 7adaaa4c..00000000 --- a/testsuite/tests/typing-gadts/pr7518.ml +++ /dev/null @@ -1,50 +0,0 @@ -type _ t = I : int t;; -let f (type a) (x : a t) (y : int) = - match x, y with - | I, (_:a) -> () -;; -[%%expect{| -type _ t = I : int t -val f : 'a t -> int -> unit = -|}] - -type ('a, 'b) eq = Refl : ('a, 'a) eq;; -let ok (type a b) (x : (a, b) eq) = - match x, [] with - | Refl, [(_ : a) | (_ : b)] -> [] -;; -[%%expect{| -type ('a, 'b) eq = Refl : ('a, 'a) eq -Line _, characters 2-54: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(Refl, _::_::_) -Line _, characters 22-23: -Warning 12: this sub-pattern is unused. -val ok : ('a, 'b) eq -> 'c list = -|}] -let fails (type a b) (x : (a, b) eq) = - match x, [] with - | Refl, [(_ : a) | (_ : b)] -> [] - | Refl, [(_ : b) | (_ : a)] -> [] -;; -[%%expect{| -Line _, characters 2-90: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(Refl, _::_::_) -Line _, characters 22-23: -Warning 12: this sub-pattern is unused. -Line _, characters 4-29: -Warning 11: this match case is unused. -val fails : ('a, 'b) eq -> 'c list = -|}] - -(* branches must be unified! *) -let x = match [] with ["1"] -> 1 | [1.0] -> 2 | [1] -> 3 | _ -> 4;; -[%%expect{| -Line _, characters 35-40: -Error: This pattern matches values of type float list - but a pattern was expected which matches values of type string list - Type float is not compatible with type string -|}] diff --git a/testsuite/tests/typing-gadts/pr7618.ml b/testsuite/tests/typing-gadts/pr7618.ml new file mode 100644 index 00000000..5227bd65 --- /dev/null +++ b/testsuite/tests/typing-gadts/pr7618.ml @@ -0,0 +1,54 @@ +(* TEST + * expect +*) + +type _ t = I : int t;; +let f (type a) (x : a t) (y : int) = + match x, y with + | I, (_:a) -> () +;; +[%%expect{| +type _ t = I : int t +val f : 'a t -> int -> unit = +|}] + +type ('a, 'b) eq = Refl : ('a, 'a) eq;; +let ok (type a b) (x : (a, b) eq) = + match x, [] with + | Refl, [(_ : a) | (_ : b)] -> [] +;; +[%%expect{| +type ('a, 'b) eq = Refl : ('a, 'a) eq +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] +let fails (type a b) (x : (a, b) eq) = + match x, [] with + | Refl, [(_ : a) | (_ : b)] -> [] + | Refl, [(_ : b) | (_ : a)] -> [] +;; +[%%expect{| +Line _, characters 4-29: + | Refl, [(_ : a) | (_ : b)] -> [] + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This pattern matches values of type (a, b) eq * b list + but a pattern was expected which matches values of type 'a + This instance of b is ambiguous: + it would escape the scope of its equation +|}] + +(* branches must be unified! *) +let x = match [] with ["1"] -> 1 | [1.0] -> 2 | [1] -> 3 | _ -> 4;; +[%%expect{| +Line _, characters 35-40: + let x = match [] with ["1"] -> 1 | [1.0] -> 2 | [1] -> 3 | _ -> 4;; + ^^^^^ +Error: This pattern matches values of type float list + but a pattern was expected which matches values of type string list + Type float is not compatible with type string +|}] diff --git a/testsuite/tests/typing-gadts/pr7747.ml b/testsuite/tests/typing-gadts/pr7747.ml new file mode 100644 index 00000000..c3620e8a --- /dev/null +++ b/testsuite/tests/typing-gadts/pr7747.ml @@ -0,0 +1,35 @@ +(* TEST + * expect +*) + +type (_,_) eq = Refl : ('a,'a) eq + +module M = struct type t end +module N : sig type t = private M.t val eq : (t, M.t) eq end = + struct type t = M.t let eq = Refl end;; + +(* + as long as we are casting between M.t and N.t + there is no problem, this will type check. +*) + +let f x = match N.eq with Refl -> (x : N.t :> M.t);; +[%%expect{| +type (_, _) eq = Refl : ('a, 'a) eq +module M : sig type t end +module N : sig type t = private M.t val eq : (t, M.t) eq end +val f : N.t -> M.t = +|}] +let f x = match N.eq with Refl -> (x : M.t :> N.t);; +[%%expect{| +Line _, characters 34-50: + let f x = match N.eq with Refl -> (x : M.t :> N.t);; + ^^^^^^^^^^^^^^^^ +Error: Type M.t is not a subtype of N.t +|}] + +(* + but as soon we're trying to cast to another type, + the type checker will never return and memory + consumption will increase drastically. +*) diff --git a/testsuite/tests/typing-gadts/term-conv.ml b/testsuite/tests/typing-gadts/term-conv.ml index 4994bdfd..993b460e 100644 --- a/testsuite/tests/typing-gadts/term-conv.ml +++ b/testsuite/tests/typing-gadts/term-conv.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* HOAS to de Bruijn, by chak *) (* http://www.cse.unsw.edu.au/~chak/haskell/term-conv/ *) diff --git a/testsuite/tests/typing-gadts/test.ml b/testsuite/tests/typing-gadts/test.ml index 3003840f..579dece8 100644 --- a/testsuite/tests/typing-gadts/test.ml +++ b/testsuite/tests/typing-gadts/test.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module Exp = struct @@ -100,10 +104,15 @@ module Nonexhaustive = ;; [%%expect{| Line _, characters 6-34: + ......function + | C2 x -> x Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: C1 _ Line _, characters 6-77: + ......function + | Foo _ , Foo _ -> true + | Bar _, Bar _ -> true Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Bar _, Foo _) @@ -149,10 +158,14 @@ module PR6862 = struct end;; [%%expect{| Line _, characters 10-18: + class c (Some x) = object method x : int = x end + ^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: None Line _, characters 10-18: + class d (Just x) = object method x : int = x end + ^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Nothing @@ -180,6 +193,8 @@ module PR6220 = struct end;; [%%expect{| Line _, characters 43-44: + let g : int t -> int = function I -> 1 | _ -> 2 (* warn *) + ^ Warning 56: this match case is unreachable. Consider replacing it with a refutation case ' -> .' module PR6220 : @@ -246,6 +261,8 @@ module PR6801 = struct end;; [%%expect{| Line _, characters 4-50: + ....match x with + | String s -> print_endline s................. Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: Any @@ -268,6 +285,8 @@ module Existential_escape = ;; [%%expect{| Line _, characters 21-22: + let eval (D x) = x + ^ Error: This expression has type $D_'a t but an expression was expected of type 'a The type constructor $D_'a would escape its scope @@ -299,6 +318,8 @@ end ;; [%%expect{| Line _, characters 11-19: + | (IntLit _ | BoolLit _) -> () + ^^^^^^^^ Error: This pattern matches values of type int t but a pattern was expected which matches values of type s t Type int is not compatible with type s @@ -348,6 +369,8 @@ module Propagation : end |}, Principal{| Line _, characters 19-20: + | BoolLit b -> b + ^ Error: This expression has type bool but an expression was expected of type s |}];; @@ -359,10 +382,14 @@ module Normal_constrs = struct end;; [%%expect{| Line _, characters 28-29: + let f = function A -> 1 | B -> 2 + ^ Error: This variant pattern is expected to have type a The constructor B does not belong to type a |}, Principal{| Line _, characters 28-29: + let f = function A -> 1 | B -> 2 + ^ Error: This pattern matches values of type b but a pattern was expected which matches values of type a |}];; @@ -375,6 +402,8 @@ module PR6849 = struct end;; [%%expect{| Line _, characters 6-9: + Foo -> 5 + ^^^ Error: This pattern matches values of type 'a t but a pattern was expected which matches values of type int |}];; @@ -404,6 +433,8 @@ let test : type a. a t -> _ = ;; [%%expect{| Line _, characters 18-30: + function Int -> ky (1 : a) 1 (* fails *) + ^^^^^^^^^^^^ Error: This expression has type a = int but an expression was expected of type 'a This instance of int is ambiguous: @@ -416,6 +447,8 @@ let test : type a. a t -> a = fun x -> ;; [%%expect{| Line _, characters 30-42: + let r = match x with Int -> ky (1 : a) 1 (* fails *) + ^^^^^^^^^^^^ Error: This expression has type a = int but an expression was expected of type 'a This instance of int is ambiguous: @@ -428,6 +461,8 @@ let test : type a. a t -> a = fun x -> ;; [%%expect{| Line _, characters 30-42: + let r = match x with Int -> ky 1 (1 : a) (* fails *) + ^^^^^^^^^^^^ Error: This expression has type a = int but an expression was expected of type 'a This instance of int is ambiguous: @@ -502,6 +537,8 @@ let test2 : type a. a t -> a option = fun x -> ;; (* fails because u : (int | a) option ref *) [%%expect{| Line _, characters 46-48: + begin match x with Int -> u := Some 1; r := !u end; + ^^ Error: This expression has type int option but an expression was expected of type a option Type int is not compatible with type a = int @@ -538,6 +575,8 @@ let we_y1x (type a) (x : a) (v : a t) = [%%expect{| val either : 'a -> 'a -> 'a = Line _, characters 44-45: + match v with Int -> let y = either 1 x in y + ^ Error: This expression has type a = int but an expression was expected of type 'a This instance of int is ambiguous: @@ -597,6 +636,8 @@ let f (type a) (x : a t) y = ;; (* fails because of aliasing... *) [%%expect{| Line _, characters 46-47: + let module M = struct type b = a let z = (y : b) end + ^ Error: This expression has type a = int but an expression was expected of type b = int This instance of int is ambiguous: @@ -648,6 +689,8 @@ let f : type a b. (a,b) eq -> ( as 'c) -> ( as 'c) = [%%expect{| type (_, _) eq = Eq : ('a, 'a) eq Line _, characters 4-90: + ....f : type a b. (a,b) eq -> ( as 'c) -> ( as 'c) = + fun Eq o -> o Error: The universal type variable 'b cannot be generalized: it is already bound to another variable. |}];; @@ -657,6 +700,8 @@ let f : type a b. (a,b) eq -> -> = ;; (* fail *) [%%expect{| Line _, characters 14-15: + fun Eq o -> o + ^ Error: This expression has type < m : a; .. > but an expression was expected of type < m : b; .. > Type a is not compatible with type b = a @@ -668,6 +713,8 @@ let f (type a) (type b) (eq : (a,b) eq) (o : ) : = match eq with Eq -> o ;; (* should fail *) [%%expect{| Line _, characters 22-23: + match eq with Eq -> o ;; (* should fail *) + ^ Error: This expression has type < m : a; .. > but an expression was expected of type < m : b; .. > Type a is not compatible with type b = a @@ -706,6 +753,8 @@ let f : type a b. (a,b) eq -> < m : a; .. > -> < m : b > = val f : ('a, 'b) eq -> < m : 'a > -> < m : 'b > = |}, Principal{| Line _, characters 44-45: + let r : < m : b > = match eq with Eq -> o in (* fail with principal *) + ^ Error: This expression has type < m : a > but an expression was expected of type < m : b > Type a is not compatible with type b = a @@ -720,6 +769,8 @@ let f : type a b. (a,b) eq -> < m : a; .. > -> < m : b > = r;; [%%expect{| Line _, characters 44-45: + let r : < m : b > = match eq with Eq -> o in (* fail *) + ^ Error: This expression has type < m : a; .. > but an expression was expected of type < m : b > Type a is not compatible with type b = a @@ -731,17 +782,28 @@ let f : type a b. (a,b) eq -> [> `A of a] -> [> `A of b] = fun Eq o -> o ;; (* fail *) [%%expect{| Line _, characters 14-15: + fun Eq o -> o ;; (* fail *) + ^ Error: This expression has type [> `A of a ] but an expression was expected of type [> `A of b ] Type a is not compatible with type b = a This instance of a is ambiguous: it would escape the scope of its equation +|}, Principal{| +Line _, characters 9-15: + fun Eq o -> o ;; (* fail *) + ^^^^^^ +Error: This expression has type ([> `A of b ] as 'a) -> 'a + but an expression was expected of type [> `A of a ] -> [> `A of b ] + Types for tag `A are incompatible |}];; let f (type a b) (eq : (a,b) eq) (v : [> `A of a]) : [> `A of b] = match eq with Eq -> v ;; (* should fail *) [%%expect{| Line _, characters 22-23: + match eq with Eq -> v ;; (* should fail *) + ^ Error: This expression has type [> `A of a ] but an expression was expected of type [> `A of b ] Type a is not compatible with type b = a @@ -753,6 +815,8 @@ let f : type a b. (a,b) eq -> [< `A of a | `B] -> [< `A of b | `B] = fun Eq o -> o ;; (* fail *) [%%expect{| Line _, characters 4-84: + ....f : type a b. (a,b) eq -> [< `A of a | `B] -> [< `A of b | `B] = + fun Eq o -> o.............. Error: This definition has type ('a, 'b) eq -> ([< `A of 'b & 'a | `B ] as 'c) -> 'c which is less general than 'a0 'b0. ('a0, 'b0) eq -> 'c -> 'c @@ -780,6 +844,8 @@ let f : type a b. (a,b) eq -> [> `A of a | `B] -> [`A of b | `B] = val f : ('a, 'b) eq -> [ `A of 'a | `B ] -> [ `A of 'b | `B ] = |}, Principal{| Line _, characters 49-50: + let r : [`A of b | `B] = match eq with Eq -> o in (* fail with principal *) + ^ Error: This expression has type [ `A of a | `B ] but an expression was expected of type [ `A of b | `B ] Type a is not compatible with type b = a @@ -794,6 +860,8 @@ let f : type a b. (a,b) eq -> [> `A of a | `B] -> [`A of b | `B] = r;; [%%expect{| Line _, characters 49-50: + let r : [`A of b | `B] = match eq with Eq -> o in (* fail *) + ^ Error: This expression has type [> `A of a | `B ] but an expression was expected of type [ `A of b | `B ] Type a is not compatible with type b = a @@ -849,6 +917,13 @@ let f : type a. a ty -> a t -> int = fun x y -> ;; (* warn *) [%%expect{| Line _, characters 2-153: + ..match x, y with + | _, A z -> z + | _, B z -> if z then 1 else 2 + | _, C z -> truncate z + | TE TC, D [|1.0|] -> 14 + | TA, D 0 -> -1 + | TA, D z -> z Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (TE TC, D [| 0. |]) @@ -866,6 +941,8 @@ let f : type a. a ty -> a t -> int = fun x y -> ;; (* fail *) [%%expect{| Line _, characters 6-13: + | D [|1.0|], TE TC -> 14 + ^^^^^^^ Error: This pattern matches values of type 'a array but a pattern was expected which matches values of type a |}];; @@ -884,6 +961,8 @@ let f : type a. a ty -> a t -> int = fun x y -> [%%expect{| type ('a, 'b) pair = { right : 'a; left : 'b; } Line _, characters 25-32: + | {left=TE TC; right=D [|1.0|]} -> 14 + ^^^^^^^ Error: This pattern matches values of type 'a array but a pattern was expected which matches values of type a |}];; @@ -902,6 +981,13 @@ let f : type a. a ty -> a t -> int = fun x y -> [%%expect{| type ('a, 'b) pair = { left : 'a; right : 'b; } Line _, characters 2-244: + ..match {left=x; right=y} with + | {left=_; right=A z} -> z + | {left=_; right=B z} -> if z then 1 else 2 + | {left=_; right=C z} -> truncate z + | {left=TE TC; right=D [|1.0|]} -> 14 + | {left=TA; right=D 0} -> -1 + | {left=TA; right=D z} -> z Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: {left=TE TC; right=D [| 0. |]} @@ -920,6 +1006,8 @@ let f : type a b. (a M.t, b M.t) eq -> (a, b) eq = [%%expect{| module M : sig type 'a t val eq : ('a t, 'b t) eq end Line _, characters 17-19: + function Eq -> Eq (* fail *) + ^^ Error: This expression has type (a, a) eq but an expression was expected of type (a, b) eq Type a is not compatible with type b @@ -974,6 +1062,8 @@ let g (type t) (x:t) (e : t int_foo) (e' : t int_bar) = type _ int_foo = IF_constr : < foo : int; .. > int_foo type _ int_bar = IB_constr : < bar : int; .. > int_bar Line _, characters 3-4: + (x:) + ^ Error: This expression has type t = < foo : int; .. > but an expression was expected of type < foo : int > Type $0 = < bar : int; .. > is not compatible with type < > @@ -986,6 +1076,8 @@ let g (type t) (x:t) (e : t int_foo) (e' : t int_bar) = ;; [%%expect{| Line _, characters 3-4: + (x:) + ^ Error: This expression has type t = < foo : int; .. > but an expression was expected of type < bar : int; foo : int > Type $0 = < bar : int; .. > is not compatible with type < bar : int > @@ -998,6 +1090,8 @@ let g (type t) (x:t) (e : t int_foo) (e' : t int_bar) = ;; [%%expect{| Line _, characters 2-26: + (x:) + ^^^^^^^^^^^^^^^^^^^^^^^^ Error: This expression has type < bar : int; foo : int; .. > but an expression was expected of type 'a The type constructor $1 would escape its scope @@ -1070,3 +1164,69 @@ let f : type a b. (a,b) eq -> (b,int) eq -> a -> b -> _ = fun ab bint a b -> [%%expect{| val f : ('a, 'b) eq -> ('b, int) eq -> 'a -> 'b -> unit = |}];; + +let f : type a b. (a,b) eq -> (a,int) eq -> a -> b -> _ = fun ab aint a b -> + let Eq = aint in + let x = + let Eq = ab in + if true then a else b + in ignore x +;; (* ok *) +[%%expect{| +Line _, characters 24-25: + if true then a else b + ^ +Error: This expression has type b = int + but an expression was expected of type a = int + Type b = int is not compatible with type int + This instance of int is ambiguous: + it would escape the scope of its equation +|}];; + +let f : type a b. (a,b) eq -> (b,int) eq -> a -> b -> _ = fun ab bint a b -> + let Eq = bint in + let x = + let Eq = ab in + if true then a else b + in ignore x +;; (* ok *) +[%%expect{| +Line _, characters 24-25: + if true then a else b + ^ +Error: This expression has type b = int + but an expression was expected of type a = int + Type int is not compatible with type a = int + This instance of int is ambiguous: + it would escape the scope of its equation +|}];; + +let f (type a b c) (b : bool) (w1 : (a,b) eq) (w2 : (a,int) eq) (x : a) (y : b) = + let Eq = w1 in + let Eq = w2 in + if b then x else y +;; +[%%expect{| +Line _, characters 19-20: + if b then x else y + ^ +Error: This expression has type b = int + but an expression was expected of type a = int + Type a = int is not compatible with type a = int + This instance of int is ambiguous: + it would escape the scope of its equation +|}];; + +let f (type a b c) (b : bool) (w1 : (a,b) eq) (w2 : (a,int) eq) (x : a) (y : b) = + let Eq = w1 in + let Eq = w2 in + if b then y else x +[%%expect{| +Line _, characters 19-20: + if b then y else x + ^ +Error: This expression has type a = int + but an expression was expected of type b = int + This instance of int is ambiguous: + it would escape the scope of its equation +|}];; diff --git a/testsuite/tests/typing-gadts/unify_mb.ml b/testsuite/tests/typing-gadts/unify_mb.ml index 567046a0..cea21717 100644 --- a/testsuite/tests/typing-gadts/unify_mb.ml +++ b/testsuite/tests/typing-gadts/unify_mb.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* First-Order Unification by Structural Recursion *) (* Conor McBride, JFP 13(6) *) (* http://strictlypositive.org/publications.html *) diff --git a/testsuite/tests/typing-gadts/variables_in_mcomp.ml b/testsuite/tests/typing-gadts/variables_in_mcomp.ml new file mode 100644 index 00000000..0a370454 --- /dev/null +++ b/testsuite/tests/typing-gadts/variables_in_mcomp.ml @@ -0,0 +1,26 @@ +(* TEST + * expect +*) + +module M = struct + type 'a s = 'a + type t = T : 'a s -> t +end + +module N = struct + type 'a s = 'a + type t = T : 'a s -> t +end + +type (_, _) eq = Refl : ('a, 'a) eq + +let f (x : (M.t, N.t) eq)= + match x with + | Refl -> () + +[%%expect{| +module M : sig type 'a s = 'a type t = T : 'a s -> t end +module N : sig type 'a s = 'a type t = T : 'a s -> t end +type (_, _) eq = Refl : ('a, 'a) eq +val f : (M.t, N.t) eq -> unit = +|}] diff --git a/testsuite/tests/typing-gadts/yallop_bugs.ml b/testsuite/tests/typing-gadts/yallop_bugs.ml index b4e60e8c..5e86e911 100644 --- a/testsuite/tests/typing-gadts/yallop_bugs.ml +++ b/testsuite/tests/typing-gadts/yallop_bugs.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Injectivity *) type (_, _) eq = Refl : ('a, 'a) eq @@ -15,6 +19,8 @@ let magic : 'a 'b. 'a -> 'b = [%%expect{| type (_, _) eq = Refl : ('a, 'a) eq Line _, characters 44-52: + let f (Refl : (a T.t, b T.t) eq) = (x :> b) + ^^^^^^^^ Error: Type a is not a subtype of b |}];; @@ -32,6 +38,8 @@ let magic : 'a 'b. 'a -> 'b = ;; [%%expect{| Line _, characters 0-36: + type (_, +_) eq = Refl : ('a, 'a) eq + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In this GADT definition, the variance of some parameter cannot be checked |}];; @@ -49,6 +57,9 @@ let check : type s . s t * s -> bool = function [%%expect{| type _ t = IntLit : int t | BoolLit : bool t Line _, characters 39-99: + .......................................function + | BoolLit, false -> false + | IntLit , 6 -> false Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (IntLit, 0) @@ -64,6 +75,9 @@ let check : type s . (s t, s) pair -> bool = function [%%expect{| type ('a, 'b) pair = { fst : 'a; snd : 'b; } Line _, characters 45-134: + .............................................function + | {fst = BoolLit; snd = false} -> false + | {fst = IntLit ; snd = 6} -> false Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: {fst=IntLit; snd=0} diff --git a/testsuite/tests/typing-immediate/Makefile b/testsuite/tests/typing-immediate/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-immediate/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-immediate/immediate.ml b/testsuite/tests/typing-immediate/immediate.ml index 559e2a11..caa6ee60 100644 --- a/testsuite/tests/typing-immediate/immediate.ml +++ b/testsuite/tests/typing-immediate/immediate.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module type S = sig type t [@@immediate] end;; module F (M : S) : S = M;; [%%expect{| @@ -103,6 +107,8 @@ module B = struct end;; [%%expect{| Line _, characters 2-31: + type t = string [@@immediate] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Types marked with the immediate attribute must be non-pointer types like int or bool |}];; @@ -114,6 +120,8 @@ module C = struct end;; [%%expect{| Line _, characters 2-26: + type s = t [@@immediate] + ^^^^^^^^^^^^^^^^^^^^^^^^ Error: Types marked with the immediate attribute must be non-pointer types like int or bool |}];; @@ -124,6 +132,9 @@ module D : sig type t [@@immediate] end = struct end;; [%%expect{| Line _, characters 42-70: + ..........................................struct + type t = string + end.. Error: Signature mismatch: Modules do not match: sig type t = string end @@ -141,6 +152,8 @@ module M_invalid : S = struct type t = string end;; module FM_invalid = F (struct type t = string end);; [%%expect{| Line _, characters 23-49: + module M_invalid : S = struct type t = string end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Signature mismatch: Modules do not match: sig type t = string end is not included in S Type declarations do not match: @@ -157,6 +170,8 @@ module E = struct end;; [%%expect{| Line _, characters 2-26: + type t = s [@@immediate] + ^^^^^^^^^^^^^^^^^^^^^^^^ Error: Types marked with the immediate attribute must be non-pointer types like int or bool |}];; diff --git a/testsuite/tests/typing-immediate/ocamltests b/testsuite/tests/typing-immediate/ocamltests new file mode 100644 index 00000000..d3670297 --- /dev/null +++ b/testsuite/tests/typing-immediate/ocamltests @@ -0,0 +1 @@ +immediate.ml diff --git a/testsuite/tests/typing-implicit_unpack/Makefile b/testsuite/tests/typing-implicit_unpack/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-implicit_unpack/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml index 82fca3a5..89cebf85 100644 --- a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml +++ b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Implicit unpack allows to omit the signature in (val ...) expressions. diff --git a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml.reference b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml.reference deleted file mode 100644 index 5d2f4133..00000000 --- a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml.reference +++ /dev/null @@ -1,186 +0,0 @@ - -# * * * * * * * * * val sort : (module Set.S with type elt = 'a) -> 'a list -> 'a list = -val make_set : ('a -> 'a -> int) -> (module Set.S with type elt = 'a) = -val sort_cmp : ('a -> 'a -> int) -> 'a list -> 'a list = -module type S = sig type t val x : t end -# val f : (module S with type t = int) -> int = -# Characters 6-37: - let f (module M : S with type t = 'a) = M.x;; (* Error *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The type of this packed module contains variables: -(module S with type t = 'a) -# val f : (module S with type t = 'a) -> 'a = -# - : int = 1 -# type 'a s = { s : (module S with type t = 'a); } -# - : int s = {s = } -# Characters 9-19: - let f {s=(module M)} = M.x;; (* Error *) - ^^^^^^^^^^ -Error: The type of this packed module contains variables: -(module S with type t = 'a) -# val f : 'a s -> 'a = -# type s = { s : (module S with type t = int); } -# val f : s -> int = -# val f : s -> s -> int = -# module type S = sig val x : int end -# val f : (module S) -> int -> (module S) -> int = -# Characters 8-37: - let m = (module struct let x = 3 end);; (* Error *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The signature for this packaged module couldn't be inferred. -# val m : (module S) = -# - : int = 7 -# - : int = 6 -# - : int = 3 -# Characters 4-14: - let (module M) = m;; (* Error: only allowed in [let .. in] *) - ^^^^^^^^^^ -Error: Modules are not allowed in this pattern. -# Characters 14-24: - class c = let (module M) = m in object end;; (* Error again *) - ^^^^^^^^^^ -Error: Modules are not allowed in this pattern. -# module M : S -# module type S' = sig val f : int -> int end -# - : int = 6 -# module type S = sig type t type u val x : t * u end -val f : - (module S with type t = int and type u = bool) list -> - (module S with type u = bool) list = -module TypEq : - sig - type ('a, 'b) t - val apply : ('a, 'b) t -> 'a -> 'b - val refl : ('a, 'a) t - val sym : ('a, 'b) t -> ('b, 'a) t - end -module rec Typ : - sig - module type PAIR = - sig - type t - and t1 - and t2 - val eq : (t, t1 * t2) TypEq.t - val t1 : t1 Typ.typ - val t2 : t2 Typ.typ - end - type 'a typ = - Int of ('a, int) TypEq.t - | String of ('a, string) TypEq.t - | Pair of (module PAIR with type t = 'a) - end -val int : int Typ.typ = Int -val str : string Typ.typ = String -val pair : 'a Typ.typ -> 'b Typ.typ -> ('a * 'b) Typ.typ = -val to_string : 'a Typ.typ -> 'a -> string = -module type MapT = - sig - type key - type +'a t - val empty : 'a t - val is_empty : 'a t -> bool - val mem : key -> 'a t -> bool - val add : key -> 'a -> 'a t -> 'a t - val update : key -> ('a option -> 'a option) -> 'a t -> 'a t - val singleton : key -> 'a -> 'a t - val remove : key -> 'a t -> 'a t - val merge : - (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t - val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int - val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val iter : (key -> 'a -> unit) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val for_all : (key -> 'a -> bool) -> 'a t -> bool - val exists : (key -> 'a -> bool) -> 'a t -> bool - val filter : (key -> 'a -> bool) -> 'a t -> 'a t - val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t - val cardinal : 'a t -> int - val bindings : 'a t -> (key * 'a) list - val min_binding : 'a t -> key * 'a - val min_binding_opt : 'a t -> (key * 'a) option - val max_binding : 'a t -> key * 'a - val max_binding_opt : 'a t -> (key * 'a) option - val choose : 'a t -> key * 'a - val choose_opt : 'a t -> (key * 'a) option - val split : key -> 'a t -> 'a t * 'a option * 'a t - val find : key -> 'a t -> 'a - val find_opt : key -> 'a t -> 'a option - val find_first : (key -> bool) -> 'a t -> key * 'a - val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option - val find_last : (key -> bool) -> 'a t -> key * 'a - val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option - val map : ('a -> 'b) -> 'a t -> 'b t - val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t - type data - type map - val of_t : data t -> map - val to_t : map -> data t - end -type ('k, 'd, 'm) map = - (module MapT with type data = 'd and type key = 'k and type map = 'm) -val add : ('a, 'b, 'c) map -> 'a -> 'b -> 'c -> 'c = -module SSMap : - sig - type key = String.t - type 'a t = 'a Map.Make(String).t - val empty : 'a t - val is_empty : 'a t -> bool - val mem : key -> 'a t -> bool - val add : key -> 'a -> 'a t -> 'a t - val update : key -> ('a option -> 'a option) -> 'a t -> 'a t - val singleton : key -> 'a -> 'a t - val remove : key -> 'a t -> 'a t - val merge : - (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t - val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int - val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val iter : (key -> 'a -> unit) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val for_all : (key -> 'a -> bool) -> 'a t -> bool - val exists : (key -> 'a -> bool) -> 'a t -> bool - val filter : (key -> 'a -> bool) -> 'a t -> 'a t - val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t - val cardinal : 'a t -> int - val bindings : 'a t -> (key * 'a) list - val min_binding : 'a t -> key * 'a - val min_binding_opt : 'a t -> (key * 'a) option - val max_binding : 'a t -> key * 'a - val max_binding_opt : 'a t -> (key * 'a) option - val choose : 'a t -> key * 'a - val choose_opt : 'a t -> (key * 'a) option - val split : key -> 'a t -> 'a t * 'a option * 'a t - val find : key -> 'a t -> 'a - val find_opt : key -> 'a t -> 'a option - val find_first : (key -> bool) -> 'a t -> key * 'a - val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option - val find_last : (key -> bool) -> 'a t -> key * 'a - val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option - val map : ('a -> 'b) -> 'a t -> 'b t - val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t - type data = string - type map = data t - val of_t : 'a -> 'a - val to_t : 'a -> 'a - end -val ssmap : - (module MapT with type data = string and type key = string and type map = - SSMap.map) = - -# val ssmap : - (module MapT with type data = string and type key = string and type map = - SSMap.map) = - -# val ssmap : - (module MapT with type data = string and type key = string and type map = - SSMap.map) = - -# val ssmap : - (module MapT with type data = SSMap.data and type key = SSMap.key and type map = - SSMap.map) = - -# val ssmap : (SSMap.key, SSMap.data, SSMap.map) map = -# - : SSMap.key -> SSMap.data -> SSMap.map -> SSMap.map = -# diff --git a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ocaml.reference b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ocaml.reference new file mode 100644 index 00000000..db613370 --- /dev/null +++ b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ocaml.reference @@ -0,0 +1,195 @@ +val sort : (module Stdlib.Set.S with type elt = 'a) -> 'a list -> 'a list = + +val make_set : ('a -> 'a -> int) -> (module Stdlib.Set.S with type elt = 'a) = + +val sort_cmp : ('a -> 'a -> int) -> 'a list -> 'a list = +module type S = sig type t val x : t end +val f : (module S with type t = int) -> int = +Characters 6-37: + let f (module M : S with type t = 'a) = M.x;; (* Error *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The type of this packed module contains variables: +(module S with type t = 'a) +val f : (module S with type t = 'a) -> 'a = +- : int = 1 +type 'a s = { s : (module S with type t = 'a); } +- : int s = {s = } +Characters 9-19: + let f {s=(module M)} = M.x;; (* Error *) + ^^^^^^^^^^ +Error: The type of this packed module contains variables: +(module S with type t = 'a) +val f : 'a s -> 'a = +type s = { s : (module S with type t = int); } +val f : s -> int = +val f : s -> s -> int = +module type S = sig val x : int end +val f : (module S) -> int -> (module S) -> int = +Characters 8-37: + let m = (module struct let x = 3 end);; (* Error *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The signature for this packaged module couldn't be inferred. +val m : (module S) = +- : int = 7 +- : int = 6 +- : int = 3 +Characters 4-14: + let (module M) = m;; (* Error: only allowed in [let .. in] *) + ^^^^^^^^^^ +Error: Modules are not allowed in this pattern. +Characters 14-24: + class c = let (module M) = m in object end;; (* Error again *) + ^^^^^^^^^^ +Error: Modules are not allowed in this pattern. +module M : S +module type S' = sig val f : int -> int end +- : int = 6 +module type S = sig type t type u val x : t * u end +val f : + (module S with type t = int and type u = bool) list -> + (module S with type u = bool) list = +module TypEq : + sig + type ('a, 'b) t + val apply : ('a, 'b) t -> 'a -> 'b + val refl : ('a, 'a) t + val sym : ('a, 'b) t -> ('b, 'a) t + end +module rec Typ : + sig + module type PAIR = + sig + type t + and t1 + and t2 + val eq : (t, t1 * t2) TypEq.t + val t1 : t1 Typ.typ + val t2 : t2 Typ.typ + end + type 'a typ = + Int of ('a, int) TypEq.t + | String of ('a, string) TypEq.t + | Pair of (module PAIR with type t = 'a) + end +val int : int Typ.typ = Int +val str : string Typ.typ = String +val pair : 'a Typ.typ -> 'b Typ.typ -> ('a * 'b) Typ.typ = +val to_string : 'a Typ.typ -> 'a -> string = +module type MapT = + sig + type key + type +'a t + val empty : 'a t + val is_empty : 'a t -> bool + val mem : key -> 'a t -> bool + val add : key -> 'a -> 'a t -> 'a t + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t + val singleton : key -> 'a -> 'a t + val remove : key -> 'a t -> 'a t + val merge : + (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t + val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val for_all : (key -> 'a -> bool) -> 'a t -> bool + val exists : (key -> 'a -> bool) -> 'a t -> bool + val filter : (key -> 'a -> bool) -> 'a t -> 'a t + val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t + val cardinal : 'a t -> int + val bindings : 'a t -> (key * 'a) list + val min_binding : 'a t -> key * 'a + val min_binding_opt : 'a t -> (key * 'a) option + val max_binding : 'a t -> key * 'a + val max_binding_opt : 'a t -> (key * 'a) option + val choose : 'a t -> key * 'a + val choose_opt : 'a t -> (key * 'a) option + val split : key -> 'a t -> 'a t * 'a option * 'a t + val find : key -> 'a t -> 'a + val find_opt : key -> 'a t -> 'a option + val find_first : (key -> bool) -> 'a t -> key * 'a + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + val find_last : (key -> bool) -> 'a t -> key * 'a + val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t + type data + type map + val of_t : data t -> map + val to_t : map -> data t + end +type ('k, 'd, 'm) map = + (module MapT with type data = 'd and type key = 'k and type map = 'm) +val add : ('a, 'b, 'c) map -> 'a -> 'b -> 'c -> 'c = +module SSMap : + sig + type key = String.t + type 'a t = 'a Map.Make(String).t + val empty : 'a t + val is_empty : 'a t -> bool + val mem : key -> 'a t -> bool + val add : key -> 'a -> 'a t -> 'a t + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t + val singleton : key -> 'a -> 'a t + val remove : key -> 'a t -> 'a t + val merge : + (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t + val union : (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val for_all : (key -> 'a -> bool) -> 'a t -> bool + val exists : (key -> 'a -> bool) -> 'a t -> bool + val filter : (key -> 'a -> bool) -> 'a t -> 'a t + val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t + val cardinal : 'a t -> int + val bindings : 'a t -> (key * 'a) list + val min_binding : 'a t -> key * 'a + val min_binding_opt : 'a t -> (key * 'a) option + val max_binding : 'a t -> key * 'a + val max_binding_opt : 'a t -> (key * 'a) option + val choose : 'a t -> key * 'a + val choose_opt : 'a t -> (key * 'a) option + val split : key -> 'a t -> 'a t * 'a option * 'a t + val find : key -> 'a t -> 'a + val find_opt : key -> 'a t -> 'a option + val find_first : (key -> bool) -> 'a t -> key * 'a + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + val find_last : (key -> bool) -> 'a t -> key * 'a + val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t + type data = string + type map = data t + val of_t : 'a -> 'a + val to_t : 'a -> 'a + end +val ssmap : + (module MapT with type data = string and type key = string and type map = + SSMap.map) = + +val ssmap : + (module MapT with type data = string and type key = string and type map = + SSMap.map) = + +val ssmap : + (module MapT with type data = string and type key = string and type map = + SSMap.map) = + +val ssmap : + (module MapT with type data = SSMap.data and type key = SSMap.key and type map = + SSMap.map) = + +val ssmap : (SSMap.key, SSMap.data, SSMap.map) map = +- : SSMap.key -> SSMap.data -> SSMap.map -> SSMap.map = + diff --git a/testsuite/tests/typing-implicit_unpack/ocamltests b/testsuite/tests/typing-implicit_unpack/ocamltests new file mode 100644 index 00000000..3629d6f5 --- /dev/null +++ b/testsuite/tests/typing-implicit_unpack/ocamltests @@ -0,0 +1 @@ +implicit_unpack.ml diff --git a/testsuite/tests/typing-labels/Makefile b/testsuite/tests/typing-labels/Makefile deleted file mode 100644 index c11a415f..00000000 --- a/testsuite/tests/typing-labels/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-labels/mixin.ml b/testsuite/tests/typing-labels/mixin.ml index 5ca686a1..6df06748 100644 --- a/testsuite/tests/typing-labels/mixin.ml +++ b/testsuite/tests/typing-labels/mixin.ml @@ -1,3 +1,5 @@ +(* TEST *) + open StdLabels open MoreLabels diff --git a/testsuite/tests/typing-labels/mixin2.ml b/testsuite/tests/typing-labels/mixin2.ml index fd2b2897..637a677a 100644 --- a/testsuite/tests/typing-labels/mixin2.ml +++ b/testsuite/tests/typing-labels/mixin2.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Full fledge version, using objects to structure code *) open StdLabels diff --git a/testsuite/tests/typing-labels/mixin3.ml b/testsuite/tests/typing-labels/mixin3.ml index 5b987e81..d5f8c922 100644 --- a/testsuite/tests/typing-labels/mixin3.ml +++ b/testsuite/tests/typing-labels/mixin3.ml @@ -1,3 +1,5 @@ +(* TEST *) + (* Full fledge version, using objects to structure code *) open StdLabels diff --git a/testsuite/tests/typing-labels/ocamltests b/testsuite/tests/typing-labels/ocamltests new file mode 100644 index 00000000..b73143b2 --- /dev/null +++ b/testsuite/tests/typing-labels/ocamltests @@ -0,0 +1,3 @@ +mixin2.ml +mixin3.ml +mixin.ml diff --git a/testsuite/tests/typing-misc-bugs/Makefile b/testsuite/tests/typing-misc-bugs/Makefile deleted file mode 100644 index 994943bc..00000000 --- a/testsuite/tests/typing-misc-bugs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -include ../../makefiles/Makefile.okbad -include ../../makefiles/Makefile.common diff --git a/testsuite/tests/typing-misc-bugs/core_array_reduced_ok.ml b/testsuite/tests/typing-misc-bugs/core_array_reduced_ok.ml index bd55cc0a..de5eb117 100644 --- a/testsuite/tests/typing-misc-bugs/core_array_reduced_ok.ml +++ b/testsuite/tests/typing-misc-bugs/core_array_reduced_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type sexp = A of string | L of sexp list type 'a t = 'a array let _ = fun (_ : 'a t) -> () diff --git a/testsuite/tests/typing-misc-bugs/ocamltests b/testsuite/tests/typing-misc-bugs/ocamltests new file mode 100644 index 00000000..cae9a8a8 --- /dev/null +++ b/testsuite/tests/typing-misc-bugs/ocamltests @@ -0,0 +1,3 @@ +core_array_reduced_ok.ml +pr6303_bad.ml +pr6946_bad.ml diff --git a/testsuite/tests/typing-misc-bugs/pr6303_bad.compilers.reference b/testsuite/tests/typing-misc-bugs/pr6303_bad.compilers.reference new file mode 100644 index 00000000..0ad8bb9a --- /dev/null +++ b/testsuite/tests/typing-misc-bugs/pr6303_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr6303_bad.ml", line 11, characters 22-23: +Error: This expression has type int foo + but an expression was expected of type string foo + Type int is not compatible with type string diff --git a/testsuite/tests/typing-misc-bugs/pr6303_bad.ml b/testsuite/tests/typing-misc-bugs/pr6303_bad.ml index 7d4539c5..0f67b86d 100644 --- a/testsuite/tests/typing-misc-bugs/pr6303_bad.ml +++ b/testsuite/tests/typing-misc-bugs/pr6303_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type 'a foo = {x: 'a; y: int} let r = {{x = 0; y = 0} with x = 0} let r' : string foo = r diff --git a/testsuite/tests/typing-misc-bugs/pr6946_bad.compilers.reference b/testsuite/tests/typing-misc-bugs/pr6946_bad.compilers.reference new file mode 100644 index 00000000..c5a8859b --- /dev/null +++ b/testsuite/tests/typing-misc-bugs/pr6946_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr6946_bad.ml", line 10, characters 8-11: +Error: This expression has type int + This is not a function; it cannot be applied. diff --git a/testsuite/tests/typing-misc-bugs/pr6946_bad.ml b/testsuite/tests/typing-misc-bugs/pr6946_bad.ml index bbaefe90..59bcda10 100644 --- a/testsuite/tests/typing-misc-bugs/pr6946_bad.ml +++ b/testsuite/tests/typing-misc-bugs/pr6946_bad.ml @@ -1,2 +1,10 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + external foo : int = "%ignore";; let _ = foo ();; diff --git a/testsuite/tests/typing-misc/Makefile b/testsuite/tests/typing-misc/Makefile deleted file mode 100644 index 4184695d..00000000 --- a/testsuite/tests/typing-misc/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -all: pr6939.ml - $(MAKE) default - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common - -GENERATED_SOURCES = pr6939.ml *.flat-float - -ifeq "$(FLAT_FLOAT_ARRAY)" "true" -suffix = -flat -else -suffix = -noflat -endif - -pr6939.ml: pr6939.ml$(suffix) $(FLAT_FLOAT_ARRAY).flat-float - cp $< $@ - -%.flat-float: - @rm -f $(GENERATED_SOURCES) - @touch $@ diff --git a/testsuite/tests/typing-misc/constraints.ml b/testsuite/tests/typing-misc/constraints.ml index 76a360df..a47cf964 100644 --- a/testsuite/tests/typing-misc/constraints.ml +++ b/testsuite/tests/typing-misc/constraints.ml @@ -1,26 +1,40 @@ +(* TEST + * expect +*) + type 'a t = [`A of 'a t t] as 'a;; (* fails *) [%%expect{| Line _, characters 0-32: + type 'a t = [`A of 'a t t] as 'a;; (* fails *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The definition of t contains a cycle: 'a t t as 'a |}, Principal{| Line _, characters 0-32: + type 'a t = [`A of 'a t t] as 'a;; (* fails *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The definition of t contains a cycle: [ `A of 'a t t ] as 'a |}];; type 'a t = [`A of 'a t t];; (* fails *) [%%expect{| Line _, characters 0-26: + type 'a t = [`A of 'a t t];; (* fails *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In the definition of t, type 'a t t should be 'a t |}];; type 'a t = [`A of 'a t t] constraint 'a = 'a t;; (* fails since 4.04 *) [%%expect{| Line _, characters 0-47: + type 'a t = [`A of 'a t t] constraint 'a = 'a t;; (* fails since 4.04 *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The type abbreviation t is cyclic |}];; type 'a t = [`A of 'a t] constraint 'a = 'a t;; (* fails since 4.04 *) [%%expect{| Line _, characters 0-45: + type 'a t = [`A of 'a t] constraint 'a = 'a t;; (* fails since 4.04 *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The type abbreviation t is cyclic |}];; type 'a t = [`A of 'a] as 'a;; @@ -32,6 +46,8 @@ type 'a t = [ `A of 'b ] as 'b constraint 'a = [ `A of 'a ] type 'a v = [`A of u v] constraint 'a = t and t = u and u = t;; (* fails *) [%%expect{| Line _, characters 0-41: + type 'a v = [`A of u v] constraint 'a = t and t = u and u = t;; (* fails *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The definition of v contains a cycle: t |}];; @@ -58,6 +74,8 @@ end ;; (* fails *) [%%expect{| Line _, characters 2-44: + and 'o abs constraint 'o = 'o is_an_object + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The definition of abs contains a cycle: 'a is_an_object as 'a |}];; @@ -76,6 +94,8 @@ module PR6505a : val y : (< > is_an_object, < > is_an_object) abs end Line _, characters 8-17: + let _ = PR6505a.y#bang;; (* fails *) + ^^^^^^^^^ Error: This expression has type (< > PR6505a.is_an_object, < > PR6505a.is_an_object) PR6505a.abs It has no method bang @@ -87,6 +107,8 @@ module PR6505a : val y : (< >, < >) abs end Line _, characters 8-17: + let _ = PR6505a.y#bang;; (* fails *) + ^^^^^^^^^ Error: This expression has type (< >, < >) PR6505a.abs It has no method bang |}] @@ -105,6 +127,8 @@ module PR6505b : val x : (([> `Foo of int ] as 'a) is_an_object, 'a is_an_object) abs end Line _, characters 23-57: + let () = print_endline (match PR6505b.x with `Bar s -> s);; (* fails *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: `Foo _ diff --git a/testsuite/tests/typing-misc/disambiguate_principality.ml b/testsuite/tests/typing-misc/disambiguate_principality.ml new file mode 100644 index 00000000..f9908a49 --- /dev/null +++ b/testsuite/tests/typing-misc/disambiguate_principality.ml @@ -0,0 +1,283 @@ +(* TEST + * expect +*) + +(*** Record ***) + +(* Expressions *) + +module M = struct + type r = { lbl : int } +end +;; +[%%expect{| +module M : sig type r = { lbl : int; } end +|}] + +let before_a : M.r = + { lbl = 3 } +;; +[%%expect{| +val before_a : M.r = {M.lbl = 3} +|}] + +let a = + let x = ({ M.lbl = 3 } : M.r) in + x.lbl +;; +[%%expect{| +val a : int = 3 +|}] + +let after_a = + let x = ({ M.lbl = 3 } : M.r) in + { x with lbl = 4 } +;; +[%%expect{| +Line _, characters 2-20: + { x with lbl = 4 } + ^^^^^^^^^^^^^^^^^^ +Warning 23: all the fields are explicitly listed in this record: +the 'with' clause is useless. +val after_a : M.r = {M.lbl = 4} +|}] + +let b = + let x = ({ contents = { M.lbl = 3 } } : M.r ref) in + x := { lbl = 4 } +;; +[%%expect{| +val b : unit = () +|}, Principal{| +Line _, characters 7-18: + x := { lbl = 4 } + ^^^^^^^^^^^ +Warning 18: this type-based record disambiguation is not principal. +val b : unit = () +|}] + +let c = + let x = ({ contents = { M.lbl = 3 } } : M.r ref) in + !x.lbl +;; +[%%expect{| +val c : int = 3 +|}] + +let d = + let x = ({ contents = { M.lbl = 3 } } : M.r ref) in + x.contents <- { lbl = 4 } +;; +[%%expect{| +val d : unit = () +|}] + +let e = + let x = ({ contents = { M.lbl = 3 } } : M.r ref) in + { x with contents = { lbl = 4 } } +;; +[%%expect{| +Line _, characters 24-27: + { x with contents = { lbl = 4 } } + ^^^ +Error: Unbound record field lbl +|}] + +let f = + let x = ({ contents = { M.lbl = 3 } } : M.r ref) in + x.contents.lbl +;; +[%%expect{| +val f : int = 3 +|}] + +(* Patterns *) + +let g (x : M.r) = + match x with + | { lbl = _ } -> () +;; +[%%expect{| +val g : M.r -> unit = +|}] + +let h x = + match x with + | (_ : M.r) -> () + | { lbl = _ } -> () +;; +[%%expect{| +Line _, characters 4-15: + | { lbl = _ } -> () + ^^^^^^^^^^^ +Warning 11: this match case is unused. +val h : M.r -> unit = +|}, Principal{| +Line _, characters 6-9: + | { lbl = _ } -> () + ^^^ +Error: Unbound record field lbl +|}] + +let i x = + match x with + | { lbl = _ } -> () + | (_ : M.r) -> () +;; +[%%expect{| +Line _, characters 6-9: + | { lbl = _ } -> () + ^^^ +Error: Unbound record field lbl +|}] + +let j x = + match x with + | (_ : M.r) + | { lbl = _ } -> () +;; +[%%expect{| +Line _, characters 4-15: + | { lbl = _ } -> () + ^^^^^^^^^^^ +Warning 12: this sub-pattern is unused. +val j : M.r -> unit = +|}] + +let k x = + match x with + | { lbl = _ } + | (_ : M.r) -> () +;; +[%%expect{| +Line _, characters 6-9: + | { lbl = _ } + ^^^ +Error: Unbound record field lbl +|}] + +let l (x : M.r ref) = + match x with + | { contents = { lbl = _ } } -> () +;; +[%%expect{| +val l : M.r ref -> unit = +|}] + +let m x = + match x with + | { contents = { lbl = _ } } -> () +;; +[%%expect{| +Line _, characters 19-22: + | { contents = { lbl = _ } } -> () + ^^^ +Error: Unbound record field lbl +|}] + +let n x = + match x with + | (_ : M.r ref) -> () + | { contents = { lbl = _ } } -> () +;; +[%%expect{| +Line _, characters 4-30: + | { contents = { lbl = _ } } -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 11: this match case is unused. +val n : M.r ref -> unit = +|}, Principal{| +Line _, characters 19-22: + | { contents = { lbl = _ } } -> () + ^^^ +Error: Unbound record field lbl +|}] + +let o x = + match x with + | { contents = { lbl = _ } } -> () + | (_ : M.r ref) -> () +;; +[%%expect{| +Line _, characters 19-22: + | { contents = { lbl = _ } } -> () + ^^^ +Error: Unbound record field lbl +|}] + +let p x = + match x with + | (_ : M.r ref) + | { contents = { lbl = _ } } -> () +;; +[%%expect{| +Line _, characters 4-30: + | { contents = { lbl = _ } } -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 12: this sub-pattern is unused. +val p : M.r ref -> unit = +|}] + +let q x = + match x with + | { contents = { lbl = _ } } + | (_ : M.r ref) -> () +;; +[%%expect{| +Line _, characters 19-22: + | { contents = { lbl = _ } } + ^^^ +Error: Unbound record field lbl +|}] + +let r arg = + match arg with + | (x : M.r ref) -> + !x.lbl +;; +[%%expect{| +val r : M.r ref -> int = +|}] + +let s arg = + match arg with + | (x : M.r ref) -> + x := { lbl = 4 } +;; +[%%expect{| +val s : M.r ref -> unit = +|}, Principal{| +Line _, characters 9-20: + x := { lbl = 4 } + ^^^^^^^^^^^ +Warning 18: this type-based record disambiguation is not principal. +val s : M.r ref -> unit = +|}] + +let t = function + | ({ contents = { M.lbl = _ } } : M.r ref) as x -> + x := { lbl = 4 } +;; +[%%expect{| +val t : M.r ref -> unit = +|}, Principal{| +Line _, characters 9-20: + x := { lbl = 4 } + ^^^^^^^^^^^ +Warning 18: this type-based record disambiguation is not principal. +val t : M.r ref -> unit = +|}] + +let u = function + | ({ contents = { M.lbl = _ } } : M.r ref) as x -> + !x.lbl +;; +[%%expect{| +val u : M.r ref -> int = +|}, Principal{| +Line _, characters 7-10: + !x.lbl + ^^^ +Warning 18: this type-based field disambiguation is not principal. +val u : M.r ref -> int = +|}] diff --git a/testsuite/tests/typing-misc/empty_variant.ml b/testsuite/tests/typing-misc/empty_variant.ml new file mode 100644 index 00000000..88342711 --- /dev/null +++ b/testsuite/tests/typing-misc/empty_variant.ml @@ -0,0 +1,31 @@ +(* TEST + * expect +*) + +(* empty variant *) +type t = |;; +[%%expect{| +type t = | +|}];; + +let f (x:t) = match x with _ -> . +[%%expect{| +val f : t -> 'a = +|}];; + +type m = A of t | B of int * t | C of {g:t} +[%%expect{| +type m = A of t | B of int * t | C of { g : t; } +|}] + +let g (x:m) = + match x with + | A _ | B _ | C _ -> . +[%%expect{| +val g : m -> 'a = +|}] + +let f : t option -> int = function None -> 3 +[%%expect{| +val f : t option -> int = +|}] diff --git a/testsuite/tests/typing-misc/enrich_typedecl.ml b/testsuite/tests/typing-misc/enrich_typedecl.ml new file mode 100644 index 00000000..e1eadbbf --- /dev/null +++ b/testsuite/tests/typing-misc/enrich_typedecl.ml @@ -0,0 +1,256 @@ +(* TEST + * expect +*) + +module rec A : sig + type t = int * string +end = struct + type t = A | B + + let f (x : t) = + match x with + | A -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-97: + ......struct + type t = A | B + + let f (x : t) = + match x with + | A -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = A.t = A | B val f : t -> unit end + is not included in + sig type t = int * string end + Type declarations do not match: + type t = A.t = A | B + is not included in + type t = int * string +|}] + +module rec B : sig + type 'a t = 'a +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a B.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = 'a end + Type declarations do not match: + type 'a t = 'a B.t = A of 'a | B + is not included in + type 'a t = 'a +|}];; + +module rec C : sig + type 'a t = { x : 'a } +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a C.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = { x : 'a; } end + Type declarations do not match: + type 'a t = 'a C.t = A of 'a | B + is not included in + type 'a t = { x : 'a; } + Their kinds differ. +|}];; + + +module rec D : sig + type 'a t = int +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a D.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = int end + Type declarations do not match: + type 'a t = 'a D.t = A of 'a | B + is not included in + type 'a t = int +|}];; + +module rec E : sig + type 'a t = [> `Foo ] as 'a +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a E.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = 'a constraint 'a = [> `Foo ] end + Type declarations do not match: + type 'a t = 'a E.t = A of 'a | B + is not included in + type 'a t = 'a constraint 'a = [> `Foo ] +|}];; + +module rec E2 : sig + type 'a t = [ `Foo ] +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a E2.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = [ `Foo ] end + Type declarations do not match: + type 'a t = 'a E2.t = A of 'a | B + is not included in + type 'a t = [ `Foo ] +|}];; + +module rec E3 : sig + type 'a t = [< `Foo ] as 'a +end = struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () +end;; +[%%expect{| +Line _, characters 6-110: + ......struct + type 'a t = A of 'a | B + + let f (x : _ t) = + match x with + | A _ -> () + | B -> () + end.. +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a E3.t = A of 'a | B val f : 'a t -> unit end + is not included in + sig type 'a t = 'a constraint 'a = [< `Foo ] end + Type declarations do not match: + type 'a t = 'a E3.t = A of 'a | B + is not included in + type 'a t = 'a constraint 'a = [< `Foo ] +|}];; + + +module rec F : sig + type ('a, 'b) t = Foo of 'a +end = struct + type ('a, 'b) t = Foo of 'b + + (* this function typechecks properly, which means that we've added the + manisfest. *) + let coerce : 'a 'b. ('a, 'b) t -> ('a, 'b) F.t = fun x -> x +end;; +[%%expect{| +Line _, characters 6-201: + ......struct + type ('a, 'b) t = Foo of 'b + + (* this function typechecks properly, which means that we've added the + manisfest. *) + let coerce : 'a 'b. ('a, 'b) t -> ('a, 'b) F.t = fun x -> x + end.. +Error: Signature mismatch: + Modules do not match: + sig + type ('a, 'b) t = ('a, 'b) F.t = Foo of 'b + val coerce : ('a, 'b) t -> ('a, 'b) F.t + end + is not included in + sig type ('a, 'b) t = Foo of 'a end + Type declarations do not match: + type ('a, 'b) t = ('a, 'b) F.t = Foo of 'b + is not included in + type ('a, 'b) t = Foo of 'a + The types for field Foo are not equal. +|}];; diff --git a/testsuite/tests/typing-misc/inside_out.ml b/testsuite/tests/typing-misc/inside_out.ml new file mode 100644 index 00000000..077af370 --- /dev/null +++ b/testsuite/tests/typing-misc/inside_out.ml @@ -0,0 +1,123 @@ +(* TEST + * expect +*) + +type ('a, 'b) eq = Refl : ('a, 'a) eq + +type empty = (int, string) eq + +type ('a, 'b) t = Left : 'a -> ('a, 'b) t | Right : 'b -> ('a, 'b) t;; + +[%%expect{| +type ('a, 'b) eq = Refl : ('a, 'a) eq +type empty = (int, string) eq +type ('a, 'b) t = Left : 'a -> ('a, 'b) t | Right : 'b -> ('a, 'b) t +|}] + +let f1 x = + match x with + | (None : empty option) -> () +;; +[%%expect {| +val f1 : empty option -> unit = +|}] + +let f2 () = + match None with + | (None : empty option) -> () +;; +[%%expect {| +val f2 : unit -> unit = +|}] + +let f3 () = + let x = None in + match x with + | (None : empty option) -> () +;; +[%%expect {| +val f3 : unit -> unit = +|}] + +let f1' x = + match x with + | (None : empty option) -> () + | Some _ -> . +;; +[%%expect {| +val f1' : empty option -> unit = +|}] + +let f2' () = + match None with + | (None : empty option) -> () + | Some _ -> . +;; +[%%expect {| +val f2' : unit -> unit = +|}] + +let f3' () = + let x = None in + match x with + | (None : empty option) -> () + | Some _ -> . +;; +[%%expect {| +val f3' : unit -> unit = +|}] + + +let (Left () : (unit, empty) t) = Left ();; +[%%expect {| +|}] + +let f () = + let Left () = (Left () : (unit, empty) t) in + () +;; +[%%expect {| +val f : unit -> unit = +|}] + +let f () = + let (Left () : (unit, empty) t) = Left () in + () +;; +[%%expect{| +val f : unit -> unit = +|}] + +let f () = + match (Left () : (unit, empty) t) with + | Left () -> () +;; +[%%expect {| +val f : unit -> unit = +|}] + +let f () = + match (Left () : (unit, empty) t) with + | Left () -> () + | Right _ -> . +;; +[%%expect {| +val f : unit -> unit = +|}] + +let f () = + match Left () with + | (Left () : (unit, empty) t) -> () +;; +[%%expect {| +val f : unit -> unit = +|}] + +let f () = + match Left () with + | (Left () : (unit, empty) t) -> () + | (Right _ : (unit, empty) t) -> . +;; +[%%expect {| +val f : unit -> unit = +|}] diff --git a/testsuite/tests/typing-misc/labels.ml b/testsuite/tests/typing-misc/labels.ml index bd6c3a6f..a2b5c364 100644 --- a/testsuite/tests/typing-misc/labels.ml +++ b/testsuite/tests/typing-misc/labels.ml @@ -1,9 +1,15 @@ +(* TEST + * expect +*) + (* PR#5835 *) let f ~x = x + 1;; f ?x:0;; [%%expect{| val f : x:int -> int = Line _, characters 5-6: + f ?x:0;; + ^ Warning 43: the label x is not optional. - : int = 1 |}];; @@ -22,6 +28,8 @@ val g : ?x:'a -> unit -> unit = foo (fun ?opt () -> ()) ;; (* fails *) [%%expect{| Line _, characters 4-23: + foo (fun ?opt () -> ()) ;; (* fails *) + ^^^^^^^^^^^^^^^^^^^ Error: This function should have type unit -> unit but its first argument is labelled ?opt |}];; diff --git a/testsuite/tests/typing-misc/ocamltests b/testsuite/tests/typing-misc/ocamltests new file mode 100644 index 00000000..2f80cc48 --- /dev/null +++ b/testsuite/tests/typing-misc/ocamltests @@ -0,0 +1,16 @@ +constraints.ml +disambiguate_principality.ml +inside_out.ml +labels.ml +occur_check.ml +polyvars.ml +pr6939-flat-float-array.ml +pr6939-no-flat-float-array.ml +pr7103.ml +pr7228.ml +pr7668_bad.ml +printing.ml +records.ml +variant.ml +wellfounded.ml +empty_variant.ml diff --git a/testsuite/tests/typing-misc/occur_check.ml b/testsuite/tests/typing-misc/occur_check.ml index c2c95f56..90c5224e 100644 --- a/testsuite/tests/typing-misc/occur_check.ml +++ b/testsuite/tests/typing-misc/occur_check.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* PR#5907 *) type 'a t = 'a;; @@ -5,6 +9,8 @@ let f (g : 'a list -> 'a t -> 'a) s = g s s;; [%%expect{| type 'a t = 'a Line _, characters 42-43: + let f (g : 'a list -> 'a t -> 'a) s = g s s;; + ^ Error: This expression has type 'a list but an expression was expected of type 'a t = 'a The type variable 'a occurs inside 'a list @@ -12,6 +18,8 @@ Error: This expression has type 'a list let f (g : 'a * 'b -> 'a t -> 'a) s = g s s;; [%%expect{| Line _, characters 42-43: + let f (g : 'a * 'b -> 'a t -> 'a) s = g s s;; + ^ Error: This expression has type 'a * 'b but an expression was expected of type 'a t = 'a The type variable 'a occurs inside 'a * 'b diff --git a/testsuite/tests/typing-misc/polyvars.ml b/testsuite/tests/typing-misc/polyvars.ml index cb99f4e7..f14a9950 100644 --- a/testsuite/tests/typing-misc/polyvars.ml +++ b/testsuite/tests/typing-misc/polyvars.ml @@ -1,8 +1,14 @@ +(* TEST + * expect +*) + type ab = [ `A | `B ];; let f (x : [`A]) = match x with #ab -> 1;; [%%expect{| type ab = [ `A | `B ] Line _, characters 32-35: + let f (x : [`A]) = match x with #ab -> 1;; + ^^^ Error: This pattern matches values of type [? `A | `B ] but a pattern was expected which matches values of type [ `A ] The second variant type does not allow tag(s) `B @@ -10,42 +16,91 @@ Error: This pattern matches values of type [? `A | `B ] let f x = ignore (match x with #ab -> 1); ignore (x : [`A]);; [%%expect{| Line _, characters 31-34: + let f x = ignore (match x with #ab -> 1); ignore (x : [`A]);; + ^^^ Error: This pattern matches values of type [? `B ] but a pattern was expected which matches values of type [ `A ] The second variant type does not allow tag(s) `B -|}, Principal{| -Line _, characters 31-34: -Error: This pattern matches values of type [? `B ] - but a pattern was expected which matches values of type [ `A ] - Types for tag `B are incompatible |}];; let f x = ignore (match x with `A|`B -> 1); ignore (x : [`A]);; [%%expect{| Line _, characters 34-36: + let f x = ignore (match x with `A|`B -> 1); ignore (x : [`A]);; + ^^ Error: This pattern matches values of type [? `B ] but a pattern was expected which matches values of type [ `A ] The second variant type does not allow tag(s) `B -|}, Principal{| -Line _, characters 34-36: -Error: This pattern matches values of type [? `B ] - but a pattern was expected which matches values of type [ `A ] - Types for tag `B are incompatible |}];; let f (x : [< `A | `B]) = match x with `A | `B | `C -> 0;; (* warn *) [%%expect{| Line _, characters 49-51: + let f (x : [< `A | `B]) = match x with `A | `B | `C -> 0;; (* warn *) + ^^ Warning 12: this sub-pattern is unused. val f : [< `A | `B ] -> int = |}];; let f (x : [`A | `B]) = match x with `A | `B | `C -> 0;; (* fail *) [%%expect{| Line _, characters 47-49: + let f (x : [`A | `B]) = match x with `A | `B | `C -> 0;; (* fail *) + ^^ Error: This pattern matches values of type [? `C ] but a pattern was expected which matches values of type [ `A | `B ] The second variant type does not allow tag(s) `C |}];; +(* imported from in poly.ml *) +type t = A | B;; +function `A,_ -> 1 | _,A -> 2 | _,B -> 3;; +function `A,_ -> 1 | _,(A|B) -> 2;; +function Some `A, _ -> 1 | Some _, A -> 2 | None, A -> 3 | _, B -> 4;; +function Some `A, A -> 1 | Some `A, B -> 1 + | Some _, A -> 2 | None, A -> 3 | _, B -> 4;; +function A, `A -> 1 | A, `B -> 2 | B, _ -> 3;; +function `A, A -> 1 | `B, A -> 2 | _, B -> 3;; +function (`A|`B), _ -> 0 | _,(`A|`B) -> 1;; +function `B,1 -> 1 | _,1 -> 2;; +function 1,`B -> 1 | 1,_ -> 2;; +[%%expect {| +type t = A | B +- : [> `A ] * t -> int = +- : [> `A ] * t -> int = +- : [> `A ] option * t -> int = +- : [> `A ] option * t -> int = +- : t * [< `A | `B ] -> int = +- : [< `A | `B ] * t -> int = +Line _, characters 0-41: + function (`A|`B), _ -> 0 | _,(`A|`B) -> 1;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(`AnyOtherTag, `AnyOtherTag) +- : [> `A | `B ] * [> `A | `B ] -> int = +Line _, characters 0-29: + function `B,1 -> 1 | _,1 -> 2;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(_, 0) +Line _, characters 21-24: + function `B,1 -> 1 | _,1 -> 2;; + ^^^ +Warning 11: this match case is unused. +- : [< `B ] * int -> int = +Line _, characters 0-29: + function 1,`B -> 1 | 1,_ -> 2;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(0, _) +Line _, characters 21-24: + function 1,`B -> 1 | 1,_ -> 2;; + ^^^ +Warning 11: this match case is unused. +- : int * [< `B ] -> int = +|}];; + (* PR#6787 *) let revapply x f = f x;; @@ -63,6 +118,8 @@ let f : ([`A | `B ] as 'a) -> [> 'a] -> unit = fun x (y : [> 'a]) -> ();; let f (x : [`A | `B] as 'a) (y : [> 'a]) = ();; [%%expect{| Line _, characters 61-63: + let f : ([`A | `B ] as 'a) -> [> 'a] -> unit = fun x (y : [> 'a]) -> ();; + ^^ Error: The type 'a does not expand to a polymorphic variant type Hint: Did you mean `a? |}] @@ -79,8 +136,21 @@ function (`A x : t) -> x;; [%%expect{| type t = private [> `A of string ] Line _, characters 0-24: + function (`A x : t) -> x;; + ^^^^^^^^^^^^^^^^^^^^^^^^ Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: -` +` - : t -> string = |}] + +let f = function `AnyOtherTag, _ -> 1 | _, (`AnyOtherTag|`AnyOtherTag') -> 2;; +[%%expect{| +Line _, characters 8-76: + let f = function `AnyOtherTag, _ -> 1 | _, (`AnyOtherTag|`AnyOtherTag') -> 2;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(`AnyOtherTag', `AnyOtherTag'') +val f : [> `AnyOtherTag ] * [> `AnyOtherTag | `AnyOtherTag' ] -> int = +|}] diff --git a/testsuite/tests/typing-misc/pr6939-flat-float-array.ml b/testsuite/tests/typing-misc/pr6939-flat-float-array.ml new file mode 100644 index 00000000..63e59441 --- /dev/null +++ b/testsuite/tests/typing-misc/pr6939-flat-float-array.ml @@ -0,0 +1,24 @@ +(* TEST + * flat-float-array + ** expect +*) + +let rec x = [| x |]; 1.;; +[%%expect{| +Line _, characters 12-19: + let rec x = [| x |]; 1.;; + ^^^^^^^ +Warning 10: this expression should have type unit. +Line _, characters 12-23: + let rec x = [| x |]; 1.;; + ^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +|}];; + +let rec x = let u = [|y|] in 10. and y = 1.;; +[%%expect{| +Line _, characters 12-32: + let rec x = let u = [|y|] in 10. and y = 1.;; + ^^^^^^^^^^^^^^^^^^^^ +Error: This kind of expression is not allowed as right-hand side of `let rec' +|}];; diff --git a/testsuite/tests/typing-misc/pr6939-no-flat-float-array.ml b/testsuite/tests/typing-misc/pr6939-no-flat-float-array.ml new file mode 100644 index 00000000..84409761 --- /dev/null +++ b/testsuite/tests/typing-misc/pr6939-no-flat-float-array.ml @@ -0,0 +1,23 @@ +(* TEST + * no-flat-float-array + ** expect +*) + +let rec x = [| x |]; 1.;; +[%%expect{| +Line _, characters 12-19: + let rec x = [| x |]; 1.;; + ^^^^^^^ +Warning 10: this expression should have type unit. +val x : float = 1. +|}];; + +let rec x = let u = [|y|] in 10. and y = 1.;; +[%%expect{| +Line _, characters 16-17: + let rec x = let u = [|y|] in 10. and y = 1.;; + ^ +Warning 26: unused variable u. +val x : float = 10. +val y : float = 1. +|}];; diff --git a/testsuite/tests/typing-misc/pr6939.ml-flat b/testsuite/tests/typing-misc/pr6939.ml-flat deleted file mode 100644 index 61298de5..00000000 --- a/testsuite/tests/typing-misc/pr6939.ml-flat +++ /dev/null @@ -1,13 +0,0 @@ -let rec x = [| x |]; 1.;; -[%%expect{| -Line _, characters 12-19: -Warning 10: this expression should have type unit. -Line _, characters 12-23: -Error: This kind of expression is not allowed as right-hand side of `let rec' -|}];; - -let rec x = let u = [|y|] in 10. and y = 1.;; -[%%expect{| -Line _, characters 12-32: -Error: This kind of expression is not allowed as right-hand side of `let rec' -|}];; diff --git a/testsuite/tests/typing-misc/pr6939.ml-noflat b/testsuite/tests/typing-misc/pr6939.ml-noflat deleted file mode 100644 index 86f2ffd2..00000000 --- a/testsuite/tests/typing-misc/pr6939.ml-noflat +++ /dev/null @@ -1,14 +0,0 @@ -let rec x = [| x |]; 1.;; -[%%expect{| -Line _, characters 12-19: -Warning 10: this expression should have type unit. -val x : float = 1. -|}];; - -let rec x = let u = [|y|] in 10. and y = 1.;; -[%%expect{| -Line _, characters 16-17: -Warning 26: unused variable u. -val x : float = 10. -val y : float = 1. -|}];; diff --git a/testsuite/tests/typing-misc/pr7103.ml b/testsuite/tests/typing-misc/pr7103.ml index f7420fd2..706e3731 100644 --- a/testsuite/tests/typing-misc/pr7103.ml +++ b/testsuite/tests/typing-misc/pr7103.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type 'a t type a @@ -17,6 +21,8 @@ val h : [> `b ] t -> unit = let _ = fun (x : a t) -> f x;; [%%expect{| Line _, characters 27-28: + let _ = fun (x : a t) -> f x;; + ^ Error: This expression has type a t but an expression was expected of type (< .. > as 'a) t Type a is not compatible with type < .. > as 'a @@ -25,6 +31,8 @@ Error: This expression has type a t but an expression was expected of type let _ = fun (x : a t) -> g x;; [%%expect{| Line _, characters 27-28: + let _ = fun (x : a t) -> g x;; + ^ Error: This expression has type a t but an expression was expected of type ([< `b ] as 'a) t Type a is not compatible with type [< `b ] as 'a @@ -33,6 +41,8 @@ Error: This expression has type a t but an expression was expected of type let _ = fun (x : a t) -> h x;; [%%expect{| Line _, characters 27-28: + let _ = fun (x : a t) -> h x;; + ^ Error: This expression has type a t but an expression was expected of type ([> `b ] as 'a) t Type a is not compatible with type [> `b ] as 'a diff --git a/testsuite/tests/typing-misc/pr7228.ml b/testsuite/tests/typing-misc/pr7228.ml old mode 100755 new mode 100644 index a9f0cb1a..ff48b073 --- a/testsuite/tests/typing-misc/pr7228.ml +++ b/testsuite/tests/typing-misc/pr7228.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + type t = A of {mutable x: int};; fun (A r) -> r.x <- 42;; [%%expect{| @@ -11,5 +15,7 @@ fun (A r) -> r.x <- 42;; [%%expect{| type t = private A of { mutable x : int; } Line _, characters 15-16: + fun (A r) -> r.x <- 42;; + ^ Error: Cannot assign field x of the private type t.A |}];; diff --git a/testsuite/tests/typing-misc/pr7668_bad.ml b/testsuite/tests/typing-misc/pr7668_bad.ml new file mode 100644 index 00000000..8eca88d2 --- /dev/null +++ b/testsuite/tests/typing-misc/pr7668_bad.ml @@ -0,0 +1,29 @@ +(* TEST + * expect +*) + +let partition_map f xs = + let rec part left right = function + | [] -> List.rev left, List.rev right + | x::xs -> + match f x with + | `Left v -> part (v::left) right xs + | `Right v -> part left (v::right) xs + in + part [] [] xs +;; + +let f xs : (int list * int list) = partition_map (fun x -> if x then `Left () +else `Right ()) xs +;; +[%%expect{| +val partition_map : + ('a -> [< `Left of 'b | `Right of 'c ]) -> 'a list -> 'b list * 'c list = + +Line _, characters 35-96: + ...................................partition_map (fun x -> if x then `Left () + else `Right ()) xs +Error: This expression has type unit list * unit list + but an expression was expected of type int list * int list + Type unit is not compatible with type int +|}] diff --git a/testsuite/tests/typing-misc/pr7712.ml b/testsuite/tests/typing-misc/pr7712.ml new file mode 100644 index 00000000..09ffb4d2 --- /dev/null +++ b/testsuite/tests/typing-misc/pr7712.ml @@ -0,0 +1,20 @@ +(* TEST + * expect +*) + +type 'a or_error = string + +type ('a, 'b) t_ = + | Bar : ('a, 'a or_error) t_ + +type 'a t = ('a, 'a) t_ + +let f : type a. a t -> a t = function + | Bar -> Bar +;; +[%%expect{| +type 'a or_error = string +type ('a, 'b) t_ = Bar : ('a, 'a or_error) t_ +type 'a t = ('a, 'a) t_ +val f : 'a t -> 'a t = +|}];; diff --git a/testsuite/tests/typing-misc/printing.ml b/testsuite/tests/typing-misc/printing.ml index e1fe44a4..48a8c7ed 100644 --- a/testsuite/tests/typing-misc/printing.ml +++ b/testsuite/tests/typing-misc/printing.ml @@ -1,8 +1,14 @@ +(* TEST + * expect +*) + (* PR#7012 *) type t = [ 'A_name | `Hi ];; [%%expect{| Line _, characters 11-18: + type t = [ 'A_name | `Hi ];; + ^^^^^^^ Error: The type 'A_name does not expand to a polymorphic variant type Hint: Did you mean `A_name? |}];; diff --git a/testsuite/tests/typing-misc/records.ml b/testsuite/tests/typing-misc/records.ml index b87361e8..190b0b18 100644 --- a/testsuite/tests/typing-misc/records.ml +++ b/testsuite/tests/typing-misc/records.ml @@ -1,14 +1,22 @@ +(* TEST + * expect +*) + (* undefined labels *) type t = {x:int;y:int};; {x=3;z=2};; [%%expect{| type t = { x : int; y : int; } Line _, characters 5-6: + {x=3;z=2};; + ^ Error: Unbound record field z |}];; fun {x=3;z=2} -> ();; [%%expect{| Line _, characters 9-10: + fun {x=3;z=2} -> ();; + ^ Error: Unbound record field z |}];; @@ -16,6 +24,8 @@ Error: Unbound record field z {x=3; contents=2};; [%%expect{| Line _, characters 6-14: + {x=3; contents=2};; + ^^^^^^^^ Error: The record field contents belongs to the type 'a ref but is mixed here with fields of type t |}];; @@ -26,11 +36,15 @@ type u = private {mutable u:int};; [%%expect{| type u = private { mutable u : int; } Line _, characters 0-5: + {u=3};; + ^^^^^ Error: Cannot create values of the private type u |}];; fun x -> x.u <- 3;; [%%expect{| Line _, characters 11-12: + fun x -> x.u <- 3;; + ^ Error: Cannot assign field u of the private type u |}];; @@ -57,6 +71,8 @@ let f (r: int) = r.y <- 3;; [%%expect{| type foo = { mutable y : int; } Line _, characters 17-18: + let f (r: int) = r.y <- 3;; + ^ Error: This expression has type int but an expression was expected of type foo |}];; @@ -69,6 +85,8 @@ let f (r: bar) = ({ r with z = 3 } : foo) type foo = { y : int; z : int; } type bar = { x : int; } Line _, characters 20-21: + let f (r: bar) = ({ r with z = 3 } : foo) + ^ Error: This expression has type bar but an expression was expected of type foo |}];; @@ -78,12 +96,16 @@ let r : foo = { ZZZ.x = 2 };; [%%expect{| type foo = { x : int; } Line _, characters 16-21: + let r : foo = { ZZZ.x = 2 };; + ^^^^^ Error: Unbound module ZZZ |}];; (ZZZ.X : int option);; [%%expect{| Line _, characters 1-6: + (ZZZ.X : int option);; + ^^^^^ Error: Unbound module ZZZ |}];; @@ -91,6 +113,8 @@ Error: Unbound module ZZZ let f (x : Complex.t) = x.Complex.z;; [%%expect{| Line _, characters 26-35: + let f (x : Complex.t) = x.Complex.z;; + ^^^^^^^^^ Error: Unbound record field Complex.z |}];; @@ -98,6 +122,8 @@ Error: Unbound record field Complex.z { true with contents = 0 };; [%%expect{| Line _, characters 2-6: + { true with contents = 0 };; + ^^^^ Error: This expression has type bool but an expression was expected of type 'a ref |}];; @@ -110,3 +136,18 @@ type ('a, 'b) t = { fst : 'a; snd : 'b; } val with_fst : ('a, 'b) t -> 'c -> ('c, 'b) t = - : (int, string) t = {fst = 2; snd = ""} |}];; + +(* PR#7695 *) +type 'a t = { f : 'a; g : 'a };; +let x = { f = 12; g = 43 };; +{x with f = "hola"};; +[%%expect{| +type 'a t = { f : 'a; g : 'a; } +val x : int t = {f = 12; g = 43} +Line _, characters 0-19: + {x with f = "hola"};; + ^^^^^^^^^^^^^^^^^^^ +Error: This expression has type string t + but an expression was expected of type int t + Type string is not compatible with type int +|}] diff --git a/testsuite/tests/typing-misc/variant.ml b/testsuite/tests/typing-misc/variant.ml index de83454a..00ad4ea3 100644 --- a/testsuite/tests/typing-misc/variant.ml +++ b/testsuite/tests/typing-misc/variant.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* PR#6394 *) module rec X : sig @@ -8,6 +12,10 @@ end = struct end;; [%%expect{| Line _, characters 6-61: + ......struct + type t = A | B + let f = function A | B -> 0 + end.. Error: Signature mismatch: Modules do not match: sig type t = X.t = A | B val f : t -> int end diff --git a/testsuite/tests/typing-misc/wellfounded.ml b/testsuite/tests/typing-misc/wellfounded.ml index 99dc4c97..17214048 100644 --- a/testsuite/tests/typing-misc/wellfounded.ml +++ b/testsuite/tests/typing-misc/wellfounded.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* PR#6768 *) type _ prod = Prod : ('a * 'y) prod;; @@ -12,5 +16,7 @@ let f : type t. t prod -> _ = function Prod -> [%%expect{| type _ prod = Prod : ('a * 'y) prod Line _, characters 6-20: + type d = d * d + ^^^^^^^^^^^^^^ Error: The type abbreviation d is cyclic |}];; diff --git a/testsuite/tests/typing-missing-cmi/Makefile b/testsuite/tests/typing-missing-cmi/Makefile deleted file mode 100644 index bc0ce930..00000000 --- a/testsuite/tests/typing-missing-cmi/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Tests for compilation with missing cmis -# main.ml: error message when equality is missing -# main_ok.ml: allow path expansion even when the target is missing (GPR#816) - -SOURCES = subdir/m.ml a.ml b.ml c.ml main.ml main_ok.ml - -.PHONY: default -default: $(SOURCES) - @printf " ... testing 'main.ml'"; - @$(OCAMLC) -c subdir/m.ml; - @$(OCAMLC) -c -I subdir a.ml; - @$(OCAMLC) -c -I subdir b.ml; - @$(OCAMLC) -c -I subdir c.ml; - @$(OCAMLC) -c main.ml > main.ml.result 2>&1 || : - @$(DIFF) main.ml.result main.ml.reference >/dev/null \ - && echo " => passed" || echo " => failed" - @printf " ... testing 'main_ok.ml'"; - @$(OCAMLC) -c main_ok.ml && echo " => passed" || echo " => failed" - -.PHONY: clean -clean: - @rm -f subdir/m.cm[io] *.cm[io] main.ml.result - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-missing-cmi/ocamltests b/testsuite/tests/typing-missing-cmi/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/typing-missing-cmi/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/typing-missing-cmi/test.compilers.reference b/testsuite/tests/typing-missing-cmi/test.compilers.reference new file mode 100644 index 00000000..dfcfd020 --- /dev/null +++ b/testsuite/tests/typing-missing-cmi/test.compilers.reference @@ -0,0 +1,5 @@ +File "main.ml", line 1, characters 14-17: +Error: This expression has type M.b but an expression was expected of type + M.a +M.b is abstract because no corresponding cmi file was found in path. +M.a is abstract because no corresponding cmi file was found in path. diff --git a/testsuite/tests/typing-missing-cmi/test.ml b/testsuite/tests/typing-missing-cmi/test.ml new file mode 100644 index 00000000..087374e0 --- /dev/null +++ b/testsuite/tests/typing-missing-cmi/test.ml @@ -0,0 +1,24 @@ +(* TEST +files = "a.ml b.ml c.ml main.ml main_ok.ml" +* setup-ocamlc.byte-build-env +** script +script = "mkdir -p subdir" +*** script +script = "cp ${test_source_directory}/subdir/m.ml subdir" +**** ocamlc.byte +module = "subdir/m.ml" +***** ocamlc.byte +flags = "-I subdir" +module = "a.ml" +****** ocamlc.byte +module = "b.ml" +******* ocamlc.byte +module = "c.ml" +******** ocamlc.byte +flags = "" +module = "main_ok.ml" +********* ocamlc.byte +module = "main.ml" +ocamlc_byte_exit_status = "2" +********** check-ocamlc.byte-output +*) diff --git a/testsuite/tests/typing-modules-bugs/Makefile b/testsuite/tests/typing-modules-bugs/Makefile deleted file mode 100644 index 994943bc..00000000 --- a/testsuite/tests/typing-modules-bugs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -include ../../makefiles/Makefile.okbad -include ../../makefiles/Makefile.common diff --git a/testsuite/tests/typing-modules-bugs/gatien_baron_20131019_ok.ml b/testsuite/tests/typing-modules-bugs/gatien_baron_20131019_ok.ml index 58874454..1241d53c 100644 --- a/testsuite/tests/typing-modules-bugs/gatien_baron_20131019_ok.ml +++ b/testsuite/tests/typing-modules-bugs/gatien_baron_20131019_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module Std = struct module Hash = Hashtbl end;; open Std;; diff --git a/testsuite/tests/typing-modules-bugs/ocamltests b/testsuite/tests/typing-modules-bugs/ocamltests new file mode 100644 index 00000000..a2fed3e8 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/ocamltests @@ -0,0 +1,36 @@ +gatien_baron_20131019_ok.ml +pr5164_ok.ml +pr51_ok.ml +pr5663_ok.ml +pr5914_ok.ml +pr6240_ok.ml +pr6293_bad.ml +pr6427_bad.ml +pr6485_ok.ml +pr6513_ok.ml +pr6572_ok.ml +pr6651_ok.ml +pr6752_bad.ml +pr6752_ok.ml +pr6899_first_bad.ml +pr6899_ok.ml +pr6899_second_bad.ml +pr6944_ok.ml +pr6954_ok.ml +pr6981_ok.ml +pr6982_ok.ml +pr6985_ok.ml +pr6992_bad.ml +pr7036_ok.ml +pr7082_ok.ml +pr7112_bad.ml +pr7112_ok.ml +pr7152_ok.ml +pr7182_ok.ml +pr7305_principal.ml +pr7321_ok.ml +pr7414_bad.ml +pr7414_2_bad.ml +pr7519_ok.ml +pr7601_ok.ml +pr7601a_ok.ml diff --git a/testsuite/tests/typing-modules-bugs/pr5164_ok.ml b/testsuite/tests/typing-modules-bugs/pr5164_ok.ml index 5a59808e..4837aac5 100644 --- a/testsuite/tests/typing-modules-bugs/pr5164_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr5164_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type INCLUDING = sig include module type of List include module type of ListLabels diff --git a/testsuite/tests/typing-modules-bugs/pr51_ok.ml b/testsuite/tests/typing-modules-bugs/pr51_ok.ml index 0826fa31..14c517fb 100644 --- a/testsuite/tests/typing-modules-bugs/pr51_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr51_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module X=struct module type SIG=sig type t=int val x:t end module F(Y:SIG) : SIG = struct type t=Y.t let x=Y.x end diff --git a/testsuite/tests/typing-modules-bugs/pr5663_ok.ml b/testsuite/tests/typing-modules-bugs/pr5663_ok.ml index ce791f90..813c7de0 100644 --- a/testsuite/tests/typing-modules-bugs/pr5663_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr5663_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module F (M : sig type 'a t type 'a u = string diff --git a/testsuite/tests/typing-modules-bugs/pr5914_ok.ml b/testsuite/tests/typing-modules-bugs/pr5914_ok.ml index fb21cd4b..e5e7e8b9 100644 --- a/testsuite/tests/typing-modules-bugs/pr5914_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr5914_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type 't a = [ `A ] type 't wrap = 't constraint 't = [> 't wrap a ] type t = t a wrap diff --git a/testsuite/tests/typing-modules-bugs/pr6240_ok.ml b/testsuite/tests/typing-modules-bugs/pr6240_ok.ml index de1754aa..fa166aa3 100644 --- a/testsuite/tests/typing-modules-bugs/pr6240_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6240_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M : sig module type T module F (X : T) : sig end diff --git a/testsuite/tests/typing-modules-bugs/pr6293_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6293_bad.compilers.reference new file mode 100644 index 00000000..199c1cf7 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6293_bad.compilers.reference @@ -0,0 +1,10 @@ +File "pr6293_bad.ml", line 10, characters 6-38: +Error: In this `with' constraint, the new definition of t + does not match its original definition in the constrained signature: + Type declarations do not match: + type t + is not included in + type t = { a : int; b : int; } + File "pr6293_bad.ml", line 9, characters 20-50: Expected declaration + File "pr6293_bad.ml", line 10, characters 6-38: Actual declaration + Their kinds differ. diff --git a/testsuite/tests/typing-modules-bugs/pr6293_bad.ml b/testsuite/tests/typing-modules-bugs/pr6293_bad.ml index fe16fe4d..d216e2db 100644 --- a/testsuite/tests/typing-modules-bugs/pr6293_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6293_bad.ml @@ -1,2 +1,10 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig type t = { a : int; b : int; } end;; let f (module M : S with type t = int) = { M.a = 0 };; diff --git a/testsuite/tests/typing-modules-bugs/pr6427_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6427_bad.compilers.reference new file mode 100644 index 00000000..3c3c036c --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6427_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr6427_bad.ml", line 12, characters 13-65: +Error: This expression creates fresh types. + It is not allowed inside applicative functors. diff --git a/testsuite/tests/typing-modules-bugs/pr6427_bad.ml b/testsuite/tests/typing-modules-bugs/pr6427_bad.ml index 286dafb8..d05baaf0 100644 --- a/testsuite/tests/typing-modules-bugs/pr6427_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6427_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + let flag = ref false module F(S : sig module type T end) (A : S.T) (B : S.T) = struct diff --git a/testsuite/tests/typing-modules-bugs/pr6485_ok.ml b/testsuite/tests/typing-modules-bugs/pr6485_ok.ml index 28821ca8..ee90544e 100644 --- a/testsuite/tests/typing-modules-bugs/pr6485_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6485_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (** Check that rebinding module preserves private type aliases *) module String_id : sig diff --git a/testsuite/tests/typing-modules-bugs/pr6513_ok.ml b/testsuite/tests/typing-modules-bugs/pr6513_ok.ml index 7474ba93..5e3a8f06 100644 --- a/testsuite/tests/typing-modules-bugs/pr6513_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6513_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type PR6513 = sig module type S = sig type u end diff --git a/testsuite/tests/typing-modules-bugs/pr6572_ok.ml b/testsuite/tests/typing-modules-bugs/pr6572_ok.ml index 00c2f091..8f9647bc 100644 --- a/testsuite/tests/typing-modules-bugs/pr6572_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6572_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig include Set.S module E : sig val x : int end diff --git a/testsuite/tests/typing-modules-bugs/pr6651_ok.ml b/testsuite/tests/typing-modules-bugs/pr6651_ok.ml index 9c430051..c3adc8ca 100644 --- a/testsuite/tests/typing-modules-bugs/pr6651_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6651_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig module type T module X : T diff --git a/testsuite/tests/typing-modules-bugs/pr6752_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6752_bad.compilers.reference new file mode 100644 index 00000000..87fff51c --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6752_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr6752_bad.ml", line 26, characters 31-40: +Error: This expression has type 'a Queue.t + but an expression was expected of type Common0.msg Queue.t + The type constructor Common0.msg would escape its scope diff --git a/testsuite/tests/typing-modules-bugs/pr6752_bad.ml b/testsuite/tests/typing-modules-bugs/pr6752_bad.ml index 6f0f5f47..9ee4b12d 100644 --- a/testsuite/tests/typing-modules-bugs/pr6752_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6752_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Sorry, we have to disable this as this requires accepting potentially badly formed programs (after expliciting) *) diff --git a/testsuite/tests/typing-modules-bugs/pr6752_ok.ml b/testsuite/tests/typing-modules-bugs/pr6752_ok.ml index cc342ec6..d3b0fdcd 100644 --- a/testsuite/tests/typing-modules-bugs/pr6752_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6752_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Adding a type annotation is sufficient to make typing go through *) module Common0 = diff --git a/testsuite/tests/typing-modules-bugs/pr6899_first_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6899_first_bad.compilers.reference new file mode 100644 index 00000000..fb4d3461 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6899_first_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr6899_first_bad.ml", line 9, characters 4-17: +Error: The type of this expression, '_weak1 -> '_weak2 -> unit, + contains type variables that cannot be generalized diff --git a/testsuite/tests/typing-modules-bugs/pr6899_first_bad.ml b/testsuite/tests/typing-modules-bugs/pr6899_first_bad.ml index 07435e11..82b9ca12 100644 --- a/testsuite/tests/typing-modules-bugs/pr6899_first_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6899_first_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + let should_reject = let table = Hashtbl.create 1 in fun x y -> Hashtbl.add table x y diff --git a/testsuite/tests/typing-modules-bugs/pr6899_ok.ml b/testsuite/tests/typing-modules-bugs/pr6899_ok.ml index e049534d..38d91053 100644 --- a/testsuite/tests/typing-modules-bugs/pr6899_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6899_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type 'a t = 'a option let is_some = function | None -> false diff --git a/testsuite/tests/typing-modules-bugs/pr6899_second_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6899_second_bad.compilers.reference new file mode 100644 index 00000000..58b44ba7 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6899_second_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr6899_second_bad.ml", line 12, characters 6-9: +Error: The type of this expression, _[< `Test ] -> unit, + contains type variables that cannot be generalized diff --git a/testsuite/tests/typing-modules-bugs/pr6899_second_bad.ml b/testsuite/tests/typing-modules-bugs/pr6899_second_bad.ml index 4d49fe1e..4a563527 100644 --- a/testsuite/tests/typing-modules-bugs/pr6899_second_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6899_second_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + include struct let foo `Test = () let wrap f `Test = f diff --git a/testsuite/tests/typing-modules-bugs/pr6944_ok.ml b/testsuite/tests/typing-modules-bugs/pr6944_ok.ml index dffba4e9..88c325a9 100644 --- a/testsuite/tests/typing-modules-bugs/pr6944_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6944_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + let f () = let module S = String in let module N = Map.Make(S) in diff --git a/testsuite/tests/typing-modules-bugs/pr6954_ok.ml b/testsuite/tests/typing-modules-bugs/pr6954_ok.ml index 0e13489b..e72c47e2 100644 --- a/testsuite/tests/typing-modules-bugs/pr6954_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6954_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module X = struct module Y = struct module type S = sig type t end end end (* open X (* works! *) *) diff --git a/testsuite/tests/typing-modules-bugs/pr6981_ok.ml b/testsuite/tests/typing-modules-bugs/pr6981_ok.ml index e2b285b9..0cc39261 100644 --- a/testsuite/tests/typing-modules-bugs/pr6981_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6981_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig type a diff --git a/testsuite/tests/typing-modules-bugs/pr6982_ok.ml b/testsuite/tests/typing-modules-bugs/pr6982_ok.ml index 7e24940a..d3181a0a 100644 --- a/testsuite/tests/typing-modules-bugs/pr6982_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6982_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module A = struct module type A_S = sig end diff --git a/testsuite/tests/typing-modules-bugs/pr6985_ok.ml b/testsuite/tests/typing-modules-bugs/pr6985_ok.ml index f6078c97..20ed0a6b 100644 --- a/testsuite/tests/typing-modules-bugs/pr6985_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr6985_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module Foo (Bar : sig type a = private [> `A ] end) (Baz : module type of struct include Bar end) = diff --git a/testsuite/tests/typing-modules-bugs/pr6992_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr6992_bad.compilers.reference new file mode 100644 index 00000000..c6882a1c --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr6992_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr6992_bad.ml", line 16, characters 69-71: +Error: This expression has type (a, a) eq + but an expression was expected of type (a, b) eq + Type a is not compatible with type b diff --git a/testsuite/tests/typing-modules-bugs/pr6992_bad.ml b/testsuite/tests/typing-modules-bugs/pr6992_bad.ml index c2814d44..21fea7f7 100644 --- a/testsuite/tests/typing-modules-bugs/pr6992_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr6992_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR#6992, reported by Stephen Dolan *) type (_, _) eq = Eq : ('a, 'a) eq diff --git a/testsuite/tests/typing-modules-bugs/pr7036_ok.ml b/testsuite/tests/typing-modules-bugs/pr7036_ok.ml index 8a646035..011cc1b1 100644 --- a/testsuite/tests/typing-modules-bugs/pr7036_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7036_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M = struct module type S = sig type a val v : a end type 'a s = (module S with type a = 'a) diff --git a/testsuite/tests/typing-modules-bugs/pr7082_ok.ml b/testsuite/tests/typing-modules-bugs/pr7082_ok.ml index c3132dae..b73052e3 100644 --- a/testsuite/tests/typing-modules-bugs/pr7082_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7082_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type FOO = sig type t end module type BAR = sig diff --git a/testsuite/tests/typing-modules-bugs/pr7112_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr7112_bad.compilers.reference new file mode 100644 index 00000000..5e5de80a --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr7112_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr7112_bad.ml", line 13, characters 30-31: +Error: Signature mismatch: + Modules do not match: F(N).S is not included in A.S diff --git a/testsuite/tests/typing-modules-bugs/pr7112_bad.ml b/testsuite/tests/typing-modules-bugs/pr7112_bad.ml index 9f4a12d2..e67e0279 100644 --- a/testsuite/tests/typing-modules-bugs/pr7112_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr7112_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module A = struct module type S module S = struct end end module F (_ : sig end) = struct module type S module S = A.S end module M = struct end diff --git a/testsuite/tests/typing-modules-bugs/pr7112_ok.ml b/testsuite/tests/typing-modules-bugs/pr7112_ok.ml index 9da56069..949d4ab5 100644 --- a/testsuite/tests/typing-modules-bugs/pr7112_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7112_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module F (_ : sig end) = struct module type S end module M = struct end module N = M diff --git a/testsuite/tests/typing-modules-bugs/pr7152_ok.ml b/testsuite/tests/typing-modules-bugs/pr7152_ok.ml index 662d8c26..2e70dabf 100644 --- a/testsuite/tests/typing-modules-bugs/pr7152_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7152_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M : sig type make_dec val add_dec: make_dec -> unit diff --git a/testsuite/tests/typing-modules-bugs/pr7182_ok.ml b/testsuite/tests/typing-modules-bugs/pr7182_ok.ml index e7d01956..c32d1d11 100644 --- a/testsuite/tests/typing-modules-bugs/pr7182_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7182_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module rec M : sig external f : int -> int = "%identity" end = struct external f : int -> int = "%identity" end diff --git a/testsuite/tests/typing-modules-bugs/pr7305_principal.ml b/testsuite/tests/typing-modules-bugs/pr7305_principal.ml index fd20e998..045ab5aa 100644 --- a/testsuite/tests/typing-modules-bugs/pr7305_principal.ml +++ b/testsuite/tests/typing-modules-bugs/pr7305_principal.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -principal -w +18+19 -warn-error A " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type c1 = < c1: c1 > type c2 = < c1: c1; c2: c1; c3: c1; c4: c1; c5: c1; c6: c1 > type c3 = < c1: c2; c2: c2; c3: c2; c4: c2; c5: c2; c6: c2 > diff --git a/testsuite/tests/typing-modules-bugs/pr7321_ok.ml b/testsuite/tests/typing-modules-bugs/pr7321_ok.ml index 930031c2..73f40443 100644 --- a/testsuite/tests/typing-modules-bugs/pr7321_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7321_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig type 'a t end module type Sp = sig type 'a t = private 'a array end diff --git a/testsuite/tests/typing-modules-bugs/pr7414_2_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr7414_2_bad.compilers.reference new file mode 100644 index 00000000..fd43b069 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr7414_2_bad.compilers.reference @@ -0,0 +1,18 @@ +File "pr7414_2_bad.ml", line 46, characters 28-34: +Error: Signature mismatch: + Modules do not match: + functor () -> sig module Choice : T val r : '_weak1 list ref ref end + is not included in + functor () -> S + At position functor () -> + Modules do not match: + sig module Choice : T val r : '_weak1 list ref ref end + is not included in + S + At position functor () -> + Values do not match: + val r : '_weak1 list ref ref + is not included in + val r : Choice.t list ref ref + File "pr7414_2_bad.ml", line 29, characters 2-31: Expected declaration + File "pr7414_2_bad.ml", line 40, characters 8-9: Actual declaration diff --git a/testsuite/tests/typing-modules-bugs/pr7414_2_bad.ml b/testsuite/tests/typing-modules-bugs/pr7414_2_bad.ml new file mode 100644 index 00000000..0c2df938 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr7414_2_bad.ml @@ -0,0 +1,50 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + +module type T = sig + type t + val x : t + val show : t -> string +end + +module Int = struct + type t = int + let x = 0 + let show x = string_of_int x +end + +module String = struct + type t = string + let x = "Hello" + let show x = x +end + +module type S = sig + module Choice : T + val r : Choice.t list ref ref +end + +module Force (X : functor () -> S) = struct end + +let () = + let switch = ref true in + let module Choose () = struct + module Choice = + (val if !switch then (module Int : T) + else (module String : T)) + let r = ref (ref []) + end in + let module M = Choose () in + let () = switch := false in + let module N = Choose () in + let () = N.r := !M.r in + let module Ignore = Force(Choose) in + let module M' = (M : S) in + let () = (!M'.r) := [M'.Choice.x] in + let module N' = (N : S) in + List.iter (fun x -> print_string (N'.Choice.show x)) !(!N'.r) diff --git a/testsuite/tests/typing-modules-bugs/pr7414_bad.compilers.reference b/testsuite/tests/typing-modules-bugs/pr7414_bad.compilers.reference new file mode 100644 index 00000000..16894165 --- /dev/null +++ b/testsuite/tests/typing-modules-bugs/pr7414_bad.compilers.reference @@ -0,0 +1,18 @@ +File "pr7414_bad.ml", line 52, characters 22-28: +Error: Signature mismatch: + Modules do not match: + functor () -> sig module Choice : T val r : '_weak1 list ref ref end + is not included in + functor () -> S + At position functor () -> + Modules do not match: + sig module Choice : T val r : '_weak1 list ref ref end + is not included in + S + At position functor () -> + Values do not match: + val r : '_weak1 list ref ref + is not included in + val r : Choice.t list ref ref + File "pr7414_bad.ml", line 38, characters 2-31: Expected declaration + File "pr7414_bad.ml", line 33, characters 6-7: Actual declaration diff --git a/testsuite/tests/typing-modules-bugs/pr7414_bad.ml b/testsuite/tests/typing-modules-bugs/pr7414_bad.ml index 38ecfa13..979e511c 100644 --- a/testsuite/tests/typing-modules-bugs/pr7414_bad.ml +++ b/testsuite/tests/typing-modules-bugs/pr7414_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type T = sig type t val x : t diff --git a/testsuite/tests/typing-modules-bugs/pr7519_ok.ml b/testsuite/tests/typing-modules-bugs/pr7519_ok.ml index b01da150..1db6bc3d 100644 --- a/testsuite/tests/typing-modules-bugs/pr7519_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7519_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module Gen_spec = struct type 't extra = unit end module type S = sig diff --git a/testsuite/tests/typing-modules-bugs/pr7601_ok.ml b/testsuite/tests/typing-modules-bugs/pr7601_ok.ml index 7dd1db7d..4d1b8cdb 100644 --- a/testsuite/tests/typing-modules-bugs/pr7601_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7601_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (**************************************************************************) (* *) (* Crude slicer for preprocessing reachability verification tasks *) diff --git a/testsuite/tests/typing-modules-bugs/pr7601a_ok.ml b/testsuite/tests/typing-modules-bugs/pr7601a_ok.ml index 58e0eed3..58fcf4eb 100644 --- a/testsuite/tests/typing-modules-bugs/pr7601a_ok.ml +++ b/testsuite/tests/typing-modules-bugs/pr7601a_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type Param1 = sig type 'a r = [< `A of int ] as 'a val f : ?a:string -> string -> [ `A of _ ] r diff --git a/testsuite/tests/typing-modules/Makefile b/testsuite/tests/typing-modules/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-modules/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-modules/Test.ml b/testsuite/tests/typing-modules/Test.ml index 149ba154..610c8fca 100644 --- a/testsuite/tests/typing-modules/Test.ml +++ b/testsuite/tests/typing-modules/Test.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* with module *) module type S = sig type t and s = t end;; @@ -65,6 +69,8 @@ module M : sig type -'a t = private int end = ;; [%%expect{| Line _, characters 2-37: + struct type +'a t = private int end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Signature mismatch: Modules do not match: sig type +'a t = private int end @@ -86,6 +92,8 @@ module type B = A with type t = u;; (* fail *) module type A = sig type t = X of int end type u = X of bool Line _, characters 23-33: + module type B = A with type t = u;; (* fail *) + ^^^^^^^^^^ Error: This variant or record definition does not match that of type u The types for field X are not equal. |}];; @@ -96,6 +104,8 @@ Error: This variant or record definition does not match that of type u module type S = sig exception Foo of int exception Foo of bool end;; [%%expect{| Line _, characters 52-55: + module type S = sig exception Foo of int exception Foo of bool end;; + ^^^ Error: Multiple definition of the extension constructor name Foo. Names must be unique in a given structure or signature. |}];; @@ -107,5 +117,7 @@ F.x;; (* fail *) [%%expect{| module F : functor (X : sig end) -> sig val x : int end Line _, characters 0-3: -Error: The module F is a functor, not a structure + F.x;; (* fail *) + ^^^ +Error: The module F is a functor, it cannot have any components |}];; diff --git a/testsuite/tests/typing-modules/aliases.ml b/testsuite/tests/typing-modules/aliases.ml index f20a3eff..1bdfa6fd 100644 --- a/testsuite/tests/typing-modules/aliases.ml +++ b/testsuite/tests/typing-modules/aliases.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module C = Char;; C.chr 66;; @@ -310,6 +314,10 @@ module StringSet : val find_last : (elt -> bool) -> t -> elt val find_last_opt : (elt -> bool) -> t -> elt option val of_list : elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end module SSet : sig @@ -350,6 +358,10 @@ module SSet : val find_last : (elt -> bool) -> t -> elt val find_last_opt : (elt -> bool) -> t -> elt option val of_list : elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end val f : StringSet.t -> SSet.t = |}];; @@ -422,6 +434,10 @@ module A : val find_last : (elt -> bool) -> t -> elt val find_last_opt : (elt -> bool) -> t -> elt option val of_list : elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end val empty : S.t end @@ -462,7 +478,7 @@ module A2 = struct end module L1 = struct module X = A1 end module L2 = struct module X = A2 end;; -module F (L : (module type of L1)) = struct end;; +module F (L : (module type of L1 [@remove_aliases])) = struct end;; module F1 = F(L1);; (* ok *) module F2 = F(L2);; (* should succeed too *) @@ -486,7 +502,7 @@ module M = struct module I = Int type wrap' = wrap = W of (Set.Make(Int).t, Set.Make(I).t) eq end;; -module type S = module type of M;; (* keep alias *) +module type S = module type of M [@remove_aliases];; (* keep alias *) module Int2 = struct type t = int let compare x y = compare y x end;; module type S' = sig @@ -534,6 +550,10 @@ module SInt : val find_last : (elt -> bool) -> t -> elt val find_last_opt : (elt -> bool) -> t -> elt option val of_list : elt list -> t + val to_seq_from : elt -> t -> elt Seq.t + val to_seq : t -> elt Seq.t + val add_seq : elt Seq.t -> t -> t + val of_seq : elt Seq.t -> t end type (_, _) eq = Eq : ('a, 'a) eq type wrap = W of (SInt.t, SInt.t) eq @@ -549,6 +569,8 @@ module type S = end module Int2 : sig type t = int val compare : 'a -> 'a -> int end Line _, characters 10-30: + include S with module I := I + ^^^^^^^^^^^^^^^^^^^^ Error: In this `with' constraint, the new definition of I does not match its original definition in the constrained signature: Modules do not match: (module Int2) is not included in (module Int) @@ -575,7 +597,7 @@ module M = struct type wrap' = wrap = W of (Set.Make(Int).t, Set.Make(P.I).t) eq end end;; -module type S = module type of M ;; +module type S = module type of M [@remove_aliases];; [%%expect{| module M : sig @@ -600,7 +622,7 @@ module M = struct type wrap' = wrap = W of (Set.Make(Int).t, Set.Make(N.I).t) eq end end;; -module type S = module type of M ;; +module type S = module type of M [@remove_aliases];; [%%expect{| module M : sig @@ -752,3 +774,24 @@ R.M.f 3;; module rec R : sig module M = M end - : int = 3 |}];; + +module M = struct type t end +module type S = sig module N = M val x : N.t end +module type T = S with module N := M;; +[%%expect{| +module M : sig type t end +module type S = sig module N = M val x : N.t end +module type T = sig val x : M.t end +|}];; + + +module X = struct module N = struct end end +module Y : sig + module type S = sig module N = X.N end +end = struct + module type S = module type of struct include X end +end;; +[%%expect{| +module X : sig module N : sig end end +module Y : sig module type S = sig module N = X.N end end +|}];; diff --git a/testsuite/tests/typing-modules/applicative_functor_type.ml b/testsuite/tests/typing-modules/applicative_functor_type.ml new file mode 100644 index 00000000..b02a882d --- /dev/null +++ b/testsuite/tests/typing-modules/applicative_functor_type.ml @@ -0,0 +1,83 @@ +(* TEST + * expect +*) + +type t = Set.Make(String).t +[%%expect{| +type t = Set.Make(String).t +|} ] + + +(* Check the error messages of an ill-typed applicatived functor type. *) +module M = struct type t let equal = (=) end +[%%expect{| +module M : sig type t val equal : 'a -> 'a -> bool end +|} ] + +type t = Set.Make(M).t +[%%expect{| +Line _, characters 9-22: + type t = Set.Make(M).t + ^^^^^^^^^^^^^ +Error: The type of M does not match Set.Make's parameter + Modules do not match: + sig type t = M.t val equal : 'a -> 'a -> bool end + is not included in + Set.OrderedType + The value `compare' is required but not provided + File "set.mli", line 52, characters 4-31: Expected declaration +|} ] + + +(* We would report the wrong error here if we didn't strengthen the + type of the argument (type t wouldn't match). *) +module F(X : sig type t = M.t val equal : unit end) + = struct type t end +[%%expect{| +module F : + functor (X : sig type t = M.t val equal : unit end) -> sig type t end +|} ] + +type t = F(M).t +[%%expect{| +Line _, characters 9-15: + type t = F(M).t + ^^^^^^ +Error: The type of M does not match F's parameter + Modules do not match: + sig type t = M.t val equal : 'a -> 'a -> bool end + is not included in + sig type t = M.t val equal : unit end + Values do not match: + val equal : 'a -> 'a -> bool + is not included in + val equal : unit +|} ] + + +(* MPR#7611 *) +module Generative() = struct type t end +[%%expect{| +module Generative : functor () -> sig type t end +|}] + +type t = Generative(M).t +[%%expect{| +Line _, characters 9-24: + type t = Generative(M).t + ^^^^^^^^^^^^^^^ +Error: The functor Generative is generative, it cannot be applied in type + expressions +|}] + + + +module F(X : sig module type S module F : S end) = struct + type t = X.F(Parsing).t +end +[%%expect{| +Line _, characters 11-25: + type t = X.F(Parsing).t + ^^^^^^^^^^^^^^ +Error: The module X.F is abstract, it cannot be applied +|}] diff --git a/testsuite/tests/typing-modules/firstclass.ml b/testsuite/tests/typing-modules/firstclass.ml index 8bf0e422..18679d1b 100644 --- a/testsuite/tests/typing-modules/firstclass.ml +++ b/testsuite/tests/typing-modules/firstclass.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module type S = sig type u type t end;; module type S' = sig type t = int type u = bool end;; @@ -26,6 +30,8 @@ val g2 : (module S2 with type t = int and type u = bool) -> (module S') = val h : (module S2 with type t = 'a) -> (module S with type t = 'a) = Line _, characters 3-4: + (x : (module S'));; (* fail *) + ^ Error: This expression has type (module S2 with type t = int and type u = bool) but an expression was expected of type (module S') @@ -38,6 +44,8 @@ let g3 x = [%%expect{| module type S3 = sig type u type t val x : int end Line _, characters 2-67: + (x : (module S3 with type t = 'a and type u = 'b) :> (module S'));; (* fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Type (module S3 with type t = int and type u = bool) is not a subtype of (module S') |}];; diff --git a/testsuite/tests/typing-modules/generative.ml b/testsuite/tests/typing-modules/generative.ml index 0fb23150..75cc7ae7 100644 --- a/testsuite/tests/typing-modules/generative.ml +++ b/testsuite/tests/typing-modules/generative.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Using generative functors *) (* Without type *) @@ -26,6 +30,8 @@ module F : functor () -> S module G (X : sig end) : S = F ();; (* fail *) [%%expect{| Line _, characters 29-33: + module G (X : sig end) : S = F ();; (* fail *) + ^^^^ Error: This expression creates fresh types. It is not allowed inside applicative functors. |}];; @@ -44,6 +50,8 @@ module M : S module M = F(U);; (* fail *) [%%expect{| Line _, characters 11-12: + module M = F(U);; (* fail *) + ^ Error: This is a generative functor. It can only be applied to () |}];; @@ -53,6 +61,8 @@ module F2 : functor () -> sig end = F1;; (* fail *) [%%expect{| module F1 : functor (X : sig end) -> sig end Line _, characters 36-38: + module F2 : functor () -> sig end = F1;; (* fail *) + ^^ Error: Signature mismatch: Modules do not match: functor (X : sig end) -> sig end @@ -64,6 +74,8 @@ module F4 : functor (X : sig end) -> sig end = F3;; (* fail *) [%%expect{| module F3 : functor () -> sig end Line _, characters 47-49: + module F4 : functor (X : sig end) -> sig end = F3;; (* fail *) + ^^ Error: Signature mismatch: Modules do not match: functor () -> sig end diff --git a/testsuite/tests/typing-modules/ocamltests b/testsuite/tests/typing-modules/ocamltests new file mode 100644 index 00000000..24dd8694 --- /dev/null +++ b/testsuite/tests/typing-modules/ocamltests @@ -0,0 +1,12 @@ +aliases.ml +applicative_functor_type.ml +firstclass.ml +generative.ml +pr5911.ml +pr6394.ml +pr7207.ml +pr7348.ml +pr7787.ml +printing.ml +recursive.ml +Test.ml diff --git a/testsuite/tests/typing-modules/pr5911.ml b/testsuite/tests/typing-modules/pr5911.ml index e6f73539..2d8b557f 100644 --- a/testsuite/tests/typing-modules/pr5911.ml +++ b/testsuite/tests/typing-modules/pr5911.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module type S = sig type t val x : t diff --git a/testsuite/tests/typing-modules/pr6394.ml b/testsuite/tests/typing-modules/pr6394.ml new file mode 100644 index 00000000..82f4cb77 --- /dev/null +++ b/testsuite/tests/typing-modules/pr6394.ml @@ -0,0 +1,27 @@ +(* TEST + * expect +*) + +[@@@ ocaml.warning "+4"] +module rec X : sig + type t = int * bool +end = struct + type t = A | B + let f = function A | B -> 0 +end;; +[%%expect{| +Line _, characters 6-63: + ......struct + type t = A | B + let f = function A | B -> 0 + end.. +Error: Signature mismatch: + Modules do not match: + sig type t = X.t = A | B val f : t -> int end + is not included in + sig type t = int * bool end + Type declarations do not match: + type t = X.t = A | B + is not included in + type t = int * bool +|}];; diff --git a/testsuite/tests/typing-modules/pr7207.ml b/testsuite/tests/typing-modules/pr7207.ml index 1968f87c..c18176fc 100644 --- a/testsuite/tests/typing-modules/pr7207.ml +++ b/testsuite/tests/typing-modules/pr7207.ml @@ -1,7 +1,13 @@ +(* TEST + * expect +*) + module F (X : sig end) = struct type t = int end;; type t = F(Does_not_exist).t;; [%%expect{| module F : functor (X : sig end) -> sig type t = int end Line _, characters 9-28: + type t = F(Does_not_exist).t;; + ^^^^^^^^^^^^^^^^^^^ Error: Unbound module Does_not_exist |}];; diff --git a/testsuite/tests/typing-modules/pr7348.ml b/testsuite/tests/typing-modules/pr7348.ml index eac11e81..5cce4e2c 100644 --- a/testsuite/tests/typing-modules/pr7348.ml +++ b/testsuite/tests/typing-modules/pr7348.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module F (X : sig type t = private < foo:int; ..> val x : t end) = struct let x : < foo: int; ..> = X.x end;; diff --git a/testsuite/tests/typing-modules/pr7787.ml b/testsuite/tests/typing-modules/pr7787.ml new file mode 100644 index 00000000..4738df38 --- /dev/null +++ b/testsuite/tests/typing-modules/pr7787.ml @@ -0,0 +1,45 @@ +(* TEST + * expect +*) + +module O (T : sig + module N : sig + val foo : int -> int + end + end) = struct + open T + + let go () = + N.foo 42 (* finding N (from T) goes wrong *) +end + +module T = struct + module N = struct + let foo x = x + 3 + end +end;; +[%%expect{| +module O : + functor (T : sig module N : sig val foo : int -> int end end) -> + sig val go : unit -> int end +module T : sig module N : sig val foo : int -> int end end +|}] + +(* Incidentally, M isn't used in T2, but it doesn't seem to fail if + it's just "module M" and "module T2" separately *) +module rec M : sig + val go : unit -> int +end = O (T2) +and T2 : sig + include module type of struct include T end +end = struct + include T +end;; +[%%expect{| +module rec M : sig val go : unit -> int end +and T2 : sig module N = T.N end +|}] + +let () = ignore (M.go ()) +[%%expect{| +|}] diff --git a/testsuite/tests/typing-modules/printing.ml b/testsuite/tests/typing-modules/printing.ml index 1f107b8f..f6792ba8 100644 --- a/testsuite/tests/typing-modules/printing.ml +++ b/testsuite/tests/typing-modules/printing.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* PR#6650 *) module type S = sig diff --git a/testsuite/tests/typing-modules/recursive.ml b/testsuite/tests/typing-modules/recursive.ml index abf76e01..dd844c29 100644 --- a/testsuite/tests/typing-modules/recursive.ml +++ b/testsuite/tests/typing-modules/recursive.ml @@ -1,7 +1,13 @@ +(* TEST + * expect +*) + (* PR#7324 *) module rec T : sig type t = T.t end = T;; [%%expect{| Line _, characters 15-35: + module rec T : sig type t = T.t end = T;; + ^^^^^^^^^^^^^^^^^^^^ Error: The type abbreviation T.t is cyclic |}] diff --git a/testsuite/tests/typing-multifile/Makefile b/testsuite/tests/typing-multifile/Makefile deleted file mode 100644 index efcadaf2..00000000 --- a/testsuite/tests/typing-multifile/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -GENERATED= a.ml b.ml c.ml d.mli e.ml f.ml g.ml test - -default: pr7325 pr6372 pr7563 - -pr7325: - @printf " ... testing 'pr7325':" - @echo "type _ t = T" > a.ml - @echo "type 'a t = 'a A.t" > b.ml - @echo 'external f : unit -> unit B.t = "%identity"' > c.ml - @$(OCAMLC) -c a.ml b.ml && rm a.cmi && $(OCAMLC) -c c.ml \ - && echo " => passed" || echo " => failed" - -pr6372: - @printf " ... testing 'pr6372':" - @echo "type _ t = C: { f: ('a -> [<\`X]) t } -> [<\`X] t" > d.mli - @echo "open D;; let f (C {f}) = ()" > e.ml - @$(OCAMLC) -c d.mli e.ml \ - && echo " => passed" || echo " => failed" - -pr7563: - @printf " ... testing 'pr7563':" - @echo "module A = struct end" > f.ml - @echo "module Alias = A" >> f.ml - @echo "exception Alias" >> f.ml - @echo "let alias = Alias" >> f.ml - @echo "exit (if F.Alias = F.alias then 0 else 1)" > g.ml - @$(OCAMLC) f.ml g.ml -o test && $(OCAMLRUN) ./test \ - && echo " => passed" || echo " => failed" - -clean: defaultclean - @rm -f $(GENERATED) - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-multifile/a.ml b/testsuite/tests/typing-multifile/a.ml new file mode 100644 index 00000000..03ee0dcd --- /dev/null +++ b/testsuite/tests/typing-multifile/a.ml @@ -0,0 +1 @@ +type _ t = T diff --git a/testsuite/tests/typing-multifile/b.ml b/testsuite/tests/typing-multifile/b.ml new file mode 100644 index 00000000..ea1529f6 --- /dev/null +++ b/testsuite/tests/typing-multifile/b.ml @@ -0,0 +1 @@ +type 'a t = 'a A.t diff --git a/testsuite/tests/typing-multifile/c.ml b/testsuite/tests/typing-multifile/c.ml new file mode 100644 index 00000000..28e2e982 --- /dev/null +++ b/testsuite/tests/typing-multifile/c.ml @@ -0,0 +1 @@ +external f : unit -> unit B.t = "%identity" diff --git a/testsuite/tests/typing-multifile/d.mli b/testsuite/tests/typing-multifile/d.mli new file mode 100644 index 00000000..3dfbd091 --- /dev/null +++ b/testsuite/tests/typing-multifile/d.mli @@ -0,0 +1 @@ +type _ t = C: { f: ('a -> [<`X]) t } -> [<`X] t diff --git a/testsuite/tests/typing-multifile/e.ml b/testsuite/tests/typing-multifile/e.ml new file mode 100644 index 00000000..c9e89ba9 --- /dev/null +++ b/testsuite/tests/typing-multifile/e.ml @@ -0,0 +1 @@ +open D;; let f (C {f}) = () diff --git a/testsuite/tests/typing-multifile/f.ml b/testsuite/tests/typing-multifile/f.ml new file mode 100644 index 00000000..ac45c734 --- /dev/null +++ b/testsuite/tests/typing-multifile/f.ml @@ -0,0 +1,4 @@ +module A = struct end +module Alias = A +exception Alias +let alias = Alias diff --git a/testsuite/tests/typing-multifile/ocamltests b/testsuite/tests/typing-multifile/ocamltests new file mode 100644 index 00000000..af8a34d4 --- /dev/null +++ b/testsuite/tests/typing-multifile/ocamltests @@ -0,0 +1,3 @@ +pr6372.ml +pr7325.ml +pr7563.ml diff --git a/testsuite/tests/typing-multifile/pr6372.ml b/testsuite/tests/typing-multifile/pr6372.ml new file mode 100644 index 00000000..727839cf --- /dev/null +++ b/testsuite/tests/typing-multifile/pr6372.ml @@ -0,0 +1,9 @@ +(* TEST +files = "d.mli e.ml" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "d.mli" +*** ocamlc.byte +module = "e.ml" +**** check-ocamlc.byte-output +*) diff --git a/testsuite/tests/typing-multifile/pr7325.ml b/testsuite/tests/typing-multifile/pr7325.ml new file mode 100644 index 00000000..918549d7 --- /dev/null +++ b/testsuite/tests/typing-multifile/pr7325.ml @@ -0,0 +1,13 @@ +(* TEST +files = "a.ml b.ml c.ml" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "a.ml" +*** ocamlc.byte +module = "b.ml" +**** script +script = "rm a.cmi" +***** ocamlc.byte +module = "c.ml" +****** check-ocamlc.byte-output +*) \ No newline at end of file diff --git a/testsuite/tests/typing-multifile/pr7563.ml b/testsuite/tests/typing-multifile/pr7563.ml new file mode 100644 index 00000000..d7950efb --- /dev/null +++ b/testsuite/tests/typing-multifile/pr7563.ml @@ -0,0 +1,5 @@ +(* TEST +modules = "f.ml" +*) + +exit (if F.Alias = F.alias then 0 else 1) diff --git a/testsuite/tests/typing-objects-bugs/Makefile b/testsuite/tests/typing-objects-bugs/Makefile deleted file mode 100644 index 69e2ee7b..00000000 --- a/testsuite/tests/typing-objects-bugs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.okbad -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-objects-bugs/ocamltests b/testsuite/tests/typing-objects-bugs/ocamltests new file mode 100644 index 00000000..7b3c8ec4 --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/ocamltests @@ -0,0 +1,11 @@ +pr3968_bad.ml +pr4018_bad.ml +pr4435_bad.ml +pr4766_ok.ml +pr4824_ok.ml +pr4824a_bad.ml +pr5156_ok.ml +pr7284_bad.ml +pr7293_ok.ml +woodyatt_ok.ml +yamagata021012_ok.ml diff --git a/testsuite/tests/typing-objects-bugs/pr3968_bad.compilers.reference b/testsuite/tests/typing-objects-bugs/pr3968_bad.compilers.reference new file mode 100644 index 00000000..dae88bcc --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/pr3968_bad.compilers.reference @@ -0,0 +1,39 @@ +File "pr3968_bad.ml", line 20, characters 0-165: +Error: The class type + object + val l : + [ `Abs of + string * + ([ `Abs of string * expr | `App of 'a * exp ] as 'b) + | `App of expr * expr ] as 'a + val r : exp + method eval : (string, exp) Hashtbl.t -> 'b + end + is not matched by the class type exp + The class type + object + val l : + [ `Abs of + string * + ([ `Abs of string * expr | `App of 'a * exp ] as 'b) + | `App of expr * expr ] as 'a + val r : exp + method eval : (string, exp) Hashtbl.t -> 'b + end + is not matched by the class type + object method eval : (string, exp) Hashtbl.t -> expr end + The method eval has type + (string, exp) Hashtbl.t -> + ([ `Abs of string * expr + | `App of [ `Abs of string * 'a | `App of expr * expr ] * exp ] + as 'a) + but is expected to have type (string, exp) Hashtbl.t -> expr + Type + [ `Abs of string * expr + | `App of [ `Abs of string * 'a | `App of expr * expr ] * exp ] + as 'a + is not compatible with type + expr = [ `Abs of string * expr | `App of expr * expr ] + Type exp = < eval : (string, exp) Hashtbl.t -> expr > + is not compatible with type + expr = [ `Abs of string * expr | `App of expr * expr ] diff --git a/testsuite/tests/typing-objects-bugs/pr3968_bad.ml b/testsuite/tests/typing-objects-bugs/pr3968_bad.ml index 01c50666..6b04eee0 100644 --- a/testsuite/tests/typing-objects-bugs/pr3968_bad.ml +++ b/testsuite/tests/typing-objects-bugs/pr3968_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type expr = [ `Abs of string * expr | `App of expr * expr diff --git a/testsuite/tests/typing-objects-bugs/pr4018_bad.compilers.reference b/testsuite/tests/typing-objects-bugs/pr4018_bad.compilers.reference new file mode 100644 index 00000000..bbcbed53 --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/pr4018_bad.compilers.reference @@ -0,0 +1,41 @@ +File "pr4018_bad.ml", line 42, characters 11-17: +Error: This type entity = < destroy_subject : id subject; entity_id : id > + should be an instance of type + < destroy_subject : < add_observer : 'a entity_container -> 'c; .. > + as 'b; + .. > + as 'a + Type + id subject = + < add_observer : (id subject, id) observer -> unit; + notify_observers : id -> unit > + is not compatible with type + < add_observer : 'a entity_container -> 'c; .. > as 'b + Type (id subject, id) observer = < notify : id subject -> id -> unit > + is not compatible with type + 'a entity_container = + < add_entity : (< destroy_subject : < add_observer : 'a + entity_container -> + 'e; + .. >; + .. > + as 'd) -> + 'e; + notify : 'd -> id -> unit > + Type < destroy_subject : id subject; entity_id : id > + is not compatible with type + entity = < destroy_subject : id subject; entity_id : id > + Type + < add_observer : (id subject, id) observer -> unit; + notify_observers : id -> unit > + is not compatible with type + id subject = + < add_observer : (id subject, id) observer -> unit; + notify_observers : id -> unit > + Type < add_entity : 'd -> 'e; notify : 'd -> id -> unit > + is not compatible with type + 'a entity_container = + < add_entity : 'd -> 'e; notify : 'd -> id -> unit > + Type < notify : id subject -> id -> unit > is not compatible with type + (id subject, id) observer = < notify : id subject -> id -> unit > + Types for method add_entity are incompatible diff --git a/testsuite/tests/typing-objects-bugs/pr4018_bad.ml b/testsuite/tests/typing-objects-bugs/pr4018_bad.ml index 5195d463..8d23f82d 100644 --- a/testsuite/tests/typing-objects-bugs/pr4018_bad.ml +++ b/testsuite/tests/typing-objects-bugs/pr4018_bad.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) class virtual ['subject, 'event] observer = object diff --git a/testsuite/tests/typing-objects-bugs/pr4435_bad.compilers.reference b/testsuite/tests/typing-objects-bugs/pr4435_bad.compilers.reference new file mode 100644 index 00000000..84f74be0 --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/pr4435_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr4435_bad.ml", line 14, characters 6-7: +Error: Multiple definition of the type name c. + Names must be unique in a given structure or signature. diff --git a/testsuite/tests/typing-objects-bugs/pr4435_bad.ml b/testsuite/tests/typing-objects-bugs/pr4435_bad.ml index c9e1d499..f869e7d6 100644 --- a/testsuite/tests/typing-objects-bugs/pr4435_bad.ml +++ b/testsuite/tests/typing-objects-bugs/pr4435_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Two v's in the same class *) class c v = object initializer print_endline v val v = 42 end;; new c "42";; diff --git a/testsuite/tests/typing-objects-bugs/pr4766_ok.ml b/testsuite/tests/typing-objects-bugs/pr4766_ok.ml index 726cc866..d8511e56 100644 --- a/testsuite/tests/typing-objects-bugs/pr4766_ok.ml +++ b/testsuite/tests/typing-objects-bugs/pr4766_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + class virtual ['a] c = object (s : 'a) method virtual m : 'b diff --git a/testsuite/tests/typing-objects-bugs/pr4824_ok.ml b/testsuite/tests/typing-objects-bugs/pr4824_ok.ml index 90695937..7b31b5d9 100644 --- a/testsuite/tests/typing-objects-bugs/pr4824_ok.ml +++ b/testsuite/tests/typing-objects-bugs/pr4824_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M : sig class x : int -> object method m : int end diff --git a/testsuite/tests/typing-objects-bugs/pr4824a_bad.compilers.reference b/testsuite/tests/typing-objects-bugs/pr4824a_bad.compilers.reference new file mode 100644 index 00000000..01c209e3 --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/pr4824a_bad.compilers.reference @@ -0,0 +1,10 @@ +File "pr4824a_bad.ml", line 10, characters 2-45: +Error: Signature mismatch: + ... + Class declarations do not match: + class c : 'a -> object val x : 'a end + does not match + class c : 'a -> object val x : 'b end + The instance variable x has type 'a but is expected to have type 'b + This instance of 'b is ambiguous: + it would escape the scope of its equation diff --git a/testsuite/tests/typing-objects-bugs/pr4824a_bad.ml b/testsuite/tests/typing-objects-bugs/pr4824a_bad.ml index 983455b4..37002d71 100644 --- a/testsuite/tests/typing-objects-bugs/pr4824a_bad.ml +++ b/testsuite/tests/typing-objects-bugs/pr4824a_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M : sig class c : 'a -> object val x : 'b end end = struct class c x = object val x = x end end diff --git a/testsuite/tests/typing-objects-bugs/pr5156_ok.ml b/testsuite/tests/typing-objects-bugs/pr5156_ok.ml index ba8288da..6c52480c 100644 --- a/testsuite/tests/typing-objects-bugs/pr5156_ok.ml +++ b/testsuite/tests/typing-objects-bugs/pr5156_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + class type t = object end;; class ['a] o1 = object (self : #t as 'a) end;; type 'a obj = ( < .. > as 'a);; diff --git a/testsuite/tests/typing-objects-bugs/pr7284_bad.compilers.reference b/testsuite/tests/typing-objects-bugs/pr7284_bad.compilers.reference new file mode 100644 index 00000000..0969398d --- /dev/null +++ b/testsuite/tests/typing-objects-bugs/pr7284_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr7284_bad.ml", line 35, characters 30-62: +Error (warning 8): this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +V2 _ diff --git a/testsuite/tests/typing-objects-bugs/pr7284_bad.ml b/testsuite/tests/typing-objects-bugs/pr7284_bad.ml index d6ba2ea5..4d236cb5 100644 --- a/testsuite/tests/typing-objects-bugs/pr7284_bad.ml +++ b/testsuite/tests/typing-objects-bugs/pr7284_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig type o1 = < bar : int; foo : int > diff --git a/testsuite/tests/typing-objects-bugs/pr7293_ok.ml b/testsuite/tests/typing-objects-bugs/pr7293_ok.ml index 60528146..88694877 100644 --- a/testsuite/tests/typing-objects-bugs/pr7293_ok.ml +++ b/testsuite/tests/typing-objects-bugs/pr7293_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type t = T : t type s = T diff --git a/testsuite/tests/typing-objects-bugs/woodyatt_ok.ml b/testsuite/tests/typing-objects-bugs/woodyatt_ok.ml index 627158bc..d0969457 100644 --- a/testsuite/tests/typing-objects-bugs/woodyatt_ok.ml +++ b/testsuite/tests/typing-objects-bugs/woodyatt_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* test.ml *) class alfa = object(_:'self) method x: 'a. ('a, out_channel, unit) format -> 'a = Printf.printf diff --git a/testsuite/tests/typing-objects-bugs/yamagata021012_ok.ml b/testsuite/tests/typing-objects-bugs/yamagata021012_ok.ml index 0189310e..09282762 100644 --- a/testsuite/tests/typing-objects-bugs/yamagata021012_ok.ml +++ b/testsuite/tests/typing-objects-bugs/yamagata021012_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* The module begins *) exception Out_of_range diff --git a/testsuite/tests/typing-objects/Exemples.ml b/testsuite/tests/typing-objects/Exemples.ml index f0ab4d53..855ba343 100644 --- a/testsuite/tests/typing-objects/Exemples.ml +++ b/testsuite/tests/typing-objects/Exemples.ml @@ -1,55 +1,142 @@ +(* TEST + * expect +*) class point x_init = object val mutable x = x_init method get_x = x method move d = x <- x + d end;; +[%%expect{| +class point : + int -> + object val mutable x : int method get_x : int method move : int -> unit end +|}];; let p = new point 7;; +[%%expect{| +val p : point = +|}];; p#get_x;; +[%%expect{| +- : int = 7 +|}];; p#move 3;; +[%%expect{| +- : unit = () +|}];; p#get_x;; +[%%expect{| +- : int = 10 +|}];; let q = Oo.copy p;; +[%%expect{| +val q : point = +|}, Principal{| +val q : < get_x : int; move : int -> unit > = +|}];; q#move 7; p#get_x, q#get_x;; +[%%expect{| +- : int * int = (10, 17) +|}];; class color_point x (c : string) = object inherit point x val c = c method color = c end;; +[%%expect{| +class color_point : + int -> + string -> + object + val c : string + val mutable x : int + method color : string + method get_x : int + method move : int -> unit + end +|}];; let p' = new color_point 5 "red";; +[%%expect{| +val p' : color_point = +|}];; p'#get_x, p'#color;; +[%%expect{| +- : int * string = (5, "red") +|}];; let l = [p; (p' :> point)];; +[%%expect{| +val l : point list = [; ] +|}];; let get_x p = p#get_x;; +[%%expect{| +val get_x : < get_x : 'a; .. > -> 'a = +|}];; let set_x p = p#set_x;; +[%%expect{| +val set_x : < set_x : 'a; .. > -> 'a = +|}];; List.map get_x l;; +[%%expect{| +- : int list = [10; 5] +|}];; class ref x_init = object val mutable x = x_init method get = x method set y = x <- y end;; +[%%expect{| +Line _, characters 0-95: + class ref x_init = object + val mutable x = x_init + method get = x + method set y = x <- y + end.. +Error: Some type variables are unbound in this type: + class ref : + 'a -> + object + val mutable x : 'a + method get : 'a + method set : 'a -> unit + end + The method get has type 'a where 'a is unbound +|}];; class ref (x_init:int) = object val mutable x = x_init method get = x method set y = x <- y end;; +[%%expect{| +class ref : + int -> + object val mutable x : int method get : int method set : int -> unit end +|}];; class ['a] ref x_init = object val mutable x = (x_init : 'a) method get = x method set y = x <- y end;; +[%%expect{| +class ['a] ref : + 'a -> object val mutable x : 'a method get : 'a method set : 'a -> unit end +|}];; let r = new ref 1 in r#set 2; (r#get);; +[%%expect{| +- : int = 2 +|}];; class ['a] circle (c : 'a) = object val mutable center = c @@ -57,6 +144,17 @@ class ['a] circle (c : 'a) = object method set_center c = center <- c method move = (center#move : int -> unit) end;; +[%%expect{| +class ['a] circle : + 'a -> + object + constraint 'a = < move : int -> unit; .. > + val mutable center : 'a + method center : 'a + method move : int -> unit + method set_center : 'a -> unit + end +|}];; class ['a] circle (c : 'a) = object constraint 'a = #point @@ -65,57 +163,188 @@ class ['a] circle (c : 'a) = object method set_center c = center <- c method move = center#move end;; +[%%expect{| +class ['a] circle : + 'a -> + object + constraint 'a = #point + val mutable center : 'a + method center : 'a + method move : int -> unit + method set_center : 'a -> unit + end +|}];; let (c, c') = (new circle p, new circle p');; +[%%expect{| +val c : point circle = +val c' : color_point circle = +|}, Principal{| +val c : point circle = +val c' : < color : string; get_x : int; move : int -> unit > circle = +|}];; class ['a] color_circle c = object constraint 'a = #color_point inherit ['a] circle c method color = center#color end;; +[%%expect{| +class ['a] color_circle : + 'a -> + object + constraint 'a = #color_point + val mutable center : 'a + method center : 'a + method color : string + method move : int -> unit + method set_center : 'a -> unit + end +|}];; let c'' = new color_circle p;; +[%%expect{| +Line _, characters 27-28: + let c'' = new color_circle p;; + ^ +Error: This expression has type point but an expression was expected of type + #color_point + The first object type has no method color +|}];; let c'' = new color_circle p';; +[%%expect{| +val c'' : color_point color_circle = +|}];; (c'' :> color_point circle);; -(c'' :> point circle);; (* Fail *) +[%%expect{| +- : color_point circle = +|}];; +(c'' :> point circle);; +[%%expect{| +Line _, characters 0-21: + (c'' :> point circle);; + ^^^^^^^^^^^^^^^^^^^^^ +Error: Type + color_point color_circle = + < center : color_point; color : string; move : int -> unit; + set_center : color_point -> unit > + is not a subtype of + point circle = + < center : point; move : int -> unit; set_center : point -> unit > + Type point is not a subtype of color_point +|}];; (* Fail *) fun x -> (x : color_point color_circle :> point circle);; +[%%expect{| +Line _, characters 9-55: + fun x -> (x : color_point color_circle :> point circle);; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Type + color_point color_circle = + < center : color_point; color : string; move : int -> unit; + set_center : color_point -> unit > + is not a subtype of + point circle = + < center : point; move : int -> unit; set_center : point -> unit > + Type point is not a subtype of color_point +|}];; class printable_point y = object (s) inherit point y - method print = print_int s#get_x + method print = Format.print_int s#get_x end;; +[%%expect{| +class printable_point : + int -> + object + val mutable x : int + method get_x : int + method move : int -> unit + method print : unit + end +|}];; let p = new printable_point 7;; +[%%expect{| +val p : printable_point = +|}];; p#print;; +[%%expect{| +- : unit = () +|}];; class printable_color_point y c = object (self) inherit color_point y c inherit printable_point y as super method print = - print_string "("; + Format.print_string "("; super#print; - print_string ", "; - print_string (self#color); - print_string ")" + Format.print_string ", "; + Format.print_string (self#color); + Format.print_string ")" end;; +[%%expect{| +Line _, characters 10-27: + inherit printable_point y as super + ^^^^^^^^^^^^^^^^^ +Warning 13: the following instance variables are overridden by the class printable_point : + x +The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) +class printable_color_point : + int -> + string -> + object + val c : string + val mutable x : int + method color : string + method get_x : int + method move : int -> unit + method print : unit + end +|}];; let p' = new printable_color_point 7 "red";; +[%%expect{| +val p' : printable_color_point = +|}];; p'#print;; +[%%expect{| +- : unit = () +|}];; class functional_point y = object val x = y method get_x = x method move d = {< x = x + d >} end;; +[%%expect{| +class functional_point : + int -> + object ('a) val x : int method get_x : int method move : int -> 'a end +|}];; let p = new functional_point 7;; +[%%expect{| +val p : functional_point = +|}];; p#get_x;; +[%%expect{| +- : int = 7 +|}];; (p#move 3)#get_x;; +[%%expect{| +- : int = 10 +|}];; p#get_x;; +[%%expect{| +- : int = 7 +|}];; fun x -> (x :> functional_point);; +[%%expect{| +- : #functional_point -> functional_point = +|}];; (*******************************************************************) @@ -136,10 +365,10 @@ class virtual ['a] lst () = object (self) self#tl#iter f end method print (f : 'a -> unit) = - print_string "("; - self#iter (fun x -> f x; print_string "::"); - print_string "[]"; - print_string ")" + Format.print_string "("; + self#iter (fun x -> f x; Format.print_string "::"); + Format.print_string "[]"; + Format.print_string ")" end and ['a] nil () = object inherit ['a] lst () method null = true @@ -152,26 +381,86 @@ end and ['a] cons h t = object method hd = h method tl = t end;; +[%%expect{| +class virtual ['a] lst : + unit -> + object + method virtual hd : 'a + method iter : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst + method virtual null : bool + method print : ('a -> unit) -> unit + method virtual tl : 'a lst + end +and ['a] nil : + unit -> + object + method hd : 'a + method iter : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst + method null : bool + method print : ('a -> unit) -> unit + method tl : 'a lst + end +and ['a] cons : + 'a -> + 'a lst -> + object + val h : 'a + val t : 'a lst + method hd : 'a + method iter : ('a -> unit) -> unit + method map : ('a -> 'a) -> 'a lst + method null : bool + method print : ('a -> unit) -> unit + method tl : 'a lst + end +|}];; let l1 = new cons 3 (new cons 10 (new nil ()));; +[%%expect{| +val l1 : int lst = +|}];; -l1#print print_int;; +l1#print Format.print_int;; +[%%expect{| +- : unit = () +|}];; let l2 = l1#map (fun x -> x + 1);; -l2#print print_int;; +[%%expect{| +val l2 : int lst = +|}];; +l2#print Format.print_int;; +[%%expect{| +- : unit = () +|}];; let rec map_list f (x:'a lst) = if x#null then new nil() else new cons (f x#hd) (map_list f x#tl);; +[%%expect{| +val map_list : ('a -> 'b) -> 'a lst -> 'b lst = +|}];; let p1 = (map_list (fun x -> new printable_color_point x "red") l1);; +[%%expect{| +val p1 : printable_color_point lst = +|}];; p1#print (fun x -> x#print);; +[%%expect{| +- : unit = () +|}];; (*******************************************************************) class virtual comparable () = object (self : 'a) method virtual cmp : 'a -> int end;; +[%%expect{| +class virtual comparable : + unit -> object ('a) method virtual cmp : 'a -> int end +|}];; class int_comparable (x : int) = object inherit comparable () @@ -179,12 +468,27 @@ class int_comparable (x : int) = object method x = x method cmp p = compare x p#x end;; +[%%expect{| +class int_comparable : + int -> object ('a) val x : int method cmp : 'a -> int method x : int end +|}];; class int_comparable2 xi = object inherit int_comparable xi val mutable x' = xi method set_x y = x' <- y end;; +[%%expect{| +class int_comparable2 : + int -> + object ('a) + val x : int + val mutable x' : int + method cmp : 'a -> int + method set_x : int -> unit + method x : int + end +|}];; class ['a] sorted_list () = object constraint 'a = #comparable @@ -198,14 +502,53 @@ class ['a] sorted_list () = object l <- insert l method hd = List.hd l end;; +[%%expect{| +class ['a] sorted_list : + unit -> + object + constraint 'a = #comparable + val mutable l : 'a list + method add : 'a -> unit + method hd : 'a + end +|}];; let l = new sorted_list ();; +[%%expect{| +val l : _#comparable sorted_list = +|}];; let c = new int_comparable 10;; +[%%expect{| +val c : int_comparable = +|}];; l#add c;; +[%%expect{| +- : unit = () +|}];; let c2 = new int_comparable2 15;; -l#add (c2 :> int_comparable);; (* Fail : 'a comp2 is not a subtype *) +[%%expect{| +val c2 : int_comparable2 = +|}];; +l#add (c2 :> int_comparable);; +[%%expect{| +Line _, characters 6-28: + l#add (c2 :> int_comparable);; + ^^^^^^^^^^^^^^^^^^^^^^ +Error: Type + int_comparable2 = + < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > + is not a subtype of + int_comparable = < cmp : int_comparable -> int; x : int > + Type int_comparable = < cmp : int_comparable -> int; x : int > + is not a subtype of + int_comparable2 = + < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > +|}];; (* Fail : 'a comp2 is not a subtype *) (new sorted_list ())#add c2;; +[%%expect{| +- : unit = () +|}];; class int_comparable3 (x : int) = object val mutable x = x @@ -213,28 +556,112 @@ class int_comparable3 (x : int) = object method x = x method setx y = x <- y end;; +[%%expect{| +class int_comparable3 : + int -> + object + val mutable x : int + method cmp : int_comparable -> int + method setx : int -> unit + method x : int + end +|}];; let c3 = new int_comparable3 15;; +[%%expect{| +val c3 : int_comparable3 = +|}];; l#add (c3 :> int_comparable);; -(new sorted_list ())#add c3;; (* Error; strange message with -principal *) +[%%expect{| +- : unit = () +|}];; +(new sorted_list ())#add c3;; +[%%expect{| +Line _, characters 25-27: + (new sorted_list ())#add c3;; + ^^ +Error: This expression has type + int_comparable3 = + < cmp : int_comparable -> int; setx : int -> unit; x : int > + but an expression was expected of type + #comparable as 'a = < cmp : 'a -> int; .. > + Type int_comparable = < cmp : int_comparable -> int; x : int > + is not compatible with type + int_comparable3 = + < cmp : int_comparable -> int; setx : int -> unit; x : int > + The first object type has no method setx +|}, Principal{| +Line _, characters 25-27: + (new sorted_list ())#add c3;; + ^^ +Error: This expression has type + int_comparable3 = + < cmp : int_comparable -> int; setx : int -> unit; x : int > + but an expression was expected of type + #comparable as 'a = < cmp : 'a -> int; .. > + Type int_comparable = < cmp : int_comparable -> int; x : int > + is not compatible with type 'a = < cmp : 'a -> int; .. > + The first object type has no method setx +|}];; (* Error; strange message with -principal *) let sort (l : #comparable list) = List.sort (fun x -> x#cmp) l;; +[%%expect{| +val sort : (#comparable as 'a) list -> 'a list = +|}];; let pr l = - List.map (fun c -> print_int c#x; print_string " ") l; - print_newline ();; + List.map (fun c -> Format.print_int c#x; Format.print_string " ") l; + Format.print_newline ();; +[%%expect{| +Line _, characters 2-69: + List.map (fun c -> Format.print_int c#x; Format.print_string " ") l; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 10: this expression should have type unit. +val pr : < x : int; .. > list -> unit = +|}];; let l = [new int_comparable 5; (new int_comparable3 2 :> int_comparable); new int_comparable 4];; +[%%expect{| +val l : int_comparable list = [; ; ] +|}];; pr l;; +[%%expect{| +7(7, red)(3::10::[])(4::11::[])((3, red)::(10, red)::[])5 2 4 +- : unit = () +|}];; pr (sort l);; +[%%expect{| +2 4 5 +- : unit = () +|}];; let l = [new int_comparable2 2; new int_comparable2 0];; +[%%expect{| +val l : int_comparable2 list = [; ] +|}];; pr l;; +[%%expect{| +2 0 +- : unit = () +|}];; pr (sort l);; +[%%expect{| +0 2 +- : unit = () +|}];; let min (x : #comparable) y = if x#cmp y <= 0 then x else y;; +[%%expect{| +val min : (#comparable as 'a) -> 'a -> 'a = +|}];; (min (new int_comparable 7) (new int_comparable 11))#x;; +[%%expect{| +- : int = 7 +|}];; (min (new int_comparable2 5) (new int_comparable2 3))#x;; +[%%expect{| +- : int = 3 +|}];; (*******************************************************************) @@ -252,6 +679,19 @@ class ['a] link (x : 'a) = object (self : 'b) | Some l' -> l'#append l end;; +[%%expect{| +class ['a] link : + 'a -> + object ('b) + val mutable next : 'b option + val mutable x : 'a + method append : 'b option -> unit + method next : 'b option + method set_next : 'b option -> unit + method set_x : 'a -> unit + method x : 'a + end +|}];; class ['a] double_link x = object (self) inherit ['a] link x @@ -262,12 +702,31 @@ class ['a] double_link x = object (self) match l with Some l -> l#set_prev (Some self) | None -> () method set_prev l = prev <- l end;; +[%%expect{| +class ['a] double_link : + 'a -> + object ('b) + val mutable next : 'b option + val mutable prev : 'b option + val mutable x : 'a + method append : 'b option -> unit + method next : 'b option + method prev : 'b option + method set_next : 'b option -> unit + method set_prev : 'b option -> unit + method set_x : 'a -> unit + method x : 'a + end +|}];; let rec fold_right f (l : 'a #link option) accu = match l with None -> accu | Some l -> f l#x (fold_right f l#next accu);; +[%%expect{| +val fold_right : ('a -> 'b -> 'b) -> 'a #link option -> 'b -> 'b = +|}];; (*******************************************************************) @@ -288,10 +747,34 @@ class calculator () = object (self) self method equals = equals self end;; +[%%expect{| +class calculator : + unit -> + object ('a) + val mutable acc : float + val mutable arg : float + val mutable equals : 'a -> float + method acc : float + method add : 'a + method arg : float + method enter : float -> 'a + method equals : float + method sub : 'a + end +|}];; ((new calculator ())#enter 5.)#equals;; +[%%expect{| +- : float = 5. +|}];; (((new calculator ())#enter 5.)#sub#enter 3.5)#equals;; +[%%expect{| +- : float = 1.5 +|}];; ((new calculator ())#enter 5.)#add#add#equals;; +[%%expect{| +- : float = 15. +|}];; class calculator () = object (self) val mutable arg = 0. @@ -304,10 +787,34 @@ class calculator () = object (self) method sub = {< acc = equals self; equals = function s -> s#acc -. s#arg >} method equals = equals self end;; +[%%expect{| +class calculator : + unit -> + object ('a) + val mutable acc : float + val mutable arg : float + val mutable equals : 'a -> float + method acc : float + method add : 'a + method arg : float + method enter : float -> 'a + method equals : float + method sub : 'a + end +|}];; ((new calculator ())#enter 5.)#equals;; +[%%expect{| +- : float = 5. +|}];; (((new calculator ())#enter 5.)#sub#enter 3.5)#equals;; +[%%expect{| +- : float = 1.5 +|}];; ((new calculator ())#enter 5.)#add#add#equals;; +[%%expect{| +- : float = 15. +|}];; class calculator arg acc = object (self) val arg = arg @@ -325,9 +832,56 @@ end and calculator_sub arg acc = object method enter n = new calculator_sub n acc method equals = acc -. arg end;; +[%%expect{| +class calculator : + float -> + float -> + object + val acc : float + val arg : float + method add : calculator + method enter : float -> calculator + method equals : float + method sub : calculator + end +and calculator_add : + float -> + float -> + object + val acc : float + val arg : float + method add : calculator + method enter : float -> calculator + method equals : float + method sub : calculator + end +and calculator_sub : + float -> + float -> + object + val acc : float + val arg : float + method add : calculator + method enter : float -> calculator + method equals : float + method sub : calculator + end +|}];; let calculator = new calculator 0. 0.;; +[%%expect{| +val calculator : calculator = +|}];; (calculator#enter 5.)#equals;; +[%%expect{| +- : float = 5. +|}];; ((calculator#enter 5.)#sub#enter 3.5)#equals;; +[%%expect{| +- : float = 1.5 +|}];; (calculator#enter 5.)#add#add#equals;; +[%%expect{| +- : float = 15. +|}];; diff --git a/testsuite/tests/typing-objects/Exemples.ml.principal.reference b/testsuite/tests/typing-objects/Exemples.ml.principal.reference deleted file mode 100644 index 67090461..00000000 --- a/testsuite/tests/typing-objects/Exemples.ml.principal.reference +++ /dev/null @@ -1,358 +0,0 @@ - -# class point : - int -> - object val mutable x : int method get_x : int method move : int -> unit end -# val p : point = -# - : int = 7 -# - : unit = () -# - : int = 10 -# val q : < get_x : int; move : int -> unit > = -# - : int * int = (10, 17) -# class color_point : - int -> - string -> - object - val c : string - val mutable x : int - method color : string - method get_x : int - method move : int -> unit - end -# val p' : color_point = -# - : int * string = (5, "red") -# val l : point list = [; ] -# val get_x : < get_x : 'a; .. > -> 'a = -# val set_x : < set_x : 'a; .. > -> 'a = -# - : int list = [10; 5] -# Characters 1-96: - class ref x_init = object - val mutable x = x_init - method get = x - method set y = x <- y - end.. -Error: Some type variables are unbound in this type: - class ref : - 'a -> - object - val mutable x : 'a - method get : 'a - method set : 'a -> unit - end - The method get has type 'a where 'a is unbound -# class ref : - int -> - object val mutable x : int method get : int method set : int -> unit end -# class ['a] ref : - 'a -> object val mutable x : 'a method get : 'a method set : 'a -> unit end -# - : int = 2 -# class ['a] circle : - 'a -> - object - constraint 'a = < move : int -> unit; .. > - val mutable center : 'a - method center : 'a - method move : int -> unit - method set_center : 'a -> unit - end -# class ['a] circle : - 'a -> - object - constraint 'a = #point - val mutable center : 'a - method center : 'a - method move : int -> unit - method set_center : 'a -> unit - end -# val c : point circle = -val c' : < color : string; get_x : int; move : int -> unit > circle = -# class ['a] color_circle : - 'a -> - object - constraint 'a = #color_point - val mutable center : 'a - method center : 'a - method color : string - method move : int -> unit - method set_center : 'a -> unit - end -# Characters 28-29: - let c'' = new color_circle p;; - ^ -Error: This expression has type point but an expression was expected of type - #color_point - The first object type has no method color -# val c'' : color_point color_circle = -# - : color_point circle = -# Characters 0-21: - (c'' :> point circle);; (* Fail *) - ^^^^^^^^^^^^^^^^^^^^^ -Error: Type - color_point color_circle = - < center : color_point; color : string; move : int -> unit; - set_center : color_point -> unit > - is not a subtype of - point circle = - < center : point; move : int -> unit; set_center : point -> unit > - Type point is not a subtype of color_point -# Characters 9-55: - fun x -> (x : color_point color_circle :> point circle);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type - color_point color_circle = - < center : color_point; color : string; move : int -> unit; - set_center : color_point -> unit > - is not a subtype of - point circle = - < center : point; move : int -> unit; set_center : point -> unit > - Type point is not a subtype of color_point -# class printable_point : - int -> - object - val mutable x : int - method get_x : int - method move : int -> unit - method print : unit - end -# val p : printable_point = -# 7- : unit = () -# Characters 85-102: - inherit printable_point y as super - ^^^^^^^^^^^^^^^^^ -Warning 13: the following instance variables are overridden by the class printable_point : - x -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -class printable_color_point : - int -> - string -> - object - val c : string - val mutable x : int - method color : string - method get_x : int - method move : int -> unit - method print : unit - end -# val p' : printable_color_point = -# (7, red)- : unit = () -# class functional_point : - int -> - object ('a) val x : int method get_x : int method move : int -> 'a end -# val p : functional_point = -# - : int = 7 -# - : int = 10 -# - : int = 7 -# - : #functional_point -> functional_point = -# class virtual ['a] lst : - unit -> - object - method virtual hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method virtual null : bool - method print : ('a -> unit) -> unit - method virtual tl : 'a lst - end -and ['a] nil : - unit -> - object - method hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method null : bool - method print : ('a -> unit) -> unit - method tl : 'a lst - end -and ['a] cons : - 'a -> - 'a lst -> - object - val h : 'a - val t : 'a lst - method hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method null : bool - method print : ('a -> unit) -> unit - method tl : 'a lst - end -# val l1 : int lst = -# (3::10::[])- : unit = () -# val l2 : int lst = -# (4::11::[])- : unit = () -# val map_list : ('a -> 'b) -> 'a lst -> 'b lst = -# val p1 : printable_color_point lst = -# ((3, red)::(10, red)::[])- : unit = () -# class virtual comparable : - unit -> object ('a) method virtual cmp : 'a -> int end -# class int_comparable : - int -> object ('a) val x : int method cmp : 'a -> int method x : int end -# class int_comparable2 : - int -> - object ('a) - val x : int - val mutable x' : int - method cmp : 'a -> int - method set_x : int -> unit - method x : int - end -# class ['a] sorted_list : - unit -> - object - constraint 'a = #comparable - val mutable l : 'a list - method add : 'a -> unit - method hd : 'a - end -# val l : _#comparable sorted_list = -# val c : int_comparable = -# - : unit = () -# val c2 : int_comparable2 = -# Characters 6-28: - l#add (c2 :> int_comparable);; (* Fail : 'a comp2 is not a subtype *) - ^^^^^^^^^^^^^^^^^^^^^^ -Error: Type - int_comparable2 = - < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > - is not a subtype of - int_comparable = < cmp : int_comparable -> int; x : int > - Type int_comparable = < cmp : int_comparable -> int; x : int > - is not a subtype of - int_comparable2 = - < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > -# - : unit = () -# class int_comparable3 : - int -> - object - val mutable x : int - method cmp : int_comparable -> int - method setx : int -> unit - method x : int - end -# val c3 : int_comparable3 = -# - : unit = () -# Characters 25-27: - (new sorted_list ())#add c3;; (* Error; strange message with -principal *) - ^^ -Error: This expression has type - int_comparable3 = - < cmp : int_comparable -> int; setx : int -> unit; x : int > - but an expression was expected of type - #comparable as 'a = < cmp : 'a -> int; .. > - Type int_comparable = < cmp : int_comparable -> int; x : int > - is not compatible with type 'a = < cmp : 'a -> int; .. > - The first object type has no method setx -# val sort : (#comparable as 'a) list -> 'a list = -# Characters 13-66: - List.map (fun c -> print_int c#x; print_string " ") l; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 10: this expression should have type unit. -val pr : < x : int; .. > list -> unit = -# val l : int_comparable list = [; ; ] -# 5 2 4 -- : unit = () -# 2 4 5 -- : unit = () -# val l : int_comparable2 list = [; ] -# 2 0 -- : unit = () -# 0 2 -- : unit = () -# val min : (#comparable as 'a) -> 'a -> 'a = -# - : int = 7 -# - : int = 3 -# class ['a] link : - 'a -> - object ('b) - val mutable next : 'b option - val mutable x : 'a - method append : 'b option -> unit - method next : 'b option - method set_next : 'b option -> unit - method set_x : 'a -> unit - method x : 'a - end -# class ['a] double_link : - 'a -> - object ('b) - val mutable next : 'b option - val mutable prev : 'b option - val mutable x : 'a - method append : 'b option -> unit - method next : 'b option - method prev : 'b option - method set_next : 'b option -> unit - method set_prev : 'b option -> unit - method set_x : 'a -> unit - method x : 'a - end -# val fold_right : ('a -> 'b -> 'b) -> 'a #link option -> 'b -> 'b = -# class calculator : - unit -> - object ('a) - val mutable acc : float - val mutable arg : float - val mutable equals : 'a -> float - method acc : float - method add : 'a - method arg : float - method enter : float -> 'a - method equals : float - method sub : 'a - end -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# class calculator : - unit -> - object ('a) - val mutable acc : float - val mutable arg : float - val mutable equals : 'a -> float - method acc : float - method add : 'a - method arg : float - method enter : float -> 'a - method equals : float - method sub : 'a - end -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# class calculator : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -and calculator_add : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -and calculator_sub : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -# val calculator : calculator = -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# diff --git a/testsuite/tests/typing-objects/Exemples.ml.reference b/testsuite/tests/typing-objects/Exemples.ml.reference deleted file mode 100644 index cfd13603..00000000 --- a/testsuite/tests/typing-objects/Exemples.ml.reference +++ /dev/null @@ -1,360 +0,0 @@ - -# class point : - int -> - object val mutable x : int method get_x : int method move : int -> unit end -# val p : point = -# - : int = 7 -# - : unit = () -# - : int = 10 -# val q : point = -# - : int * int = (10, 17) -# class color_point : - int -> - string -> - object - val c : string - val mutable x : int - method color : string - method get_x : int - method move : int -> unit - end -# val p' : color_point = -# - : int * string = (5, "red") -# val l : point list = [; ] -# val get_x : < get_x : 'a; .. > -> 'a = -# val set_x : < set_x : 'a; .. > -> 'a = -# - : int list = [10; 5] -# Characters 1-96: - class ref x_init = object - val mutable x = x_init - method get = x - method set y = x <- y - end.. -Error: Some type variables are unbound in this type: - class ref : - 'a -> - object - val mutable x : 'a - method get : 'a - method set : 'a -> unit - end - The method get has type 'a where 'a is unbound -# class ref : - int -> - object val mutable x : int method get : int method set : int -> unit end -# class ['a] ref : - 'a -> object val mutable x : 'a method get : 'a method set : 'a -> unit end -# - : int = 2 -# class ['a] circle : - 'a -> - object - constraint 'a = < move : int -> unit; .. > - val mutable center : 'a - method center : 'a - method move : int -> unit - method set_center : 'a -> unit - end -# class ['a] circle : - 'a -> - object - constraint 'a = #point - val mutable center : 'a - method center : 'a - method move : int -> unit - method set_center : 'a -> unit - end -# val c : point circle = -val c' : color_point circle = -# class ['a] color_circle : - 'a -> - object - constraint 'a = #color_point - val mutable center : 'a - method center : 'a - method color : string - method move : int -> unit - method set_center : 'a -> unit - end -# Characters 28-29: - let c'' = new color_circle p;; - ^ -Error: This expression has type point but an expression was expected of type - #color_point - The first object type has no method color -# val c'' : color_point color_circle = -# - : color_point circle = -# Characters 0-21: - (c'' :> point circle);; (* Fail *) - ^^^^^^^^^^^^^^^^^^^^^ -Error: Type - color_point color_circle = - < center : color_point; color : string; move : int -> unit; - set_center : color_point -> unit > - is not a subtype of - point circle = - < center : point; move : int -> unit; set_center : point -> unit > - Type point is not a subtype of color_point -# Characters 9-55: - fun x -> (x : color_point color_circle :> point circle);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type - color_point color_circle = - < center : color_point; color : string; move : int -> unit; - set_center : color_point -> unit > - is not a subtype of - point circle = - < center : point; move : int -> unit; set_center : point -> unit > - Type point is not a subtype of color_point -# class printable_point : - int -> - object - val mutable x : int - method get_x : int - method move : int -> unit - method print : unit - end -# val p : printable_point = -# 7- : unit = () -# Characters 85-102: - inherit printable_point y as super - ^^^^^^^^^^^^^^^^^ -Warning 13: the following instance variables are overridden by the class printable_point : - x -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -class printable_color_point : - int -> - string -> - object - val c : string - val mutable x : int - method color : string - method get_x : int - method move : int -> unit - method print : unit - end -# val p' : printable_color_point = -# (7, red)- : unit = () -# class functional_point : - int -> - object ('a) val x : int method get_x : int method move : int -> 'a end -# val p : functional_point = -# - : int = 7 -# - : int = 10 -# - : int = 7 -# - : #functional_point -> functional_point = -# class virtual ['a] lst : - unit -> - object - method virtual hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method virtual null : bool - method print : ('a -> unit) -> unit - method virtual tl : 'a lst - end -and ['a] nil : - unit -> - object - method hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method null : bool - method print : ('a -> unit) -> unit - method tl : 'a lst - end -and ['a] cons : - 'a -> - 'a lst -> - object - val h : 'a - val t : 'a lst - method hd : 'a - method iter : ('a -> unit) -> unit - method map : ('a -> 'a) -> 'a lst - method null : bool - method print : ('a -> unit) -> unit - method tl : 'a lst - end -# val l1 : int lst = -# (3::10::[])- : unit = () -# val l2 : int lst = -# (4::11::[])- : unit = () -# val map_list : ('a -> 'b) -> 'a lst -> 'b lst = -# val p1 : printable_color_point lst = -# ((3, red)::(10, red)::[])- : unit = () -# class virtual comparable : - unit -> object ('a) method virtual cmp : 'a -> int end -# class int_comparable : - int -> object ('a) val x : int method cmp : 'a -> int method x : int end -# class int_comparable2 : - int -> - object ('a) - val x : int - val mutable x' : int - method cmp : 'a -> int - method set_x : int -> unit - method x : int - end -# class ['a] sorted_list : - unit -> - object - constraint 'a = #comparable - val mutable l : 'a list - method add : 'a -> unit - method hd : 'a - end -# val l : _#comparable sorted_list = -# val c : int_comparable = -# - : unit = () -# val c2 : int_comparable2 = -# Characters 6-28: - l#add (c2 :> int_comparable);; (* Fail : 'a comp2 is not a subtype *) - ^^^^^^^^^^^^^^^^^^^^^^ -Error: Type - int_comparable2 = - < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > - is not a subtype of - int_comparable = < cmp : int_comparable -> int; x : int > - Type int_comparable = < cmp : int_comparable -> int; x : int > - is not a subtype of - int_comparable2 = - < cmp : int_comparable2 -> int; set_x : int -> unit; x : int > -# - : unit = () -# class int_comparable3 : - int -> - object - val mutable x : int - method cmp : int_comparable -> int - method setx : int -> unit - method x : int - end -# val c3 : int_comparable3 = -# - : unit = () -# Characters 25-27: - (new sorted_list ())#add c3;; (* Error; strange message with -principal *) - ^^ -Error: This expression has type - int_comparable3 = - < cmp : int_comparable -> int; setx : int -> unit; x : int > - but an expression was expected of type - #comparable as 'a = < cmp : 'a -> int; .. > - Type int_comparable = < cmp : int_comparable -> int; x : int > - is not compatible with type - int_comparable3 = - < cmp : int_comparable -> int; setx : int -> unit; x : int > - The first object type has no method setx -# val sort : (#comparable as 'a) list -> 'a list = -# Characters 13-66: - List.map (fun c -> print_int c#x; print_string " ") l; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 10: this expression should have type unit. -val pr : < x : int; .. > list -> unit = -# val l : int_comparable list = [; ; ] -# 5 2 4 -- : unit = () -# 2 4 5 -- : unit = () -# val l : int_comparable2 list = [; ] -# 2 0 -- : unit = () -# 0 2 -- : unit = () -# val min : (#comparable as 'a) -> 'a -> 'a = -# - : int = 7 -# - : int = 3 -# class ['a] link : - 'a -> - object ('b) - val mutable next : 'b option - val mutable x : 'a - method append : 'b option -> unit - method next : 'b option - method set_next : 'b option -> unit - method set_x : 'a -> unit - method x : 'a - end -# class ['a] double_link : - 'a -> - object ('b) - val mutable next : 'b option - val mutable prev : 'b option - val mutable x : 'a - method append : 'b option -> unit - method next : 'b option - method prev : 'b option - method set_next : 'b option -> unit - method set_prev : 'b option -> unit - method set_x : 'a -> unit - method x : 'a - end -# val fold_right : ('a -> 'b -> 'b) -> 'a #link option -> 'b -> 'b = -# class calculator : - unit -> - object ('a) - val mutable acc : float - val mutable arg : float - val mutable equals : 'a -> float - method acc : float - method add : 'a - method arg : float - method enter : float -> 'a - method equals : float - method sub : 'a - end -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# class calculator : - unit -> - object ('a) - val mutable acc : float - val mutable arg : float - val mutable equals : 'a -> float - method acc : float - method add : 'a - method arg : float - method enter : float -> 'a - method equals : float - method sub : 'a - end -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# class calculator : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -and calculator_add : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -and calculator_sub : - float -> - float -> - object - val acc : float - val arg : float - method add : calculator - method enter : float -> calculator - method equals : float - method sub : calculator - end -# val calculator : calculator = -# - : float = 5. -# - : float = 1.5 -# - : float = 15. -# diff --git a/testsuite/tests/typing-objects/Makefile b/testsuite/tests/typing-objects/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-objects/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-objects/Tests.ml b/testsuite/tests/typing-objects/Tests.ml index b646ade3..0777d1d4 100644 --- a/testsuite/tests/typing-objects/Tests.ml +++ b/testsuite/tests/typing-objects/Tests.ml @@ -1,5 +1,14 @@ +(* TEST + * expect +*) + (* Subtyping is "syntactic" *) fun (x : < x : int >) y z -> (y :> 'a), (x :> 'a), (z :> 'a);; +[%%expect{| +- : < x : int > -> + < x : int > -> < x : int > -> < x : int > * < x : int > * < x : int > += +|}];; (* - : (< x : int > as 'a) -> 'a -> 'a * 'a = *) (* Quirks of class typing. *) @@ -8,6 +17,10 @@ class ['a] c () = object end and ['a] d () = object inherit ['a] c () end;; +[%%expect{| +class ['a] c : unit -> object constraint 'a = int method f : int c end +and ['a] d : unit -> object constraint 'a = int method f : int c end +|}];; (* class ['a] c : unit -> object constraint 'a = int method f : 'a c end *) (* and ['a] d : unit -> object constraint 'a = int method f : 'a c end *) @@ -17,6 +30,15 @@ class ['a] c () = object end and d () = object inherit ['a] c () end;; +[%%expect{| +Line _, characters 4-45: + ....and d () = object + inherit ['a] c () + end.. +Error: Some type variables are unbound in this type: + class d : unit -> object method f : 'a -> unit end + The method f has type 'a -> unit where 'a is unbound +|}];; (* Create instance #c *) class virtual c () = object @@ -24,6 +46,11 @@ end and ['a] d () = object constraint 'a = #c method f (x : #c) = (x#x : int) end;; +[%%expect{| +class virtual c : unit -> object end +and ['a] d : + unit -> object constraint 'a = < x : int; .. > method f : 'a -> int end +|}];; (* class virtual c : unit -> object end *) (* and ['a] d : *) (* unit -> object constraint 'a = < x : int; .. > method f : 'a -> int end *) @@ -33,6 +60,10 @@ class ['a] c () = object end and ['a] d () = object constraint 'a = 'b #c end;; +[%%expect{| +class ['a] c : unit -> object constraint 'a = int end +and ['a] d : unit -> object constraint 'a = int #c end +|}];; (* class ['a] c : unit -> object constraint 'a = int end and ['a] d : unit -> object constraint 'a = int #c end *) @@ -41,7 +72,14 @@ class ['a] c (x : 'a) = object (self : 'b) constraint 'a = 'b method f = self end;; +[%%expect{| +class ['a] c : + 'a -> object ('a) constraint 'a = < f : 'a; .. > method f : 'a end +|}];; new c;; +[%%expect{| +- : ('a c as 'a) -> 'a = +|}];; (* class ['a] c : 'a -> object ('a) constraint 'a = < f : 'a; .. > method f : 'a end *) (* - : ('a c as 'a) -> 'a = *) @@ -49,6 +87,13 @@ new c;; class x () = object method virtual f : int end;; +[%%expect{| +Line _, characters 0-48: + class x () = object + method virtual f : int + end.. +Error: This class should be virtual. The following methods are undefined : f +|}];; (* The class x should be virtual: its methods f is undefined *) (* Supplementary method g *) @@ -57,12 +102,28 @@ and virtual d x = object (_ : 'a) inherit c x method g = true end;; +[%%expect{| +Line _, characters 49-57: + class virtual c ((x : 'a): < f : int >) = object (_ : 'a) end + ^^^^^^^^ +Error: This pattern cannot match self: it only matches values of type + < f : int > +|}];; (* Constraint not respected *) class ['a] c () = object constraint 'a = int method f x = (x : bool c) end;; +[%%expect{| +Line _, characters 0-78: + class ['a] c () = object + constraint 'a = int + method f x = (x : bool c) + end.. +Error: The abbreviation c is used with parameters bool c + which are incompatible with constraints int c +|}];; (* Different constraints *) class ['a, 'b] c () = object @@ -70,34 +131,113 @@ class ['a, 'b] c () = object constraint 'b = 'a * * 'c * 'd method f (x : 'a) (y : 'b) = () end;; +[%%expect{| +class ['a, 'b] c : + unit -> + object + constraint 'a = int -> 'c + constraint 'b = 'a * < x : 'b > * 'c * 'd + method f : 'a -> 'b -> unit + end +|}];; class ['a, 'b] d () = object inherit ['a, 'b] c () end;; +[%%expect{| +class ['a, 'b] d : + unit -> + object + constraint 'a = int -> 'c + constraint 'b = 'a * < x : 'b > * 'c * 'd + method f : 'a -> 'b -> unit + end +|}];; (* Non-generic constraint *) let x = ref [];; +[%%expect{| +val x : '_weak1 list ref = {contents = []} +|}];; class ['a] c () = object method f = (x : 'a) end;; +[%%expect{| +Line _, characters 0-50: + class ['a] c () = object + method f = (x : 'a) + end.. +Error: The type of this class, + class ['a] c : + unit -> object constraint 'a = '_weak1 list ref method f : 'a end, + contains type variables that cannot be generalized +|}];; (* Abbreviations *) type 'a c = and 'a d = ;; +[%%expect{| +Line _, characters 0-32: + type 'a c = + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: In the definition of d, type int c should be 'a c +|}];; type 'a c = and 'a d = ;; +[%%expect{| +type 'a c = < f : 'a c; g : 'a d > +and 'a d = < f : 'a c > +|}];; type 'a c = and 'a d = ;; +[%%expect{| +type 'a c = < f : 'a c > +and 'a d = < f : int c > +|}];; type 'a u = < x : 'a> -and 'a t = 'a t u;; (* fails since 4.04 *) +and 'a t = 'a t u;; +[%%expect{| +Line _, characters 0-17: + and 'a t = 'a t u;; + ^^^^^^^^^^^^^^^^^ +Error: The definition of t contains a cycle: + 'a t u +|}];; (* fails since 4.04 *) type 'a u = 'a and 'a t = 'a t u;; +[%%expect{| +Line _, characters 0-17: + and 'a t = 'a t u;; + ^^^^^^^^^^^^^^^^^ +Error: The type abbreviation t is cyclic +|}];; type 'a u = 'a;; +[%%expect{| +type 'a u = 'a +|}];; type t = t u * t u;; +[%%expect{| +Line _, characters 0-18: + type t = t u * t u;; + ^^^^^^^^^^^^^^^^^^ +Error: The type abbreviation t is cyclic +|}];; type t = as 'a;; +[%%expect{| +type t = < x : 'a > as 'a +|}];; type 'a u = 'a;; +[%%expect{| +type 'a u = 'a +|}];; fun (x : t) (y : 'a u) -> x = y;; +[%%expect{| +- : t -> t u -> bool = +|}];; fun (x : t) (y : 'a u) -> y = x;; +[%%expect{| +- : t -> t u -> bool = +|}];; (* - : t -> t u -> bool = *) (* Modules *) @@ -111,6 +251,21 @@ module M = method g = y end end;; +[%%expect{| +module M : + sig + class ['a, 'b] c : + int -> + 'b -> + object + constraint 'a = int -> bool + val x : float list + val y : 'b + method f : 'a -> unit + method g : 'b + end + end +|}];; module M' = (M : sig class virtual ['a, 'b] c : int -> 'b -> object @@ -121,31 +276,125 @@ module M' = (M : method g : 'b end end);; +[%%expect{| +module M' : + sig + class virtual ['a, 'b] c : + int -> + 'b -> + object + constraint 'a = int -> bool + val x : float list + val y : 'b + method f : 'a -> unit + method g : 'b + end + end +|}];; class ['a, 'b] d () y = object inherit ['a, 'b] M.c 7 y end;; +[%%expect{| +class ['a, 'b] d : + unit -> + 'b -> + object + constraint 'a = int -> bool + val x : float list + val y : 'b + method f : 'a -> unit + method g : 'b + end +|}];; class ['a, 'b] e () y = object inherit ['a, 'b] M'.c 1 y end;; +[%%expect{| +class ['a, 'b] e : + unit -> + 'b -> + object + constraint 'a = int -> bool + val x : float list + val y : 'b + method f : 'a -> unit + method g : 'b + end +|}];; (new M.c 3 "a")#g;; +[%%expect{| +- : string = "a" +|}];; (new d () 10)#g;; +[%%expect{| +- : int = 10 +|}];; (new e () 7.1)#g;; +[%%expect{| +- : float = 7.1 +|}];; open M;; +[%%expect{| +|}];; (new c 5 true)#g;; +[%%expect{| +- : bool = true +|}];; (* #cl when cl is closed *) module M = struct class ['a] c () = object method f (x : 'a) = () end end;; +[%%expect{| +module M : sig class ['a] c : unit -> object method f : 'a -> unit end end +|}];; module M' = (M : sig class ['a] c : unit -> object method f : 'a -> unit end end);; +[%%expect{| +module M' : sig class ['a] c : unit -> object method f : 'a -> unit end end +|}];; fun x -> (x :> 'a #M.c);; +[%%expect{| +- : ('a #M.c as 'b) -> 'b = +|}];; fun x -> (x :> 'a #M'.c);; +[%%expect{| +- : ('a #M'.c as 'b) -> 'b = +|}];; class ['a] c (x : 'b #c) = object end;; +[%%expect{| +class ['a] c : 'a #c -> object end +|}];; class ['a] c (x : 'b #c) = object end;; +[%%expect{| +class ['a] c : 'a #c -> object end +|}];; (* Computation order *) class c () = object method f = 1 end and d () = object method f = 2 end;; +[%%expect{| +class c : unit -> object method f : int end +and d : unit -> object method f : int end +|}];; class e () = object inherit c () inherit d () end;; +[%%expect{| +class e : unit -> object method f : int end +|}];; (new e ())#f;; +[%%expect{| +- : int = 2 +|}];; class c () = object val x = - true val y = -. () end;; +[%%expect{| +Line _, characters 30-34: + class c () = object val x = - true val y = -. () end;; + ^^^^ +Error: This expression has type bool but an expression was expected of type + int +|}];; class c () = object method f = 1 method g = 1 method h = 1 end;; +[%%expect{| +class c : unit -> object method f : int method g : int method h : int end +|}];; class d () = object method h = 2 method i = 2 method j = 2 end;; +[%%expect{| +class d : unit -> object method h : int method i : int method j : int end +|}];; class e () = object method f = 3 inherit c () @@ -154,11 +403,34 @@ class e () = object inherit d () method j = 3 end;; +[%%expect{| +class e : + unit -> + object + method f : int + method g : int + method h : int + method i : int + method j : int + end +|}];; let e = new e ();; +[%%expect{| +val e : e = +|}];; e#f, e#g, e#h, e#i, e#j;; +[%%expect{| +- : int * int * int * int * int = (1, 3, 2, 2, 3) +|}];; class c a = object val x = 1 val y = 1 val z = 1 val a = a end;; +[%%expect{| +class c : 'a -> object val a : 'a val x : int val y : int val z : int end +|}];; class d b = object val z = 2 val t = 2 val u = 2 val b = b end;; +[%%expect{| +class d : 'a -> object val b : 'a val t : int val u : int val z : int end +|}];; class e () = object val x = 3 inherit c 5 @@ -174,8 +446,56 @@ class e () = object method a = a method b = b end;; +[%%expect{| +Line _, characters 10-13: + inherit c 5 + ^^^ +Warning 13: the following instance variables are overridden by the class c : + x +The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) +Line _, characters 6-7: + val y = 3 + ^ +Warning 13: the instance variable y is overridden. +The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) +Line _, characters 10-13: + inherit d 7 + ^^^ +Warning 13: the following instance variables are overridden by the class d : + t z +The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) +Line _, characters 6-7: + val u = 3 + ^ +Warning 13: the instance variable u is overridden. +The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) +class e : + unit -> + object + val a : int + val b : int + val t : int + val u : int + val x : int + val y : int + val z : int + method a : int + method b : int + method t : int + method u : int + method x : int + method y : int + method z : int + end +|}];; let e = new e ();; +[%%expect{| +val e : e = +|}];; e#x, e#y, e#z, e#t, e#u, e#a, e#b;; +[%%expect{| +- : int * int * int * int * int * int * int = (1, 3, 2, 2, 3, 5, 7) +|}];; class c (x : int) (y : int) = object val x = x @@ -183,13 +503,35 @@ class c (x : int) (y : int) = object method x = x method y = y end;; +[%%expect{| +class c : + int -> + int -> object val x : int val y : int method x : int method y : int end +|}];; class d x y = object inherit c x y end;; +[%%expect{| +class d : + int -> + int -> object val x : int val y : int method x : int method y : int end +|}];; let c = new c 1 2 in c#x, c#y;; +[%%expect{| +- : int * int = (1, 2) +|}];; let d = new d 1 2 in d#x, d#y;; +[%%expect{| +- : int * int = (1, 2) +|}];; (* Parameters which does not appear in the object type *) class ['a] c (x : 'a) = object end;; +[%%expect{| +class ['a] c : 'a -> object end +|}];; new c;; +[%%expect{| +- : 'a -> 'a c = +|}];; (* Private variables *) (* @@ -197,22 +539,49 @@ module type M = sig class c : unit -> object val x : int end class d : unit -> object inherit c val private x : int val x : bool end end;; +[%%expect{| +foo +|}];; class c (x : int) = val private mutable x = x method get = x method set y = x <- y end;; +[%%expect{| +foo +|}];; let c = new c 5;; +[%%expect{| +foo +|}];; c#get;; +[%%expect{| +foo +|}];; c#set 7; c#get;; +[%%expect{| +foo +|}];; class c () = val x = 1 val y = 1 method c = x end;; +[%%expect{| +foo +|}];; class d () = inherit c () val private x method d = x end;; +[%%expect{| +foo +|}];; class e () = val x = 2 val y = 2 inherit d () method x = x method y = y end;; +[%%expect{| +foo +|}];; let e = new e () in e#x, e#y, e#c, e#d;; +[%%expect{| +foo +|}];; *) (* Forgotten variables in interfaces *) @@ -228,109 +597,292 @@ module M : method xc = x end end;; +[%%expect{| +module M : sig class c : unit -> object method xc : int end end +|}];; class d () = object val x = 2 method xd = x inherit M.c () end;; +[%%expect{| +class d : unit -> object val x : int method xc : int method xd : int end +|}];; let d = new d () in d#xc, d#xd;; +[%%expect{| +- : int * int = (1, 2) +|}];; class virtual ['a] matrix (sz, init : int * 'a) = object val m = Array.make_matrix sz sz init method add (mtx : 'a matrix) = (mtx#m.(0).(0) : 'a) end;; +[%%expect{| +Line _, characters 0-153: + class virtual ['a] matrix (sz, init : int * 'a) = object + val m = Array.make_matrix sz sz init + method add (mtx : 'a matrix) = (mtx#m.(0).(0) : 'a) + end.. +Error: The abbreviation 'a matrix expands to type < add : 'a matrix -> 'a > + but is used with type < m : 'a array array; .. > +|}];; class c () = object method m = new c () end;; +[%%expect{| +class c : unit -> object method m : c end +|}];; (new c ())#m;; +[%%expect{| +- : c = +|}];; module M = struct class c () = object method m = new c () end end;; +[%%expect{| +module M : sig class c : unit -> object method m : c end end +|}];; (new M.c ())#m;; +[%%expect{| +- : M.c = +|}];; type uu = A of int | B of ( as 'a);; +[%%expect{| +type uu = A of int | B of (< leq : 'a > as 'a) +|}];; class virtual c () = object (_ : 'a) method virtual m : 'a end;; +[%%expect{| +class virtual c : unit -> object ('a) method virtual m : 'a end +|}];; module S = (struct let f (x : #c) = x end : sig val f : (#c as 'a) -> 'a end);; +[%%expect{| +module S : sig val f : (#c as 'a) -> 'a end +|}];; module S = (struct let f (x : #c) = x end : sig val f : #c -> #c end);; +[%%expect{| +Line _, characters 12-43: + ............struct + let f (x : #c) = x + end...... +Error: Signature mismatch: + Modules do not match: + sig val f : (#c as 'a) -> 'a end + is not included in + sig val f : #c -> #c end + Values do not match: + val f : (#c as 'a) -> 'a + is not included in + val f : #c -> #c +|}];; module M = struct type t = int class t () = object end end;; +[%%expect{| +Line _, characters 37-38: + module M = struct type t = int class t () = object end end;; + ^ +Error: Multiple definition of the type name t. + Names must be unique in a given structure or signature. +|}];; fun x -> (x :> < m : 'a -> 'a > as 'a);; +[%%expect{| +- : < m : (< m : 'a > as 'b) -> 'b as 'a; .. > -> 'b = +|}];; fun x -> (x : int -> bool :> 'a -> 'a);; +[%%expect{| +Line _, characters 9-38: + fun x -> (x : int -> bool :> 'a -> 'a);; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Type int -> bool is not a subtype of int -> int + Type bool is not a subtype of int +|}];; fun x -> (x : int -> bool :> int -> int);; +[%%expect{| +Line _, characters 9-40: + fun x -> (x : int -> bool :> int -> int);; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Type int -> bool is not a subtype of int -> int + Type bool is not a subtype of int +|}];; fun x -> (x : < > :> < .. >);; +[%%expect{| +- : < > -> < > = +|}];; fun x -> (x : < .. > :> < >);; +[%%expect{| +- : < .. > -> < > = +|}];; let x = ref [];; +[%%expect{| +val x : '_weak2 list ref = {contents = []} +|}];; module F(X : sig end) = struct type t = int let _ = (x : < m : t> list ref) end;; +[%%expect{| +module F : functor (X : sig end) -> sig type t = int end +|}];; x;; +[%%expect{| +- : < m : int > list ref = {contents = []} +|}];; type 'a t;; +[%%expect{| +type 'a t +|}];; fun (x : 'a t as 'a) -> ();; +[%%expect{| +Line _, characters 9-19: + fun (x : 'a t as 'a) -> ();; + ^^^^^^^^^^ +Error: This alias is bound to type 'a t but is used as an instance of type 'a + The type variable 'a occurs inside 'a t +|}];; fun (x : 'a t) -> (x : 'a); ();; +[%%expect{| +Line _, characters 19-20: + fun (x : 'a t) -> (x : 'a); ();; + ^ +Error: This expression has type 'a t but an expression was expected of type + 'a + The type variable 'a occurs inside 'a t +|}];; type 'a t = < x : 'a >;; +[%%expect{| +type 'a t = < x : 'a > +|}];; fun (x : 'a t as 'a) -> ();; +[%%expect{| +- : ('a t as 'a) -> unit = +|}];; fun (x : 'a t) -> (x : 'a); ();; +[%%expect{| +Line _, characters 18-26: + fun (x : 'a t) -> (x : 'a); ();; + ^^^^^^^^ +Warning 10: this expression should have type unit. +- : ('a t as 'a) t -> unit = +|}];; class ['a] c () = object constraint 'a = < .. > -> unit method m = (fun x -> () : 'a) end;; +[%%expect{| +class ['a] c : + unit -> + object constraint 'a = (< .. > as 'b) -> unit method m : 'b -> unit end +|}];; class ['a] c () = object constraint 'a = unit -> < .. > method m (f : 'a) = f () end;; +[%%expect{| +class ['a] c : + unit -> + object constraint 'a = unit -> (< .. > as 'b) method m : 'a -> 'b end +|}];; class c () = object (self) method private m = 1 method n = self#m end;; +[%%expect{| +class c : unit -> object method private m : int method n : int end +|}];; class d () = object (self) inherit c () method o = self#m end;; +[%%expect{| +class d : + unit -> object method private m : int method n : int method o : int end +|}];; let x = new d () in x#n, x#o;; +[%%expect{| +- : int * int = (1, 1) +|}];; class c () = object method virtual m : int method private m = 1 end;; +[%%expect{| +class c : unit -> object method m : int end +|}];; (* Marshaling (cf. PR#5436) *) let r = ref 0;; +[%%expect{| +val r : int ref = {contents = 0} +|}];; let id o = Oo.id o - !r;; +[%%expect{| +val id : < .. > -> int = +|}];; r := Oo.id (object end);; +[%%expect{| +- : unit = () +|}];; id (object end);; +[%%expect{| +- : int = 1 +|}];; id (object end);; +[%%expect{| +- : int = 2 +|}];; let o = object end in let s = Marshal.to_string o [] in let o' : < > = Marshal.from_string s 0 in let o'' : < > = Marshal.from_string s 0 in (id o, id o', id o'');; +[%%expect{| +- : int * int * int = (3, 4, 5) +|}];; let o = object val x = 33 method m = x end in let s = Marshal.to_string o [Marshal.Closures] in let o' : = Marshal.from_string s 0 in let o'' : = Marshal.from_string s 0 in (id o, id o', id o'', o#m, o'#m);; +[%%expect{| +- : int * int * int * int * int = (6, 7, 8, 33, 33) +|}];; let o = object val x = 33 val y = 44 method m = x end in let s = Marshal.to_string (o,o) [Marshal.Closures] in let (o1, o2) : ( * ) = Marshal.from_string s 0 in let (o3, o4) : ( * ) = Marshal.from_string s 0 in (id o, id o1, id o2, id o3, id o4, o#m, o1#m);; +[%%expect{| +- : int * int * int * int * int * int * int = (9, 10, 10, 11, 11, 33, 33) +|}];; (* Recursion (cf. PR#5291) *) class a = let _ = new b in object end and b = let _ = new a in object end;; +[%%expect{| +Line _, characters 10-37: + class a = let _ = new b in object end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of recursive class expression is not allowed +|}];; class a = let _ = new a in object end;; +[%%expect{| +Line _, characters 10-37: + class a = let _ = new a in object end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: This kind of recursive class expression is not allowed +|}];; diff --git a/testsuite/tests/typing-objects/Tests.ml.principal.reference b/testsuite/tests/typing-objects/Tests.ml.principal.reference deleted file mode 100644 index ba027f1d..00000000 --- a/testsuite/tests/typing-objects/Tests.ml.principal.reference +++ /dev/null @@ -1,317 +0,0 @@ - -# - : < x : int > -> - < x : int > -> < x : int > -> < x : int > * < x : int > * < x : int > -= -# class ['a] c : unit -> object constraint 'a = int method f : int c end -and ['a] d : unit -> object constraint 'a = int method f : int c end -# Characters 230-271: - ....and d () = object - inherit ['a] c () - end.. -Error: Some type variables are unbound in this type: - class d : unit -> object method f : 'a -> unit end - The method f has type 'a -> unit where 'a is unbound -# class virtual c : unit -> object end -and ['a] d : - unit -> object constraint 'a = < x : int; .. > method f : 'a -> int end -# class ['a] c : unit -> object constraint 'a = int end -and ['a] d : unit -> object constraint 'a = int #c end -# * class ['a] c : - 'a -> object ('a) constraint 'a = < f : 'a; .. > method f : 'a end -# - : ('a c as 'a) -> 'a = -# * Characters 128-176: - class x () = object - method virtual f : int - end.. -Error: This class should be virtual. The following methods are undefined : f -# Characters 144-152: - class virtual c ((x : 'a): < f : int >) = object (_ : 'a) end - ^^^^^^^^ -Error: This pattern cannot match self: it only matches values of type - < f : int > -# Characters 32-110: - class ['a] c () = object - constraint 'a = int - method f x = (x : bool c) - end.. -Error: The abbreviation c is used with parameters bool c - which are incompatible with constraints int c -# class ['a, 'b] c : - unit -> - object - constraint 'a = int -> 'c - constraint 'b = 'a * < x : 'b > * 'c * 'd - method f : 'a -> 'b -> unit - end -# class ['a, 'b] d : - unit -> - object - constraint 'a = int -> 'c - constraint 'b = 'a * < x : 'b > * 'c * 'd - method f : 'a -> 'b -> unit - end -# val x : '_weak1 list ref = {contents = []} -# Characters 0-50: - class ['a] c () = object - method f = (x : 'a) - end.. -Error: The type of this class, - class ['a] c : - unit -> object constraint 'a = '_weak1 list ref method f : 'a end, - contains type variables that cannot be generalized -# Characters 21-53: - type 'a c = - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: In the definition of d, type int c should be 'a c -# type 'a c = < f : 'a c; g : 'a d > -and 'a d = < f : 'a c > -# type 'a c = < f : 'a c > -and 'a d = < f : int c > -# Characters 22-39: - and 'a t = 'a t u;; (* fails since 4.04 *) - ^^^^^^^^^^^^^^^^^ -Error: The definition of t contains a cycle: - 'a t u -# Characters 15-32: - and 'a t = 'a t u;; - ^^^^^^^^^^^^^^^^^ -Error: The type abbreviation t is cyclic -# type 'a u = 'a -# Characters 0-18: - type t = t u * t u;; - ^^^^^^^^^^^^^^^^^^ -Error: The type abbreviation t is cyclic -# type t = < x : 'a > as 'a -# type 'a u = 'a -# - : t -> t u -> bool = -# - : t -> t u -> bool = -# module M : - sig - class ['a, 'b] c : - int -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end - end -# module M' : - sig - class virtual ['a, 'b] c : - int -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end - end -# class ['a, 'b] d : - unit -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end -# class ['a, 'b] e : - unit -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end -# - : string = "a" -# - : int = 10 -# - : float = 7.1 -# # - : bool = true -# module M : sig class ['a] c : unit -> object method f : 'a -> unit end end -# module M' : sig class ['a] c : unit -> object method f : 'a -> unit end end -# - : ('a #M.c as 'b) -> 'b = -# - : ('a #M'.c as 'b) -> 'b = -# class ['a] c : 'a #c -> object end -# class ['a] c : 'a #c -> object end -# class c : unit -> object method f : int end -and d : unit -> object method f : int end -# class e : unit -> object method f : int end -# - : int = 2 -# Characters 30-34: - class c () = object val x = - true val y = -. () end;; - ^^^^ -Error: This expression has type bool but an expression was expected of type - int -# class c : unit -> object method f : int method g : int method h : int end -# class d : unit -> object method h : int method i : int method j : int end -# class e : - unit -> - object - method f : int - method g : int - method h : int - method i : int - method j : int - end -# val e : e = -# - : int * int * int * int * int = (1, 3, 2, 2, 3) -# class c : 'a -> object val a : 'a val x : int val y : int val z : int end -# class d : 'a -> object val b : 'a val t : int val u : int val z : int end -# Characters 42-45: - inherit c 5 - ^^^ -Warning 13: the following instance variables are overridden by the class c : - x -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 52-53: - val y = 3 - ^ -Warning 13: the instance variable y is overridden. -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 80-83: - inherit d 7 - ^^^ -Warning 13: the following instance variables are overridden by the class d : - t z -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 90-91: - val u = 3 - ^ -Warning 13: the instance variable u is overridden. -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -class e : - unit -> - object - val a : int - val b : int - val t : int - val u : int - val x : int - val y : int - val z : int - method a : int - method b : int - method t : int - method u : int - method x : int - method y : int - method z : int - end -# val e : e = -# - : int * int * int * int * int * int * int = (1, 3, 2, 2, 3, 5, 7) -# class c : - int -> - int -> object val x : int val y : int method x : int method y : int end -# class d : - int -> - int -> object val x : int val y : int method x : int method y : int end -# - : int * int = (1, 2) -# - : int * int = (1, 2) -# class ['a] c : 'a -> object end -# - : 'a -> 'a c = -# * * * * * * * * * * * * * * * * * * * * * module M : sig class c : unit -> object method xc : int end end -# class d : unit -> object val x : int method xc : int method xd : int end -# - : int * int = (1, 2) -# Characters 1-154: - class virtual ['a] matrix (sz, init : int * 'a) = object - val m = Array.make_matrix sz sz init - method add (mtx : 'a matrix) = (mtx#m.(0).(0) : 'a) - end.. -Error: The abbreviation 'a matrix expands to type < add : 'a matrix -> 'a > - but is used with type < m : 'a array array; .. > -# class c : unit -> object method m : c end -# - : c = -# module M : sig class c : unit -> object method m : c end end -# - : M.c = -# type uu = A of int | B of (< leq : 'a > as 'a) -# class virtual c : unit -> object ('a) method virtual m : 'a end -# module S : sig val f : (#c as 'a) -> 'a end -# Characters 12-43: - ............struct - let f (x : #c) = x - end...... -Error: Signature mismatch: - Modules do not match: - sig val f : (#c as 'a) -> 'a end - is not included in - sig val f : #c -> #c end - Values do not match: - val f : (#c as 'a) -> 'a - is not included in - val f : #c -> #c -# Characters 38-39: - module M = struct type t = int class t () = object end end;; - ^ -Error: Multiple definition of the type name t. - Names must be unique in a given structure or signature. -# - : < m : (< m : 'a > as 'b) -> 'b as 'a; .. > -> 'b = -# Characters 10-39: - fun x -> (x : int -> bool :> 'a -> 'a);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type int -> bool is not a subtype of int -> int - Type bool is not a subtype of int -# Characters 9-40: - fun x -> (x : int -> bool :> int -> int);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type int -> bool is not a subtype of int -> int - Type bool is not a subtype of int -# - : < > -> < > = -# - : < .. > -> < > = -# val x : '_weak2 list ref = {contents = []} -# module F : functor (X : sig end) -> sig type t = int end -# - : < m : int > list ref = {contents = []} -# type 'a t -# Characters 9-19: - fun (x : 'a t as 'a) -> ();; - ^^^^^^^^^^ -Error: This alias is bound to type 'a t but is used as an instance of type 'a - The type variable 'a occurs inside 'a t -# Characters 19-20: - fun (x : 'a t) -> (x : 'a); ();; - ^ -Error: This expression has type 'a t but an expression was expected of type - 'a - The type variable 'a occurs inside 'a t -# type 'a t = < x : 'a > -# - : ('a t as 'a) -> unit = -# Characters 18-26: - fun (x : 'a t) -> (x : 'a); ();; - ^^^^^^^^ -Warning 10: this expression should have type unit. -- : ('a t as 'a) t -> unit = -# class ['a] c : - unit -> - object constraint 'a = (< .. > as 'b) -> unit method m : 'b -> unit end -# class ['a] c : - unit -> - object constraint 'a = unit -> (< .. > as 'b) method m : 'a -> 'b end -# class c : unit -> object method private m : int method n : int end -# class d : - unit -> object method private m : int method n : int method o : int end -# - : int * int = (1, 1) -# class c : unit -> object method m : int end -# val r : int ref = {contents = 0} -# val id : < .. > -> int = -# - : unit = () -# - : int = 1 -# - : int = 2 -# - : int * int * int = (3, 4, 5) -# - : int * int * int * int * int = (6, 7, 8, 33, 33) -# - : int * int * int * int * int * int * int = (9, 10, 10, 11, 11, 33, 33) -# Characters 42-69: - class a = let _ = new b in object end - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of recursive class expression is not allowed -# Characters 11-38: - class a = let _ = new a in object end;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of recursive class expression is not allowed -# diff --git a/testsuite/tests/typing-objects/Tests.ml.reference b/testsuite/tests/typing-objects/Tests.ml.reference deleted file mode 100644 index ba027f1d..00000000 --- a/testsuite/tests/typing-objects/Tests.ml.reference +++ /dev/null @@ -1,317 +0,0 @@ - -# - : < x : int > -> - < x : int > -> < x : int > -> < x : int > * < x : int > * < x : int > -= -# class ['a] c : unit -> object constraint 'a = int method f : int c end -and ['a] d : unit -> object constraint 'a = int method f : int c end -# Characters 230-271: - ....and d () = object - inherit ['a] c () - end.. -Error: Some type variables are unbound in this type: - class d : unit -> object method f : 'a -> unit end - The method f has type 'a -> unit where 'a is unbound -# class virtual c : unit -> object end -and ['a] d : - unit -> object constraint 'a = < x : int; .. > method f : 'a -> int end -# class ['a] c : unit -> object constraint 'a = int end -and ['a] d : unit -> object constraint 'a = int #c end -# * class ['a] c : - 'a -> object ('a) constraint 'a = < f : 'a; .. > method f : 'a end -# - : ('a c as 'a) -> 'a = -# * Characters 128-176: - class x () = object - method virtual f : int - end.. -Error: This class should be virtual. The following methods are undefined : f -# Characters 144-152: - class virtual c ((x : 'a): < f : int >) = object (_ : 'a) end - ^^^^^^^^ -Error: This pattern cannot match self: it only matches values of type - < f : int > -# Characters 32-110: - class ['a] c () = object - constraint 'a = int - method f x = (x : bool c) - end.. -Error: The abbreviation c is used with parameters bool c - which are incompatible with constraints int c -# class ['a, 'b] c : - unit -> - object - constraint 'a = int -> 'c - constraint 'b = 'a * < x : 'b > * 'c * 'd - method f : 'a -> 'b -> unit - end -# class ['a, 'b] d : - unit -> - object - constraint 'a = int -> 'c - constraint 'b = 'a * < x : 'b > * 'c * 'd - method f : 'a -> 'b -> unit - end -# val x : '_weak1 list ref = {contents = []} -# Characters 0-50: - class ['a] c () = object - method f = (x : 'a) - end.. -Error: The type of this class, - class ['a] c : - unit -> object constraint 'a = '_weak1 list ref method f : 'a end, - contains type variables that cannot be generalized -# Characters 21-53: - type 'a c = - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: In the definition of d, type int c should be 'a c -# type 'a c = < f : 'a c; g : 'a d > -and 'a d = < f : 'a c > -# type 'a c = < f : 'a c > -and 'a d = < f : int c > -# Characters 22-39: - and 'a t = 'a t u;; (* fails since 4.04 *) - ^^^^^^^^^^^^^^^^^ -Error: The definition of t contains a cycle: - 'a t u -# Characters 15-32: - and 'a t = 'a t u;; - ^^^^^^^^^^^^^^^^^ -Error: The type abbreviation t is cyclic -# type 'a u = 'a -# Characters 0-18: - type t = t u * t u;; - ^^^^^^^^^^^^^^^^^^ -Error: The type abbreviation t is cyclic -# type t = < x : 'a > as 'a -# type 'a u = 'a -# - : t -> t u -> bool = -# - : t -> t u -> bool = -# module M : - sig - class ['a, 'b] c : - int -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end - end -# module M' : - sig - class virtual ['a, 'b] c : - int -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end - end -# class ['a, 'b] d : - unit -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end -# class ['a, 'b] e : - unit -> - 'b -> - object - constraint 'a = int -> bool - val x : float list - val y : 'b - method f : 'a -> unit - method g : 'b - end -# - : string = "a" -# - : int = 10 -# - : float = 7.1 -# # - : bool = true -# module M : sig class ['a] c : unit -> object method f : 'a -> unit end end -# module M' : sig class ['a] c : unit -> object method f : 'a -> unit end end -# - : ('a #M.c as 'b) -> 'b = -# - : ('a #M'.c as 'b) -> 'b = -# class ['a] c : 'a #c -> object end -# class ['a] c : 'a #c -> object end -# class c : unit -> object method f : int end -and d : unit -> object method f : int end -# class e : unit -> object method f : int end -# - : int = 2 -# Characters 30-34: - class c () = object val x = - true val y = -. () end;; - ^^^^ -Error: This expression has type bool but an expression was expected of type - int -# class c : unit -> object method f : int method g : int method h : int end -# class d : unit -> object method h : int method i : int method j : int end -# class e : - unit -> - object - method f : int - method g : int - method h : int - method i : int - method j : int - end -# val e : e = -# - : int * int * int * int * int = (1, 3, 2, 2, 3) -# class c : 'a -> object val a : 'a val x : int val y : int val z : int end -# class d : 'a -> object val b : 'a val t : int val u : int val z : int end -# Characters 42-45: - inherit c 5 - ^^^ -Warning 13: the following instance variables are overridden by the class c : - x -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 52-53: - val y = 3 - ^ -Warning 13: the instance variable y is overridden. -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 80-83: - inherit d 7 - ^^^ -Warning 13: the following instance variables are overridden by the class d : - t z -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -Characters 90-91: - val u = 3 - ^ -Warning 13: the instance variable u is overridden. -The behaviour changed in ocaml 3.10 (previous behaviour was hiding.) -class e : - unit -> - object - val a : int - val b : int - val t : int - val u : int - val x : int - val y : int - val z : int - method a : int - method b : int - method t : int - method u : int - method x : int - method y : int - method z : int - end -# val e : e = -# - : int * int * int * int * int * int * int = (1, 3, 2, 2, 3, 5, 7) -# class c : - int -> - int -> object val x : int val y : int method x : int method y : int end -# class d : - int -> - int -> object val x : int val y : int method x : int method y : int end -# - : int * int = (1, 2) -# - : int * int = (1, 2) -# class ['a] c : 'a -> object end -# - : 'a -> 'a c = -# * * * * * * * * * * * * * * * * * * * * * module M : sig class c : unit -> object method xc : int end end -# class d : unit -> object val x : int method xc : int method xd : int end -# - : int * int = (1, 2) -# Characters 1-154: - class virtual ['a] matrix (sz, init : int * 'a) = object - val m = Array.make_matrix sz sz init - method add (mtx : 'a matrix) = (mtx#m.(0).(0) : 'a) - end.. -Error: The abbreviation 'a matrix expands to type < add : 'a matrix -> 'a > - but is used with type < m : 'a array array; .. > -# class c : unit -> object method m : c end -# - : c = -# module M : sig class c : unit -> object method m : c end end -# - : M.c = -# type uu = A of int | B of (< leq : 'a > as 'a) -# class virtual c : unit -> object ('a) method virtual m : 'a end -# module S : sig val f : (#c as 'a) -> 'a end -# Characters 12-43: - ............struct - let f (x : #c) = x - end...... -Error: Signature mismatch: - Modules do not match: - sig val f : (#c as 'a) -> 'a end - is not included in - sig val f : #c -> #c end - Values do not match: - val f : (#c as 'a) -> 'a - is not included in - val f : #c -> #c -# Characters 38-39: - module M = struct type t = int class t () = object end end;; - ^ -Error: Multiple definition of the type name t. - Names must be unique in a given structure or signature. -# - : < m : (< m : 'a > as 'b) -> 'b as 'a; .. > -> 'b = -# Characters 10-39: - fun x -> (x : int -> bool :> 'a -> 'a);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type int -> bool is not a subtype of int -> int - Type bool is not a subtype of int -# Characters 9-40: - fun x -> (x : int -> bool :> int -> int);; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Type int -> bool is not a subtype of int -> int - Type bool is not a subtype of int -# - : < > -> < > = -# - : < .. > -> < > = -# val x : '_weak2 list ref = {contents = []} -# module F : functor (X : sig end) -> sig type t = int end -# - : < m : int > list ref = {contents = []} -# type 'a t -# Characters 9-19: - fun (x : 'a t as 'a) -> ();; - ^^^^^^^^^^ -Error: This alias is bound to type 'a t but is used as an instance of type 'a - The type variable 'a occurs inside 'a t -# Characters 19-20: - fun (x : 'a t) -> (x : 'a); ();; - ^ -Error: This expression has type 'a t but an expression was expected of type - 'a - The type variable 'a occurs inside 'a t -# type 'a t = < x : 'a > -# - : ('a t as 'a) -> unit = -# Characters 18-26: - fun (x : 'a t) -> (x : 'a); ();; - ^^^^^^^^ -Warning 10: this expression should have type unit. -- : ('a t as 'a) t -> unit = -# class ['a] c : - unit -> - object constraint 'a = (< .. > as 'b) -> unit method m : 'b -> unit end -# class ['a] c : - unit -> - object constraint 'a = unit -> (< .. > as 'b) method m : 'a -> 'b end -# class c : unit -> object method private m : int method n : int end -# class d : - unit -> object method private m : int method n : int method o : int end -# - : int * int = (1, 1) -# class c : unit -> object method m : int end -# val r : int ref = {contents = 0} -# val id : < .. > -> int = -# - : unit = () -# - : int = 1 -# - : int = 2 -# - : int * int * int = (3, 4, 5) -# - : int * int * int * int * int = (6, 7, 8, 33, 33) -# - : int * int * int * int * int * int * int = (9, 10, 10, 11, 11, 33, 33) -# Characters 42-69: - class a = let _ = new b in object end - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of recursive class expression is not allowed -# Characters 11-38: - class a = let _ = new a in object end;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: This kind of recursive class expression is not allowed -# diff --git a/testsuite/tests/typing-objects/dummy.ml b/testsuite/tests/typing-objects/dummy.ml new file mode 100644 index 00000000..f0be9e9b --- /dev/null +++ b/testsuite/tests/typing-objects/dummy.ml @@ -0,0 +1,177 @@ +(* TEST + * expect +*) + +class virtual child1 parent = + object + method private parent = parent + end + +and virtual child2 = + object(_ : 'self) + constraint 'parent = < previous: 'self option; .. > + method private virtual parent: 'parent + end + +[%%expect{| +class virtual child1 : 'a -> object method private parent : 'a end +and virtual child2 : + object ('a) + method private virtual parent : < previous : 'a option; .. > + end +|}] + +class virtual child1' parent = + object + method private parent = parent + end + +and virtual child2' = + object(_ : 'self) + constraint 'parent = < previous: 'self option; .. > + method private virtual parent: 'parent + end + +and foo = object(self) + method previous = None + method child = + object + inherit child1' self + inherit child2' + end +end;; + +[%%expect{| +Line _, characters 22-26: + inherit child1' self + ^^^^ +Error: This expression has type < child : 'a; previous : 'b option; .. > + but an expression was expected of type 'c + Self type cannot escape its class +|}] + +(* Whether we have [class foo1] or [let foo1] doesn't change a thing. *) +class foo1 = object(self) + method previous = None + method child = + object + inherit child1 self + inherit child2 + end +end;; +[%%expect{| +class foo1 : object method child : child2 method previous : child2 option end +|}] + +class nested = object + method obj = object(self) + method previous = None + method child () = + object + inherit child1 self + inherit child2 + end + end +end;; +[%%expect{| +class nested : + object + method obj : < child : unit -> child2; previous : child2 option > + end +|}] + +class just_to_see = object(self) + method previous = None + method child = + let o = + object + inherit child1 self + inherit child2 + end + in + o +end;; +[%%expect{| +class just_to_see : + object method child : child2 method previous : child2 option end +|}] + +class just_to_see2 = object + method obj = object(self) + method previous = None + method child = + let o = + object + inherit child1 self + inherit child2 + end + in + o + end +end;; +[%%expect{| +class just_to_see2 : + object method obj : < child : child2; previous : child2 option > end +|}] + +type gadt = Not_really_though : gadt + +class just_to_see3 = object(self) + method previous = None + method child Not_really_though = + object + inherit child1 self + inherit child2 + end +end;; +[%%expect{| +type gadt = Not_really_though : gadt +class just_to_see3 : + object method child : gadt -> child2 method previous : child2 option end +|}] + +class leading_up_to = object(self : 'a) + method previous : 'a option = None + method child = + object + inherit child1 self + inherit child2 + end +end;; +[%%expect{| +Line _, characters 4-65: + ....object + inherit child1 self + inherit child2 + end +Error: Cannot close type of object literal: + < child : '_weak1; previous : 'a option; _.. > as 'a + it has been unified with the self type of a class that is not yet + completely defined. +|}] + +class assertion_failure = object(self : 'a) + method previous : 'a option = None + method child = + object + inherit child1 self + inherit child2 + + method previous = None + method child = assert false + end +end;; +[%%expect{| +Line _, characters 4-129: + ....object + inherit child1 self + inherit child2 + + method previous = None + method child = assert false + end +Error: Cannot close type of object literal: + < child : '_weak2; previous : 'a option; _.. > as 'a + it has been unified with the self type of a class that is not yet + completely defined. +|}] diff --git a/testsuite/tests/typing-objects/ocamltests b/testsuite/tests/typing-objects/ocamltests new file mode 100644 index 00000000..fcada949 --- /dev/null +++ b/testsuite/tests/typing-objects/ocamltests @@ -0,0 +1,10 @@ +dummy.ml +Exemples.ml +open_in_classes.ml +pr5545.ml +pr5619_bad.ml +pr5858.ml +pr6123_bad.ml +pr6383.ml +pr6907_bad.ml +Tests.ml diff --git a/testsuite/tests/typing-objects/open_in_classes.ml b/testsuite/tests/typing-objects/open_in_classes.ml old mode 100755 new mode 100644 index 24c0b34d..05f33b91 --- a/testsuite/tests/typing-objects/open_in_classes.ml +++ b/testsuite/tests/typing-objects/open_in_classes.ml @@ -1,17 +1,30 @@ +(* TEST + * expect +*) + module M = struct type t = int let x = 42 end ;; +[%%expect{| +module M : sig type t = int val x : int end +|}] class c = let open M in object method f : t = x end ;; +[%%expect{| +class c : object method f : M.t end +|}] class type ct = let open M in object method f : t end ;; +[%%expect{| +class type ct = object method f : M.t end +|}] diff --git a/testsuite/tests/typing-objects/open_in_classes.ml.reference b/testsuite/tests/typing-objects/open_in_classes.ml.reference deleted file mode 100644 index eaafa30f..00000000 --- a/testsuite/tests/typing-objects/open_in_classes.ml.reference +++ /dev/null @@ -1,5 +0,0 @@ - -# module M : sig type t = int val x : int end -# class c : object method f : M.t end -# class type ct = object method f : M.t end -# diff --git a/testsuite/tests/typing-objects/pr5545.ml b/testsuite/tests/typing-objects/pr5545.ml index 1273e6f0..8bb92adf 100644 --- a/testsuite/tests/typing-objects/pr5545.ml +++ b/testsuite/tests/typing-objects/pr5545.ml @@ -1,10 +1,20 @@ +(* TEST + * expect +*) + type foo = int;; +[%%expect{| +type foo = int +|}] class o = object(this) method x : foo = 10 method y : int = this # x end;; +[%%expect{| +class o : object method x : foo method y : int end +|}] class o = @@ -12,6 +22,9 @@ class o = method x : foo = 10 method y = (this # x : int) end;; +[%%expect{| +class o : object method x : foo method y : int end +|}] @@ -20,3 +33,6 @@ class o = method x : int = (10 : int) method y = (this # x : foo) end;; +[%%expect{| +class o : object method x : int method y : foo end +|}] diff --git a/testsuite/tests/typing-objects/pr5545.ml.principal.reference b/testsuite/tests/typing-objects/pr5545.ml.principal.reference deleted file mode 100644 index 4f7fda96..00000000 --- a/testsuite/tests/typing-objects/pr5545.ml.principal.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# type foo = int -# class o : object method x : foo method y : int end -# class o : object method x : foo method y : int end -# class o : object method x : int method y : foo end -# diff --git a/testsuite/tests/typing-objects/pr5545.ml.reference b/testsuite/tests/typing-objects/pr5545.ml.reference deleted file mode 100644 index 4f7fda96..00000000 --- a/testsuite/tests/typing-objects/pr5545.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# type foo = int -# class o : object method x : foo method y : int end -# class o : object method x : foo method y : int end -# class o : object method x : int method y : foo end -# diff --git a/testsuite/tests/typing-objects/pr5619_bad.ml b/testsuite/tests/typing-objects/pr5619_bad.ml index 8608dd02..bd23693c 100644 --- a/testsuite/tests/typing-objects/pr5619_bad.ml +++ b/testsuite/tests/typing-objects/pr5619_bad.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + class type foo_t = object method foo: string @@ -8,6 +12,11 @@ type 'a name = | Int: int name ;; +[%%expect{| +class type foo_t = object method foo : string end +type 'a name = Foo : foo_t name | Int : int name +|}] + class foo = object(self) method foo = "foo" @@ -16,6 +25,10 @@ class foo = Foo -> (self :> ) end ;; +[%%expect{| +class foo : + object method cast : foo_t name -> < foo : string > method foo : string end +|}] class foo: foo_t = object(self) @@ -26,3 +39,17 @@ class foo: foo_t = | _ -> raise Exit end ;; +[%%expect{| +Line _, characters 2-156: + ..object(self) + method foo = "foo" + method cast: type a. a name -> a = + function + Foo -> (self :> foo_t) + | _ -> raise Exit + end +Error: The class type + object method cast : 'a name -> 'a method foo : string end + is not matched by the class type foo_t + The public method cast cannot be hidden +|}] diff --git a/testsuite/tests/typing-objects/pr5619_bad.ml.principal.reference b/testsuite/tests/typing-objects/pr5619_bad.ml.principal.reference deleted file mode 100644 index 0b50417a..00000000 --- a/testsuite/tests/typing-objects/pr5619_bad.ml.principal.reference +++ /dev/null @@ -1,18 +0,0 @@ - -# class type foo_t = object method foo : string end -type 'a name = Foo : foo_t name | Int : int name -# class foo : - object method cast : foo_t name -> < foo : string > method foo : string end -# Characters 22-176: - ..object(self) - method foo = "foo" - method cast: type a. a name -> a = - function - Foo -> (self :> foo_t) - | _ -> raise Exit - end -Error: The class type - object method cast : 'a name -> 'a method foo : string end - is not matched by the class type foo_t - The public method cast cannot be hidden -# diff --git a/testsuite/tests/typing-objects/pr5619_bad.ml.reference b/testsuite/tests/typing-objects/pr5619_bad.ml.reference deleted file mode 100644 index 0b50417a..00000000 --- a/testsuite/tests/typing-objects/pr5619_bad.ml.reference +++ /dev/null @@ -1,18 +0,0 @@ - -# class type foo_t = object method foo : string end -type 'a name = Foo : foo_t name | Int : int name -# class foo : - object method cast : foo_t name -> < foo : string > method foo : string end -# Characters 22-176: - ..object(self) - method foo = "foo" - method cast: type a. a name -> a = - function - Foo -> (self :> foo_t) - | _ -> raise Exit - end -Error: The class type - object method cast : 'a name -> 'a method foo : string end - is not matched by the class type foo_t - The public method cast cannot be hidden -# diff --git a/testsuite/tests/typing-objects/pr5858.ml b/testsuite/tests/typing-objects/pr5858.ml index 3795cf31..4b92cb1d 100644 --- a/testsuite/tests/typing-objects/pr5858.ml +++ b/testsuite/tests/typing-objects/pr5858.ml @@ -1,2 +1,16 @@ +(* TEST + * expect +*) + class type c = object end;; +[%%expect{| +class type c = object end +|}] + module type S = sig class c: c end;; +[%%expect{| +Line _, characters 29-30: + module type S = sig class c: c end;; + ^ +Error: The class type c is not yet completely defined +|}] diff --git a/testsuite/tests/typing-objects/pr5858.ml.reference b/testsuite/tests/typing-objects/pr5858.ml.reference deleted file mode 100644 index 94e63484..00000000 --- a/testsuite/tests/typing-objects/pr5858.ml.reference +++ /dev/null @@ -1,7 +0,0 @@ - -# class type c = object end -# Characters 29-30: - module type S = sig class c: c end;; - ^ -Error: The class type c is not yet completely defined -# diff --git a/testsuite/tests/typing-objects/pr6123_bad.ml b/testsuite/tests/typing-objects/pr6123_bad.ml index a773f8d7..55a8b8b0 100644 --- a/testsuite/tests/typing-objects/pr6123_bad.ml +++ b/testsuite/tests/typing-objects/pr6123_bad.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + class virtual name = object end @@ -21,3 +25,11 @@ object inherit name end ;; +[%%expect{| +Line _, characters 50-54: + let args = List.map (fun ty -> new argument(self, ty)) args_ty in + ^^^^ +Error: This expression has type < arguments : 'a; .. > + but an expression was expected of type 'b + Self type cannot escape its class +|}] diff --git a/testsuite/tests/typing-objects/pr6123_bad.ml.principal.reference b/testsuite/tests/typing-objects/pr6123_bad.ml.principal.reference deleted file mode 100644 index eb3b05c0..00000000 --- a/testsuite/tests/typing-objects/pr6123_bad.ml.principal.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# Characters 253-257: - let args = List.map (fun ty -> new argument(self, ty)) args_ty in - ^^^^ -Error: This expression has type < arguments : 'a; .. > - but an expression was expected of type 'b - Self type cannot escape its class -# diff --git a/testsuite/tests/typing-objects/pr6123_bad.ml.reference b/testsuite/tests/typing-objects/pr6123_bad.ml.reference deleted file mode 100644 index eb3b05c0..00000000 --- a/testsuite/tests/typing-objects/pr6123_bad.ml.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# Characters 253-257: - let args = List.map (fun ty -> new argument(self, ty)) args_ty in - ^^^^ -Error: This expression has type < arguments : 'a; .. > - but an expression was expected of type 'b - Self type cannot escape its class -# diff --git a/testsuite/tests/typing-objects/pr6383.ml b/testsuite/tests/typing-objects/pr6383.ml index bd2fdb06..c039de87 100644 --- a/testsuite/tests/typing-objects/pr6383.ml +++ b/testsuite/tests/typing-objects/pr6383.ml @@ -1 +1,11 @@ +(* TEST + * expect +*) + let f (x: #M.foo) = 0;; +[%%expect{| +Line _, characters 11-16: + let f (x: #M.foo) = 0;; + ^^^^^ +Error: Unbound module M +|}];; diff --git a/testsuite/tests/typing-objects/pr6383.ml.reference b/testsuite/tests/typing-objects/pr6383.ml.reference deleted file mode 100644 index 6c92acc3..00000000 --- a/testsuite/tests/typing-objects/pr6383.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# Characters 11-16: - let f (x: #M.foo) = 0;; - ^^^^^ -Error: Unbound module M -# diff --git a/testsuite/tests/typing-objects/pr6907_bad.ml b/testsuite/tests/typing-objects/pr6907_bad.ml index 0a9a7a1d..afdfc971 100644 --- a/testsuite/tests/typing-objects/pr6907_bad.ml +++ b/testsuite/tests/typing-objects/pr6907_bad.ml @@ -1,7 +1,23 @@ +(* TEST + * expect +*) + class type ['e] t = object('s) method update : 'e -> 's end;; +[%%expect{| +class type ['e] t = object ('a) method update : 'e -> 'a end +|}];; module type S = sig class base : 'e -> ['e] t end;; +[%%expect{| +Line _, characters 2-27: + class base : 'e -> ['e] t + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Some type variables are unbound in this type: + class base : 'e -> ['e] t + The method update has type 'e -> < update : 'a; .. > as 'a where 'e + is unbound +|}];; diff --git a/testsuite/tests/typing-objects/pr6907_bad.ml.reference b/testsuite/tests/typing-objects/pr6907_bad.ml.reference deleted file mode 100644 index 3a4ef9af..00000000 --- a/testsuite/tests/typing-objects/pr6907_bad.ml.reference +++ /dev/null @@ -1,10 +0,0 @@ - -# class type ['e] t = object ('a) method update : 'e -> 'a end -# Characters 23-48: - class base : 'e -> ['e] t - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Some type variables are unbound in this type: - class base : 'e -> ['e] t - The method update has type 'e -> < update : 'a; .. > as 'a where 'e - is unbound -# diff --git a/testsuite/tests/typing-objects/pr7711_ok.ml b/testsuite/tests/typing-objects/pr7711_ok.ml new file mode 100644 index 00000000..7f188cf5 --- /dev/null +++ b/testsuite/tests/typing-objects/pr7711_ok.ml @@ -0,0 +1,15 @@ +(* TEST + * expect +*) + +type 'a r = int; .. > as 'a;; +[%%expect{| +type 'a r = 'a constraint 'a = < w : int -> int; .. > +|}];; + +class type virtual ct = object('self) + constraint 'self = 'not_self r +end;; +[%%expect{| +class type virtual ct = object method virtual w : int -> int end +|}];; diff --git a/testsuite/tests/typing-ocamlc-i/Makefile b/testsuite/tests/typing-ocamlc-i/Makefile deleted file mode 100644 index 8131fe6b..00000000 --- a/testsuite/tests/typing-ocamlc-i/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Check ocamlc -i - -SOURCES = pr7620_bad.ml - -all: - @printf " ... testing '$(SOURCES)'" - @$(OCAMLC) -i $(SOURCES) 2> /dev/null \ - && echo " => failed" || echo " => passed" - -clean: defaultclean - @rm -f *~ - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common - diff --git a/testsuite/tests/typing-ocamlc-i/ocamltests b/testsuite/tests/typing-ocamlc-i/ocamltests new file mode 100644 index 00000000..dd3bd42f --- /dev/null +++ b/testsuite/tests/typing-ocamlc-i/ocamltests @@ -0,0 +1 @@ +pr7620_bad.ml diff --git a/testsuite/tests/typing-ocamlc-i/pr7620_bad.compilers.reference b/testsuite/tests/typing-ocamlc-i/pr7620_bad.compilers.reference new file mode 100644 index 00000000..99d84e40 --- /dev/null +++ b/testsuite/tests/typing-ocamlc-i/pr7620_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr7620_bad.ml", line 10, characters 17-19: +Error: This pattern matches values of type [? `B ] + but a pattern was expected which matches values of type [ `A ] + Types for tag `B are incompatible diff --git a/testsuite/tests/typing-ocamlc-i/pr7620_bad.ml b/testsuite/tests/typing-ocamlc-i/pr7620_bad.ml index ad03d563..6c6cc395 100644 --- a/testsuite/tests/typing-ocamlc-i/pr7620_bad.ml +++ b/testsuite/tests/typing-ocamlc-i/pr7620_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = "-i" +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + let t = (function `A | `B -> () : 'a) (`A : [`A]); (failwith "dummy" : 'a) (* to know how 'a is unified *) diff --git a/testsuite/tests/typing-pattern_open/Makefile b/testsuite/tests/typing-pattern_open/Makefile deleted file mode 100644 index 9625a3fb..00000000 --- a/testsuite/tests/typing-pattern_open/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-pattern_open/ocamltests b/testsuite/tests/typing-pattern_open/ocamltests new file mode 100644 index 00000000..10150243 --- /dev/null +++ b/testsuite/tests/typing-pattern_open/ocamltests @@ -0,0 +1 @@ +pattern_open.ml diff --git a/testsuite/tests/typing-pattern_open/pattern_open.ml b/testsuite/tests/typing-pattern_open/pattern_open.ml index 07390ad5..b5d4eeeb 100644 --- a/testsuite/tests/typing-pattern_open/pattern_open.ml +++ b/testsuite/tests/typing-pattern_open/pattern_open.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + let pp fmt = Printf.printf fmt type 'a box = B of 'a diff --git a/testsuite/tests/typing-pattern_open/pattern_open.ml.reference b/testsuite/tests/typing-pattern_open/pattern_open.ml.reference deleted file mode 100644 index f97b7374..00000000 --- a/testsuite/tests/typing-pattern_open/pattern_open.ml.reference +++ /dev/null @@ -1,81 +0,0 @@ - -# val pp : ('a, out_channel, unit) format -> 'a = -type 'a box = B of 'a -module M : sig type c = C type t = { x : c box; } end -# module N : sig type d = D val d : d type t = { x : d box; } end -# val f : M.t -> 'a -> M.c * 'a = -# val g : int -> int -> int = -# val g : M.c list -> M.c list = -# val h : M.c array -> M.c option = -# val f2 : M.c box box -> M.c = -# # # module L : - sig - type _ c = C : unit c - type t = { t : unit c; } - type r = { r : unit c; } - val x : unit -> unit - end -# module K : - sig - type _ c = C : unit c - type t = { t : unit c; } - type r = { r : unit c; } - val x : unit -> unit - end -# Right value K.x -# module Exterior : - sig - module Gadt : - sig - module Boolean : - sig - type t = { b : bool; } - type wrong = false | true - val print : unit -> unit - end - type _ t = - Bool : Boolean.t -> bool t - | Int : int -> int t - | Eq : 'a t * 'a t -> bool t - val print : unit -> unit - end - val print : unit -> unit - end -# Right function print -Right function print -val eval : 't Exterior.Gadt.t -> 't = -# module Existential : - sig type printable = E : 'a * ('a -> unit) -> printable end -val print : Existential.printable -> unit = -# * module S : - sig - type 'a t = Sep : unit t - type ex = Ex : 'a * 'a -> ex - val s : unit t - end -# Characters 58-61: - | S.(Sep), (S.(Sep,Sep), Sep) -> () - ^^^ -Error: Unbound constructor Sep -# Characters 50-52: - | S.(Ex(a,b)), Ex(c,d) -> () - ^^ -Error: Unbound constructor Ex -# Characters 48-49: - | S.(Sep) -> s - ^ -Error: Unbound value s -# module PR6437 : - sig - module Ctx : - sig - type ('a, 'b) t = - Nil : (unit, unit) t - | Cons : ('a, 'b) t -> ('a * unit, 'b * unit) t - end - module Var : - sig type 'a t = O : ('a * unit) t | S : 'a t -> ('a * unit) t end - end -val f : ('g1, 'g2) PR6437.Ctx.t * 'g1 PR6437.Var.t -> 'g2 PR6437.Var.t = - -# diff --git a/testsuite/tests/typing-pattern_open/pattern_open.ocaml.reference b/testsuite/tests/typing-pattern_open/pattern_open.ocaml.reference new file mode 100644 index 00000000..28bc57ca --- /dev/null +++ b/testsuite/tests/typing-pattern_open/pattern_open.ocaml.reference @@ -0,0 +1,80 @@ +val pp : ('a, out_channel, unit) format -> 'a = +type 'a box = B of 'a +module M : sig type c = C type t = { x : c box; } end +module N : sig type d = D val d : d type t = { x : d box; } end +val f : M.t -> 'a -> M.c * 'a = +val g : int -> int -> int = +val g : M.c list -> M.c list = +val h : M.c array -> M.c option = +val f2 : M.c box box -> M.c = +module L : + sig + type _ c = C : unit c + type t = { t : unit c; } + type r = { r : unit c; } + val x : unit -> unit + end +module K : + sig + type _ c = C : unit c + type t = { t : unit c; } + type r = { r : unit c; } + val x : unit -> unit + end +Right value K.x +module Exterior : + sig + module Gadt : + sig + module Boolean : + sig + type t = { b : bool; } + type wrong = false | true + val print : unit -> unit + end + type _ t = + Bool : Boolean.t -> bool t + | Int : int -> int t + | Eq : 'a t * 'a t -> bool t + val print : unit -> unit + end + val print : unit -> unit + end +Right function print +Right function print +val eval : 't Exterior.Gadt.t -> 't = +module Existential : + sig type printable = E : 'a * ('a -> unit) -> printable end +val print : Existential.printable -> unit = +module S : + sig + type 'a t = Sep : unit t + type ex = Ex : 'a * 'a -> ex + val s : unit t + end +Characters 58-61: + | S.(Sep), (S.(Sep,Sep), Sep) -> () + ^^^ +Error: Unbound constructor Sep +Characters 50-52: + | S.(Ex(a,b)), Ex(c,d) -> () + ^^ +Error: Unbound constructor Ex +Characters 48-49: + | S.(Sep) -> s + ^ +Error: Unbound value s +module PR6437 : + sig + module Ctx : + sig + type ('a, 'b) t = + Nil : (unit, unit) t + | Cons : ('a, 'b) t -> ('a * unit, 'b * unit) t + end + module Var : + sig type 'a t = O : ('a * unit) t | S : 'a t -> ('a * unit) t end + end +val f : ('g1, 'g2) PR6437.Ctx.t * 'g1 PR6437.Var.t -> 'g2 PR6437.Var.t = + + diff --git a/testsuite/tests/typing-poly-bugs/Makefile b/testsuite/tests/typing-poly-bugs/Makefile deleted file mode 100644 index 69e2ee7b..00000000 --- a/testsuite/tests/typing-poly-bugs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.okbad -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-poly-bugs/ocamltests b/testsuite/tests/typing-poly-bugs/ocamltests new file mode 100644 index 00000000..1e05cf5d --- /dev/null +++ b/testsuite/tests/typing-poly-bugs/ocamltests @@ -0,0 +1,3 @@ +pr5322_ok.ml +pr5673_bad.ml +pr5673_ok.ml diff --git a/testsuite/tests/typing-poly-bugs/pr5322_ok.ml b/testsuite/tests/typing-poly-bugs/pr5322_ok.ml index d6cbca1a..aeda3322 100644 --- a/testsuite/tests/typing-poly-bugs/pr5322_ok.ml +++ b/testsuite/tests/typing-poly-bugs/pr5322_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type 'par t = 'par module M : sig val x : end = struct let x : = Obj.magic () end diff --git a/testsuite/tests/typing-poly-bugs/pr5673_bad.compilers.reference b/testsuite/tests/typing-poly-bugs/pr5673_bad.compilers.reference new file mode 100644 index 00000000..63dbdb98 --- /dev/null +++ b/testsuite/tests/typing-poly-bugs/pr5673_bad.compilers.reference @@ -0,0 +1,11 @@ +File "pr5673_bad.ml", line 31, characters 22-23: +Error: This expression has type + refer1 = < poly : 'a 'b 'c. ('b, 'c) #Classdef.cl2 as 'a > + but an expression was expected of type + refer2 = < poly : 'd 'b 'c. ('b, 'c) #Classdef.cl2 as 'd > + Type + ('b, 'c) Classdef.cl1 = + < m : 'b -> 'c -> int; raise_trouble : int -> 'b > + is not compatible with type + < m : 'b -> 'c -> int; raise_trouble : int -> 'b > + The type variable 'e occurs inside 'e diff --git a/testsuite/tests/typing-poly-bugs/pr5673_bad.ml b/testsuite/tests/typing-poly-bugs/pr5673_bad.ml index 99088000..cddd0932 100644 --- a/testsuite/tests/typing-poly-bugs/pr5673_bad.ml +++ b/testsuite/tests/typing-poly-bugs/pr5673_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module Classdef = struct class virtual ['a, 'b, 'c] cl0 = object diff --git a/testsuite/tests/typing-poly-bugs/pr5673_ok.ml b/testsuite/tests/typing-poly-bugs/pr5673_ok.ml index 26ad1606..535ced53 100644 --- a/testsuite/tests/typing-poly-bugs/pr5673_ok.ml +++ b/testsuite/tests/typing-poly-bugs/pr5673_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module Classdef = struct class virtual ['a, 'b, 'c] cl0 = object diff --git a/testsuite/tests/typing-poly/Makefile b/testsuite/tests/typing-poly/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-poly/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-poly/ocamltests b/testsuite/tests/typing-poly/ocamltests new file mode 100644 index 00000000..be3e7110 --- /dev/null +++ b/testsuite/tests/typing-poly/ocamltests @@ -0,0 +1 @@ +poly.ml diff --git a/testsuite/tests/typing-poly/poly.ml b/testsuite/tests/typing-poly/poly.ml index bc1990c7..5f727c4e 100644 --- a/testsuite/tests/typing-poly/poly.ml +++ b/testsuite/tests/typing-poly/poly.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + (* Polymorphic methods are now available in the main branch. Enjoy. @@ -229,6 +233,8 @@ class ['a] ostream1 : end |}, Principal{| Line _, characters 4-16: + self#tl#fold ~f ~init:(f self#hd init) + ^^^^^^^^^^^^ Warning 18: this use of a polymorphic method is not principal. class ['a] ostream1 : hd:'a -> @@ -386,6 +392,8 @@ val c : circle = val d : float = 11. val f : < m : 'a. 'a -> 'a > -> < m : 'b. 'b -> 'b > = Line _, characters 41-42: + let f (x : < m : 'a. 'a -> 'a list >) = (x : < m : 'b. 'b -> 'c >) + ^ Error: This expression has type < m : 'b. 'b -> 'b list > but an expression was expected of type < m : 'b. 'b -> 'c > The universal variable 'b would escape its scope @@ -436,6 +444,8 @@ end ;; [%%expect {| Line _, characters 12-17: + method id x = x + ^^^^^ Error: This method has type 'a -> 'a which is less general than 'b. 'b -> 'a |}];; @@ -446,6 +456,8 @@ end ;; [%%expect {| Line _, characters 12-17: + method id x = x + ^^^^^ Error: This method has type 'a -> 'a which is less general than 'b. 'b -> 'a |}];; @@ -457,6 +469,8 @@ end ;; [%%expect {| Line _, characters 12-17: + method id _ = x + ^^^^^ Error: This method has type 'b -> 'b which is less general than 'a. 'a -> 'a |}];; @@ -471,6 +485,10 @@ end ;; [%%expect {| Line _, characters 12-79: + ............x = + match r with + None -> r <- Some x; x + | Some y -> y Error: This method has type 'b -> 'b which is less general than 'a. 'a -> 'a |}];; @@ -496,6 +514,8 @@ let f4 f = ignore(f : id); f#id 1, f#id true val f1 : id -> int * bool = val f2 : id -> int * bool = Line _, characters 24-28: + let f3 f = f#id 1, f#id true + ^^^^ Error: This expression has type bool but an expression was expected of type int |}];; @@ -524,6 +544,8 @@ type 'a foo = 'a foo list class id2 : object method id : 'a -> 'a method mono : int -> int end val app : int * bool = (1, true) Line _, characters 0-25: + type 'a foo = 'a foo list + ^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The type abbreviation foo is cyclic |}];; @@ -732,6 +754,8 @@ bad2.bad2 <- Some (ref None);; [%%expect {| type bad = { bad : 'a. 'a option ref; } Line _, characters 17-25: + let bad = {bad = ref None};; + ^^^^^^^^ Error: This field value has type 'b option ref which is less general than 'a. 'a option ref |}];; @@ -785,6 +809,8 @@ and virtual int_list = object method virtual visit : 'a.('a visitor -> 'a) end;; [%%expect {| Line _, characters 30-51: + object method virtual visit : 'a.('a visitor -> 'a) end;; + ^^^^^^^^^^^^^^^^^^^^^ Error: The universal type variable 'a cannot be generalized: it escapes its scope. |}];; @@ -810,6 +836,8 @@ type t = { f : 'a 'b. ('b -> (#ct as 'a) -> 'b) -> 'b; } type t = u and u = t;; [%%expect {| Line _, characters 0-10: + type t = u and u = t;; + ^^^^^^^^^^ Error: The definition of t contains a cycle: u |}];; @@ -826,6 +854,8 @@ type t = [ `A of t a ] type ('a,'b) t constraint 'a = 'b and ('a,'b) u = ('a,'b) t;; [%%expect {| Line _, characters 50-59: + type ('a,'b) t constraint 'a = 'b and ('a,'b) u = ('a,'b) t;; + ^^^^^^^^^ Error: Constraints are not satisfied in this type. Type ('a, 'b) t should be an instance of ('c, 'c) t |}];; @@ -844,6 +874,8 @@ type 'a u = 'a and 'a v = 'a u t constraint 'a = int;; [%%expect {| type 'a t constraint 'a = int Line _, characters 26-32: + type 'a u = 'a and 'a v = 'a u t;; + ^^^^^^ Error: Constraints are not satisfied in this type. Type 'a u t should be an instance of int t |}];; @@ -857,6 +889,8 @@ type 'a u = 'a and 'a v = 'a u t constraint 'a = int;; type g = int type 'a t = unit constraint 'a = g Line _, characters 26-32: + type 'a u = 'a and 'a v = 'a u t;; + ^^^^^^ Error: Constraints are not satisfied in this type. Type 'a u t should be an instance of g t |}];; @@ -865,6 +899,8 @@ Error: Constraints are not satisfied in this type. type 'a u = < m : 'a v > and 'a v = 'a list u;; [%%expect {| Line _, characters 0-24: + type 'a u = < m : 'a v > and 'a v = 'a list u;; + ^^^^^^^^^^^^^^^^^^^^^^^^ Error: In the definition of v, type 'a list u should be 'a u |}];; @@ -890,53 +926,13 @@ type 'a t = < a : 'a > type u = 'a t as 'a |}];; - -(* Variant tests *) -type t = A | B;; -function `A,_ -> 1 | _,A -> 2 | _,B -> 3;; -function `A,_ -> 1 | _,(A|B) -> 2;; -function Some `A, _ -> 1 | Some _, A -> 2 | None, A -> 3 | _, B -> 4;; -function Some `A, A -> 1 | Some `A, B -> 1 - | Some _, A -> 2 | None, A -> 3 | _, B -> 4;; -function A, `A -> 1 | A, `B -> 2 | B, _ -> 3;; -function `A, A -> 1 | `B, A -> 2 | _, B -> 3;; -function (`A|`B), _ -> 0 | _,(`A|`B) -> 1;; -function `B,1 -> 1 | _,1 -> 2;; -function 1,`B -> 1 | 1,_ -> 2;; -[%%expect {| -type t = A | B -- : [> `A ] * t -> int = -- : [> `A ] * t -> int = -- : [> `A ] option * t -> int = -- : [> `A ] option * t -> int = -- : t * [< `A | `B ] -> int = -- : [< `A | `B ] * t -> int = -Line _, characters 0-41: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(`, `) -- : [> `A | `B ] * [> `A | `B ] -> int = -Line _, characters 0-29: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(_, 0) -Line _, characters 21-24: -Warning 11: this match case is unused. -- : [< `B ] * int -> int = -Line _, characters 0-29: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(0, _) -Line _, characters 21-24: -Warning 11: this match case is unused. -- : int * [< `B ] -> int = -|}];; - (* pass typetexp, but fails during Typedecl.check_recursion *) type ('a, 'b) a = 'a -> unit constraint 'a = [> `B of ('a, 'b) b as 'b] and ('a, 'b) b = 'b -> unit constraint 'b = [> `A of ('a, 'b) a as 'a];; [%%expect {| Line _, characters 0-71: + type ('a, 'b) a = 'a -> unit constraint 'a = [> `B of ('a, 'b) b as 'b] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: The definition of a contains a cycle: [> `B of ('a, 'b) b as 'b ] as 'a |}];; @@ -1013,10 +1009,14 @@ class c : object method m : int end val f : unit -> c = val f : unit -> c = Line _, characters 11-60: + let f () = object method private n = 1 method m = {<>}#n end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Warning 15: the following private methods were made public implicitly: n. val f : unit -> < m : int; n : int > = Line _, characters 11-56: + let f () = object (self:c) method n = 1 method m = 2 end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This object is expected to have type c but actually has type < m : int; n : 'a > The first object type has no method n @@ -1033,6 +1033,8 @@ type bar' = let f (x : foo') = (x : bar');; [%%expect {| Line _, characters 3-4: + (x : > as 'bar) >);; + ^ Error: This expression has type < m : 'a. 'a * < m : 'a * 'b > > as 'b but an expression was expected of type < m : 'a. 'a * (< m : 'a * < m : 'c. 'c * 'd > > as 'd) > @@ -1050,6 +1052,8 @@ let f x = :> ('a * 'foo)> as 'foo);; [%%expect {| Line _, characters 3-4: + (x : )> as 'bar);; + ^ Error: This expression has type < m : 'b. 'b * ('b * < m : 'c. 'c * 'a > as 'a) > but an expression was expected of type @@ -1065,6 +1069,8 @@ module M = struct type t = as 'foo end;; [%%expect {| Line _, characters 2-64: + = struct let f (x : as 'foo) = () end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Signature mismatch: Modules do not match: sig val f : (< m : 'a. 'a * ('a * 'b) > as 'b) -> unit end @@ -1123,6 +1129,8 @@ type v = private [> t ] type u = private [< t ] - : u -> v = Line _, characters 9-21: + fun x -> (x : v :> u);; + ^^^^^^^^^^^^ Error: Type v = [> `A | `B ] is not a subtype of u = [< `A | `B ] |}];; @@ -1142,6 +1150,8 @@ let f6 x = (x : ] as 'a> :> ] as 'a>);; [%%expect {| Line _, characters 2-88: + ..(x : as 'a) -> int> + :> as 'b) -> int>).. Error: Type < m : 'a. (< p : int; .. > as 'a) -> int > is not a subtype of < m : 'b. (< p : int; q : int; .. > as 'b) -> int > Type < p : int; q : int; .. > as 'c is not a subtype of @@ -1165,14 +1175,20 @@ val f : < m : 'a. 'a -> 'a > -> < m : 'a. 'a -> 'a > array = |}, Principal{| val f : < m : 'a. 'a -> 'a > -> < m : 'a. 'a -> 'a > = Line _, characters 9-16: + fun x -> (f x)#m;; (* Warning 18 *) + ^^^^^^^ Warning 18: this use of a polymorphic method is not principal. - : < m : 'a. 'a -> 'a > -> 'b -> 'b = val f : < m : 'a. 'a -> 'a > * 'b -> < m : 'a. 'a -> 'a > = Line _, characters 9-20: + fun x -> (f (x,x))#m;; (* Warning 18 *) + ^^^^^^^^^^^ Warning 18: this use of a polymorphic method is not principal. - : < m : 'a. 'a -> 'a > -> 'b -> 'b = val f : < m : 'a. 'a -> 'a > -> < m : 'a. 'a -> 'a > array = Line _, characters 9-20: + fun x -> (f x).(0)#m;; (* Warning 18 *) + ^^^^^^^^^^^ Warning 18: this use of a polymorphic method is not principal. - : < m : 'a. 'a -> 'a > -> 'b -> 'b = |}];; @@ -1200,9 +1216,13 @@ class c : object method id : 'a -> 'a end type u = c option val just : 'a option -> 'a = Line _, characters 42-62: + let f x = let l = [Some x; (None : u)] in (just(List.hd l))#id;; + ^^^^^^^^^^^^^^^^^^^^ Warning 18: this use of a polymorphic method is not principal. val f : c -> 'a -> 'a = Line _, characters 36-47: + let x = List.hd [Some x; none] in (just x)#id;; + ^^^^^^^^^^^ Warning 18: this use of a polymorphic method is not principal. val g : c -> 'a -> 'a = val h : < id : 'a; .. > -> 'a = @@ -1244,6 +1264,8 @@ val g : 'a -> int = type 'a t = Leaf of 'a | Node of ('a * 'a) t val depth : 'a t -> int = Line _, characters 2-42: + function Leaf _ -> 1 | Node x -> 1 + d x + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This definition has type 'a t -> int which is less general than 'a0. 'a0 t -> int |}];; @@ -1258,6 +1280,8 @@ type t = { f : 'a. [> `B of 'a | `Int of int ] as 'a; } val zero : t = {f = `Int 0} type t = { f : 'a. [< `Int of int ] as 'a; } Line _, characters 16-22: + let zero = {f = `Int 0} ;; (* fails *) + ^^^^^^ Error: This expression has type [> `Int of int ] but an expression was expected of type [< `Int of int ] Types for tag `Int are incompatible @@ -1308,6 +1332,8 @@ let f ?x y = y in {f};; (* fail *) type t = { f : 'a. 'a -> unit; } - : t = {f = } Line _, characters 19-20: + let f ?x y = y in {f};; (* fail *) + ^ Error: This field value has type unit -> unit which is less general than 'a. 'a -> unit |}];; @@ -1337,7 +1363,7 @@ let {foo} = (raise Exit : t);; type s = A of int let (A x) = (raise Exit : s);; [%%expect {| -Exception: Pervasives.Exit. +Exception: Stdlib.Pervasives.Exit. |}];; (* PR#5224 *) @@ -1345,6 +1371,8 @@ Exception: Pervasives.Exit. type 'x t = < f : 'y. 'y t >;; [%%expect {| Line _, characters 0-28: + type 'x t = < f : 'y. 'y t >;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: In the definition of t, type 'y t should be 'x t |}];; @@ -1376,43 +1404,35 @@ end;; [%%expect {| val n : < m : 'x 'a. ([< `Foo of 'x ] as 'a) -> 'x > = |}];; -(* ok, but not with -principal *) +(* ok *) let n = object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;; [%%expect {| val n : < m : 'x. [< `Foo of 'x ] -> 'x > = -|}, Principal{| -Line _, characters 47-68: -Error: This method has type ([< `Foo of 'b ] as 'a) -> 'b - which is less general than 'x. 'a -> 'x |}];; (* fail *) let (n : < m : 'a. [< `Foo of int] -> 'a >) = object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;; [%%expect {| Line _, characters 2-72: + object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This expression has type < m : 'x. [< `Foo of 'x ] -> 'x > but an expression was expected of type < m : 'a. [< `Foo of int ] -> 'a > The universal variable 'x would escape its scope -|}, Principal{| -Line _, characters 47-68: -Error: This method has type ([< `Foo of 'b ] as 'a) -> 'b - which is less general than 'x. 'a -> 'x |}];; (* fail *) let (n : 'b -> < m : 'a . ([< `Foo of int] as 'b) -> 'a >) = fun x -> object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;; [%%expect {| Line _, characters 2-72: + object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This expression has type < m : 'x. [< `Foo of 'x ] -> 'x > but an expression was expected of type < m : 'a. [< `Foo of int ] -> 'a > The universal variable 'x would escape its scope -|}, Principal{| -Line _, characters 47-68: -Error: This method has type ([< `Foo of 'b ] as 'a) -> 'b - which is less general than 'x. 'a -> 'x |}];; (* PR#6171 *) @@ -1421,6 +1441,8 @@ let f b (x: 'x) = if b then x else M.A;; [%%expect {| Line _, characters 19-22: + if b then x else M.A;; + ^^^ Error: This expression has type M.t but an expression was expected of type 'x The type constructor M.t would escape its scope |}];; @@ -1513,6 +1535,8 @@ type t = and g = [%%expect{| Line _, characters 10-11: + type t = + ^ Error: The type constructor g is not yet completely defined |}] @@ -1522,6 +1546,8 @@ type g = [%%expect{| type t = int Line _, characters 10-11: + type g = + ^ Error: The type int is not an object type |}] @@ -1561,6 +1587,8 @@ type r2 = < a : int > type gg = float; a:int> [%%expect{| Line _, characters 27-30: + type gg = float; a:int> + ^^^ Error: Method 'a' has type int, which should be int -> float |}] @@ -1569,6 +1597,8 @@ type g = [%%expect{| type t = < a : int; b : string > Line _, characters 19-20: + type g = + ^ Error: Method 'b' has type string, which should be float |}] @@ -1584,6 +1614,8 @@ type t = < f : int > type t = < int #A.t1 > [%%expect{| Line _, characters 11-20: + type t = < int #A.t1 > + ^^^^^^^^^ Error: Illegal open object type |}] @@ -1598,11 +1630,23 @@ type 'a t = < m : 'a > constraint 'a = int |}] (* GPR#1142 *) +external reraise : exn -> 'a = "%reraise" + module M () = struct let f : 'a -> 'a = assert false let g : 'a -> 'a = raise Not_found + let h : 'a -> 'a = reraise Not_found + let i : 'a -> 'a = raise_notrace Not_found end [%%expect{| -module M : functor () -> sig val f : 'a -> 'a val g : 'a -> 'a end +external reraise : exn -> 'a = "%reraise" +module M : + functor () -> + sig + val f : 'a -> 'a + val g : 'a -> 'a + val h : 'a -> 'a + val i : 'a -> 'a + end |}] diff --git a/testsuite/tests/typing-polyvariants-bugs-2/Makefile b/testsuite/tests/typing-polyvariants-bugs-2/Makefile deleted file mode 100644 index 2775418c..00000000 --- a/testsuite/tests/typing-polyvariants-bugs-2/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -default: - @printf " ... testing 'pr3918':" - @($(OCAMLC) -c pr3918a.mli \ - && $(OCAMLC) -c pr3918b.mli \ - && $(OCAMLC) -c pr3918c.ml \ - && echo " => passed") || echo " => failed" - -clean: defaultclean - -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-polyvariants-bugs-2/ocamltests b/testsuite/tests/typing-polyvariants-bugs-2/ocamltests new file mode 100644 index 00000000..740258ee --- /dev/null +++ b/testsuite/tests/typing-polyvariants-bugs-2/ocamltests @@ -0,0 +1 @@ +pr3918c.ml diff --git a/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.compilers.reference b/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.compilers.reference new file mode 100644 index 00000000..bd8cef8b --- /dev/null +++ b/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.compilers.reference @@ -0,0 +1,4 @@ +File "pr3918c.ml", line 24, characters 11-12: +Error: This expression has type 'b Pr3918b.vlist = 'a + but an expression was expected of type 'b Pr3918b.vlist + The type variable 'a occurs inside 'a diff --git a/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.ml b/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.ml index c49ed6e0..f3a7ccca 100644 --- a/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.ml +++ b/testsuite/tests/typing-polyvariants-bugs-2/pr3918c.ml @@ -1,3 +1,18 @@ +(* TEST +files = "pr3918a.mli pr3918b.mli" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "pr3918a.mli" +*** ocamlc.byte +module = "pr3918b.mli" +**** script +script = "rm -f pr3918a.cmi" +***** ocamlc.byte +module = "pr3918c.ml" +ocamlc_byte_exit_status = "2" +***** check-ocamlc.byte-output +*) + (* ocamlc -c pr3918a.mli pr3918b.mli rm -f pr3918a.cmi diff --git a/testsuite/tests/typing-polyvariants-bugs/Makefile b/testsuite/tests/typing-polyvariants-bugs/Makefile deleted file mode 100644 index 69e2ee7b..00000000 --- a/testsuite/tests/typing-polyvariants-bugs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.okbad -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-polyvariants-bugs/ocamltests b/testsuite/tests/typing-polyvariants-bugs/ocamltests new file mode 100644 index 00000000..d589e6c1 --- /dev/null +++ b/testsuite/tests/typing-polyvariants-bugs/ocamltests @@ -0,0 +1,6 @@ +pr4775_ok.ml +pr4933_ok.ml +pr5057_ok.ml +pr5057a_bad.ml +pr7199_ok.ml +privrowsabate_ok.ml diff --git a/testsuite/tests/typing-polyvariants-bugs/pr4775_ok.ml b/testsuite/tests/typing-polyvariants-bugs/pr4775_ok.ml index ef857149..e471f4ec 100644 --- a/testsuite/tests/typing-polyvariants-bugs/pr4775_ok.ml +++ b/testsuite/tests/typing-polyvariants-bugs/pr4775_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type Poly = sig type 'a t = 'a constraint 'a = [> ] end diff --git a/testsuite/tests/typing-polyvariants-bugs/pr4933_ok.ml b/testsuite/tests/typing-polyvariants-bugs/pr4933_ok.ml index b486290c..35316922 100644 --- a/testsuite/tests/typing-polyvariants-bugs/pr4933_ok.ml +++ b/testsuite/tests/typing-polyvariants-bugs/pr4933_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type Priv = sig type t = private int end diff --git a/testsuite/tests/typing-polyvariants-bugs/pr5057_ok.ml b/testsuite/tests/typing-polyvariants-bugs/pr5057_ok.ml index 86cb665a..8edd6b7f 100644 --- a/testsuite/tests/typing-polyvariants-bugs/pr5057_ok.ml +++ b/testsuite/tests/typing-polyvariants-bugs/pr5057_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR5057 *) module TT = struct diff --git a/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.compilers.reference b/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.compilers.reference new file mode 100644 index 00000000..67200052 --- /dev/null +++ b/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr5057a_bad.ml", line 14, characters 48-49: +Error: This expression has type 'a but an expression was expected of type + int -> T.t -> bool + The type constructor T.t would escape its scope diff --git a/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.ml b/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.ml index 15bb776b..11a84c59 100644 --- a/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.ml +++ b/testsuite/tests/typing-polyvariants-bugs/pr5057a_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* This one should fail *) let f flag = diff --git a/testsuite/tests/typing-polyvariants-bugs/pr7199_ok.ml b/testsuite/tests/typing-polyvariants-bugs/pr7199_ok.ml index dd1d05c1..02675e05 100644 --- a/testsuite/tests/typing-polyvariants-bugs/pr7199_ok.ml +++ b/testsuite/tests/typing-polyvariants-bugs/pr7199_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type S = sig type +'a t diff --git a/testsuite/tests/typing-polyvariants-bugs/privrowsabate_ok.ml b/testsuite/tests/typing-polyvariants-bugs/privrowsabate_ok.ml index 4e31243b..7c738346 100644 --- a/testsuite/tests/typing-polyvariants-bugs/privrowsabate_ok.ml +++ b/testsuite/tests/typing-polyvariants-bugs/privrowsabate_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type 'a termpc = [`And of 'a * 'a |`Or of 'a * 'a diff --git a/testsuite/tests/typing-private-bugs/Makefile b/testsuite/tests/typing-private-bugs/Makefile deleted file mode 100644 index 69e2ee7b..00000000 --- a/testsuite/tests/typing-private-bugs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.okbad -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-private-bugs/ocamltests b/testsuite/tests/typing-private-bugs/ocamltests new file mode 100644 index 00000000..d9326a59 --- /dev/null +++ b/testsuite/tests/typing-private-bugs/ocamltests @@ -0,0 +1,2 @@ +pr5026_bad.ml +pr5469_ok.ml diff --git a/testsuite/tests/typing-private-bugs/pr5026_bad.compilers.reference b/testsuite/tests/typing-private-bugs/pr5026_bad.compilers.reference new file mode 100644 index 00000000..906ef1cc --- /dev/null +++ b/testsuite/tests/typing-private-bugs/pr5026_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr5026_bad.ml", line 11, characters 0-36: +Error: The definition of wrapped contains a cycle: + sexp diff --git a/testsuite/tests/typing-private-bugs/pr5026_bad.ml b/testsuite/tests/typing-private-bugs/pr5026_bad.ml index 10699952..52c135b3 100644 --- a/testsuite/tests/typing-private-bugs/pr5026_bad.ml +++ b/testsuite/tests/typing-private-bugs/pr5026_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type untyped;; type -'a typed = private untyped;; type -'typing wrapped = private sexp diff --git a/testsuite/tests/typing-private-bugs/pr5469_ok.ml b/testsuite/tests/typing-private-bugs/pr5469_ok.ml index 74d35549..e7311b1a 100644 --- a/testsuite/tests/typing-private-bugs/pr5469_ok.ml +++ b/testsuite/tests/typing-private-bugs/pr5469_ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M (T:sig type t end) = struct type t = private { t : T.t } end module P diff --git a/testsuite/tests/typing-private/Makefile b/testsuite/tests/typing-private/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-private/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-private/ocamltests b/testsuite/tests/typing-private/ocamltests new file mode 100644 index 00000000..8f13acc4 --- /dev/null +++ b/testsuite/tests/typing-private/ocamltests @@ -0,0 +1 @@ +private.ml diff --git a/testsuite/tests/typing-private/private.compilers.principal.reference b/testsuite/tests/typing-private/private.compilers.principal.reference new file mode 100644 index 00000000..e8adbea9 --- /dev/null +++ b/testsuite/tests/typing-private/private.compilers.principal.reference @@ -0,0 +1,126 @@ +module Foobar : sig type t = private int end +module F0 : sig type t = private int end +Characters 21-22: + let f (x : F0.t) = (x : Foobar.t);; (* fails *) + ^ +Error: This expression has type F0.t but an expression was expected of type + Foobar.t +module F = Foobar +val f : F.t -> Foobar.t = +module M : sig type t = < m : int > end +module M1 : sig type t = private < m : int; .. > end +module M2 : sig type t = private < m : int; .. > end +Characters 19-20: + fun (x : M1.t) -> (x : M2.t);; (* fails *) + ^ +Error: This expression has type M1.t but an expression was expected of type + M2.t +module M3 : sig type t = private M1.t end +- : M3.t -> M1.t = +- : M3.t -> M.t = +Characters 44-46: + module M4 : sig type t = private M3.t end = M2;; (* fails *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M2.t end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = M2.t + is not included in + type t = private M3.t +Characters 44-45: + module M4 : sig type t = private M3.t end = M;; (* fails *) + ^ +Error: Signature mismatch: + Modules do not match: + sig type t = < m : int > end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = < m : int > + is not included in + type t = private M3.t +Characters 44-46: + module M4 : sig type t = private M3.t end = M1;; (* might be ok *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M1.t end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = M1.t + is not included in + type t = private M3.t +module M5 : sig type t = private M1.t end +Characters 53-55: + module M6 : sig type t = private < n:int; .. > end = M1;; (* fails *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M1.t end + is not included in + sig type t = private < n : int; .. > end + Type declarations do not match: + type t = M1.t + is not included in + type t = private < n : int; .. > +Characters 69-118: + struct type t = int let f (x : int) = (x : t) end;; (* must fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Signature mismatch: + Modules do not match: + sig type t = int val f : int -> t end + is not included in + sig type t = private Foobar.t val f : int -> t end + Type declarations do not match: + type t = int + is not included in + type t = private Foobar.t +module M : sig type t = private T of int val mk : int -> t end +module M1 : sig type t = M.t val mk : int -> t end +module M2 : sig type t = M.t val mk : int -> t end +module M3 : sig type t = M.t val mk : int -> t end +Characters 21-44: + type t = M.t = T of int + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This variant or record definition does not match that of type M.t + A private type would be revealed. +module M5 : sig type t = M.t = private T of int val mk : int -> t end +module M6 : sig type t = private T of int val mk : int -> t end +module M' : + sig type t_priv = private T of int type t = t_priv val mk : int -> t end +module M3' : sig type t = M'.t val mk : int -> t end +module M : sig type 'a t = private T of 'a end +module M1 : sig type 'a t = 'a M.t = private T of 'a end +module Test : sig type t = private A end +module Test2 : sig type t = Test.t = private A end +val f : Test.t -> Test2.t = +val f : Test2.t -> unit = +Characters 8-15: + let a = Test2.A;; (* fail *) + ^^^^^^^ +Error: Cannot create values of the private type Test2.t +Characters 148-171: + module Test2 : module type of Test with type t = private Test.t = Test;; + ^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: spurious use of private +module Test2 : sig type t = Test.t = private A end +type t = private < x : int; .. > +type t = private < x : int; .. > +type t = private < x : int > +type t = private < x : int > +Characters -1--1: + type 'a t = private < x : int; .. > as 'a;; + +Error: Type declarations do not match: + type 'a t = private 'a constraint 'a = < x : int; .. > + is not included in + type 'a t + Their constraints differ. +type 'a t = private 'a constraint 'a = < x : int; .. > +type t = [ `Closed ] +type nonrec t = private [> t ] + diff --git a/testsuite/tests/typing-private/private.compilers.reference b/testsuite/tests/typing-private/private.compilers.reference new file mode 100644 index 00000000..17a936b5 --- /dev/null +++ b/testsuite/tests/typing-private/private.compilers.reference @@ -0,0 +1,126 @@ +module Foobar : sig type t = private int end +module F0 : sig type t = private int end +Characters 21-22: + let f (x : F0.t) = (x : Foobar.t);; (* fails *) + ^ +Error: This expression has type F0.t but an expression was expected of type + Foobar.t +module F = Foobar +val f : F.t -> Foobar.t = +module M : sig type t = < m : int > end +module M1 : sig type t = private < m : int; .. > end +module M2 : sig type t = private < m : int; .. > end +Characters 19-20: + fun (x : M1.t) -> (x : M2.t);; (* fails *) + ^ +Error: This expression has type M1.t but an expression was expected of type + M2.t +module M3 : sig type t = private M1.t end +- : M3.t -> M1.t = +- : M3.t -> M.t = +Characters 44-46: + module M4 : sig type t = private M3.t end = M2;; (* fails *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M2.t end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = M2.t + is not included in + type t = private M3.t +Characters 44-45: + module M4 : sig type t = private M3.t end = M;; (* fails *) + ^ +Error: Signature mismatch: + Modules do not match: + sig type t = < m : int > end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = < m : int > + is not included in + type t = private M3.t +Characters 44-46: + module M4 : sig type t = private M3.t end = M1;; (* might be ok *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M1.t end + is not included in + sig type t = private M3.t end + Type declarations do not match: + type t = M1.t + is not included in + type t = private M3.t +module M5 : sig type t = private M1.t end +Characters 53-55: + module M6 : sig type t = private < n:int; .. > end = M1;; (* fails *) + ^^ +Error: Signature mismatch: + Modules do not match: + sig type t = M1.t end + is not included in + sig type t = private < n : int; .. > end + Type declarations do not match: + type t = M1.t + is not included in + type t = private < n : int; .. > +Characters 69-118: + struct type t = int let f (x : int) = (x : t) end;; (* must fail *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Signature mismatch: + Modules do not match: + sig type t = int val f : int -> t end + is not included in + sig type t = private Foobar.t val f : int -> t end + Type declarations do not match: + type t = int + is not included in + type t = private Foobar.t +module M : sig type t = private T of int val mk : int -> t end +module M1 : sig type t = M.t val mk : int -> t end +module M2 : sig type t = M.t val mk : int -> t end +module M3 : sig type t = M.t val mk : int -> t end +Characters 21-44: + type t = M.t = T of int + ^^^^^^^^^^^^^^^^^^^^^^^ +Error: This variant or record definition does not match that of type M.t + A private type would be revealed. +module M5 : sig type t = M.t = private T of int val mk : int -> t end +module M6 : sig type t = private T of int val mk : int -> t end +module M' : + sig type t_priv = private T of int type t = t_priv val mk : int -> t end +module M3' : sig type t = M'.t val mk : int -> t end +module M : sig type 'a t = private T of 'a end +module M1 : sig type 'a t = 'a M.t = private T of 'a end +module Test : sig type t = private A end +module Test2 : sig type t = Test.t = private A end +val f : Test.t -> Test2.t = +val f : Test2.t -> unit = +Characters 8-15: + let a = Test2.A;; (* fail *) + ^^^^^^^ +Error: Cannot create values of the private type Test2.t +Characters 148-171: + module Test2 : module type of Test with type t = private Test.t = Test;; + ^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: spurious use of private +module Test2 : sig type t = Test.t = private A end +type t = private < x : int; .. > +type t = private < x : int; .. > +type t = private < x : int > +type t = private < x : int > +Characters -1--1: + type 'a t = private < x : int; .. > as 'a;; + +Error: Type declarations do not match: + type 'a t = private < x : int; .. > constraint 'a = 'a t + is not included in + type 'a t + Their constraints differ. +type 'a t = private 'a constraint 'a = < x : int; .. > +type t = [ `Closed ] +type nonrec t = private [> t ] + diff --git a/testsuite/tests/typing-private/private.ml b/testsuite/tests/typing-private/private.ml index fd3b7bd7..bc559708 100644 --- a/testsuite/tests/typing-private/private.ml +++ b/testsuite/tests/typing-private/private.ml @@ -1,3 +1,8 @@ +(* TEST + * toplevel + * toplevel with principal +*) + module Foobar : sig type t = private int end = struct diff --git a/testsuite/tests/typing-private/private.ml.principal.reference b/testsuite/tests/typing-private/private.ml.principal.reference deleted file mode 100644 index 39b9440f..00000000 --- a/testsuite/tests/typing-private/private.ml.principal.reference +++ /dev/null @@ -1,127 +0,0 @@ - -# module Foobar : sig type t = private int end -# module F0 : sig type t = private int end -# Characters 21-22: - let f (x : F0.t) = (x : Foobar.t);; (* fails *) - ^ -Error: This expression has type F0.t but an expression was expected of type - Foobar.t -# module F = Foobar -# val f : F.t -> Foobar.t = -# module M : sig type t = < m : int > end -# module M1 : sig type t = private < m : int; .. > end -# module M2 : sig type t = private < m : int; .. > end -# Characters 19-20: - fun (x : M1.t) -> (x : M2.t);; (* fails *) - ^ -Error: This expression has type M1.t but an expression was expected of type - M2.t -# module M3 : sig type t = private M1.t end -# - : M3.t -> M1.t = -# - : M3.t -> M.t = -# Characters 44-46: - module M4 : sig type t = private M3.t end = M2;; (* fails *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M2.t end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = M2.t - is not included in - type t = private M3.t -# Characters 44-45: - module M4 : sig type t = private M3.t end = M;; (* fails *) - ^ -Error: Signature mismatch: - Modules do not match: - sig type t = < m : int > end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = < m : int > - is not included in - type t = private M3.t -# Characters 44-46: - module M4 : sig type t = private M3.t end = M1;; (* might be ok *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M1.t end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = M1.t - is not included in - type t = private M3.t -# module M5 : sig type t = private M1.t end -# Characters 53-55: - module M6 : sig type t = private < n:int; .. > end = M1;; (* fails *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M1.t end - is not included in - sig type t = private < n : int; .. > end - Type declarations do not match: - type t = M1.t - is not included in - type t = private < n : int; .. > -# Characters 69-118: - struct type t = int let f (x : int) = (x : t) end;; (* must fail *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Signature mismatch: - Modules do not match: - sig type t = int val f : int -> t end - is not included in - sig type t = private Foobar.t val f : int -> t end - Type declarations do not match: - type t = int - is not included in - type t = private Foobar.t -# module M : sig type t = private T of int val mk : int -> t end -# module M1 : sig type t = M.t val mk : int -> t end -# module M2 : sig type t = M.t val mk : int -> t end -# module M3 : sig type t = M.t val mk : int -> t end -# Characters 21-44: - type t = M.t = T of int - ^^^^^^^^^^^^^^^^^^^^^^^ -Error: This variant or record definition does not match that of type M.t - A private type would be revealed. -# module M5 : sig type t = M.t = private T of int val mk : int -> t end -# module M6 : sig type t = private T of int val mk : int -> t end -# module M' : - sig type t_priv = private T of int type t = t_priv val mk : int -> t end -# module M3' : sig type t = M'.t val mk : int -> t end -# module M : sig type 'a t = private T of 'a end -# module M1 : sig type 'a t = 'a M.t = private T of 'a end -# module Test : sig type t = private A end -module Test2 : sig type t = Test.t = private A end -# val f : Test.t -> Test2.t = -# val f : Test2.t -> unit = -# Characters 8-15: - let a = Test2.A;; (* fail *) - ^^^^^^^ -Error: Cannot create values of the private type Test2.t -# * Characters 148-171: - module Test2 : module type of Test with type t = private Test.t = Test;; - ^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: spurious use of private -module Test2 : sig type t = Test.t = private A end -# type t = private < x : int; .. > -# type t = private < x : int; .. > -# type t = private < x : int > -# type t = private < x : int > -# Characters -1--1: - type 'a t = private < x : int; .. > as 'a;; - -Error: Type declarations do not match: - type 'a t = private 'a constraint 'a = < x : int; .. > - is not included in - type 'a t - Their constraints differ. -# type 'a t = private 'a constraint 'a = < x : int; .. > -# type t = [ `Closed ] -# type nonrec t = private [> t ] -# diff --git a/testsuite/tests/typing-private/private.ml.reference b/testsuite/tests/typing-private/private.ml.reference deleted file mode 100644 index ace6cbdb..00000000 --- a/testsuite/tests/typing-private/private.ml.reference +++ /dev/null @@ -1,127 +0,0 @@ - -# module Foobar : sig type t = private int end -# module F0 : sig type t = private int end -# Characters 21-22: - let f (x : F0.t) = (x : Foobar.t);; (* fails *) - ^ -Error: This expression has type F0.t but an expression was expected of type - Foobar.t -# module F = Foobar -# val f : F.t -> Foobar.t = -# module M : sig type t = < m : int > end -# module M1 : sig type t = private < m : int; .. > end -# module M2 : sig type t = private < m : int; .. > end -# Characters 19-20: - fun (x : M1.t) -> (x : M2.t);; (* fails *) - ^ -Error: This expression has type M1.t but an expression was expected of type - M2.t -# module M3 : sig type t = private M1.t end -# - : M3.t -> M1.t = -# - : M3.t -> M.t = -# Characters 44-46: - module M4 : sig type t = private M3.t end = M2;; (* fails *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M2.t end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = M2.t - is not included in - type t = private M3.t -# Characters 44-45: - module M4 : sig type t = private M3.t end = M;; (* fails *) - ^ -Error: Signature mismatch: - Modules do not match: - sig type t = < m : int > end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = < m : int > - is not included in - type t = private M3.t -# Characters 44-46: - module M4 : sig type t = private M3.t end = M1;; (* might be ok *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M1.t end - is not included in - sig type t = private M3.t end - Type declarations do not match: - type t = M1.t - is not included in - type t = private M3.t -# module M5 : sig type t = private M1.t end -# Characters 53-55: - module M6 : sig type t = private < n:int; .. > end = M1;; (* fails *) - ^^ -Error: Signature mismatch: - Modules do not match: - sig type t = M1.t end - is not included in - sig type t = private < n : int; .. > end - Type declarations do not match: - type t = M1.t - is not included in - type t = private < n : int; .. > -# Characters 69-118: - struct type t = int let f (x : int) = (x : t) end;; (* must fail *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Signature mismatch: - Modules do not match: - sig type t = int val f : int -> t end - is not included in - sig type t = private Foobar.t val f : int -> t end - Type declarations do not match: - type t = int - is not included in - type t = private Foobar.t -# module M : sig type t = private T of int val mk : int -> t end -# module M1 : sig type t = M.t val mk : int -> t end -# module M2 : sig type t = M.t val mk : int -> t end -# module M3 : sig type t = M.t val mk : int -> t end -# Characters 21-44: - type t = M.t = T of int - ^^^^^^^^^^^^^^^^^^^^^^^ -Error: This variant or record definition does not match that of type M.t - A private type would be revealed. -# module M5 : sig type t = M.t = private T of int val mk : int -> t end -# module M6 : sig type t = private T of int val mk : int -> t end -# module M' : - sig type t_priv = private T of int type t = t_priv val mk : int -> t end -# module M3' : sig type t = M'.t val mk : int -> t end -# module M : sig type 'a t = private T of 'a end -# module M1 : sig type 'a t = 'a M.t = private T of 'a end -# module Test : sig type t = private A end -module Test2 : sig type t = Test.t = private A end -# val f : Test.t -> Test2.t = -# val f : Test2.t -> unit = -# Characters 8-15: - let a = Test2.A;; (* fail *) - ^^^^^^^ -Error: Cannot create values of the private type Test2.t -# * Characters 148-171: - module Test2 : module type of Test with type t = private Test.t = Test;; - ^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: spurious use of private -module Test2 : sig type t = Test.t = private A end -# type t = private < x : int; .. > -# type t = private < x : int; .. > -# type t = private < x : int > -# type t = private < x : int > -# Characters -1--1: - type 'a t = private < x : int; .. > as 'a;; - -Error: Type declarations do not match: - type 'a t = private < x : int; .. > constraint 'a = 'a t - is not included in - type 'a t - Their constraints differ. -# type 'a t = private 'a constraint 'a = < x : int; .. > -# type t = [ `Closed ] -# type nonrec t = private [> t ] -# diff --git a/testsuite/tests/typing-recmod/Makefile b/testsuite/tests/typing-recmod/Makefile deleted file mode 100644 index 69e2ee7b..00000000 --- a/testsuite/tests/typing-recmod/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.okbad -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-recmod/ocamltests b/testsuite/tests/typing-recmod/ocamltests new file mode 100644 index 00000000..5429e9d1 --- /dev/null +++ b/testsuite/tests/typing-recmod/ocamltests @@ -0,0 +1,22 @@ +t01bad.ml +t02bad.ml +t03ok.ml +t04bad.ml +t05bad.ml +t06ok.ml +t07bad.ml +t08bad.ml +t09bad.ml +t10ok.ml +t11bad.ml +t12bad.ml +t13ok.ml +t14bad.ml +t15bad.ml +t16ok.ml +t17ok.ml +t18ok.ml +t19ok.ml +t20ok.ml +t21ok.ml +t22ok.ml diff --git a/testsuite/tests/typing-recmod/t01bad.compilers.reference b/testsuite/tests/typing-recmod/t01bad.compilers.reference new file mode 100644 index 00000000..d40baa5c --- /dev/null +++ b/testsuite/tests/typing-recmod/t01bad.compilers.reference @@ -0,0 +1,2 @@ +File "t01bad.ml", line 10, characters 15-35: +Error: The type abbreviation A.t is cyclic diff --git a/testsuite/tests/typing-recmod/t01bad.ml b/testsuite/tests/typing-recmod/t01bad.ml index 8a471e07..f0ae828a 100644 --- a/testsuite/tests/typing-recmod/t01bad.ml +++ b/testsuite/tests/typing-recmod/t01bad.ml @@ -1,2 +1,10 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (t = t) *) module rec A : sig type t = A.t end = struct type t = A.t end;; diff --git a/testsuite/tests/typing-recmod/t02bad.compilers.reference b/testsuite/tests/typing-recmod/t02bad.compilers.reference new file mode 100644 index 00000000..bc5f0d57 --- /dev/null +++ b/testsuite/tests/typing-recmod/t02bad.compilers.reference @@ -0,0 +1,3 @@ +File "t02bad.ml", line 10, characters 15-35: +Error: The definition of A.t contains a cycle: + B.t diff --git a/testsuite/tests/typing-recmod/t02bad.ml b/testsuite/tests/typing-recmod/t02bad.ml index b4301a41..9a490d89 100644 --- a/testsuite/tests/typing-recmod/t02bad.ml +++ b/testsuite/tests/typing-recmod/t02bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (t = t) *) module rec A : sig type t = B.t end = struct type t = B.t end and B : sig type t = A.t end = struct type t = A.t end;; diff --git a/testsuite/tests/typing-recmod/t03ok.ml b/testsuite/tests/typing-recmod/t03ok.ml index 577ea20a..948d9bf8 100644 --- a/testsuite/tests/typing-recmod/t03ok.ml +++ b/testsuite/tests/typing-recmod/t03ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* OK (t = int) *) module rec A : sig type t = B.t end = struct type t = B.t end and B : sig type t = int end = struct type t = int end;; diff --git a/testsuite/tests/typing-recmod/t04bad.compilers.reference b/testsuite/tests/typing-recmod/t04bad.compilers.reference new file mode 100644 index 00000000..e8924181 --- /dev/null +++ b/testsuite/tests/typing-recmod/t04bad.compilers.reference @@ -0,0 +1,3 @@ +File "t04bad.ml", line 10, characters 15-41: +Error: The definition of A.t contains a cycle: + int * A.t diff --git a/testsuite/tests/typing-recmod/t04bad.ml b/testsuite/tests/typing-recmod/t04bad.ml index ad3f985a..3de1bb10 100644 --- a/testsuite/tests/typing-recmod/t04bad.ml +++ b/testsuite/tests/typing-recmod/t04bad.ml @@ -1,2 +1,10 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (t = int * t) *) module rec A : sig type t = int * A.t end = struct type t = int * A.t end;; diff --git a/testsuite/tests/typing-recmod/t05bad.compilers.reference b/testsuite/tests/typing-recmod/t05bad.compilers.reference new file mode 100644 index 00000000..7bbe96d3 --- /dev/null +++ b/testsuite/tests/typing-recmod/t05bad.compilers.reference @@ -0,0 +1,3 @@ +File "t05bad.ml", line 10, characters 15-42: +Error: The definition of A.t contains a cycle: + B.t -> int diff --git a/testsuite/tests/typing-recmod/t05bad.ml b/testsuite/tests/typing-recmod/t05bad.ml index 08fe60f0..c413cec2 100644 --- a/testsuite/tests/typing-recmod/t05bad.ml +++ b/testsuite/tests/typing-recmod/t05bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (t = t -> int) *) module rec A : sig type t = B.t -> int end = struct type t = B.t -> int end and B : sig type t = A.t end = struct type t = A.t end;; diff --git a/testsuite/tests/typing-recmod/t06ok.ml b/testsuite/tests/typing-recmod/t06ok.ml index a220a8e0..4305f243 100644 --- a/testsuite/tests/typing-recmod/t06ok.ml +++ b/testsuite/tests/typing-recmod/t06ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* OK (t = ) *) module rec A : sig type t = end = struct type t = end and B : sig type t = A.t end = struct type t = A.t end;; diff --git a/testsuite/tests/typing-recmod/t07bad.compilers.reference b/testsuite/tests/typing-recmod/t07bad.compilers.reference new file mode 100644 index 00000000..78b4bcf2 --- /dev/null +++ b/testsuite/tests/typing-recmod/t07bad.compilers.reference @@ -0,0 +1,2 @@ +File "t07bad.ml", line 10, characters 15-51: +Error: In the definition of A.t, type 'a list A.t should be 'a A.t diff --git a/testsuite/tests/typing-recmod/t07bad.ml b/testsuite/tests/typing-recmod/t07bad.ml index ec24ea4d..1aa75ab7 100644 --- a/testsuite/tests/typing-recmod/t07bad.ml +++ b/testsuite/tests/typing-recmod/t07bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (not regular) *) module rec A : sig type 'a t = end = struct type 'a t = end;; diff --git a/testsuite/tests/typing-recmod/t08bad.compilers.reference b/testsuite/tests/typing-recmod/t08bad.compilers.reference new file mode 100644 index 00000000..14ab2141 --- /dev/null +++ b/testsuite/tests/typing-recmod/t08bad.compilers.reference @@ -0,0 +1,2 @@ +File "t08bad.ml", line 10, characters 15-68: +Error: In the definition of B.t, type 'a array A.t should be 'a A.t diff --git a/testsuite/tests/typing-recmod/t08bad.ml b/testsuite/tests/typing-recmod/t08bad.ml index 5ebafd11..0647311b 100644 --- a/testsuite/tests/typing-recmod/t08bad.ml +++ b/testsuite/tests/typing-recmod/t08bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (not regular) *) module rec A : sig type 'a t = end = struct type 'a t = end diff --git a/testsuite/tests/typing-recmod/t09bad.compilers.reference b/testsuite/tests/typing-recmod/t09bad.compilers.reference new file mode 100644 index 00000000..28b6547f --- /dev/null +++ b/testsuite/tests/typing-recmod/t09bad.compilers.reference @@ -0,0 +1,2 @@ +File "t09bad.ml", line 10, characters 15-41: +Error: In the definition of B.t, type 'a array A.t should be 'a A.t diff --git a/testsuite/tests/typing-recmod/t09bad.ml b/testsuite/tests/typing-recmod/t09bad.ml index ade5bcb7..ce281c5f 100644 --- a/testsuite/tests/typing-recmod/t09bad.ml +++ b/testsuite/tests/typing-recmod/t09bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (not regular) *) module rec A : sig type 'a t = 'a B.t end = struct type 'a t = 'a B.t end diff --git a/testsuite/tests/typing-recmod/t10ok.ml b/testsuite/tests/typing-recmod/t10ok.ml index 3094a42a..e91fe998 100644 --- a/testsuite/tests/typing-recmod/t10ok.ml +++ b/testsuite/tests/typing-recmod/t10ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* OK *) module rec A : sig type 'a t = 'a array B.t * 'a list B.t end = struct type 'a t = 'a array B.t * 'a list B.t end diff --git a/testsuite/tests/typing-recmod/t11bad.compilers.reference b/testsuite/tests/typing-recmod/t11bad.compilers.reference new file mode 100644 index 00000000..a5371e89 --- /dev/null +++ b/testsuite/tests/typing-recmod/t11bad.compilers.reference @@ -0,0 +1,2 @@ +File "t11bad.ml", line 12, characters 15-52: +Error: In the definition of B.t, type 'a array B.t should be 'a B.t diff --git a/testsuite/tests/typing-recmod/t11bad.ml b/testsuite/tests/typing-recmod/t11bad.ml index e18339ac..1c8fbee2 100644 --- a/testsuite/tests/typing-recmod/t11bad.ml +++ b/testsuite/tests/typing-recmod/t11bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (not regular) *) module rec A : sig type 'a t = 'a list B.t end = struct type 'a t = 'a list B.t end diff --git a/testsuite/tests/typing-recmod/t12bad.compilers.reference b/testsuite/tests/typing-recmod/t12bad.compilers.reference new file mode 100644 index 00000000..d7705c7d --- /dev/null +++ b/testsuite/tests/typing-recmod/t12bad.compilers.reference @@ -0,0 +1,2 @@ +File "t12bad.ml", line 11, characters 4-101: +Error: In the definition of M.c, type 'b M.c should be 'a M.c diff --git a/testsuite/tests/typing-recmod/t12bad.ml b/testsuite/tests/typing-recmod/t12bad.ml index 71100e6e..a0094bed 100644 --- a/testsuite/tests/typing-recmod/t12bad.ml +++ b/testsuite/tests/typing-recmod/t12bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad (not regular) *) module rec M : sig diff --git a/testsuite/tests/typing-recmod/t13ok.ml b/testsuite/tests/typing-recmod/t13ok.ml index 4fea6e1f..5ba8026e 100644 --- a/testsuite/tests/typing-recmod/t13ok.ml +++ b/testsuite/tests/typing-recmod/t13ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* OK *) class type [ 'node ] extension = object method node : 'node end class type [ 'ext ] node = object constraint 'ext = 'ext node #extension end diff --git a/testsuite/tests/typing-recmod/t14bad.compilers.reference b/testsuite/tests/typing-recmod/t14bad.compilers.reference new file mode 100644 index 00000000..6f3ce696 --- /dev/null +++ b/testsuite/tests/typing-recmod/t14bad.compilers.reference @@ -0,0 +1,3 @@ +File "t14bad.ml", line 23, characters 17-37: +Error: The definition of U.D.t contains a cycle: + U'.t diff --git a/testsuite/tests/typing-recmod/t14bad.ml b/testsuite/tests/typing-recmod/t14bad.ml index 1b92a28c..cd98ef3f 100644 --- a/testsuite/tests/typing-recmod/t14bad.ml +++ b/testsuite/tests/typing-recmod/t14bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad - PR 4261 *) module PR_4261 = struct diff --git a/testsuite/tests/typing-recmod/t15bad.compilers.reference b/testsuite/tests/typing-recmod/t15bad.compilers.reference new file mode 100644 index 00000000..009248cb --- /dev/null +++ b/testsuite/tests/typing-recmod/t15bad.compilers.reference @@ -0,0 +1,2 @@ +File "t15bad.ml", line 11, characters 15-35: +Error: The type abbreviation M.t is cyclic diff --git a/testsuite/tests/typing-recmod/t15bad.ml b/testsuite/tests/typing-recmod/t15bad.ml index b387ae53..71aa31c1 100644 --- a/testsuite/tests/typing-recmod/t15bad.ml +++ b/testsuite/tests/typing-recmod/t15bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Bad - PR 4512 *) module type S' = sig type t = int end module rec M : S' with type t = M.t = struct type t = M.t end;; diff --git a/testsuite/tests/typing-recmod/t16ok.ml b/testsuite/tests/typing-recmod/t16ok.ml index 583b69bb..abd6d6a4 100644 --- a/testsuite/tests/typing-recmod/t16ok.ml +++ b/testsuite/tests/typing-recmod/t16ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR#4450 *) module PR_4450_1 = struct diff --git a/testsuite/tests/typing-recmod/t17ok.ml b/testsuite/tests/typing-recmod/t17ok.ml index 4521b66c..b59e80e2 100644 --- a/testsuite/tests/typing-recmod/t17ok.ml +++ b/testsuite/tests/typing-recmod/t17ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* A synthetic example of bootstrapped data structure (suggested by J-C Filliatre) *) diff --git a/testsuite/tests/typing-recmod/t18ok.ml b/testsuite/tests/typing-recmod/t18ok.ml index 64fcf6ab..3523f338 100644 --- a/testsuite/tests/typing-recmod/t18ok.ml +++ b/testsuite/tests/typing-recmod/t18ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR 4470: simplified from OMake's sources *) module rec DirElt diff --git a/testsuite/tests/typing-recmod/t19ok.ml b/testsuite/tests/typing-recmod/t19ok.ml index e51fa5c9..91666d73 100644 --- a/testsuite/tests/typing-recmod/t19ok.ml +++ b/testsuite/tests/typing-recmod/t19ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR 4758, PR 4266 *) module PR_4758 = struct diff --git a/testsuite/tests/typing-recmod/t20ok.ml b/testsuite/tests/typing-recmod/t20ok.ml index fec78c1d..98222594 100644 --- a/testsuite/tests/typing-recmod/t20ok.ml +++ b/testsuite/tests/typing-recmod/t20ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* PR 4557 *) module PR_4557 = struct module F ( X : Set.OrderedType ) = struct diff --git a/testsuite/tests/typing-recmod/t21ok.ml b/testsuite/tests/typing-recmod/t21ok.ml index 0415fe48..59cdcc9f 100644 --- a/testsuite/tests/typing-recmod/t21ok.ml +++ b/testsuite/tests/typing-recmod/t21ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module F ( X : Set.OrderedType ) = struct module rec Mod : sig module XSet : diff --git a/testsuite/tests/typing-recmod/t22ok.ml b/testsuite/tests/typing-recmod/t22ok.ml index de96eced..bfc119f4 100644 --- a/testsuite/tests/typing-recmod/t22ok.ml +++ b/testsuite/tests/typing-recmod/t22ok.ml @@ -1,3 +1,10 @@ +(* TEST +flags = " -w a " +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + (* Tests for recursive modules *) let test number result expected = diff --git a/testsuite/tests/typing-recordarg/Makefile b/testsuite/tests/typing-recordarg/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-recordarg/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-recordarg/ocamltests b/testsuite/tests/typing-recordarg/ocamltests new file mode 100644 index 00000000..793492cf --- /dev/null +++ b/testsuite/tests/typing-recordarg/ocamltests @@ -0,0 +1 @@ +recordarg.ml diff --git a/testsuite/tests/typing-recordarg/recordarg.ml b/testsuite/tests/typing-recordarg/recordarg.ml index ebd8d056..5477de1e 100644 --- a/testsuite/tests/typing-recordarg/recordarg.ml +++ b/testsuite/tests/typing-recordarg/recordarg.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + type t = A of {x:int; mutable y:int};; let f (A r) = r;; (* -> escape *) let f (A r) = r.x;; (* ok *) diff --git a/testsuite/tests/typing-recordarg/recordarg.ml.reference b/testsuite/tests/typing-recordarg/recordarg.ml.reference deleted file mode 100644 index 5a671d65..00000000 --- a/testsuite/tests/typing-recordarg/recordarg.ml.reference +++ /dev/null @@ -1,67 +0,0 @@ - -# type t = A of { x : int; mutable y : int; } -# Characters 14-15: - let f (A r) = r;; (* -> escape *) - ^ -Error: This form is not allowed as the type of the inlined record could escape. -# val f : t -> int = -# val f : int -> t = -# val f : t -> t = -# Characters 14-15: - let f () = A {a = 1};; (* customized error message *) - ^ -Error: The field a is not part of the record argument for the t.A constructor -# val f : unit -> t = -# type _ t = A : { x : 'a; y : 'b; } -> 'a t -# val f : 'a t -> 'a t = -# val f : 'a t -> 'a t = -# module M : - sig - type 'a t = A of { x : 'a; } | B : { u : 'b; } -> unit t - exception Foo of { x : int; } - end -# module N : - sig - type 'b t = 'b M.t = A of { x : 'b; } | B : { u : 'bla; } -> unit t - exception Foo of { x : int; } - end -# module type S = sig exception A of { x : int; } end -# Characters 65-74: - module A = (val X.x) - ^^^^^^^^^ -Error: This expression creates fresh types. - It is not allowed inside applicative functors. -# Characters 61-62: - exception A of {x : string} - ^ -Error: Multiple definition of the extension constructor name A. - Names must be unique in a given structure or signature. -# Characters 58-59: - exception A of {x : string} - ^ -Error: Multiple definition of the extension constructor name A. - Names must be unique in a given structure or signature. -# module M1 : sig exception A of { x : int; } end -# Characters 34-44: - include M1 - ^^^^^^^^^^ -Error: Multiple definition of the extension constructor name A. - Names must be unique in a given structure or signature. -# module type S1 = sig exception A of { x : int; } end -# Characters 36-46: - include S1 - ^^^^^^^^^^ -Error: Multiple definition of the extension constructor name A. - Names must be unique in a given structure or signature. -# module M : sig exception A of { x : int; } end -# module X1 : sig type t = .. end -# module X2 : sig type t = .. end -# Characters 62-63: - type X2.t += A of {x: int} - ^ -Error: Multiple definition of the extension constructor name A. - Names must be unique in a given structure or signature. -# type _ c = C : [ `A ] c -type t = T : { x : [< `A ] c; } -> t -# val f : t -> unit = -# diff --git a/testsuite/tests/typing-recordarg/recordarg.ocaml.reference b/testsuite/tests/typing-recordarg/recordarg.ocaml.reference new file mode 100644 index 00000000..75537f00 --- /dev/null +++ b/testsuite/tests/typing-recordarg/recordarg.ocaml.reference @@ -0,0 +1,66 @@ +type t = A of { x : int; mutable y : int; } +Characters 14-15: + let f (A r) = r;; (* -> escape *) + ^ +Error: This form is not allowed as the type of the inlined record could escape. +val f : t -> int = +val f : int -> t = +val f : t -> t = +Characters 14-15: + let f () = A {a = 1};; (* customized error message *) + ^ +Error: The field a is not part of the record argument for the t.A constructor +val f : unit -> t = +type _ t = A : { x : 'a; y : 'b; } -> 'a t +val f : 'a t -> 'a t = +val f : 'a t -> 'a t = +module M : + sig + type 'a t = A of { x : 'a; } | B : { u : 'b; } -> unit t + exception Foo of { x : int; } + end +module N : + sig + type 'b t = 'b M.t = A of { x : 'b; } | B : { u : 'bla; } -> unit t + exception Foo of { x : int; } + end +module type S = sig exception A of { x : int; } end +Characters 65-74: + module A = (val X.x) + ^^^^^^^^^ +Error: This expression creates fresh types. + It is not allowed inside applicative functors. +Characters 61-62: + exception A of {x : string} + ^ +Error: Multiple definition of the extension constructor name A. + Names must be unique in a given structure or signature. +Characters 58-59: + exception A of {x : string} + ^ +Error: Multiple definition of the extension constructor name A. + Names must be unique in a given structure or signature. +module M1 : sig exception A of { x : int; } end +Characters 34-44: + include M1 + ^^^^^^^^^^ +Error: Multiple definition of the extension constructor name A. + Names must be unique in a given structure or signature. +module type S1 = sig exception A of { x : int; } end +Characters 36-46: + include S1 + ^^^^^^^^^^ +Error: Multiple definition of the extension constructor name A. + Names must be unique in a given structure or signature. +module M : sig exception A of { x : int; } end +module X1 : sig type t = .. end +module X2 : sig type t = .. end +Characters 62-63: + type X2.t += A of {x: int} + ^ +Error: Multiple definition of the extension constructor name A. + Names must be unique in a given structure or signature. +type _ c = C : [ `A ] c +type t = T : { x : [< `A ] c; } -> t +val f : t -> unit = + diff --git a/testsuite/tests/typing-rectypes-bugs/Makefile b/testsuite/tests/typing-rectypes-bugs/Makefile deleted file mode 100644 index 5d8e8dbd..00000000 --- a/testsuite/tests/typing-rectypes-bugs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -include ../../makefiles/Makefile.okbad -include ../../makefiles/Makefile.common -COMPFLAGS = -rectypes diff --git a/testsuite/tests/typing-rectypes-bugs/ocamltests b/testsuite/tests/typing-rectypes-bugs/ocamltests new file mode 100644 index 00000000..3ad748d0 --- /dev/null +++ b/testsuite/tests/typing-rectypes-bugs/ocamltests @@ -0,0 +1,3 @@ +pr5343_bad.ml +pr6174_bad.ml +pr6870_bad.ml diff --git a/testsuite/tests/typing-rectypes-bugs/pr5343_bad.compilers.reference b/testsuite/tests/typing-rectypes-bugs/pr5343_bad.compilers.reference new file mode 100644 index 00000000..71a12595 --- /dev/null +++ b/testsuite/tests/typing-rectypes-bugs/pr5343_bad.compilers.reference @@ -0,0 +1,2 @@ +File "pr5343_bad.ml", line 11, characters 2-14: +Error: The type abbreviation u is cyclic diff --git a/testsuite/tests/typing-rectypes-bugs/pr5343_bad.ml b/testsuite/tests/typing-rectypes-bugs/pr5343_bad.ml index 0484c677..588c9479 100644 --- a/testsuite/tests/typing-rectypes-bugs/pr5343_bad.ml +++ b/testsuite/tests/typing-rectypes-bugs/pr5343_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a -rectypes " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module M : sig type 'a t type u = u t and v = v t diff --git a/testsuite/tests/typing-rectypes-bugs/pr6174_bad.compilers.reference b/testsuite/tests/typing-rectypes-bugs/pr6174_bad.compilers.reference new file mode 100644 index 00000000..56d8c42f --- /dev/null +++ b/testsuite/tests/typing-rectypes-bugs/pr6174_bad.compilers.reference @@ -0,0 +1,3 @@ +File "pr6174_bad.ml", line 11, characters 24-25: +Error: This expression has type $0 but an expression was expected of type + $1 = ($2 -> $1) -> $1 diff --git a/testsuite/tests/typing-rectypes-bugs/pr6174_bad.ml b/testsuite/tests/typing-rectypes-bugs/pr6174_bad.ml index 84f79ba0..1c95a47d 100644 --- a/testsuite/tests/typing-rectypes-bugs/pr6174_bad.ml +++ b/testsuite/tests/typing-rectypes-bugs/pr6174_bad.ml @@ -1,3 +1,11 @@ +(* TEST +flags = " -w a -rectypes " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + type _ t = C : ((('a -> 'o) -> 'o) -> ('b -> 'o) -> 'o) t let f : type a o. ((a -> o) -> o) t -> (a -> o) -> o = fun C k -> k (fun x -> x);; diff --git a/testsuite/tests/typing-rectypes-bugs/pr6870_bad.compilers.reference b/testsuite/tests/typing-rectypes-bugs/pr6870_bad.compilers.reference new file mode 100644 index 00000000..c3e1ff63 --- /dev/null +++ b/testsuite/tests/typing-rectypes-bugs/pr6870_bad.compilers.reference @@ -0,0 +1,4 @@ +File "pr6870_bad.ml", line 10, characters 38-50: +Error: This alias is bound to type 'a T.t but is used as an instance of type + 'a + The type variable 'a occurs inside 'a T.t diff --git a/testsuite/tests/typing-rectypes-bugs/pr6870_bad.ml b/testsuite/tests/typing-rectypes-bugs/pr6870_bad.ml index ed834605..4c771b87 100644 --- a/testsuite/tests/typing-rectypes-bugs/pr6870_bad.ml +++ b/testsuite/tests/typing-rectypes-bugs/pr6870_bad.ml @@ -1,2 +1,10 @@ +(* TEST +flags = " -w a -rectypes " +ocamlc_byte_exit_status = "2" +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output +*) + module type T = sig type 'a t end module Fix (T : T) = struct type r = ('r T.t as 'r) end diff --git a/testsuite/tests/typing-safe-linking/Makefile b/testsuite/tests/typing-safe-linking/Makefile deleted file mode 100644 index 9ecd47c2..00000000 --- a/testsuite/tests/typing-safe-linking/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Check safety of linking - -SOURCES = a.ml b_bad.ml -OBJECTS = $(SOURCES:%.ml=%.cmo) - -all: a.cmo - @printf " ... testing 'b_bad.ml'" - @$(OCAMLC) $(ADD_COMPFLAGS) -c -safe-string -warn-error +8 b_bad.ml 2> /dev/null \ - && echo " => failed" || echo " => passed" - -clean: - @rm -f *.cmo *.cmi - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-safe-linking/b_bad.compilers.reference b/testsuite/tests/typing-safe-linking/b_bad.compilers.reference new file mode 100644 index 00000000..818f3a0a --- /dev/null +++ b/testsuite/tests/typing-safe-linking/b_bad.compilers.reference @@ -0,0 +1,6 @@ +File "b_bad.ml", line 13, characters 29-66: +Error (warning 8): this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Y +File "b_bad.ml", line 17, characters 11-14: +Error: Unbound value A.y diff --git a/testsuite/tests/typing-safe-linking/b_bad.ml b/testsuite/tests/typing-safe-linking/b_bad.ml index 6615070a..2fc7d558 100644 --- a/testsuite/tests/typing-safe-linking/b_bad.ml +++ b/testsuite/tests/typing-safe-linking/b_bad.ml @@ -1,3 +1,15 @@ +(* TEST +files = "a.ml" +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "a.ml" +*** ocamlc.byte +module = "b_bad.ml" +flags = "-safe-string -warn-error +8" +ocamlc_byte_exit_status = "2" +**** check-ocamlc.byte-output +*) + let f : string A.t -> unit = function A.X s -> print_endline s diff --git a/testsuite/tests/typing-safe-linking/ocamltests b/testsuite/tests/typing-safe-linking/ocamltests new file mode 100644 index 00000000..da0c8356 --- /dev/null +++ b/testsuite/tests/typing-safe-linking/ocamltests @@ -0,0 +1 @@ +b_bad.ml diff --git a/testsuite/tests/typing-shadowing-of-pervasives-submodules/largeFile.ml b/testsuite/tests/typing-shadowing-of-pervasives-submodules/largeFile.ml new file mode 100644 index 00000000..e9066706 --- /dev/null +++ b/testsuite/tests/typing-shadowing-of-pervasives-submodules/largeFile.ml @@ -0,0 +1 @@ +let message = "Hello, world!" diff --git a/testsuite/tests/typing-shadowing-of-pervasives-submodules/ocamltests b/testsuite/tests/typing-shadowing-of-pervasives-submodules/ocamltests new file mode 100644 index 00000000..2ac9cbae --- /dev/null +++ b/testsuite/tests/typing-shadowing-of-pervasives-submodules/ocamltests @@ -0,0 +1 @@ +redefine_largefile.ml diff --git a/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.ml b/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.ml new file mode 100644 index 00000000..5d4ac627 --- /dev/null +++ b/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.ml @@ -0,0 +1,4 @@ +(* TEST + modules = "largeFile.ml" +*) +print_string LargeFile.message diff --git a/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.reference b/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.reference new file mode 100644 index 00000000..af5626b4 --- /dev/null +++ b/testsuite/tests/typing-shadowing-of-pervasives-submodules/redefine_largefile.reference @@ -0,0 +1 @@ +Hello, world! diff --git a/testsuite/tests/typing-short-paths/Makefile b/testsuite/tests/typing-short-paths/Makefile deleted file mode 100644 index 10856782..00000000 --- a/testsuite/tests/typing-short-paths/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common -TOPFLAGS = -short-paths - -default: gpr1223_foo.cmi gpr1223_bar.cmi - -gpr1223_bar.cmi: gpr1223_foo.cmi diff --git a/testsuite/tests/typing-short-paths/gpr1223.compilers.reference b/testsuite/tests/typing-short-paths/gpr1223.compilers.reference new file mode 100644 index 00000000..bd28b952 --- /dev/null +++ b/testsuite/tests/typing-short-paths/gpr1223.compilers.reference @@ -0,0 +1,3 @@ +val y : Gpr1223_bar.N.O.t = Gpr1223_bar.N.O.T +val x : Gpr1223_bar.M.t = Gpr1223_bar.M.T + diff --git a/testsuite/tests/typing-short-paths/gpr1223.ml b/testsuite/tests/typing-short-paths/gpr1223.ml index 0c481dbb..a8ac8b57 100644 --- a/testsuite/tests/typing-short-paths/gpr1223.ml +++ b/testsuite/tests/typing-short-paths/gpr1223.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -short-paths " + modules = "gpr1223_foo.mli gpr1223_bar.mli" + * toplevel +*) let y = Gpr1223_bar.N.O.T;; diff --git a/testsuite/tests/typing-short-paths/gpr1223.ml.reference b/testsuite/tests/typing-short-paths/gpr1223.ml.reference deleted file mode 100644 index cf578cdb..00000000 --- a/testsuite/tests/typing-short-paths/gpr1223.ml.reference +++ /dev/null @@ -1,4 +0,0 @@ - -# val y : Gpr1223_bar.N.O.t = Gpr1223_bar.N.O.T -# val x : Gpr1223_bar.M.t = Gpr1223_bar.M.T -# diff --git a/testsuite/tests/typing-short-paths/ocamltests b/testsuite/tests/typing-short-paths/ocamltests new file mode 100644 index 00000000..227e7697 --- /dev/null +++ b/testsuite/tests/typing-short-paths/ocamltests @@ -0,0 +1,5 @@ +gpr1223.ml +pr5918.ml +pr6836.ml +pr7543.ml +short-paths.ml diff --git a/testsuite/tests/typing-short-paths/pr5918.compilers.reference b/testsuite/tests/typing-short-paths/pr5918.compilers.reference new file mode 100644 index 00000000..2ca36b02 --- /dev/null +++ b/testsuite/tests/typing-short-paths/pr5918.compilers.reference @@ -0,0 +1,5 @@ +Characters 136-146: + let _ = { a = () } + ^^^^^^^^^^ +Error: Some record fields are undefined: b + diff --git a/testsuite/tests/typing-short-paths/pr5918.ml b/testsuite/tests/typing-short-paths/pr5918.ml index 604f66d8..191ee1fd 100644 --- a/testsuite/tests/typing-short-paths/pr5918.ml +++ b/testsuite/tests/typing-short-paths/pr5918.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -short-paths " + * toplevel +*) + module rec A : sig type t end = struct diff --git a/testsuite/tests/typing-short-paths/pr5918.ml.reference b/testsuite/tests/typing-short-paths/pr5918.ml.reference deleted file mode 100644 index 3364e16d..00000000 --- a/testsuite/tests/typing-short-paths/pr5918.ml.reference +++ /dev/null @@ -1,6 +0,0 @@ - -# Characters 82-92: - let _ = { a = () } - ^^^^^^^^^^ -Error: Some record fields are undefined: b -# diff --git a/testsuite/tests/typing-short-paths/pr6836.compilers.reference b/testsuite/tests/typing-short-paths/pr6836.compilers.reference new file mode 100644 index 00000000..54fccac1 --- /dev/null +++ b/testsuite/tests/typing-short-paths/pr6836.compilers.reference @@ -0,0 +1,6 @@ +type t = [ `A | `B ] +type 'a u = t +val a : [< t > `A ] = `A +type 'a s = 'a +val b : [< t > `B ] = `B + diff --git a/testsuite/tests/typing-short-paths/pr6836.ml b/testsuite/tests/typing-short-paths/pr6836.ml index 121bc463..ade6635b 100644 --- a/testsuite/tests/typing-short-paths/pr6836.ml +++ b/testsuite/tests/typing-short-paths/pr6836.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -short-paths " + * toplevel +*) + type t = [`A | `B];; type 'a u = t;; let a : [< int u] = `A;; diff --git a/testsuite/tests/typing-short-paths/pr6836.ml.reference b/testsuite/tests/typing-short-paths/pr6836.ml.reference deleted file mode 100644 index cc77356e..00000000 --- a/testsuite/tests/typing-short-paths/pr6836.ml.reference +++ /dev/null @@ -1,7 +0,0 @@ - -# type t = [ `A | `B ] -# type 'a u = t -# val a : [< t > `A ] = `A -# type 'a s = 'a -# val b : [< t > `B ] = `B -# diff --git a/testsuite/tests/typing-short-paths/pr7543.compilers.reference b/testsuite/tests/typing-short-paths/pr7543.compilers.reference new file mode 100644 index 00000000..6b52e2ac --- /dev/null +++ b/testsuite/tests/typing-short-paths/pr7543.compilers.reference @@ -0,0 +1,17 @@ +module type S = sig type t end +module N : sig type 'a t = 'a end +val f : (module S with type t = unit) -> unit = +Characters 19-20: + let () = f (module N);; + ^ +Error: Signature mismatch: + Modules do not match: + sig type 'a t = 'a end + is not included in + sig type t = N.t end + Type declarations do not match: + type 'a t = 'a + is not included in + type t = N.t + They have different arities. + diff --git a/testsuite/tests/typing-short-paths/pr7543.ml b/testsuite/tests/typing-short-paths/pr7543.ml index 9c890614..abe5d530 100644 --- a/testsuite/tests/typing-short-paths/pr7543.ml +++ b/testsuite/tests/typing-short-paths/pr7543.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -short-paths " + * toplevel +*) + (** Test that short-path printtyp does not fail on packed module. Packed modules does not respect the arity of type constructor, which can break diff --git a/testsuite/tests/typing-short-paths/pr7543.ml.reference b/testsuite/tests/typing-short-paths/pr7543.ml.reference deleted file mode 100644 index 74fe45c2..00000000 --- a/testsuite/tests/typing-short-paths/pr7543.ml.reference +++ /dev/null @@ -1,18 +0,0 @@ - -# * * * * module type S = sig type t end -# module N : sig type 'a t = 'a end -# val f : (module S with type t = unit) -> unit = -# Characters 19-20: - let () = f (module N);; - ^ -Error: Signature mismatch: - Modules do not match: - sig type 'a t = 'a end - is not included in - sig type t = N.t end - Type declarations do not match: - type 'a t = 'a - is not included in - type t = N.t - They have different arities. -# diff --git a/testsuite/tests/typing-short-paths/short-paths.compilers.reference b/testsuite/tests/typing-short-paths/short-paths.compilers.reference new file mode 100644 index 00000000..7b505609 --- /dev/null +++ b/testsuite/tests/typing-short-paths/short-paths.compilers.reference @@ -0,0 +1,99 @@ +module Core : + sig + module Int : + sig + module T : + sig + type t = int + val compare : 'a -> 'a -> t + val ( + ) : t -> t -> t + end + type t = int + val compare : 'a -> 'a -> t + val ( + ) : t -> t -> t + module Map : + sig + type key = t + type 'a t = 'a Map.Make(T).t + val empty : 'a t + val is_empty : 'a t -> bool + val mem : key -> 'a t -> bool + val add : key -> 'a -> 'a t -> 'a t + val update : key -> ('a option -> 'a option) -> 'a t -> 'a t + val singleton : key -> 'a -> 'a t + val remove : key -> 'a t -> 'a t + val merge : + (key -> 'a option -> 'b option -> 'c option) -> + 'a t -> 'b t -> 'c t + val union : + (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + val compare : ('a -> 'a -> key) -> 'a t -> 'a t -> key + val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val iter : (key -> 'a -> unit) -> 'a t -> unit + val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b + val for_all : (key -> 'a -> bool) -> 'a t -> bool + val exists : (key -> 'a -> bool) -> 'a t -> bool + val filter : (key -> 'a -> bool) -> 'a t -> 'a t + val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t + val cardinal : 'a t -> key + val bindings : 'a t -> (key * 'a) list + val min_binding : 'a t -> key * 'a + val min_binding_opt : 'a t -> (key * 'a) option + val max_binding : 'a t -> key * 'a + val max_binding_opt : 'a t -> (key * 'a) option + val choose : 'a t -> key * 'a + val choose_opt : 'a t -> (key * 'a) option + val split : key -> 'a t -> 'a t * 'a option * 'a t + val find : key -> 'a t -> 'a + val find_opt : key -> 'a t -> 'a option + val find_first : (key -> bool) -> 'a t -> key * 'a + val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option + val find_last : (key -> bool) -> 'a t -> key * 'a + val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option + val map : ('a -> 'b) -> 'a t -> 'b t + val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t + val to_seq : 'a t -> (key * 'a) Seq.t + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + val of_seq : (key * 'a) Seq.t -> 'a t + end + end + module Std : sig module Int = Int end + end +val x : 'a Int.Map.t = +Characters 8-9: + let y = x + x ;; + ^ +Error: This expression has type 'a Int.Map.t + but an expression was expected of type int +module M : sig type t = A type u = C end +module N : sig type t = B end +- : M.t = A +- : N.t = B +- : u = C +type t = M.t = A +type u = M.u = C +- : u = C +module L : sig type v = V end +- : v = V +module L : sig type v = V end +- : v = V +type t1 = A +module M1 : sig type u = v and v = t1 end +module N1 : sig type u = v and v = t1 end +type t1 = B +module N2 : sig type u = v and v = N1.v end +module type PR6566 = sig type t = string end +module PR6566 : sig type t = int end +Characters 26-32: + module PR6566' : PR6566 = PR6566;; + ^^^^^^ +Error: Signature mismatch: + Modules do not match: sig type t = int end is not included in PR6566 + Type declarations do not match: + type t = int + is not included in + type t = string +module A : sig module B : sig type t = T end end +module M2 : sig type u = A.B.t type foo = int type v = u end + diff --git a/testsuite/tests/typing-short-paths/short-paths.ml b/testsuite/tests/typing-short-paths/short-paths.ml index 5d691aca..b55e4133 100644 --- a/testsuite/tests/typing-short-paths/short-paths.ml +++ b/testsuite/tests/typing-short-paths/short-paths.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -short-paths " + * toplevel +*) + module Core = struct module Int = struct module T = struct diff --git a/testsuite/tests/typing-short-paths/short-paths.ml.reference b/testsuite/tests/typing-short-paths/short-paths.ml.reference deleted file mode 100644 index 22babba5..00000000 --- a/testsuite/tests/typing-short-paths/short-paths.ml.reference +++ /dev/null @@ -1,96 +0,0 @@ - -# module Core : - sig - module Int : - sig - module T : - sig - type t = int - val compare : 'a -> 'a -> t - val ( + ) : t -> t -> t - end - type t = int - val compare : 'a -> 'a -> t - val ( + ) : t -> t -> t - module Map : - sig - type key = t - type 'a t = 'a Map.Make(T).t - val empty : 'a t - val is_empty : 'a t -> bool - val mem : key -> 'a t -> bool - val add : key -> 'a -> 'a t -> 'a t - val update : key -> ('a option -> 'a option) -> 'a t -> 'a t - val singleton : key -> 'a -> 'a t - val remove : key -> 'a t -> 'a t - val merge : - (key -> 'a option -> 'b option -> 'c option) -> - 'a t -> 'b t -> 'c t - val union : - (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - val compare : ('a -> 'a -> key) -> 'a t -> 'a t -> key - val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool - val iter : (key -> 'a -> unit) -> 'a t -> unit - val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b - val for_all : (key -> 'a -> bool) -> 'a t -> bool - val exists : (key -> 'a -> bool) -> 'a t -> bool - val filter : (key -> 'a -> bool) -> 'a t -> 'a t - val partition : (key -> 'a -> bool) -> 'a t -> 'a t * 'a t - val cardinal : 'a t -> key - val bindings : 'a t -> (key * 'a) list - val min_binding : 'a t -> key * 'a - val min_binding_opt : 'a t -> (key * 'a) option - val max_binding : 'a t -> key * 'a - val max_binding_opt : 'a t -> (key * 'a) option - val choose : 'a t -> key * 'a - val choose_opt : 'a t -> (key * 'a) option - val split : key -> 'a t -> 'a t * 'a option * 'a t - val find : key -> 'a t -> 'a - val find_opt : key -> 'a t -> 'a option - val find_first : (key -> bool) -> 'a t -> key * 'a - val find_first_opt : (key -> bool) -> 'a t -> (key * 'a) option - val find_last : (key -> bool) -> 'a t -> key * 'a - val find_last_opt : (key -> bool) -> 'a t -> (key * 'a) option - val map : ('a -> 'b) -> 'a t -> 'b t - val mapi : (key -> 'a -> 'b) -> 'a t -> 'b t - end - end - module Std : sig module Int = Int end - end -# # val x : 'a Int.Map.t = -# Characters 8-9: - let y = x + x ;; - ^ -Error: This expression has type 'a Int.Map.t - but an expression was expected of type int -# module M : sig type t = A type u = C end -module N : sig type t = B end -# - : M.t = A -# - : N.t = B -# - : u = C -# type t = M.t = A -type u = M.u = C -# - : u = C -# module L : sig type v = V end -# - : v = V -# module L : sig type v = V end -# - : v = V -# type t1 = A -# module M1 : sig type u = v and v = t1 end -# module N1 : sig type u = v and v = t1 end -# type t1 = B -# module N2 : sig type u = v and v = N1.v end -# module type PR6566 = sig type t = string end -# module PR6566 : sig type t = int end -# Characters 26-32: - module PR6566' : PR6566 = PR6566;; - ^^^^^^ -Error: Signature mismatch: - Modules do not match: sig type t = int end is not included in PR6566 - Type declarations do not match: - type t = int - is not included in - type t = string -# module A : sig module B : sig type t = T end end -# module M2 : sig type u = A.B.t type foo = int type v = u end -# diff --git a/testsuite/tests/typing-signatures/Makefile b/testsuite/tests/typing-signatures/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-signatures/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-signatures/els.ml b/testsuite/tests/typing-signatures/els.ml index dfc2e074..a438c735 100644 --- a/testsuite/tests/typing-signatures/els.ml +++ b/testsuite/tests/typing-signatures/els.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + (* Adapted from: An Expressive Language of Signatures by Norman Ramsey, Kathleen Fisher and Paul Govereau *) diff --git a/testsuite/tests/typing-signatures/els.ml.reference b/testsuite/tests/typing-signatures/els.ml.reference deleted file mode 100644 index 460820b7..00000000 --- a/testsuite/tests/typing-signatures/els.ml.reference +++ /dev/null @@ -1,95 +0,0 @@ - -# * module type VALUE = sig type value type state type usert end -# module type CORE0 = - sig - module V : VALUE - val setglobal : V.state -> string -> V.value -> unit - end -# module type CORE = - sig - module V : VALUE - val setglobal : V.state -> string -> V.value -> unit - val apply : V.value -> V.state -> V.value list -> V.value - end -# module type AST = - sig - module Value : VALUE - type chunk - type program - val get_value : chunk -> Value.value - end -# module type EVALUATOR = - sig - module Value : VALUE - module Ast : - sig type chunk type program val get_value : chunk -> Value.value end - type state = Value.state - type value = Value.value - exception Error of string - val compile : Ast.program -> string - val setglobal : Value.state -> string -> Value.value -> unit - end -# module type PARSER = sig type chunk val parse : string -> chunk end -# module type INTERP = - sig - module Value : VALUE - module Ast : - sig type chunk type program val get_value : chunk -> Value.value end - type state = Value.state - type value = Value.value - exception Error of string - val compile : Ast.program -> string - val setglobal : Value.state -> string -> Value.value -> unit - module Parser : - sig type chunk = Ast.chunk val parse : string -> chunk end - val dostring : state -> string -> value list - val mk : unit -> state - end -# module type USERTYPE = - sig type t val eq : t -> t -> bool val to_string : t -> string end -# module type TYPEVIEW = - sig type combined type t val map : (combined -> t) * (t -> combined) end -# module type COMBINED_COMMON = - sig - module T : sig type t end - module TV1 : sig type t val map : (T.t -> t) * (t -> T.t) end - module TV2 : sig type t val map : (T.t -> t) * (t -> T.t) end - end -# module type COMBINED_TYPE = - sig - module T : USERTYPE - module TV1 : sig type t val map : (T.t -> t) * (t -> T.t) end - module TV2 : sig type t val map : (T.t -> t) * (t -> T.t) end - end -# module type BARECODE = sig type state val init : state -> unit end -# module USERCODE : - functor (X : TYPEVIEW) -> - sig - module type F = - functor - (C : sig - module V : - sig type value type state type usert = X.combined end - val setglobal : V.state -> string -> V.value -> unit - val apply : V.value -> V.state -> V.value list -> V.value - end) -> - sig val init : C.V.state -> unit end - end -# module Weapon : sig type t end -# module type WEAPON_LIB = - sig - type t = Weapon.t - module T : - sig type t = t val eq : t -> t -> bool val to_string : t -> string end - module Make : - functor - (TV : sig - type combined - type t = t - val map : (combined -> t) * (t -> combined) - end) -> - USERCODE(TV).F - end -# module type X = functor (X : CORE) -> BARECODE -# module type X = CORE -> BARECODE -# diff --git a/testsuite/tests/typing-signatures/els.ocaml.reference b/testsuite/tests/typing-signatures/els.ocaml.reference new file mode 100644 index 00000000..5254b22b --- /dev/null +++ b/testsuite/tests/typing-signatures/els.ocaml.reference @@ -0,0 +1,94 @@ +module type VALUE = sig type value type state type usert end +module type CORE0 = + sig + module V : VALUE + val setglobal : V.state -> string -> V.value -> unit + end +module type CORE = + sig + module V : VALUE + val setglobal : V.state -> string -> V.value -> unit + val apply : V.value -> V.state -> V.value list -> V.value + end +module type AST = + sig + module Value : VALUE + type chunk + type program + val get_value : chunk -> Value.value + end +module type EVALUATOR = + sig + module Value : VALUE + module Ast : + sig type chunk type program val get_value : chunk -> Value.value end + type state = Value.state + type value = Value.value + exception Error of string + val compile : Ast.program -> string + val setglobal : Value.state -> string -> Value.value -> unit + end +module type PARSER = sig type chunk val parse : string -> chunk end +module type INTERP = + sig + module Value : VALUE + module Ast : + sig type chunk type program val get_value : chunk -> Value.value end + type state = Value.state + type value = Value.value + exception Error of string + val compile : Ast.program -> string + val setglobal : Value.state -> string -> Value.value -> unit + module Parser : + sig type chunk = Ast.chunk val parse : string -> chunk end + val dostring : state -> string -> value list + val mk : unit -> state + end +module type USERTYPE = + sig type t val eq : t -> t -> bool val to_string : t -> string end +module type TYPEVIEW = + sig type combined type t val map : (combined -> t) * (t -> combined) end +module type COMBINED_COMMON = + sig + module T : sig type t end + module TV1 : sig type t val map : (T.t -> t) * (t -> T.t) end + module TV2 : sig type t val map : (T.t -> t) * (t -> T.t) end + end +module type COMBINED_TYPE = + sig + module T : USERTYPE + module TV1 : sig type t val map : (T.t -> t) * (t -> T.t) end + module TV2 : sig type t val map : (T.t -> t) * (t -> T.t) end + end +module type BARECODE = sig type state val init : state -> unit end +module USERCODE : + functor (X : TYPEVIEW) -> + sig + module type F = + functor + (C : sig + module V : + sig type value type state type usert = X.combined end + val setglobal : V.state -> string -> V.value -> unit + val apply : V.value -> V.state -> V.value list -> V.value + end) -> + sig val init : C.V.state -> unit end + end +module Weapon : sig type t end +module type WEAPON_LIB = + sig + type t = Weapon.t + module T : + sig type t = t val eq : t -> t -> bool val to_string : t -> string end + module Make : + functor + (TV : sig + type combined + type t = t + val map : (combined -> t) * (t -> combined) + end) -> + USERCODE(TV).F + end +module type X = functor (X : CORE) -> BARECODE +module type X = CORE -> BARECODE + diff --git a/testsuite/tests/typing-signatures/ocamltests b/testsuite/tests/typing-signatures/ocamltests new file mode 100644 index 00000000..c209fe4c --- /dev/null +++ b/testsuite/tests/typing-signatures/ocamltests @@ -0,0 +1,3 @@ +els.ml +pr6371.ml +pr6672.ml diff --git a/testsuite/tests/typing-signatures/pr6371.ml b/testsuite/tests/typing-signatures/pr6371.ml index d717b9e6..c5516c3f 100644 --- a/testsuite/tests/typing-signatures/pr6371.ml +++ b/testsuite/tests/typing-signatures/pr6371.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + module M = struct type t = int * (< m : 'a > as 'a) end;; diff --git a/testsuite/tests/typing-signatures/pr6371.ml.reference b/testsuite/tests/typing-signatures/pr6371.ml.reference deleted file mode 100644 index d6d916a7..00000000 --- a/testsuite/tests/typing-signatures/pr6371.ml.reference +++ /dev/null @@ -1,4 +0,0 @@ - -# module M : sig type t = int * (< m : 'a > as 'a) end -# module type S = sig module M : sig type t = int * (< m : 'a > as 'a) end end -# diff --git a/testsuite/tests/typing-signatures/pr6371.ocaml.reference b/testsuite/tests/typing-signatures/pr6371.ocaml.reference new file mode 100644 index 00000000..bd100af0 --- /dev/null +++ b/testsuite/tests/typing-signatures/pr6371.ocaml.reference @@ -0,0 +1,3 @@ +module M : sig type t = int * (< m : 'a > as 'a) end +module type S = sig module M : sig type t = int * (< m : 'a > as 'a) end end + diff --git a/testsuite/tests/typing-signatures/pr6672.ml b/testsuite/tests/typing-signatures/pr6672.ml index 5b168f05..66852161 100644 --- a/testsuite/tests/typing-signatures/pr6672.ml +++ b/testsuite/tests/typing-signatures/pr6672.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + module type S = sig type 'a t end;; module type T = S with type +'a t = 'a list;; module type T = S with type -'a t = 'a list;; diff --git a/testsuite/tests/typing-signatures/pr6672.ml.reference b/testsuite/tests/typing-signatures/pr6672.ml.reference deleted file mode 100644 index 959cee7e..00000000 --- a/testsuite/tests/typing-signatures/pr6672.ml.reference +++ /dev/null @@ -1,10 +0,0 @@ - -# module type S = sig type 'a t end -# module type T = sig type 'a t = 'a list end -# Characters 23-43: - module type T = S with type -'a t = 'a list;; - ^^^^^^^^^^^^^^^^^^^^ -Error: In this definition, expected parameter variances are not satisfied. - The 1st type parameter was expected to be contravariant, - but it is injective covariant. -# diff --git a/testsuite/tests/typing-signatures/pr6672.ocaml.reference b/testsuite/tests/typing-signatures/pr6672.ocaml.reference new file mode 100644 index 00000000..17e9b1ed --- /dev/null +++ b/testsuite/tests/typing-signatures/pr6672.ocaml.reference @@ -0,0 +1,9 @@ +module type S = sig type 'a t end +module type T = sig type 'a t = 'a list end +Characters 23-43: + module type T = S with type -'a t = 'a list;; + ^^^^^^^^^^^^^^^^^^^^ +Error: In this definition, expected parameter variances are not satisfied. + The 1st type parameter was expected to be contravariant, + but it is injective covariant. + diff --git a/testsuite/tests/typing-sigsubst/Makefile b/testsuite/tests/typing-sigsubst/Makefile deleted file mode 100644 index 0b15e777..00000000 --- a/testsuite/tests/typing-sigsubst/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.expect -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-sigsubst/ocamltests b/testsuite/tests/typing-sigsubst/ocamltests new file mode 100644 index 00000000..278c5eef --- /dev/null +++ b/testsuite/tests/typing-sigsubst/ocamltests @@ -0,0 +1 @@ +sigsubst.ml diff --git a/testsuite/tests/typing-sigsubst/sigsubst.ml b/testsuite/tests/typing-sigsubst/sigsubst.ml index 96aea573..379bf546 100644 --- a/testsuite/tests/typing-sigsubst/sigsubst.ml +++ b/testsuite/tests/typing-sigsubst/sigsubst.ml @@ -1,3 +1,7 @@ +(* TEST + * expect +*) + module type Printable = sig type t val print : Format.formatter -> t -> unit @@ -19,6 +23,8 @@ module type PrintableComparable = sig end [%%expect {| Line _, characters 2-36: + include Comparable with type t = t + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: Multiple definition of the type name t. Names must be unique in a given structure or signature. |}] @@ -40,6 +46,10 @@ module type S0 = sig end with type M.t = int [%%expect {| Line _, characters 17-115: + .................sig + module rec M : sig type t = M2.t end + and M2 : sig type t = int end + end with type M.t = int Error: In this `with' constraint, the new definition of M.t does not match its original definition in the constrained signature: Type declarations do not match: @@ -159,6 +169,11 @@ end with type 'a t2 := 'a t * bool [%%expect {| type 'a t constraint 'a = 'b list Line _, characters 16-142: + ................sig + type 'a t2 constraint 'a = 'b list + type 'a mylist = 'a list + val x : int mylist t2 + end with type 'a t2 := 'a t * bool Error: Destructive substitutions are not supported for constrained types (other than when replacing a type constructor with a type constructor with the same arguments). @@ -230,6 +245,10 @@ module type S = sig end with type M.t := float [%%expect {| Line _, characters 16-89: + ................sig + module M : sig type t end + module A = M + end with type M.t := float Error: This `with' constraint on M.t changes M, which is aliased in the constrained signature (as A). |}] @@ -254,6 +273,8 @@ module type S = module type S2 = S with type M.t := float [%%expect {| Line _, characters 17-41: + module type S2 = S with type M.t := float + ^^^^^^^^^^^^^^^^^^^^^^^^ Error: This `with' constraint on M.t makes the applicative functor type F(M).t ill-typed in the constrained signature: Modules do not match: @@ -286,6 +307,10 @@ end with type M2.t := int [%%expect {| module Id : functor (X : sig type t end) -> sig type t = X.t end Line _, characters 17-120: + .................sig + module rec M : sig type t = A of Id(M2).t end + and M2 : sig type t end + end with type M2.t := int Error: This `with' constraint on M2.t makes the applicative functor type Id(M2).t ill-typed in the constrained signature: Modules do not match: sig end is not included in sig type t end @@ -325,6 +350,16 @@ module type S = sig end with module M.N := A [%%expect {| Line _, characters 16-159: + ................sig + module M : sig + module N : sig + module P : sig + type t + end + end + end + module Alias = M + end with module M.N := A Error: This `with' constraint on M.N changes M, which is aliased in the constrained signature (as Alias). |}] diff --git a/testsuite/tests/typing-typeparam/Makefile b/testsuite/tests/typing-typeparam/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-typeparam/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-typeparam/newtype.ml b/testsuite/tests/typing-typeparam/newtype.ml index d32f4c91..b41d0dfc 100644 --- a/testsuite/tests/typing-typeparam/newtype.ml +++ b/testsuite/tests/typing-typeparam/newtype.ml @@ -1,3 +1,7 @@ +(* TEST + * toplevel +*) + let property (type t) () = let module M = struct exception E of t end in (fun x -> M.E x), (function M.E x -> Some x | _ -> None) diff --git a/testsuite/tests/typing-typeparam/newtype.ml.reference b/testsuite/tests/typing-typeparam/newtype.ml.reference deleted file mode 100644 index 21769753..00000000 --- a/testsuite/tests/typing-typeparam/newtype.ml.reference +++ /dev/null @@ -1,19 +0,0 @@ - -# val property : unit -> ('a -> exn) * (exn -> 'a option) = -# false -true -true -false -# val sort_uniq : ('a -> 'a -> int) -> 'a list -> 'a list = -# abc,xyz -# Characters 33-34: - let f x (type a) (y : a) = (x = y);; (* Fails *) - ^ -Error: This expression has type a but an expression was expected of type 'a - The type constructor a would escape its scope -# Characters 117-118: - method n : 'a -> 'a = fun (type g) (x:g) -> self#m x - ^ -Error: This expression has type g but an expression was expected of type 'a - The type constructor g would escape its scope -# diff --git a/testsuite/tests/typing-typeparam/newtype.ocaml.reference b/testsuite/tests/typing-typeparam/newtype.ocaml.reference new file mode 100644 index 00000000..dab29770 --- /dev/null +++ b/testsuite/tests/typing-typeparam/newtype.ocaml.reference @@ -0,0 +1,18 @@ +val property : unit -> ('a -> exn) * (exn -> 'a option) = +false +true +true +false +val sort_uniq : ('a -> 'a -> int) -> 'a list -> 'a list = +abc,xyz +Characters 33-34: + let f x (type a) (y : a) = (x = y);; (* Fails *) + ^ +Error: This expression has type a but an expression was expected of type 'a + The type constructor a would escape its scope +Characters 117-118: + method n : 'a -> 'a = fun (type g) (x:g) -> self#m x + ^ +Error: This expression has type g but an expression was expected of type 'a + The type constructor g would escape its scope + diff --git a/testsuite/tests/typing-typeparam/ocamltests b/testsuite/tests/typing-typeparam/ocamltests new file mode 100644 index 00000000..cbf31880 --- /dev/null +++ b/testsuite/tests/typing-typeparam/ocamltests @@ -0,0 +1 @@ +newtype.ml diff --git a/testsuite/tests/typing-unboxed-types/Makefile b/testsuite/tests/typing-unboxed-types/Makefile deleted file mode 100644 index e0a77e84..00000000 --- a/testsuite/tests/typing-unboxed-types/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -newdefault: test.ml.reference - @$(MAKE) default - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common - -GENERATED_SOURCES = test.ml.reference *.flat-float - -ifeq "$(FLAT_FLOAT_ARRAY)" "true" -suffix = -flat -else -suffix = -noflat -endif - -test.ml.reference: test.ml.reference$(suffix) $(FLAT_FLOAT_ARRAY).flat-float - @cp $< $@ - -%.flat-float: - @rm -f $(GENERATED_SOURCES) - @touch $@ diff --git a/testsuite/tests/typing-unboxed-types/ocamltests b/testsuite/tests/typing-unboxed-types/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/typing-unboxed-types/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/typing-unboxed-types/test.ml b/testsuite/tests/typing-unboxed-types/test.ml index 4391fcbb..25f03be2 100644 --- a/testsuite/tests/typing-unboxed-types/test.ml +++ b/testsuite/tests/typing-unboxed-types/test.ml @@ -1,3 +1,12 @@ +(* TEST + * flat-float-array + ** toplevel + compiler_reference = "${test_source_directory}/test.ml.reference-flat" + * no-flat-float-array + ** toplevel + compiler_reference = "${test_source_directory}/test.ml.reference-noflat" +*) + (* Check the unboxing *) (* For concrete types *) @@ -161,3 +170,12 @@ type 'a s type ('a, 'p) t = private 'a s type 'a packed = T : ('a, _) t -> 'a packed [@@unboxed] ;; + +(* MPR#7682 *) +type f = {field: 'a. 'a list} [@@unboxed];; +let g = Array.make 10 { field=[] };; +let h = g.(5);; + +(* Using [@@immediate] information (GPR#1469) *) +type 'a t [@@immediate];; +type u = U : 'a t -> u [@@unboxed];; diff --git a/testsuite/tests/typing-unboxed-types/test.ml.reference-flat b/testsuite/tests/typing-unboxed-types/test.ml.reference-flat index f6d6aaa1..a9515e4d 100644 --- a/testsuite/tests/typing-unboxed-types/test.ml.reference-flat +++ b/testsuite/tests/typing-unboxed-types/test.ml.reference-flat @@ -1,46 +1,45 @@ - -# type t1 = A of string [@@unboxed] -# - : bool = true -# type t2 = { f : string; } [@@unboxed] -# - : bool = true -# type t3 = B of { g : string; } [@@unboxed] -# - : bool = true -# Characters 29-58: +type t1 = A of string [@@unboxed] +- : bool = true +type t2 = { f : string; } [@@unboxed] +- : bool = true +type t3 = B of { g : string; } [@@unboxed] +- : bool = true +Characters 29-58: type t4 = C [@@ocaml.unboxed];; (* no argument *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has no argument. -# Characters 0-45: +Characters 0-45: type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has more than one argument. -# Characters 0-33: +Characters 0-33: type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 0-40: +Characters 0-40: type t6 = G of int | H [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 0-51: +Characters 0-51: type t7 = I of string | J of bool [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 1-50: +Characters 1-50: type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one field. -# Characters 0-56: +Characters 0-56: type t9 = K of { j : string; l : int } [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has more than one argument. -# type t10 = A of t10 [@@unboxed] -# Characters 12-15: +type t10 = A of t10 [@@unboxed] +Characters 12-15: let rec x = A x;; ^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 121-172: +Characters 121-172: ......struct type t = A of string [@@ocaml.unboxed] end.. @@ -55,7 +54,7 @@ Error: Signature mismatch: type t = A of string Their internal representations differ: the first declaration uses unboxed representation. -# Characters 63-96: +Characters 63-96: ......struct type t = A of string end.. @@ -70,7 +69,7 @@ Error: Signature mismatch: type t = A of string [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# Characters 48-102: +Characters 48-102: ......struct type t = { f : string } [@@ocaml.unboxed] end.. @@ -85,7 +84,7 @@ Error: Signature mismatch: type t = { f : string; } Their internal representations differ: the first declaration uses unboxed representation. -# Characters 66-102: +Characters 66-102: ......struct type t = { f : string } end.. @@ -100,7 +99,7 @@ Error: Signature mismatch: type t = { f : string; } [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# Characters 53-112: +Characters 53-112: ......struct type t = A of { f : string } [@@ocaml.unboxed] end.. @@ -115,7 +114,7 @@ Error: Signature mismatch: type t = A of { f : string; } Their internal representations differ: the first declaration uses unboxed representation. -# Characters 71-112: +Characters 71-112: ......struct type t = A of { f : string } end.. @@ -130,27 +129,27 @@ Error: Signature mismatch: type t = A of { f : string; } [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# type t11 = L of float [@@unboxed] -# - : unit = () -# type 'a t12 = M of 'a t12 [@@unboxed] -# val f : int t12 array -> int t12 = -# type t13 = A : 'a t12 -> t13 [@@unboxed] -# type t14 -# type t15 = A of t14 [@@unboxed] -# type 'a abs -# Characters 0-45: +type t11 = L of float [@@unboxed] +- : unit = () +type 'a t12 = M of 'a t12 [@@unboxed] +val f : int t12 array -> int t12 = +type t13 = A : 'a t12 -> t13 [@@unboxed] +type t14 +type t15 = A of t14 [@@unboxed] +type 'a abs +Characters 0-45: type t16 = A : _ abs -> t16 [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# Characters 19-69: +Characters 19-69: type t18 = A : _ list abs -> t18 [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# * Characters 176-256: +Characters 176-256: ......struct type t = A of float [@@ocaml.unboxed] type u = { f1 : t; f2 : t } @@ -163,44 +162,51 @@ Error: Signature mismatch: type u = { f1 : t; f2 : t; } Their internal representations differ: the first declaration uses unboxed float representation. -# * * module T : sig type t [@@immediate] end -# * type 'a s = S : 'a -> 'a s [@@unboxed] -# Characters 0-33: +module T : sig type t [@@immediate] end +type 'a s = S : 'a -> 'a s [@@unboxed] +Characters 0-33: type t = T : _ s -> t [@@unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# type 'a s = S : 'a -> 'a option s [@@unboxed] -# Characters 0-33: +type 'a s = S : 'a -> 'a option s [@@unboxed] +Characters 0-33: type t = T : _ s -> t [@@unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# module M : +module M : sig type 'a r constraint 'a = unit -> 'b val inj : 'b -> (unit -> 'b) r end -# Characters 14-59: +Characters 14-59: type t = T : (unit -> _) M.r -> t [@@unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# type 'a s = S : (unit -> 'a) M.r -> 'a option s [@@unboxed] -# Characters 14-47: +type 'a s = S : (unit -> 'a) M.r -> 'a option s [@@unboxed] +Characters 14-47: type t = T : _ s -> t [@@unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# type 'a t = T : 'a s -> 'a t [@@unboxed] -# Characters 42-81: +type 'a t = T : 'a s -> 'a t [@@unboxed] +Characters 42-81: type _ s = S : 'a t -> _ s [@@unboxed] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it might contain both float and non-float values. You should annotate it with [@@ocaml.boxed]. -# type 'a s +type 'a s type ('a, 'p) t = private 'a s type 'a packed = T : ('a, 'b) t -> 'a packed [@@unboxed] -# +type f = { field : 'a. 'a list; } [@@unboxed] +val g : f array = + [|{field = []}; {field = []}; {field = []}; {field = []}; {field = []}; + {field = []}; {field = []}; {field = []}; {field = []}; {field = []}|] +val h : f = {field = []} +type 'a t [@@immediate] +type u = U : 'a t -> u [@@unboxed] + diff --git a/testsuite/tests/typing-unboxed-types/test.ml.reference-noflat b/testsuite/tests/typing-unboxed-types/test.ml.reference-noflat index 73c03fd8..49fd74e9 100644 --- a/testsuite/tests/typing-unboxed-types/test.ml.reference-noflat +++ b/testsuite/tests/typing-unboxed-types/test.ml.reference-noflat @@ -1,46 +1,45 @@ - -# type t1 = A of string [@@unboxed] -# - : bool = true -# type t2 = { f : string; } [@@unboxed] -# - : bool = true -# type t3 = B of { g : string; } [@@unboxed] -# - : bool = true -# Characters 29-58: +type t1 = A of string [@@unboxed] +- : bool = true +type t2 = { f : string; } [@@unboxed] +- : bool = true +type t3 = B of { g : string; } [@@unboxed] +- : bool = true +Characters 29-58: type t4 = C [@@ocaml.unboxed];; (* no argument *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has no argument. -# Characters 0-45: +Characters 0-45: type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has more than one argument. -# Characters 0-33: +Characters 0-33: type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 0-40: +Characters 0-40: type t6 = G of int | H [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 0-51: +Characters 0-51: type t7 = I of string | J of bool [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one constructor. -# Characters 1-50: +Characters 1-50: type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because it has more than one field. -# Characters 0-56: +Characters 0-56: type t9 = K of { j : string; l : int } [@@ocaml.unboxed];; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This type cannot be unboxed because its constructor has more than one argument. -# type t10 = A of t10 [@@unboxed] -# Characters 12-15: +type t10 = A of t10 [@@unboxed] +Characters 12-15: let rec x = A x;; ^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' -# Characters 121-172: +Characters 121-172: ......struct type t = A of string [@@ocaml.unboxed] end.. @@ -55,7 +54,7 @@ Error: Signature mismatch: type t = A of string Their internal representations differ: the first declaration uses unboxed representation. -# Characters 63-96: +Characters 63-96: ......struct type t = A of string end.. @@ -70,7 +69,7 @@ Error: Signature mismatch: type t = A of string [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# Characters 48-102: +Characters 48-102: ......struct type t = { f : string } [@@ocaml.unboxed] end.. @@ -85,7 +84,7 @@ Error: Signature mismatch: type t = { f : string; } Their internal representations differ: the first declaration uses unboxed representation. -# Characters 66-102: +Characters 66-102: ......struct type t = { f : string } end.. @@ -100,7 +99,7 @@ Error: Signature mismatch: type t = { f : string; } [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# Characters 53-112: +Characters 53-112: ......struct type t = A of { f : string } [@@ocaml.unboxed] end.. @@ -115,7 +114,7 @@ Error: Signature mismatch: type t = A of { f : string; } Their internal representations differ: the first declaration uses unboxed representation. -# Characters 71-112: +Characters 71-112: ......struct type t = A of { f : string } end.. @@ -130,17 +129,17 @@ Error: Signature mismatch: type t = A of { f : string; } [@@unboxed] Their internal representations differ: the second declaration uses unboxed representation. -# type t11 = L of float [@@unboxed] -# - : unit = () -# type 'a t12 = M of 'a t12 [@@unboxed] -# val f : int t12 array -> int t12 = -# type t13 = A : 'a t12 -> t13 [@@unboxed] -# type t14 -# type t15 = A of t14 [@@unboxed] -# type 'a abs -# type t16 = A : 'a abs -> t16 [@@unboxed] -# type t18 = A : 'a list abs -> t18 [@@unboxed] -# * Characters 176-256: +type t11 = L of float [@@unboxed] +- : unit = () +type 'a t12 = M of 'a t12 [@@unboxed] +val f : int t12 array -> int t12 = +type t13 = A : 'a t12 -> t13 [@@unboxed] +type t14 +type t15 = A of t14 [@@unboxed] +type 'a abs +type t16 = A : 'a abs -> t16 [@@unboxed] +type t18 = A : 'a list abs -> t18 [@@unboxed] +Characters 176-256: ......struct type t = A of float [@@ocaml.unboxed] type u = { f1 : t; f2 : t } @@ -153,20 +152,27 @@ Error: Signature mismatch: type u = { f1 : t; f2 : t; } Their internal representations differ: the first declaration uses unboxed float representation. -# * * module T : sig type t [@@immediate] end -# * type 'a s = S : 'a -> 'a s [@@unboxed] -# type t = T : 'a s -> t [@@unboxed] -# type 'a s = S : 'a -> 'a option s [@@unboxed] -# type t = T : 'a s -> t [@@unboxed] -# module M : +module T : sig type t [@@immediate] end +type 'a s = S : 'a -> 'a s [@@unboxed] +type t = T : 'a s -> t [@@unboxed] +type 'a s = S : 'a -> 'a option s [@@unboxed] +type t = T : 'a s -> t [@@unboxed] +module M : sig type 'a r constraint 'a = unit -> 'b val inj : 'b -> (unit -> 'b) r end -# type t = T : (unit -> 'a) M.r -> t [@@unboxed] -# type 'a s = S : (unit -> 'a) M.r -> 'a option s [@@unboxed] -# type t = T : 'a s -> t [@@unboxed] -# type 'a t = T : 'a s -> 'a t [@@unboxed] -# type _ s = S : 'a t -> 'b s [@@unboxed] +type t = T : (unit -> 'a) M.r -> t [@@unboxed] +type 'a s = S : (unit -> 'a) M.r -> 'a option s [@@unboxed] +type t = T : 'a s -> t [@@unboxed] +type 'a t = T : 'a s -> 'a t [@@unboxed] +type _ s = S : 'a t -> 'b s [@@unboxed] and _ t = T : 'a -> 'a s t -# type 'a s +type 'a s type ('a, 'p) t = private 'a s type 'a packed = T : ('a, 'b) t -> 'a packed [@@unboxed] -# +type f = { field : 'a. 'a list; } [@@unboxed] +val g : f array = + [|{field = []}; {field = []}; {field = []}; {field = []}; {field = []}; + {field = []}; {field = []}; {field = []}; {field = []}; {field = []}|] +val h : f = {field = []} +type 'a t [@@immediate] +type u = U : 'a t -> u [@@unboxed] + diff --git a/testsuite/tests/typing-unboxed/Makefile b/testsuite/tests/typing-unboxed/Makefile deleted file mode 100644 index 7fc00661..00000000 --- a/testsuite/tests/typing-unboxed/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tests/typing-unboxed/ocamltests b/testsuite/tests/typing-unboxed/ocamltests new file mode 100644 index 00000000..31c13b44 --- /dev/null +++ b/testsuite/tests/typing-unboxed/ocamltests @@ -0,0 +1 @@ +test.ml diff --git a/testsuite/tests/typing-unboxed/test.ml b/testsuite/tests/typing-unboxed/test.ml index 85265c1f..b577013d 100644 --- a/testsuite/tests/typing-unboxed/test.ml +++ b/testsuite/tests/typing-unboxed/test.ml @@ -1,3 +1,6 @@ +(* TEST + * toplevel +*) external a : (int [@untagged]) -> unit = "a" "a_nat" external b : (int32 [@unboxed]) -> unit = "b" "b_nat" diff --git a/testsuite/tests/typing-unboxed/test.ml.reference b/testsuite/tests/typing-unboxed/test.ml.reference deleted file mode 100644 index 803bf571..00000000 --- a/testsuite/tests/typing-unboxed/test.ml.reference +++ /dev/null @@ -1,192 +0,0 @@ - -# external a : (int [@untagged]) -> unit = "a" "a_nat" -external b : (int32 [@unboxed]) -> unit = "b" "b_nat" -external c : (int64 [@unboxed]) -> unit = "c" "c_nat" -external d : (nativeint [@unboxed]) -> unit = "d" "d_nat" -external e : (float [@unboxed]) -> unit = "e" "e_nat" -type t = private int -external f : (t [@untagged]) -> unit = "f" "f_nat" -module M : - sig - external a : int -> (int [@untagged]) = "a" "a_nat" - external b : (int [@untagged]) -> int = "b" "b_nat" - end -# Characters 382-451: - external f : (int32 [@unboxed]) -> (int32 [@unboxed]) = "f" "noalloc" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 63-122: - external a : float -> float = "a" "noalloc" "a_nat" "float" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: [@@unboxed] + [@@noalloc] should be used instead of "float" -Characters 125-176: - external b : float -> float = "b" "noalloc" "b_nat" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: [@@noalloc] should be used instead of "noalloc" -Characters 179-228: - external c : float -> float = "c" "c_nat" "float" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: [@@unboxed] + [@@noalloc] should be used instead of "float" -Characters 231-274: - external d : float -> float = "d" "noalloc" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 3: deprecated: [@@noalloc] should be used instead of "noalloc" -Characters 441-505: - ......struct - external f : int -> (int [@untagged]) = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : int -> (int [@untagged]) = "f" "f_nat" end - is not included in - sig external f : int -> int = "f" "f_nat" end - Values do not match: - external f : int -> (int [@untagged]) = "f" "f_nat" - is not included in - external f : int -> int = "f" "f_nat" -# Characters 65-129: - ......struct - external f : (int [@untagged]) -> int = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : (int [@untagged]) -> int = "f" "f_nat" end - is not included in - sig external f : int -> int = "a" "a_nat" end - Values do not match: - external f : (int [@untagged]) -> int = "f" "f_nat" - is not included in - external f : int -> int = "a" "a_nat" -# Characters 69-136: - ......struct - external f : float -> (float [@unboxed]) = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : float -> (float [@unboxed]) = "f" "f_nat" end - is not included in - sig external f : float -> float = "f" "f_nat" end - Values do not match: - external f : float -> (float [@unboxed]) = "f" "f_nat" - is not included in - external f : float -> float = "f" "f_nat" -# Characters 69-136: - ......struct - external f : (float [@unboxed]) -> float = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : (float [@unboxed]) -> float = "f" "f_nat" end - is not included in - sig external f : float -> float = "a" "a_nat" end - Values do not match: - external f : (float [@unboxed]) -> float = "f" "f_nat" - is not included in - external f : float -> float = "a" "a_nat" -# Characters 149-199: - ......struct - external f : int -> int = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : int -> int = "f" "f_nat" end - is not included in - sig external f : int -> (int [@untagged]) = "f" "f_nat" end - Values do not match: - external f : int -> int = "f" "f_nat" - is not included in - external f : int -> (int [@untagged]) = "f" "f_nat" -# Characters 79-129: - ......struct - external f : int -> int = "a" "a_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : int -> int = "a" "a_nat" end - is not included in - sig external f : (int [@untagged]) -> int = "f" "f_nat" end - Values do not match: - external f : int -> int = "a" "a_nat" - is not included in - external f : (int [@untagged]) -> int = "f" "f_nat" -# Characters 82-136: - ......struct - external f : float -> float = "f" "f_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : float -> float = "f" "f_nat" end - is not included in - sig external f : float -> (float [@unboxed]) = "f" "f_nat" end - Values do not match: - external f : float -> float = "f" "f_nat" - is not included in - external f : float -> (float [@unboxed]) = "f" "f_nat" -# Characters 82-136: - ......struct - external f : float -> float = "a" "a_nat" - end.. -Error: Signature mismatch: - Modules do not match: - sig external f : float -> float = "a" "a_nat" end - is not included in - sig external f : (float [@unboxed]) -> float = "f" "f_nat" end - Values do not match: - external f : float -> float = "a" "a_nat" - is not included in - external f : (float [@unboxed]) -> float = "f" "f_nat" -# Characters 67-72: - external g : (float [@untagged]) -> float = "g" "g_nat";; - ^^^^^ -Error: Don't know how to untag this type. Only int can be untagged -# Characters 14-17: - external h : (int [@unboxed]) -> float = "h" "h_nat";; - ^^^ -Error: Don't know how to unbox this type. Only float, int32, int64 and nativeint can be unboxed -# Characters 52-64: - external i : int -> float [@unboxed] = "i" "i_nat";; - ^^^^^^^^^^^^ -Error: Don't know how to unbox this type. Only float, int32, int64 and nativeint can be unboxed -# Characters 61-66: - external j : int -> (float [@unboxed]) * float = "j" "j_nat";; - ^^^^^ -Error: The attribute '@unboxed' should be attached to a direct argument or result of the primitive, it should not occur deeply into its type -# * external k : int -> float = "k" "k_nat" -# Characters 58-119: - external l : float -> float = "l" "l_nat" "float" [@@unboxed];; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Cannot use "float" in conjunction with [@unboxed]/[@untagged] -# Characters 0-62: - external m : (float [@unboxed]) -> float = "m" "m_nat" "float";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Cannot use "float" in conjunction with [@unboxed]/[@untagged] -# Characters 0-55: - external n : float -> float = "n" "noalloc" [@@noalloc];; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: Cannot use "noalloc" in conjunction with [@@noalloc] -# Characters 70-115: - external o : (float[@unboxed]) -> float = "o";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 0-45: - external p : float -> (float[@unboxed]) = "p";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 0-44: - external q : (int[@untagged]) -> float = "q";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 0-42: - external r : int -> (int[@untagged]) = "r";; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 0-42: - external s : int -> int = "s" [@@untagged];; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# Characters 0-45: - external t : float -> float = "t" [@@unboxed];; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present -# type 'a b = B of 'a b b [@@unboxed] -# diff --git a/testsuite/tests/typing-unboxed/test.ocaml.reference b/testsuite/tests/typing-unboxed/test.ocaml.reference new file mode 100644 index 00000000..335fed79 --- /dev/null +++ b/testsuite/tests/typing-unboxed/test.ocaml.reference @@ -0,0 +1,191 @@ +external a : (int [@untagged]) -> unit = "a" "a_nat" +external b : (int32 [@unboxed]) -> unit = "b" "b_nat" +external c : (int64 [@unboxed]) -> unit = "c" "c_nat" +external d : (nativeint [@unboxed]) -> unit = "d" "d_nat" +external e : (float [@unboxed]) -> unit = "e" "e_nat" +type t = private int +external f : (t [@untagged]) -> unit = "f" "f_nat" +module M : + sig + external a : int -> (int [@untagged]) = "a" "a_nat" + external b : (int [@untagged]) -> int = "b" "b_nat" + end +Characters 382-451: + external f : (int32 [@unboxed]) -> (int32 [@unboxed]) = "f" "noalloc" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 63-122: + external a : float -> float = "a" "noalloc" "a_nat" "float" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: [@@unboxed] + [@@noalloc] should be used instead of "float" +Characters 125-176: + external b : float -> float = "b" "noalloc" "b_nat" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: [@@noalloc] should be used instead of "noalloc" +Characters 179-228: + external c : float -> float = "c" "c_nat" "float" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: [@@unboxed] + [@@noalloc] should be used instead of "float" +Characters 231-274: + external d : float -> float = "d" "noalloc" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 3: deprecated: [@@noalloc] should be used instead of "noalloc" +Characters 441-505: + ......struct + external f : int -> (int [@untagged]) = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : int -> (int [@untagged]) = "f" "f_nat" end + is not included in + sig external f : int -> int = "f" "f_nat" end + Values do not match: + external f : int -> (int [@untagged]) = "f" "f_nat" + is not included in + external f : int -> int = "f" "f_nat" +Characters 65-129: + ......struct + external f : (int [@untagged]) -> int = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : (int [@untagged]) -> int = "f" "f_nat" end + is not included in + sig external f : int -> int = "a" "a_nat" end + Values do not match: + external f : (int [@untagged]) -> int = "f" "f_nat" + is not included in + external f : int -> int = "a" "a_nat" +Characters 69-136: + ......struct + external f : float -> (float [@unboxed]) = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : float -> (float [@unboxed]) = "f" "f_nat" end + is not included in + sig external f : float -> float = "f" "f_nat" end + Values do not match: + external f : float -> (float [@unboxed]) = "f" "f_nat" + is not included in + external f : float -> float = "f" "f_nat" +Characters 69-136: + ......struct + external f : (float [@unboxed]) -> float = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : (float [@unboxed]) -> float = "f" "f_nat" end + is not included in + sig external f : float -> float = "a" "a_nat" end + Values do not match: + external f : (float [@unboxed]) -> float = "f" "f_nat" + is not included in + external f : float -> float = "a" "a_nat" +Characters 149-199: + ......struct + external f : int -> int = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : int -> int = "f" "f_nat" end + is not included in + sig external f : int -> (int [@untagged]) = "f" "f_nat" end + Values do not match: + external f : int -> int = "f" "f_nat" + is not included in + external f : int -> (int [@untagged]) = "f" "f_nat" +Characters 79-129: + ......struct + external f : int -> int = "a" "a_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : int -> int = "a" "a_nat" end + is not included in + sig external f : (int [@untagged]) -> int = "f" "f_nat" end + Values do not match: + external f : int -> int = "a" "a_nat" + is not included in + external f : (int [@untagged]) -> int = "f" "f_nat" +Characters 82-136: + ......struct + external f : float -> float = "f" "f_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : float -> float = "f" "f_nat" end + is not included in + sig external f : float -> (float [@unboxed]) = "f" "f_nat" end + Values do not match: + external f : float -> float = "f" "f_nat" + is not included in + external f : float -> (float [@unboxed]) = "f" "f_nat" +Characters 82-136: + ......struct + external f : float -> float = "a" "a_nat" + end.. +Error: Signature mismatch: + Modules do not match: + sig external f : float -> float = "a" "a_nat" end + is not included in + sig external f : (float [@unboxed]) -> float = "f" "f_nat" end + Values do not match: + external f : float -> float = "a" "a_nat" + is not included in + external f : (float [@unboxed]) -> float = "f" "f_nat" +Characters 67-72: + external g : (float [@untagged]) -> float = "g" "g_nat";; + ^^^^^ +Error: Don't know how to untag this type. Only int can be untagged +Characters 14-17: + external h : (int [@unboxed]) -> float = "h" "h_nat";; + ^^^ +Error: Don't know how to unbox this type. Only float, int32, int64 and nativeint can be unboxed +Characters 52-64: + external i : int -> float [@unboxed] = "i" "i_nat";; + ^^^^^^^^^^^^ +Error: Don't know how to unbox this type. Only float, int32, int64 and nativeint can be unboxed +Characters 61-66: + external j : int -> (float [@unboxed]) * float = "j" "j_nat";; + ^^^^^ +Error: The attribute '@unboxed' should be attached to a direct argument or result of the primitive, it should not occur deeply into its type +external k : int -> float = "k" "k_nat" +Characters 58-119: + external l : float -> float = "l" "l_nat" "float" [@@unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Cannot use "float" in conjunction with [@unboxed]/[@untagged] +Characters 0-62: + external m : (float [@unboxed]) -> float = "m" "m_nat" "float";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Cannot use "float" in conjunction with [@unboxed]/[@untagged] +Characters 0-55: + external n : float -> float = "n" "noalloc" [@@noalloc];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: Cannot use "noalloc" in conjunction with [@@noalloc] +Characters 70-115: + external o : (float[@unboxed]) -> float = "o";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 0-45: + external p : float -> (float[@unboxed]) = "p";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 0-44: + external q : (int[@untagged]) -> float = "q";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 0-42: + external r : int -> (int[@untagged]) = "r";; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 0-42: + external s : int -> int = "s" [@@untagged];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +Characters 0-45: + external t : float -> float = "t" [@@unboxed];; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error: The native code version of the primitive is mandatory when attributes [@untagged] or [@unboxed] are present +type 'a b = B of 'a b b [@@unboxed] + diff --git a/testsuite/tests/typing-warnings/Makefile b/testsuite/tests/typing-warnings/Makefile deleted file mode 100644 index 646c8d49..00000000 --- a/testsuite/tests/typing-warnings/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -include $(BASEDIR)/makefiles/Makefile.toplevel -include $(BASEDIR)/makefiles/Makefile.common -TOPFLAGS = -w A -strict-sequence diff --git a/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.compilers.reference b/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.compilers.reference new file mode 100644 index 00000000..f0b7dc59 --- /dev/null +++ b/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.compilers.reference @@ -0,0 +1,163 @@ +- : unit = () + +<---------------------------------------------------------------------- +To check the result file for this test, it suffices to look for "val" +lines corresponding to toplevel answers. If they start with + + val ambiguous_... + +then just above there should be the warning text for Warning 57 +(we try to avoid all other warnings). If they start with + + val not_ambiguous_... + +then just above there should be *no* warning text. +----------------------------------------------------------------------> + +type expr = Val of int | Rest +Characters 46-71: + | ((Val x, _) | (_, Val x)) when x < 0 -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable x may match different arguments. (See manual section 9.5) +val ambiguous_typical_example : expr * expr -> unit = +Note that an Assert_failure is expected just below. +Exception: Assert_failure ("//toplevel//", 30, 6). +val not_ambiguous__no_orpat : int option -> unit = +val not_ambiguous__no_guard : [< `A | `B | `C ] -> unit = +val not_ambiguous__no_patvar_in_guard : + bool -> [> `B of 'a | `C of 'a ] -> unit = +val not_ambiguous__disjoint_cases : [> `B of bool | `C of bool ] -> unit = + +val not_ambiguous__prefix_variables : + [> `B of bool * 'a option * 'a option ] -> unit = +Characters 33-72: + | (`B (x, _, Some y) | `B (x, Some y, _)) when y -> ignore x + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable y may match different arguments. (See manual section 9.5) +val ambiguous__y : [> `B of 'a * bool option * bool option ] -> unit = +val not_ambiguous__rhs_not_protected : + [> `B of 'a * bool option * bool option ] -> unit = +Characters 35-74: + | (`B (x, _, Some y) | `B (x, Some y, _)) when x < y -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable y may match different arguments. (See manual section 9.5) +val ambiguous__x_y : [> `B of 'a * 'a option * 'a option ] -> unit = +Characters 37-76: + | (`B (x, z, Some y) | `B (x, Some y, z)) when x < y || Some x = z -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variables y,z may match different arguments. (See manual section 9.5) +val ambiguous__x_y_z : [> `B of 'a * 'a option * 'a option ] -> unit = +val not_ambiguous__disjoint_in_depth : + [> `A of [> `B of bool | `C of bool ] ] -> unit = +val not_ambiguous__prefix_variables_in_depth : + [> `A of [> `B of bool * [> `C1 | `C2 ] ] ] -> unit = +Characters 40-76: + | `A (`B (Some x, _) | `B (_, Some x)) when x -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable x may match different arguments. (See manual section 9.5) +val ambiguous__in_depth : + [> `A of [> `B of bool option * bool option ] ] -> unit = +val not_ambiguous__several_orpats : + [> `A of + [> `B of 'a * 'b option * 'c option ] * + [> `C of 'a * 'd option * 'e option ] * + [> `D1 of 'f * 'a * 'g option * 'h | `D2 of 'i * 'a * 'j * 'k option ] ] -> + unit = +Characters 43-140: + ....`A ((`B (Some x, _) | `B (_, Some x)), + (`C (Some y, Some _, _) | `C (Some y, _, Some _)))................. +Warning 57: Ambiguous or-pattern variables under guard; +variable x may match different arguments. (See manual section 9.5) +val ambiguous__first_orpat : + [> `A of + [> `B of 'a option * 'a option ] * + [> `C of 'a option * 'b option * 'c option ] ] -> + unit = +Characters 44-141: + ....`A ((`B (Some x, Some _, _) | `B (Some x, _, Some _)), + (`C (Some y, _) | `C (_, Some y)))................. +Warning 57: Ambiguous or-pattern variables under guard; +variable y may match different arguments. (See manual section 9.5) +val ambiguous__second_orpat : + [> `A of + [> `B of 'a option * 'b option * 'c option ] * + [> `C of 'a option * 'a option ] ] -> + unit = +val not_ambiguous__pairs : bool * 'a option * 'b option -> unit = +val not_ambiguous__vars : bool -> unit = +val not_ambiguous__as : + ('a list * 'b list -> bool) -> 'a list * 'b list -> unit = +val not_ambiguous__as_var : ('a list * 'b -> bool) -> 'a list * 'b -> unit = + +val not_ambiguous__var_as : + ('a list * 'b -> bool) -> ('a list * 'b) * 'c option * 'd option -> unit = + +val not_ambiguous__lazy : ('a list * 'b list) * bool lazy_t -> unit = +type t = A of int * int option * int option | B +val not_ambiguous__constructor : t -> unit = +type amoi = Z of int | Y of int * int | X of amoi * amoi +Characters 40-73: + ..X (Z x,Y (y,0)) + | X (Z y,Y (x,_)) +Warning 57: Ambiguous or-pattern variables under guard; +variables x,y may match different arguments. (See manual section 9.5) +val ambiguous__amoi : amoi -> int = +module type S = sig val b : bool end +Characters 56-101: + ....(module M:S),_,(1,_) + | _,(module M:S),(_,1)................... +Warning 57: Ambiguous or-pattern variables under guard; +variable M may match different arguments. (See manual section 9.5) +val ambiguous__module_variable : + (module S) * (module S) * (int * int) -> bool -> int = +val not_ambiguous__module_variable : + (module S) * (module S) * (int * int) -> bool -> int = +type t2 = A of int * int | B of int * int +Characters 55-56: + | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 + ^ +Warning 41: A belongs to several types: t2 t +The first one was selected. Please disambiguate if this is wrong. +Characters 42-138: + .........................................function + | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 + | _ -> 2 +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type t2. +Characters 55-107: + | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variables x,y may match different arguments. (See manual section 9.5) +val ambiguous_xy_but_not_ambiguous_z : (int -> int -> bool) -> t2 -> int = + +val not_ambiguous__as_disjoint_on_second_column_split : + int option * int -> unit = +no warning below +val solved_ambiguity_typical_example : expr * expr -> unit = +yet a warning below +Characters 164-189: + | ((Val y, _) | (_, Val y)) when y < 0 -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable y may match different arguments. (See manual section 9.5) +val guarded_ambiguity : expr * expr -> unit = +type a = A1 | A2 +type 'a alg = Val of 'a | Binop of 'a alg * 'a alg +warning below +Characters 100-125: + | ((Val x, _) | (_, Val x)) when pred x -> () + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 57: Ambiguous or-pattern variables under guard; +variable x may match different arguments. (See manual section 9.5) +val cmp : (a -> bool) -> a alg -> a alg -> unit = +type a = A1 +type 'a alg = Val of 'a | Binop of 'a alg * 'a alg +no warning below +val cmp : (a -> bool) -> a alg -> a alg -> unit = + diff --git a/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml b/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml index 2b52368e..9570afd2 100644 --- a/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml +++ b/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; @@ -197,10 +202,86 @@ let not_ambiguous__module_variable x b = match x with (* Mixed case *) -type t = A of int * int | B of int * int +type t2 = A of int * int | B of int * int ;; let ambiguous_xy_but_not_ambiguous_z g = function | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 | _ -> 2 ;; + +(* Regression test against an erroneous simplification of the algorithm + + One cannot compute the stable variable of the first row of a matrix + after its simplification and before splitting the + submatrices. Indeed, further splits on the submatrices may reveal + that some rows of this first column belong to disjoint submatrices, + and thus that the variables are more stable than is visible when + looking at the full column. +*) +let not_ambiguous__as_disjoint_on_second_column_split = function +| ((Some a, (1 as b)) | (Some b, (2 as a))) when a = 0 -> ignore a; ignore b +| _ -> () +;; + +let () = print_endline "no warning below";; +(* we check for the ambiguous case first, so there + is no warning *) +let solved_ambiguity_typical_example = function + | (Val x, Val y) -> + if x < 0 || y < 0 + then () + else () + | ((Val x, _) | (_, Val x)) when x < 0 -> () + | (_, Rest) -> () + | (_, Val x) -> + (* the reader can expect *) + assert (x >= 0); + (* to hold here. *) + () +;; + +let () = print_endline "yet a warning below";; +(* if the check for the ambiguous case is guarded, + there is still a warning *) +let guarded_ambiguity = function + | (Val x, Val y) when x < 0 || y < 0 -> () + | ((Val y, _) | (_, Val y)) when y < 0 -> () + | (_, Rest) -> () + | (_, Val x) -> + (* the reader can expect *) + assert (x >= 0); + (* to hold here. *) + () +;; + +(* see GPR#1552 *) +type a = A1 | A2;; + +type 'a alg = + | Val of 'a + | Binop of 'a alg * 'a alg;; + +let () = print_endline "warning below";; +let cmp (pred : a -> bool) (x : a alg) (y : a alg) = + match x, y with + | Val A1, Val A1 -> () + | ((Val x, _) | (_, Val x)) when pred x -> () + (* below: silence exhaustiveness/fragility warnings *) + | (Val (A1 | A2) | Binop _), _ -> () +;; + +type a = A1;; + +type 'a alg = + | Val of 'a + | Binop of 'a alg * 'a alg;; + +let () = print_endline "no warning below";; +let cmp (pred : a -> bool) (x : a alg) (y : a alg) = + match x, y with + | Val A1, Val A1 -> () + | ((Val x, _) | (_, Val x)) when pred x -> () + (* below: silence exhaustiveness/fragility warnings *) + | (Val A1 | Binop _), _ -> () +;; diff --git a/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml.reference b/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml.reference deleted file mode 100644 index ece388aa..00000000 --- a/testsuite/tests/typing-warnings/ambiguous_guarded_disjunction.ml.reference +++ /dev/null @@ -1,140 +0,0 @@ - -# - : unit = () -# -<---------------------------------------------------------------------- -To check the result file for this test, it suffices to look for "val" -lines corresponding to toplevel answers. If they start with - - val ambiguous_... - -then just above there should be the warning text for Warning 57 -(we try to avoid all other warnings). If they start with - - val not_ambiguous_... - -then just above there should be *no* warning text. -----------------------------------------------------------------------> - -# type expr = Val of int | Rest -# Characters 46-71: - | ((Val x, _) | (_, Val x)) when x < 0 -> () - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variable x may match different arguments. (See manual section 8.5) -val ambiguous_typical_example : expr * expr -> unit = -# Note that an Assert_failure is expected just below. -# Exception: Assert_failure ("//toplevel//", 25, 6). -# val not_ambiguous__no_orpat : int option -> unit = -# val not_ambiguous__no_guard : [< `A | `B | `C ] -> unit = -# val not_ambiguous__no_patvar_in_guard : - bool -> [> `B of 'a | `C of 'a ] -> unit = -# val not_ambiguous__disjoint_cases : [> `B of bool | `C of bool ] -> unit = - -# * * * val not_ambiguous__prefix_variables : - [> `B of bool * 'a option * 'a option ] -> unit = -# Characters 33-72: - | (`B (x, _, Some y) | `B (x, Some y, _)) when y -> ignore x - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variable y may match different arguments. (See manual section 8.5) -val ambiguous__y : [> `B of 'a * bool option * bool option ] -> unit = -# * * * * * * * * val not_ambiguous__rhs_not_protected : - [> `B of 'a * bool option * bool option ] -> unit = -# Characters 35-74: - | (`B (x, _, Some y) | `B (x, Some y, _)) when x < y -> () - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variable y may match different arguments. (See manual section 8.5) -val ambiguous__x_y : [> `B of 'a * 'a option * 'a option ] -> unit = -# Characters 37-76: - | (`B (x, z, Some y) | `B (x, Some y, z)) when x < y || Some x = z -> () - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variables y,z may match different arguments. (See manual section 8.5) -val ambiguous__x_y_z : [> `B of 'a * 'a option * 'a option ] -> unit = -# val not_ambiguous__disjoint_in_depth : - [> `A of [> `B of bool | `C of bool ] ] -> unit = -# val not_ambiguous__prefix_variables_in_depth : - [> `A of [> `B of bool * [> `C1 | `C2 ] ] ] -> unit = -# Characters 40-76: - | `A (`B (Some x, _) | `B (_, Some x)) when x -> () - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variable x may match different arguments. (See manual section 8.5) -val ambiguous__in_depth : - [> `A of [> `B of bool option * bool option ] ] -> unit = -# val not_ambiguous__several_orpats : - [> `A of - [> `B of 'a * 'b option * 'c option ] * - [> `C of 'a * 'd option * 'e option ] * - [> `D1 of 'f * 'a * 'g option * 'h | `D2 of 'i * 'a * 'j * 'k option ] ] -> - unit = -# Characters 43-140: - ....`A ((`B (Some x, _) | `B (_, Some x)), - (`C (Some y, Some _, _) | `C (Some y, _, Some _)))................. -Warning 57: Ambiguous or-pattern variables under guard; -variable x may match different arguments. (See manual section 8.5) -val ambiguous__first_orpat : - [> `A of - [> `B of 'a option * 'a option ] * - [> `C of 'a option * 'b option * 'c option ] ] -> - unit = -# Characters 44-141: - ....`A ((`B (Some x, Some _, _) | `B (Some x, _, Some _)), - (`C (Some y, _) | `C (_, Some y)))................. -Warning 57: Ambiguous or-pattern variables under guard; -variable y may match different arguments. (See manual section 8.5) -val ambiguous__second_orpat : - [> `A of - [> `B of 'a option * 'b option * 'c option ] * - [> `C of 'a option * 'a option ] ] -> - unit = -# val not_ambiguous__pairs : bool * 'a option * 'b option -> unit = -# val not_ambiguous__vars : bool -> unit = -# val not_ambiguous__as : - ('a list * 'b list -> bool) -> 'a list * 'b list -> unit = -# val not_ambiguous__as_var : ('a list * 'b -> bool) -> 'a list * 'b -> unit = - -# val not_ambiguous__var_as : - ('a list * 'b -> bool) -> ('a list * 'b) * 'c option * 'd option -> unit = - -# val not_ambiguous__lazy : ('a list * 'b list) * bool lazy_t -> unit = -# type t = A of int * int option * int option | B -# val not_ambiguous__constructor : t -> unit = -# type amoi = Z of int | Y of int * int | X of amoi * amoi -# Characters 40-73: - ..X (Z x,Y (y,0)) - | X (Z y,Y (x,_)) -Warning 57: Ambiguous or-pattern variables under guard; -variables x,y may match different arguments. (See manual section 8.5) -val ambiguous__amoi : amoi -> int = -# module type S = sig val b : bool end -# Characters 56-101: - ....(module M:S),_,(1,_) - | _,(module M:S),(_,1)................... -Warning 57: Ambiguous or-pattern variables under guard; -variable M may match different arguments. (See manual section 8.5) -val ambiguous__module_variable : - (module S) * (module S) * (int * int) -> bool -> int = -# val not_ambiguous__module_variable : - (module S) * (module S) * (int * int) -> bool -> int = -# type t = A of int * int | B of int * int -# Characters 55-56: - | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 - ^ -Warning 41: A belongs to several types: t t -The first one was selected. Please disambiguate if this is wrong. -Characters 42-138: - .........................................function - | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 - | _ -> 2 -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type t. -Characters 55-107: - | A (x as z,(0 as y))|A (0 as y as z,x)|B (x,(y as z)) when g x (y+z) -> 1 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 57: Ambiguous or-pattern variables under guard; -variables x,y may match different arguments. (See manual section 8.5) -val ambiguous_xy_but_not_ambiguous_z : (int -> int -> bool) -> t -> int = - -# diff --git a/testsuite/tests/typing-warnings/application.compilers.reference b/testsuite/tests/typing-warnings/application.compilers.reference new file mode 100644 index 00000000..f5ec668b --- /dev/null +++ b/testsuite/tests/typing-warnings/application.compilers.reference @@ -0,0 +1,13 @@ +- : unit = () +Characters 16-19: + let _ = ignore (+);; + ^^^ +Warning 5: this function application is partial, +maybe some arguments are missing. +- : unit = () +Characters 19-20: + let _ = raise Exit 3;; + ^ +Warning 20: this argument will not be used by the function. +Exception: Stdlib.Pervasives.Exit. + diff --git a/testsuite/tests/typing-warnings/application.ml b/testsuite/tests/typing-warnings/application.ml index 8948dc8c..0232adc9 100644 --- a/testsuite/tests/typing-warnings/application.ml +++ b/testsuite/tests/typing-warnings/application.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; diff --git a/testsuite/tests/typing-warnings/application.ml.reference b/testsuite/tests/typing-warnings/application.ml.reference deleted file mode 100644 index d35fd40e..00000000 --- a/testsuite/tests/typing-warnings/application.ml.reference +++ /dev/null @@ -1,14 +0,0 @@ - -# - : unit = () -# Characters 16-19: - let _ = ignore (+);; - ^^^ -Warning 5: this function application is partial, -maybe some arguments are missing. -- : unit = () -# Characters 19-20: - let _ = raise Exit 3;; - ^ -Warning 20: this argument will not be used by the function. -Exception: Pervasives.Exit. -# diff --git a/testsuite/tests/typing-warnings/coercions.compilers.principal.reference b/testsuite/tests/typing-warnings/coercions.compilers.principal.reference new file mode 100644 index 00000000..cbc423c7 --- /dev/null +++ b/testsuite/tests/typing-warnings/coercions.compilers.principal.reference @@ -0,0 +1,25 @@ +Characters 168-171: + fun b -> if b then format_of_string "x" else "y";; + ^^^ +Warning 18: this coercion to format6 is not principal. +- : bool -> ('a, 'b, 'c, 'd, 'd, 'a) format6 = +Characters 28-48: + fun b -> if b then "x" else format_of_string "y";; + ^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type + ('a, 'b, 'c, 'd, 'd, 'a) format6 = + ('a, 'b, 'c, 'd, 'd, 'a) CamlinternalFormatBasics.format6 + but an expression was expected of type string +- : bool -> ('a, 'b, 'a) format = +module PR7135 : + sig + module M : sig type t = private int end + type t = M.t + val lift2 : (int -> int -> int) -> t -> t -> int + end +Characters 133-143: + let f x = let y = if true then x else (x:t) in (y :> int) + ^^^^^^^^^^ +Warning 18: this ground coercion is not principal. +module Test1 : sig type t = private int val f : t -> int end + diff --git a/testsuite/tests/typing-warnings/coercions.compilers.reference b/testsuite/tests/typing-warnings/coercions.compilers.reference new file mode 100644 index 00000000..84136fe0 --- /dev/null +++ b/testsuite/tests/typing-warnings/coercions.compilers.reference @@ -0,0 +1,17 @@ +- : bool -> ('a, 'b, 'c, 'd, 'd, 'a) format6 = +Characters 28-48: + fun b -> if b then "x" else format_of_string "y";; + ^^^^^^^^^^^^^^^^^^^^ +Error: This expression has type + ('a, 'b, 'c, 'd, 'd, 'a) format6 = + ('a, 'b, 'c, 'd, 'd, 'a) CamlinternalFormatBasics.format6 + but an expression was expected of type string +- : bool -> ('a, 'b, 'a) format = +module PR7135 : + sig + module M : sig type t = private int end + type t = M.t + val lift2 : (int -> int -> int) -> t -> t -> int + end +module Test1 : sig type t = private int val f : t -> int end + diff --git a/testsuite/tests/typing-warnings/coercions.ml b/testsuite/tests/typing-warnings/coercions.ml index 5fd77e1a..69e17138 100644 --- a/testsuite/tests/typing-warnings/coercions.ml +++ b/testsuite/tests/typing-warnings/coercions.ml @@ -1,3 +1,9 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel + * toplevel with principal +*) + (* comment 9644 of PR#6000 *) fun b -> if b then format_of_string "x" else "y";; diff --git a/testsuite/tests/typing-warnings/coercions.ml.principal.reference b/testsuite/tests/typing-warnings/coercions.ml.principal.reference deleted file mode 100644 index c16dd9f8..00000000 --- a/testsuite/tests/typing-warnings/coercions.ml.principal.reference +++ /dev/null @@ -1,26 +0,0 @@ - -# Characters 76-79: - fun b -> if b then format_of_string "x" else "y";; - ^^^ -Warning 18: this coercion to format6 is not principal. -- : bool -> ('a, 'b, 'c, 'd, 'd, 'a) format6 = -# Characters 28-48: - fun b -> if b then "x" else format_of_string "y";; - ^^^^^^^^^^^^^^^^^^^^ -Error: This expression has type - ('a, 'b, 'c, 'd, 'd, 'a) format6 = - ('a, 'b, 'c, 'd, 'd, 'a) CamlinternalFormatBasics.format6 - but an expression was expected of type string -# - : bool -> ('a, 'b, 'a) format = -# module PR7135 : - sig - module M : sig type t = private int end - type t = M.t - val lift2 : (int -> int -> int) -> t -> t -> int - end -# Characters 133-143: - let f x = let y = if true then x else (x:t) in (y :> int) - ^^^^^^^^^^ -Warning 18: this ground coercion is not principal. -module Test1 : sig type t = private int val f : t -> int end -# diff --git a/testsuite/tests/typing-warnings/coercions.ml.reference b/testsuite/tests/typing-warnings/coercions.ml.reference deleted file mode 100644 index f5ff65b7..00000000 --- a/testsuite/tests/typing-warnings/coercions.ml.reference +++ /dev/null @@ -1,18 +0,0 @@ - -# - : bool -> ('a, 'b, 'c, 'd, 'd, 'a) format6 = -# Characters 28-48: - fun b -> if b then "x" else format_of_string "y";; - ^^^^^^^^^^^^^^^^^^^^ -Error: This expression has type - ('a, 'b, 'c, 'd, 'd, 'a) format6 = - ('a, 'b, 'c, 'd, 'd, 'a) CamlinternalFormatBasics.format6 - but an expression was expected of type string -# - : bool -> ('a, 'b, 'a) format = -# module PR7135 : - sig - module M : sig type t = private int end - type t = M.t - val lift2 : (int -> int -> int) -> t -> t -> int - end -# module Test1 : sig type t = private int val f : t -> int end -# diff --git a/testsuite/tests/typing-warnings/exhaustiveness.compilers.reference b/testsuite/tests/typing-warnings/exhaustiveness.compilers.reference new file mode 100644 index 00000000..03c0fe7c --- /dev/null +++ b/testsuite/tests/typing-warnings/exhaustiveness.compilers.reference @@ -0,0 +1,152 @@ +Characters 121-173: + ........function + None, None -> 1 + | Some _, Some _ -> 2.. +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +((Some _, None)|(None, Some _)) +val f : 'a option * 'b option -> int = +type _ t = A : int t | B : bool t | C : char t | D : float t +type (_, _, _, _) u = U : (int, int, int, int) u +type v = E | F | G +Characters 124-205: + .function A, A, A, A, A, A, A, _, U, U -> 1 + | _, _, _, _, _, _, _, G, _, _ -> 1 +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(A, A, A, A, A, A, B, (E|F), _, _) +Characters 172-200: + | _, _, _, _, _, _, _, G, _, _ -> 1 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 56: this match case is unreachable. +Consider replacing it with a refutation case ' -> .' +val f : + 'a t * 'b t * 'c t * 'd t * 'e t * 'f t * 'g t * v * ('a, 'b, 'c, 'd) u * + ('e, 'f, 'g, 'g) u -> int = +Characters 40-68: + let f (x : int t) = match x with A -> 1 | _ -> 2;; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type t. +Characters 62-63: + let f (x : int t) = match x with A -> 1 | _ -> 2;; (* warn *) + ^ +Warning 56: this match case is unreachable. +Consider replacing it with a refutation case ' -> .' +val f : int t -> int = +Characters 53-54: + let f (x : unit t option) = match x with None -> 1 | _ -> 2 ;; (* warn? *) + ^ +Warning 56: this match case is unreachable. +Consider replacing it with a refutation case ' -> .' +val f : unit t option -> int = +Characters 53-59: + let f (x : unit t option) = match x with None -> 1 | Some _ -> 2 ;; (* warn *) + ^^^^^^ +Warning 56: this match case is unreachable. +Consider replacing it with a refutation case ' -> .' +val f : unit t option -> int = +val f : int t option -> int = +Characters 27-49: + let f (x : int t option) = match x with None -> 1;; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some A +val f : int t option -> int = +type 'a box = Box of 'a +type 'a pair = { left : 'a; right : 'a; } +Characters 50-69: + let f : (int t box pair * bool) option -> unit = function None -> ();; + ^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some ({left=Box A; right=Box A}, _) +val f : (int t box pair * bool) option -> unit = +val f : (string t box pair * bool) option -> unit = +Characters 8-39: + let f = function {left=Box 0; _ } -> ();; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +{left=Box 1; _ } +val f : int box pair -> unit = +Characters 8-47: + let f = function {left=Box 0;right=Box 1} -> ();; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +{left=Box 0; right=Box 0} +val f : int box pair -> unit = +type _ t = Int : int t | Bool : bool t +val f : 'a t -> 'a = +val g : int t -> int = +val h : 'a t -> 'a t -> bool = +type (_, _) cmp = Eq : ('a, 'a) cmp | Any : ('a, 'b) cmp +module A : sig type a type b val eq : (a, b) cmp end +Characters 33-51: + let f : (A.a, A.b) cmp -> unit = function Any -> () + ^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Eq +val f : (A.a, A.b) cmp -> unit = +val deep : char t option -> char = +type zero = Zero +type _ succ = Succ +type (_, _, _) plus = + Plus0 : (zero, 'a, 'a) plus + | PlusS : ('a, 'b, 'c) plus -> ('a succ, 'b, 'c succ) plus +val trivial : (zero succ, zero, zero) plus option -> bool = +val easy : (zero, zero succ, zero) plus option -> bool = +Characters 71-93: + function None -> false + ^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some (PlusS _) +val harder : (zero succ, zero succ, zero succ) plus option -> bool = +val harder : (zero succ, zero succ, zero succ) plus option -> bool = +val inv_zero : ('a, 'b, 'c) plus -> ('c, 'd, zero) plus -> bool = +type _ t = Int : int t +val f : bool t -> 'a = +Characters 54-55: + let f () = match None with _ -> .;; (* error *) + ^ +Error: This match case could not be refuted. + Here is an example of a value that would reach it: _ +Characters 47-48: + let g () = match None with _ -> () | exception _ -> .;; (* error *) + ^ +Error: This match case could not be refuted. + Here is an example of a value that would reach it: _ +Characters 27-28: + let h () = match None with _ -> . | exception _ -> .;; (* error *) + ^ +Error: This match case could not be refuted. + Here is an example of a value that would reach it: _ +val f : 'a option -> unit = +Characters 47-77: + let f x y = match 1 with 1 when x = y -> 1;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +All clauses in this pattern-matching are guarded. +val f : 'a -> 'a -> int = +Characters 62-91: + let f = function {contents=_}, 0 -> 0;; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +(_, 1) +val f : 'a ref * int -> int = +Characters 68-148: + ........function + | None -> () + | Some x when x > 0 -> () + | Some x when x <= 0 -> () +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some _ +(However, some guarded clause may match this value.) +val f : int option -> unit = + diff --git a/testsuite/tests/typing-warnings/exhaustiveness.ml b/testsuite/tests/typing-warnings/exhaustiveness.ml index c1e78a2a..bc79d166 100644 --- a/testsuite/tests/typing-warnings/exhaustiveness.ml +++ b/testsuite/tests/typing-warnings/exhaustiveness.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + (* Warn about all relevant cases when possible *) let f = function None, None -> 1 @@ -111,3 +116,10 @@ let f x y = match 1 with 1 when x = y -> 1;; (* #7504, Example with no constraints on a record *) let f = function {contents=_}, 0 -> 0;; + +(* inexhaustive however some guarded clause might match *) +let f = function + | None -> () + | Some x when x > 0 -> () + | Some x when x <= 0 -> () +;; diff --git a/testsuite/tests/typing-warnings/exhaustiveness.ml.reference b/testsuite/tests/typing-warnings/exhaustiveness.ml.reference deleted file mode 100644 index 0bb5b0b8..00000000 --- a/testsuite/tests/typing-warnings/exhaustiveness.ml.reference +++ /dev/null @@ -1,143 +0,0 @@ - -# Characters 58-110: - ........function - None, None -> 1 - | Some _, Some _ -> 2.. -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -((Some _, None)|(None, Some _)) -val f : 'a option * 'b option -> int = -# type _ t = A : int t | B : bool t | C : char t | D : float t -type (_, _, _, _) u = U : (int, int, int, int) u -type v = E | F | G -# Characters 124-205: - .function A, A, A, A, A, A, A, _, U, U -> 1 - | _, _, _, _, _, _, _, G, _, _ -> 1 -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(A, A, A, A, A, A, B, (E|F), _, _) -Characters 172-200: - | _, _, _, _, _, _, _, G, _, _ -> 1 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 56: this match case is unreachable. -Consider replacing it with a refutation case ' -> .' -val f : - 'a t * 'b t * 'c t * 'd t * 'e t * 'f t * 'g t * v * ('a, 'b, 'c, 'd) u * - ('e, 'f, 'g, 'g) u -> int = -# Characters 40-68: - let f (x : int t) = match x with A -> 1 | _ -> 2;; (* warn *) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type t. -Characters 62-63: - let f (x : int t) = match x with A -> 1 | _ -> 2;; (* warn *) - ^ -Warning 56: this match case is unreachable. -Consider replacing it with a refutation case ' -> .' -val f : int t -> int = -# Characters 53-54: - let f (x : unit t option) = match x with None -> 1 | _ -> 2 ;; (* warn? *) - ^ -Warning 56: this match case is unreachable. -Consider replacing it with a refutation case ' -> .' -val f : unit t option -> int = -# Characters 53-59: - let f (x : unit t option) = match x with None -> 1 | Some _ -> 2 ;; (* warn *) - ^^^^^^ -Warning 56: this match case is unreachable. -Consider replacing it with a refutation case ' -> .' -val f : unit t option -> int = -# val f : int t option -> int = -# Characters 27-49: - let f (x : int t option) = match x with None -> 1;; (* warn *) - ^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Some A -val f : int t option -> int = -# type 'a box = Box of 'a -type 'a pair = { left : 'a; right : 'a; } -# Characters 50-69: - let f : (int t box pair * bool) option -> unit = function None -> ();; - ^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Some ({left=Box A; right=Box A}, _) -val f : (int t box pair * bool) option -> unit = -# val f : (string t box pair * bool) option -> unit = -# Characters 8-39: - let f = function {left=Box 0; _ } -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -{left=Box 1; _ } -val f : int box pair -> unit = -# Characters 8-47: - let f = function {left=Box 0;right=Box 1} -> ();; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -{left=Box 0; right=Box 0} -val f : int box pair -> unit = -# type _ t = Int : int t | Bool : bool t -# val f : 'a t -> 'a = -# val g : int t -> int = -# val h : 'a t -> 'a t -> bool = -# type (_, _) cmp = Eq : ('a, 'a) cmp | Any : ('a, 'b) cmp -module A : sig type a type b val eq : (a, b) cmp end -# Characters 33-51: - let f : (A.a, A.b) cmp -> unit = function Any -> () - ^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Eq -val f : (A.a, A.b) cmp -> unit = -# val deep : char t option -> char = -# type zero = Zero -type _ succ = Succ -# type (_, _, _) plus = - Plus0 : (zero, 'a, 'a) plus - | PlusS : ('a, 'b, 'c) plus -> ('a succ, 'b, 'c succ) plus -# val trivial : (zero succ, zero, zero) plus option -> bool = -# val easy : (zero, zero succ, zero) plus option -> bool = -# Characters 71-93: - function None -> false - ^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Some (PlusS _) -val harder : (zero succ, zero succ, zero succ) plus option -> bool = -# val harder : (zero succ, zero succ, zero succ) plus option -> bool = -# val inv_zero : ('a, 'b, 'c) plus -> ('c, 'd, zero) plus -> bool = -# type _ t = Int : int t -# val f : bool t -> 'a = -# Characters 54-55: - let f () = match None with _ -> .;; (* error *) - ^ -Error: This match case could not be refuted. - Here is an example of a value that would reach it: _ -# Characters 47-48: - let g () = match None with _ -> () | exception _ -> .;; (* error *) - ^ -Error: This match case could not be refuted. - Here is an example of a value that would reach it: _ -# Characters 27-28: - let h () = match None with _ -> . | exception _ -> .;; (* error *) - ^ -Error: This match case could not be refuted. - Here is an example of a value that would reach it: _ -# val f : 'a option -> unit = -# Characters 47-77: - let f x y = match 1 with 1 when x = y -> 1;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -All clauses in this pattern-matching are guarded. -val f : 'a -> 'a -> int = -# Characters 62-91: - let f = function {contents=_}, 0 -> 0;; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -(_, 1) -val f : 'a ref * int -> int = -# diff --git a/testsuite/tests/typing-warnings/ocamltests b/testsuite/tests/typing-warnings/ocamltests new file mode 100644 index 00000000..46b2664e --- /dev/null +++ b/testsuite/tests/typing-warnings/ocamltests @@ -0,0 +1,14 @@ +ambiguous_guarded_disjunction.ml +application.ml +coercions.ml +exhaustiveness.ml +pr5892.ml +pr6587.ml +pr6872.ml +pr7085.ml +pr7115.ml +pr7261.ml +pr7297.ml +pr7553.ml +records.ml +unused_types.ml diff --git a/testsuite/tests/typing-warnings/pr5892.compilers.reference b/testsuite/tests/typing-warnings/pr5892.compilers.reference new file mode 100644 index 00000000..3c195d93 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr5892.compilers.reference @@ -0,0 +1,11 @@ +type _ choice = + Left : CamlinternalOO.label choice + | Right : CamlinternalOO.tag choice +Characters 31-52: + let f : label choice -> bool = function Left -> true;; (* warn *) + ^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Right +val f : CamlinternalOO.label choice -> bool = + diff --git a/testsuite/tests/typing-warnings/pr5892.ml b/testsuite/tests/typing-warnings/pr5892.ml index bbc73b55..a1ac2b31 100644 --- a/testsuite/tests/typing-warnings/pr5892.ml +++ b/testsuite/tests/typing-warnings/pr5892.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + open CamlinternalOO;; type _ choice = Left : label choice | Right : tag choice;; let f : label choice -> bool = function Left -> true;; (* warn *) diff --git a/testsuite/tests/typing-warnings/pr5892.ml.reference b/testsuite/tests/typing-warnings/pr5892.ml.reference deleted file mode 100644 index e56687af..00000000 --- a/testsuite/tests/typing-warnings/pr5892.ml.reference +++ /dev/null @@ -1,12 +0,0 @@ - -# # type _ choice = - Left : CamlinternalOO.label choice - | Right : CamlinternalOO.tag choice -# Characters 31-52: - let f : label choice -> bool = function Left -> true;; (* warn *) - ^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Right -val f : CamlinternalOO.label choice -> bool = -# diff --git a/testsuite/tests/typing-warnings/pr6587.compilers.reference b/testsuite/tests/typing-warnings/pr6587.compilers.reference new file mode 100644 index 00000000..5b46ca55 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr6587.compilers.reference @@ -0,0 +1,16 @@ +module A : sig val f : fpclass -> fpclass end +type fpclass = A +Characters 49-85: + ..struct + let f A = FP_normal + end +Error: Signature mismatch: + Modules do not match: + sig val f : fpclass -> Stdlib.fpclass end + is not included in + sig val f : fpclass -> fpclass end + Values do not match: + val f : fpclass -> Stdlib.fpclass + is not included in + val f : fpclass -> fpclass + diff --git a/testsuite/tests/typing-warnings/pr6587.ml b/testsuite/tests/typing-warnings/pr6587.ml index ec51f696..96cd8949 100644 --- a/testsuite/tests/typing-warnings/pr6587.ml +++ b/testsuite/tests/typing-warnings/pr6587.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + module A: sig val f: fpclass -> fpclass end = struct diff --git a/testsuite/tests/typing-warnings/pr6587.ml.reference b/testsuite/tests/typing-warnings/pr6587.ml.reference deleted file mode 100644 index 81286b41..00000000 --- a/testsuite/tests/typing-warnings/pr6587.ml.reference +++ /dev/null @@ -1,17 +0,0 @@ - -# module A : sig val f : fpclass -> fpclass end -# type fpclass = A -# Characters 49-85: - ..struct - let f A = FP_normal - end -Error: Signature mismatch: - Modules do not match: - sig val f : fpclass -> Pervasives.fpclass end - is not included in - sig val f : fpclass -> fpclass end - Values do not match: - val f : fpclass -> Pervasives.fpclass - is not included in - val f : fpclass -> fpclass -# diff --git a/testsuite/tests/typing-warnings/pr6872.compilers.principal.reference b/testsuite/tests/typing-warnings/pr6872.compilers.principal.reference new file mode 100644 index 00000000..f4b8f013 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr6872.compilers.principal.reference @@ -0,0 +1,38 @@ +- : unit = () +exception A +type a = A +Characters 1-2: + A;; + ^ +Warning 41: A belongs to several types: a exn +The first one was selected. Please disambiguate if this is wrong. +- : a = A +Characters 6-7: + raise A;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Exception: A. +- : a -> unit = +Characters 26-27: + function Not_found -> 1 | A -> 2 | _ -> 3;; + ^ +Warning 41: A belongs to several types: a exn +The first one was selected. Please disambiguate if this is wrong. +Characters 26-27: + function Not_found -> 1 | A -> 2 | _ -> 3;; + ^ +Error: This pattern matches values of type a + but a pattern was expected which matches values of type exn +Characters 10-11: + try raise A with A -> 2;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 17-18: + try raise A with A -> 2;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +- : int = 2 + diff --git a/testsuite/tests/typing-warnings/pr6872.compilers.reference b/testsuite/tests/typing-warnings/pr6872.compilers.reference new file mode 100644 index 00000000..f852c1b9 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr6872.compilers.reference @@ -0,0 +1,34 @@ +- : unit = () +exception A +type a = A +Characters 1-2: + A;; + ^ +Warning 41: A belongs to several types: a exn +The first one was selected. Please disambiguate if this is wrong. +- : a = A +Characters 6-7: + raise A;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Exception: A. +- : a -> unit = +Characters 26-27: + function Not_found -> 1 | A -> 2 | _ -> 3;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +- : exn -> int = +Characters 10-11: + try raise A with A -> 2;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 17-18: + try raise A with A -> 2;; + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +- : int = 2 + diff --git a/testsuite/tests/typing-warnings/pr6872.ml b/testsuite/tests/typing-warnings/pr6872.ml index 73870a02..86cc9a96 100644 --- a/testsuite/tests/typing-warnings/pr6872.ml +++ b/testsuite/tests/typing-warnings/pr6872.ml @@ -1,3 +1,9 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel + * toplevel with principal +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; diff --git a/testsuite/tests/typing-warnings/pr6872.ml.principal.reference b/testsuite/tests/typing-warnings/pr6872.ml.principal.reference deleted file mode 100644 index 616b4548..00000000 --- a/testsuite/tests/typing-warnings/pr6872.ml.principal.reference +++ /dev/null @@ -1,39 +0,0 @@ - -# - : unit = () -# exception A -# type a = A -# Characters 1-2: - A;; - ^ -Warning 41: A belongs to several types: a exn -The first one was selected. Please disambiguate if this is wrong. -- : a = A -# Characters 6-7: - raise A;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Exception: A. -# - : a -> unit = -# Characters 26-27: - function Not_found -> 1 | A -> 2 | _ -> 3;; - ^ -Warning 41: A belongs to several types: a exn -The first one was selected. Please disambiguate if this is wrong. -Characters 26-27: - function Not_found -> 1 | A -> 2 | _ -> 3;; - ^ -Error: This pattern matches values of type a - but a pattern was expected which matches values of type exn -# Characters 10-11: - try raise A with A -> 2;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 17-18: - try raise A with A -> 2;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -- : int = 2 -# diff --git a/testsuite/tests/typing-warnings/pr6872.ml.reference b/testsuite/tests/typing-warnings/pr6872.ml.reference deleted file mode 100644 index 5cd4291f..00000000 --- a/testsuite/tests/typing-warnings/pr6872.ml.reference +++ /dev/null @@ -1,35 +0,0 @@ - -# - : unit = () -# exception A -# type a = A -# Characters 1-2: - A;; - ^ -Warning 41: A belongs to several types: a exn -The first one was selected. Please disambiguate if this is wrong. -- : a = A -# Characters 6-7: - raise A;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Exception: A. -# - : a -> unit = -# Characters 26-27: - function Not_found -> 1 | A -> 2 | _ -> 3;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -- : exn -> int = -# Characters 10-11: - try raise A with A -> 2;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 17-18: - try raise A with A -> 2;; - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -- : int = 2 -# diff --git a/testsuite/tests/typing-warnings/pr7085.compilers.reference b/testsuite/tests/typing-warnings/pr7085.compilers.reference new file mode 100644 index 00000000..3b24db3f --- /dev/null +++ b/testsuite/tests/typing-warnings/pr7085.compilers.reference @@ -0,0 +1,19 @@ +Characters 355-385: + match M.is_t () with None -> 0 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some (Is Eq) +module TypEq : sig type (_, _) t = Eq : ('a, 'a) t end +module type T = + sig + type _ is_t = Is : ('a, 'b) TypEq.t -> 'a is_t + val is_t : unit -> unit is_t option + end +module Make : functor (M : T) -> sig val f : unit -> int end +Characters 89-90: + let g : t -> int = function _ -> . + ^ +Error: This match case could not be refuted. + Here is an example of a value that would reach it: T (Is Eq) + diff --git a/testsuite/tests/typing-warnings/pr7085.ml b/testsuite/tests/typing-warnings/pr7085.ml index 21ca0d67..b2185c92 100644 --- a/testsuite/tests/typing-warnings/pr7085.ml +++ b/testsuite/tests/typing-warnings/pr7085.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + module TypEq = struct type (_, _) t = Eq : ('a, 'a) t end diff --git a/testsuite/tests/typing-warnings/pr7085.ml.reference b/testsuite/tests/typing-warnings/pr7085.ml.reference deleted file mode 100644 index 3a54d4ad..00000000 --- a/testsuite/tests/typing-warnings/pr7085.ml.reference +++ /dev/null @@ -1,20 +0,0 @@ - -# Characters 292-322: - match M.is_t () with None -> 0 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Some (Is Eq) -module TypEq : sig type (_, _) t = Eq : ('a, 'a) t end -module type T = - sig - type _ is_t = Is : ('a, 'b) TypEq.t -> 'a is_t - val is_t : unit -> unit is_t option - end -module Make : functor (M : T) -> sig val f : unit -> int end -# Characters 89-90: - let g : t -> int = function _ -> . - ^ -Error: This match case could not be refuted. - Here is an example of a value that would reach it: T (Is Eq) -# diff --git a/testsuite/tests/typing-warnings/pr7115.compilers.reference b/testsuite/tests/typing-warnings/pr7115.compilers.reference new file mode 100644 index 00000000..1d795c1a --- /dev/null +++ b/testsuite/tests/typing-warnings/pr7115.compilers.reference @@ -0,0 +1,21 @@ +type t = A : t +Characters 40-41: + let _f ~x (* x unused argument *) = function + ^ +Warning 27: unused variable x. +module X1 : sig end +Characters 36-37: + let x = 42 (* unused value *) + ^ +Warning 32: unused value x. +module X2 : sig end +Characters 54-55: + module O = struct let x = 42 (* unused *) end + ^ +Warning 32: unused value x. +Characters 80-86: + open O (* unused open *) + ^^^^^^ +Warning 33: unused open O. +module X3 : sig end + diff --git a/testsuite/tests/typing-warnings/pr7115.ml b/testsuite/tests/typing-warnings/pr7115.ml old mode 100755 new mode 100644 index 1a892061..b8a6c6fc --- a/testsuite/tests/typing-warnings/pr7115.ml +++ b/testsuite/tests/typing-warnings/pr7115.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + type t = A : t;; module X1 : sig end = struct diff --git a/testsuite/tests/typing-warnings/pr7115.ml.reference b/testsuite/tests/typing-warnings/pr7115.ml.reference deleted file mode 100644 index 8a4fcd6a..00000000 --- a/testsuite/tests/typing-warnings/pr7115.ml.reference +++ /dev/null @@ -1,22 +0,0 @@ - -# type t = A : t -# Characters 40-41: - let _f ~x (* x unused argument *) = function - ^ -Warning 27: unused variable x. -module X1 : sig end -# Characters 36-37: - let x = 42 (* unused value *) - ^ -Warning 32: unused value x. -module X2 : sig end -# Characters 54-55: - module O = struct let x = 42 (* unused *) end - ^ -Warning 32: unused value x. -Characters 80-86: - open O (* unused open *) - ^^^^^^ -Warning 33: unused open O. -module X3 : sig end -# diff --git a/testsuite/tests/typing-warnings/pr7261.compilers.reference b/testsuite/tests/typing-warnings/pr7261.compilers.reference new file mode 100644 index 00000000..6c66e6d9 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr7261.compilers.reference @@ -0,0 +1,10 @@ +Characters 93-95: + Foo: [> `Bla ] as 'b ) * 'b -> foo;; + ^^ +Error: Syntax error +Characters 46-60: + Foo: 'b * 'b -> foo constraint 'b = [> `Bla ];; + ^^^^^^^^^^^^^^ +Warning 62: Type constraints do not apply to GADT cases of variant types. +type foo = Foo : 'b * 'b -> foo + diff --git a/testsuite/tests/typing-warnings/pr7261.ml b/testsuite/tests/typing-warnings/pr7261.ml index aa2c5bd0..ecbbdda2 100644 --- a/testsuite/tests/typing-warnings/pr7261.ml +++ b/testsuite/tests/typing-warnings/pr7261.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + type foo = Foo: [> `Bla ] as 'b ) * 'b -> foo;; type foo = diff --git a/testsuite/tests/typing-warnings/pr7261.ml.reference b/testsuite/tests/typing-warnings/pr7261.ml.reference deleted file mode 100644 index cc66d883..00000000 --- a/testsuite/tests/typing-warnings/pr7261.ml.reference +++ /dev/null @@ -1,11 +0,0 @@ - -# Characters 30-32: - Foo: [> `Bla ] as 'b ) * 'b -> foo;; - ^^ -Error: Syntax error -# Characters 46-60: - Foo: 'b * 'b -> foo constraint 'b = [> `Bla ];; - ^^^^^^^^^^^^^^ -Warning 62: Type constraints do not apply to GADT cases of variant types. -type foo = Foo : 'b * 'b -> foo -# diff --git a/testsuite/tests/typing-warnings/pr7297.compilers.reference b/testsuite/tests/typing-warnings/pr7297.compilers.reference new file mode 100644 index 00000000..b8926110 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr7297.compilers.reference @@ -0,0 +1,7 @@ +- : unit = () +Characters 10-20: + let () = raise Exit; () ;; (* warn *) + ^^^^^^^^^^ +Warning 21: this statement never returns (or has an unsound type.) +Exception: Stdlib.Pervasives.Exit. + diff --git a/testsuite/tests/typing-warnings/pr7297.ml b/testsuite/tests/typing-warnings/pr7297.ml index f55c0a32..055823f0 100644 --- a/testsuite/tests/typing-warnings/pr7297.ml +++ b/testsuite/tests/typing-warnings/pr7297.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false;; diff --git a/testsuite/tests/typing-warnings/pr7297.ml.reference b/testsuite/tests/typing-warnings/pr7297.ml.reference deleted file mode 100644 index bc8580fc..00000000 --- a/testsuite/tests/typing-warnings/pr7297.ml.reference +++ /dev/null @@ -1,8 +0,0 @@ - -# - : unit = () -# Characters 10-20: - let () = raise Exit; () ;; (* warn *) - ^^^^^^^^^^ -Warning 21: this statement never returns (or has an unsound type.) -Exception: Pervasives.Exit. -# diff --git a/testsuite/tests/typing-warnings/pr7553.compilers.reference b/testsuite/tests/typing-warnings/pr7553.compilers.reference new file mode 100644 index 00000000..7a173ed7 --- /dev/null +++ b/testsuite/tests/typing-warnings/pr7553.compilers.reference @@ -0,0 +1,19 @@ +module A : sig type foo end +module rec B : sig type bar = Bar of A.foo end +Characters 22-28: + open A + ^^^^^^ +Warning 33: unused open A. +module rec C : sig end +Characters 110-114: + let None = None + ^^^^ +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +Some _ +Characters 93-99: + open A + ^^^^^^ +Warning 33: unused open A. +module rec D : sig module M : sig module X : sig end end end + diff --git a/testsuite/tests/typing-warnings/pr7553.ml b/testsuite/tests/typing-warnings/pr7553.ml index 8e526d6f..70b968e7 100644 --- a/testsuite/tests/typing-warnings/pr7553.ml +++ b/testsuite/tests/typing-warnings/pr7553.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + module A = struct type foo end;; module rec B : sig diff --git a/testsuite/tests/typing-warnings/pr7553.ml.reference b/testsuite/tests/typing-warnings/pr7553.ml.reference deleted file mode 100644 index ead6b028..00000000 --- a/testsuite/tests/typing-warnings/pr7553.ml.reference +++ /dev/null @@ -1,20 +0,0 @@ - -# module A : sig type foo end -# module rec B : sig type bar = Bar of A.foo end -# Characters 22-28: - open A - ^^^^^^ -Warning 33: unused open A. -module rec C : sig end -# Characters 110-114: - let None = None - ^^^^ -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -Some _ -Characters 93-99: - open A - ^^^^^^ -Warning 33: unused open A. -module rec D : sig module M : sig module X : sig end end end -# diff --git a/testsuite/tests/typing-warnings/records.compilers.principal.reference b/testsuite/tests/typing-warnings/records.compilers.principal.reference new file mode 100644 index 00000000..38e5e0fd --- /dev/null +++ b/testsuite/tests/typing-warnings/records.compilers.principal.reference @@ -0,0 +1,320 @@ +module M1 : + sig type t = { x : int; y : int; } type u = { x : bool; y : bool; } end +Characters 49-50: + let f1 (r:t) = r.x (* ok *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 89-90: + let f2 r = ignore (r:t); r.x (* non principal *) + ^ +Warning 18: this type-based field disambiguation is not principal. +Characters 89-90: + let f2 r = ignore (r:t); r.x (* non principal *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 148-149: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 151-152: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 148-149: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 27: unused variable x. +module OK : + sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end +Characters 55-61: + let f r = match r with {x; y} -> y + y + ^^^^^^ +Warning 41: these field labels belong to several types: M1.u M1.t +The first one was selected. Please disambiguate if this is wrong. +Characters 65-66: + let f r = match r with {x; y} -> y + y + ^ +Error: This expression has type bool but an expression was expected of type + int +Characters 85-91: + {x; y} -> y + y + ^^^^^^ +Warning 41: these field labels belong to several types: M1.u M1.t +The first one was selected. Please disambiguate if this is wrong. +Characters 85-91: + {x; y} -> y + y + ^^^^^^ +Error: This pattern matches values of type M1.u + but a pattern was expected which matches values of type M1.t +module M : sig type t = { x : int; } type u = { x : bool; } end +Characters 18-21: + let f (r:M.t) = r.M.x;; (* ok *) + ^^^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +val f : M.t -> int = +Characters 18-19: + let f (r:M.t) = r.x;; (* warning *) + ^ +Warning 40: x was selected from type M.t. +It is not visible in the current scope, and will not +be selected if the type becomes unknown. +Characters 18-19: + let f (r:M.t) = r.x;; (* warning *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +val f : M.t -> int = +Characters 8-9: + let f ({x}:M.t) = x;; (* warning *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 7-10: + let f ({x}:M.t) = x;; (* warning *) + ^^^ +Warning 40: this record of type M.t contains fields that are +not visible in the current scope: x. +They will not be selected if the type becomes unknown. +val f : M.t -> int = +module M : sig type t = { x : int; y : int; } end +module N : sig type u = { x : bool; y : bool; } end +Characters 57-58: + let f (r:M.t) = r.x + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 30-36: + open N + ^^^^^^ +Warning 33: unused open N. +module OK : sig val f : M.t -> int end +module M : + sig + type t = { x : int; } + module N : sig type s = t = { x : int; } end + type u = { x : bool; } + end +module OK : sig val f : M.t -> int end +module M : + sig + type u = { x : bool; y : int; z : char; } + type t = { x : int; y : bool; } + end +Characters 37-38: + let f {x;z} = x,z + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 36-41: + let f {x;z} = x,z + ^^^^^ +Warning 9: the following labels are not bound in this record pattern: +y +Either bind these labels explicitly or add '; _' to the pattern. +module OK : sig val f : M.u -> bool * char end +Characters 38-52: + let r = {x=true;z='z'} + ^^^^^^^^^^^^^^ +Error: Some record fields are undefined: y +Characters 90-91: + let r = {x=3; y=true} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 95-96: + let r = {x=3; y=true} + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +module OK : + sig + type u = { x : int; y : bool; } + type t = { x : bool; y : int; z : char; } + val r : u + end +Characters 111-112: + let b : bar = {x=3; y=4} + ^ +Error: This record expression is expected to have type bar + The field y does not belong to type bar +module M : sig type foo = { x : int; y : int; } end +module N : sig type bar = { x : int; y : int; } end +Characters 19-22: + let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) + ^^^ +Error: The record field N.y belongs to the type N.bar + but is mixed here with fields of type M.foo +module MN : + sig + type foo = M.foo = { x : int; y : int; } + type bar = N.bar = { x : int; y : int; } + end +module NM : + sig + type bar = N.bar = { x : int; y : int; } + type foo = M.foo = { x : int; y : int; } + end +Characters 8-28: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^^^^^^^^^^^^^^^^^ +Warning 41: x belongs to several types: MN.bar MN.foo +The first one was selected. Please disambiguate if this is wrong. +Characters 8-28: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^^^^^^^^^^^^^^^^^ +Warning 41: y belongs to several types: NM.foo NM.bar +The first one was selected. Please disambiguate if this is wrong. +Characters 19-23: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^ +Error: The record field NM.y belongs to the type NM.foo = M.foo + but is mixed here with fields of type MN.bar = N.bar +module M : + sig + type foo = { x : int; y : int; } + type bar = { x : int; y : int; z : int; } + end +Characters 65-66: + let f r = ignore (r: foo); {r with x = 2; z = 3} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 72-73: + let f r = ignore (r: foo); {r with x = 2; z = 3} + ^ +Error: This record expression is expected to have type M.foo + The field z does not belong to type M.foo +module M : + sig + type foo = M.foo = { x : int; y : int; } + type bar = M.bar = { x : int; y : int; z : int; } + type other = { a : int; b : int; } + end +Characters 66-67: + let f r = ignore (r: foo); { r with x = 3; a = 4 } + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 73-74: + let f r = ignore (r: foo); { r with x = 3; a = 4 } + ^ +Error: This record expression is expected to have type M.foo + The field a does not belong to type M.foo +Characters 39-40: + let r = {x=1; y=2} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 44-45: + let r = {x=1; y=2} + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 67-68: + let r: other = {x=1; y=2} + ^ +Error: This record expression is expected to have type M.other + The field x does not belong to type M.other +module A : sig type t = { x : int; } end +module B : sig type t = { x : int; } end +Characters 20-23: + let f (r : B.t) = r.A.x;; (* fail *) + ^^^ +Error: The field A.x belongs to the record type A.t + but a field was expected belonging to the record type B.t +Characters 88-91: + let a : t = {x=1;yyz=2} + ^^^ +Error: This record expression is expected to have type t + The field yyz does not belong to type t +Hint: Did you mean yyy? +type t = A +type s = A +class f : t -> object end +Characters 12-13: + class g = f A;; (* ok *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +class g : f +class f : 'a -> 'a -> object end +Characters 13-14: + class g = f (A : t) A;; (* warn with -principal *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 20-21: + class g = f (A : t) A;; (* warn with -principal *) + ^ +Warning 18: this type-based constructor disambiguation is not principal. +Characters 20-21: + class g = f (A : t) A;; (* warn with -principal *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +class g : f +Characters 199-200: + let y : t = {x = 0} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 114-120: + open M (* this open is unused, it isn't reported as shadowing 'x' *) + ^^^^^^ +Warning 33: unused open M. +module Shadow1 : + sig + type t = { x : int; } + module M : sig type s = { x : string; } end + val y : t + end +Characters 97-103: + open M (* this open shadows label 'x' *) + ^^^^^^ +Warning 45: this open statement shadows the label x (which is later used) +Characters 149-157: + let y = {x = ""} + ^^^^^^^^ +Warning 41: these field labels belong to several types: M.s t +The first one was selected. Please disambiguate if this is wrong. +module Shadow2 : + sig + type t = { x : int; } + module M : sig type s = { x : string; } end + val y : M.s + end +Characters 167-170: + let f (u : u) = match u with `Key {loc} -> loc + ^^^ +Warning 42: this use of loc relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +module P6235 : + sig + type t = { loc : string; } + type v = { loc : string; x : int; } + type u = [ `Key of t ] + val f : u -> string + end +Characters 219-224: + |`Key {loc} -> loc + ^^^^^ +Warning 41: these field labels belong to several types: v t +The first one was selected. Please disambiguate if this is wrong. +Characters 219-224: + |`Key {loc} -> loc + ^^^^^ +Warning 9: the following labels are not bound in this record pattern: +x +Either bind these labels explicitly or add '; _' to the pattern. +Characters 214-224: + |`Key {loc} -> loc + ^^^^^^^^^^ +Error: This pattern matches values of type [? `Key of v ] + but a pattern was expected which matches values of type u + Types for tag `Key are incompatible + diff --git a/testsuite/tests/typing-warnings/records.compilers.reference b/testsuite/tests/typing-warnings/records.compilers.reference new file mode 100644 index 00000000..0864f679 --- /dev/null +++ b/testsuite/tests/typing-warnings/records.compilers.reference @@ -0,0 +1,312 @@ +module M1 : + sig type t = { x : int; y : int; } type u = { x : bool; y : bool; } end +Characters 49-50: + let f1 (r:t) = r.x (* ok *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 89-90: + let f2 r = ignore (r:t); r.x (* non principal *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 148-149: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 151-152: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 148-149: + match r with {x; y} -> y + y (* ok *) + ^ +Warning 27: unused variable x. +module OK : + sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end +Characters 55-61: + let f r = match r with {x; y} -> y + y + ^^^^^^ +Warning 41: these field labels belong to several types: M1.u M1.t +The first one was selected. Please disambiguate if this is wrong. +Characters 65-66: + let f r = match r with {x; y} -> y + y + ^ +Error: This expression has type bool but an expression was expected of type + int +Characters 86-87: + {x; y} -> y + y + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 89-90: + {x; y} -> y + y + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 86-87: + {x; y} -> y + y + ^ +Warning 27: unused variable x. +module F2 : sig val f : M1.t -> int end +module M : sig type t = { x : int; } type u = { x : bool; } end +Characters 18-21: + let f (r:M.t) = r.M.x;; (* ok *) + ^^^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +val f : M.t -> int = +Characters 18-19: + let f (r:M.t) = r.x;; (* warning *) + ^ +Warning 40: x was selected from type M.t. +It is not visible in the current scope, and will not +be selected if the type becomes unknown. +Characters 18-19: + let f (r:M.t) = r.x;; (* warning *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +val f : M.t -> int = +Characters 8-9: + let f ({x}:M.t) = x;; (* warning *) + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 7-10: + let f ({x}:M.t) = x;; (* warning *) + ^^^ +Warning 40: this record of type M.t contains fields that are +not visible in the current scope: x. +They will not be selected if the type becomes unknown. +val f : M.t -> int = +module M : sig type t = { x : int; y : int; } end +module N : sig type u = { x : bool; y : bool; } end +Characters 57-58: + let f (r:M.t) = r.x + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 30-36: + open N + ^^^^^^ +Warning 33: unused open N. +module OK : sig val f : M.t -> int end +module M : + sig + type t = { x : int; } + module N : sig type s = t = { x : int; } end + type u = { x : bool; } + end +module OK : sig val f : M.t -> int end +module M : + sig + type u = { x : bool; y : int; z : char; } + type t = { x : int; y : bool; } + end +Characters 37-38: + let f {x;z} = x,z + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 36-41: + let f {x;z} = x,z + ^^^^^ +Warning 9: the following labels are not bound in this record pattern: +y +Either bind these labels explicitly or add '; _' to the pattern. +module OK : sig val f : M.u -> bool * char end +Characters 38-52: + let r = {x=true;z='z'} + ^^^^^^^^^^^^^^ +Error: Some record fields are undefined: y +Characters 90-91: + let r = {x=3; y=true} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 95-96: + let r = {x=3; y=true} + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +module OK : + sig + type u = { x : int; y : bool; } + type t = { x : bool; y : int; z : char; } + val r : u + end +Characters 111-112: + let b : bar = {x=3; y=4} + ^ +Error: This record expression is expected to have type bar + The field y does not belong to type bar +module M : sig type foo = { x : int; y : int; } end +module N : sig type bar = { x : int; y : int; } end +Characters 19-22: + let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) + ^^^ +Error: The record field N.y belongs to the type N.bar + but is mixed here with fields of type M.foo +module MN : + sig + type foo = M.foo = { x : int; y : int; } + type bar = N.bar = { x : int; y : int; } + end +module NM : + sig + type bar = N.bar = { x : int; y : int; } + type foo = M.foo = { x : int; y : int; } + end +Characters 8-28: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^^^^^^^^^^^^^^^^^ +Warning 41: x belongs to several types: MN.bar MN.foo +The first one was selected. Please disambiguate if this is wrong. +Characters 8-28: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^^^^^^^^^^^^^^^^^ +Warning 41: y belongs to several types: NM.foo NM.bar +The first one was selected. Please disambiguate if this is wrong. +Characters 19-23: + let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) + ^^^^ +Error: The record field NM.y belongs to the type NM.foo = M.foo + but is mixed here with fields of type MN.bar = N.bar +module M : + sig + type foo = { x : int; y : int; } + type bar = { x : int; y : int; z : int; } + end +Characters 65-66: + let f r = ignore (r: foo); {r with x = 2; z = 3} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 72-73: + let f r = ignore (r: foo); {r with x = 2; z = 3} + ^ +Error: This record expression is expected to have type M.foo + The field z does not belong to type M.foo +module M : + sig + type foo = M.foo = { x : int; y : int; } + type bar = M.bar = { x : int; y : int; z : int; } + type other = { a : int; b : int; } + end +Characters 66-67: + let f r = ignore (r: foo); { r with x = 3; a = 4 } + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 73-74: + let f r = ignore (r: foo); { r with x = 3; a = 4 } + ^ +Error: This record expression is expected to have type M.foo + The field a does not belong to type M.foo +Characters 39-40: + let r = {x=1; y=2} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 44-45: + let r = {x=1; y=2} + ^ +Warning 42: this use of y relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 67-68: + let r: other = {x=1; y=2} + ^ +Error: This record expression is expected to have type M.other + The field x does not belong to type M.other +module A : sig type t = { x : int; } end +module B : sig type t = { x : int; } end +Characters 20-23: + let f (r : B.t) = r.A.x;; (* fail *) + ^^^ +Error: The field A.x belongs to the record type A.t + but a field was expected belonging to the record type B.t +Characters 88-91: + let a : t = {x=1;yyz=2} + ^^^ +Error: This record expression is expected to have type t + The field yyz does not belong to type t +Hint: Did you mean yyy? +type t = A +type s = A +class f : t -> object end +Characters 12-13: + class g = f A;; (* ok *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +class g : f +class f : 'a -> 'a -> object end +Characters 13-14: + class g = f (A : t) A;; (* warn with -principal *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 20-21: + class g = f (A : t) A;; (* warn with -principal *) + ^ +Warning 42: this use of A relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +class g : f +Characters 199-200: + let y : t = {x = 0} + ^ +Warning 42: this use of x relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +Characters 114-120: + open M (* this open is unused, it isn't reported as shadowing 'x' *) + ^^^^^^ +Warning 33: unused open M. +module Shadow1 : + sig + type t = { x : int; } + module M : sig type s = { x : string; } end + val y : t + end +Characters 97-103: + open M (* this open shadows label 'x' *) + ^^^^^^ +Warning 45: this open statement shadows the label x (which is later used) +Characters 149-157: + let y = {x = ""} + ^^^^^^^^ +Warning 41: these field labels belong to several types: M.s t +The first one was selected. Please disambiguate if this is wrong. +module Shadow2 : + sig + type t = { x : int; } + module M : sig type s = { x : string; } end + val y : M.s + end +Characters 167-170: + let f (u : u) = match u with `Key {loc} -> loc + ^^^ +Warning 42: this use of loc relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +module P6235 : + sig + type t = { loc : string; } + type v = { loc : string; x : int; } + type u = [ `Key of t ] + val f : u -> string + end +Characters 220-223: + |`Key {loc} -> loc + ^^^ +Warning 42: this use of loc relies on type-directed disambiguation, +it will not compile with OCaml 4.00 or earlier. +module P6235' : + sig + type t = { loc : string; } + type v = { loc : string; x : int; } + type u = [ `Key of t ] + val f : u -> string + end + diff --git a/testsuite/tests/typing-warnings/records.ml b/testsuite/tests/typing-warnings/records.ml index 768bb965..52663ec2 100644 --- a/testsuite/tests/typing-warnings/records.ml +++ b/testsuite/tests/typing-warnings/records.ml @@ -1,3 +1,9 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel + * toplevel with principal +*) + (* Use type information *) module M1 = struct type t = {x: int; y: int} diff --git a/testsuite/tests/typing-warnings/records.ml.principal.reference b/testsuite/tests/typing-warnings/records.ml.principal.reference deleted file mode 100644 index 989fce35..00000000 --- a/testsuite/tests/typing-warnings/records.ml.principal.reference +++ /dev/null @@ -1,321 +0,0 @@ - -# module M1 : - sig type t = { x : int; y : int; } type u = { x : bool; y : bool; } end -# Characters 49-50: - let f1 (r:t) = r.x (* ok *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 89-90: - let f2 r = ignore (r:t); r.x (* non principal *) - ^ -Warning 18: this type-based field disambiguation is not principal. -Characters 89-90: - let f2 r = ignore (r:t); r.x (* non principal *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 148-149: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 151-152: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 148-149: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 27: unused variable x. -module OK : - sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end -# Characters 55-61: - let f r = match r with {x; y} -> y + y - ^^^^^^ -Warning 41: these field labels belong to several types: M1.u M1.t -The first one was selected. Please disambiguate if this is wrong. -Characters 65-66: - let f r = match r with {x; y} -> y + y - ^ -Error: This expression has type bool but an expression was expected of type - int -# Characters 85-91: - {x; y} -> y + y - ^^^^^^ -Warning 41: these field labels belong to several types: M1.u M1.t -The first one was selected. Please disambiguate if this is wrong. -Characters 85-91: - {x; y} -> y + y - ^^^^^^ -Error: This pattern matches values of type M1.u - but a pattern was expected which matches values of type M1.t -# module M : sig type t = { x : int; } type u = { x : bool; } end -# Characters 18-21: - let f (r:M.t) = r.M.x;; (* ok *) - ^^^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -val f : M.t -> int = -# Characters 18-19: - let f (r:M.t) = r.x;; (* warning *) - ^ -Warning 40: x was selected from type M.t. -It is not visible in the current scope, and will not -be selected if the type becomes unknown. -Characters 18-19: - let f (r:M.t) = r.x;; (* warning *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -val f : M.t -> int = -# Characters 8-9: - let f ({x}:M.t) = x;; (* warning *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 7-10: - let f ({x}:M.t) = x;; (* warning *) - ^^^ -Warning 40: this record of type M.t contains fields that are -not visible in the current scope: x. -They will not be selected if the type becomes unknown. -val f : M.t -> int = -# module M : sig type t = { x : int; y : int; } end -# module N : sig type u = { x : bool; y : bool; } end -# Characters 57-58: - let f (r:M.t) = r.x - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 30-36: - open N - ^^^^^^ -Warning 33: unused open N. -module OK : sig val f : M.t -> int end -# module M : - sig - type t = { x : int; } - module N : sig type s = t = { x : int; } end - type u = { x : bool; } - end -# module OK : sig val f : M.t -> int end -# module M : - sig - type u = { x : bool; y : int; z : char; } - type t = { x : int; y : bool; } - end -# Characters 37-38: - let f {x;z} = x,z - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 36-41: - let f {x;z} = x,z - ^^^^^ -Warning 9: the following labels are not bound in this record pattern: -y -Either bind these labels explicitly or add '; _' to the pattern. -module OK : sig val f : M.u -> bool * char end -# Characters 38-52: - let r = {x=true;z='z'} - ^^^^^^^^^^^^^^ -Error: Some record fields are undefined: y -# Characters 90-91: - let r = {x=3; y=true} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 95-96: - let r = {x=3; y=true} - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -module OK : - sig - type u = { x : int; y : bool; } - type t = { x : bool; y : int; z : char; } - val r : u - end -# Characters 111-112: - let b : bar = {x=3; y=4} - ^ -Error: This record expression is expected to have type bar - The field y does not belong to type bar -# module M : sig type foo = { x : int; y : int; } end -# module N : sig type bar = { x : int; y : int; } end -# Characters 19-22: - let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) - ^^^ -Error: The record field N.y belongs to the type N.bar - but is mixed here with fields of type M.foo -# module MN : - sig - type foo = M.foo = { x : int; y : int; } - type bar = N.bar = { x : int; y : int; } - end -module NM : - sig - type bar = N.bar = { x : int; y : int; } - type foo = M.foo = { x : int; y : int; } - end -# Characters 8-28: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^^^^^^^^^^^^^^^^^ -Warning 41: x belongs to several types: MN.bar MN.foo -The first one was selected. Please disambiguate if this is wrong. -Characters 8-28: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^^^^^^^^^^^^^^^^^ -Warning 41: y belongs to several types: NM.foo NM.bar -The first one was selected. Please disambiguate if this is wrong. -Characters 19-23: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^ -Error: The record field NM.y belongs to the type NM.foo = M.foo - but is mixed here with fields of type MN.bar = N.bar -# module M : - sig - type foo = { x : int; y : int; } - type bar = { x : int; y : int; z : int; } - end -# Characters 65-66: - let f r = ignore (r: foo); {r with x = 2; z = 3} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 72-73: - let f r = ignore (r: foo); {r with x = 2; z = 3} - ^ -Error: This record expression is expected to have type M.foo - The field z does not belong to type M.foo -# module M : - sig - type foo = M.foo = { x : int; y : int; } - type bar = M.bar = { x : int; y : int; z : int; } - type other = { a : int; b : int; } - end -# Characters 66-67: - let f r = ignore (r: foo); { r with x = 3; a = 4 } - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 73-74: - let f r = ignore (r: foo); { r with x = 3; a = 4 } - ^ -Error: This record expression is expected to have type M.foo - The field a does not belong to type M.foo -# Characters 39-40: - let r = {x=1; y=2} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 44-45: - let r = {x=1; y=2} - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 67-68: - let r: other = {x=1; y=2} - ^ -Error: This record expression is expected to have type M.other - The field x does not belong to type M.other -# module A : sig type t = { x : int; } end -module B : sig type t = { x : int; } end -# Characters 20-23: - let f (r : B.t) = r.A.x;; (* fail *) - ^^^ -Error: The field A.x belongs to the record type A.t - but a field was expected belonging to the record type B.t -# Characters 88-91: - let a : t = {x=1;yyz=2} - ^^^ -Error: This record expression is expected to have type t - The field yyz does not belong to type t -Hint: Did you mean yyy? -# type t = A -type s = A -class f : t -> object end -# Characters 12-13: - class g = f A;; (* ok *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -class g : f -# class f : 'a -> 'a -> object end -# Characters 13-14: - class g = f (A : t) A;; (* warn with -principal *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 20-21: - class g = f (A : t) A;; (* warn with -principal *) - ^ -Warning 18: this type-based constructor disambiguation is not principal. -Characters 20-21: - class g = f (A : t) A;; (* warn with -principal *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -class g : f -# Characters 199-200: - let y : t = {x = 0} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 114-120: - open M (* this open is unused, it isn't reported as shadowing 'x' *) - ^^^^^^ -Warning 33: unused open M. -module Shadow1 : - sig - type t = { x : int; } - module M : sig type s = { x : string; } end - val y : t - end -# Characters 97-103: - open M (* this open shadows label 'x' *) - ^^^^^^ -Warning 45: this open statement shadows the label x (which is later used) -Characters 149-157: - let y = {x = ""} - ^^^^^^^^ -Warning 41: these field labels belong to several types: M.s t -The first one was selected. Please disambiguate if this is wrong. -module Shadow2 : - sig - type t = { x : int; } - module M : sig type s = { x : string; } end - val y : M.s - end -# Characters 167-170: - let f (u : u) = match u with `Key {loc} -> loc - ^^^ -Warning 42: this use of loc relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -module P6235 : - sig - type t = { loc : string; } - type v = { loc : string; x : int; } - type u = [ `Key of t ] - val f : u -> string - end -# Characters 219-224: - |`Key {loc} -> loc - ^^^^^ -Warning 41: these field labels belong to several types: v t -The first one was selected. Please disambiguate if this is wrong. -Characters 219-224: - |`Key {loc} -> loc - ^^^^^ -Warning 9: the following labels are not bound in this record pattern: -x -Either bind these labels explicitly or add '; _' to the pattern. -Characters 214-224: - |`Key {loc} -> loc - ^^^^^^^^^^ -Error: This pattern matches values of type [? `Key of v ] - but a pattern was expected which matches values of type u - Types for tag `Key are incompatible -# diff --git a/testsuite/tests/typing-warnings/records.ml.reference b/testsuite/tests/typing-warnings/records.ml.reference deleted file mode 100644 index 349721e6..00000000 --- a/testsuite/tests/typing-warnings/records.ml.reference +++ /dev/null @@ -1,313 +0,0 @@ - -# module M1 : - sig type t = { x : int; y : int; } type u = { x : bool; y : bool; } end -# Characters 49-50: - let f1 (r:t) = r.x (* ok *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 89-90: - let f2 r = ignore (r:t); r.x (* non principal *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 148-149: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 151-152: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 148-149: - match r with {x; y} -> y + y (* ok *) - ^ -Warning 27: unused variable x. -module OK : - sig val f1 : M1.t -> int val f2 : M1.t -> int val f3 : M1.t -> int end -# Characters 55-61: - let f r = match r with {x; y} -> y + y - ^^^^^^ -Warning 41: these field labels belong to several types: M1.u M1.t -The first one was selected. Please disambiguate if this is wrong. -Characters 65-66: - let f r = match r with {x; y} -> y + y - ^ -Error: This expression has type bool but an expression was expected of type - int -# Characters 86-87: - {x; y} -> y + y - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 89-90: - {x; y} -> y + y - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 86-87: - {x; y} -> y + y - ^ -Warning 27: unused variable x. -module F2 : sig val f : M1.t -> int end -# module M : sig type t = { x : int; } type u = { x : bool; } end -# Characters 18-21: - let f (r:M.t) = r.M.x;; (* ok *) - ^^^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -val f : M.t -> int = -# Characters 18-19: - let f (r:M.t) = r.x;; (* warning *) - ^ -Warning 40: x was selected from type M.t. -It is not visible in the current scope, and will not -be selected if the type becomes unknown. -Characters 18-19: - let f (r:M.t) = r.x;; (* warning *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -val f : M.t -> int = -# Characters 8-9: - let f ({x}:M.t) = x;; (* warning *) - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 7-10: - let f ({x}:M.t) = x;; (* warning *) - ^^^ -Warning 40: this record of type M.t contains fields that are -not visible in the current scope: x. -They will not be selected if the type becomes unknown. -val f : M.t -> int = -# module M : sig type t = { x : int; y : int; } end -# module N : sig type u = { x : bool; y : bool; } end -# Characters 57-58: - let f (r:M.t) = r.x - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 30-36: - open N - ^^^^^^ -Warning 33: unused open N. -module OK : sig val f : M.t -> int end -# module M : - sig - type t = { x : int; } - module N : sig type s = t = { x : int; } end - type u = { x : bool; } - end -# module OK : sig val f : M.t -> int end -# module M : - sig - type u = { x : bool; y : int; z : char; } - type t = { x : int; y : bool; } - end -# Characters 37-38: - let f {x;z} = x,z - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 36-41: - let f {x;z} = x,z - ^^^^^ -Warning 9: the following labels are not bound in this record pattern: -y -Either bind these labels explicitly or add '; _' to the pattern. -module OK : sig val f : M.u -> bool * char end -# Characters 38-52: - let r = {x=true;z='z'} - ^^^^^^^^^^^^^^ -Error: Some record fields are undefined: y -# Characters 90-91: - let r = {x=3; y=true} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 95-96: - let r = {x=3; y=true} - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -module OK : - sig - type u = { x : int; y : bool; } - type t = { x : bool; y : int; z : char; } - val r : u - end -# Characters 111-112: - let b : bar = {x=3; y=4} - ^ -Error: This record expression is expected to have type bar - The field y does not belong to type bar -# module M : sig type foo = { x : int; y : int; } end -# module N : sig type bar = { x : int; y : int; } end -# Characters 19-22: - let r = { M.x = 3; N.y = 4; };; (* error: different definitions *) - ^^^ -Error: The record field N.y belongs to the type N.bar - but is mixed here with fields of type M.foo -# module MN : - sig - type foo = M.foo = { x : int; y : int; } - type bar = N.bar = { x : int; y : int; } - end -module NM : - sig - type bar = N.bar = { x : int; y : int; } - type foo = M.foo = { x : int; y : int; } - end -# Characters 8-28: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^^^^^^^^^^^^^^^^^ -Warning 41: x belongs to several types: MN.bar MN.foo -The first one was selected. Please disambiguate if this is wrong. -Characters 8-28: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^^^^^^^^^^^^^^^^^ -Warning 41: y belongs to several types: NM.foo NM.bar -The first one was selected. Please disambiguate if this is wrong. -Characters 19-23: - let r = {MN.x = 3; NM.y = 4};; (* error: type would change with order *) - ^^^^ -Error: The record field NM.y belongs to the type NM.foo = M.foo - but is mixed here with fields of type MN.bar = N.bar -# module M : - sig - type foo = { x : int; y : int; } - type bar = { x : int; y : int; z : int; } - end -# Characters 65-66: - let f r = ignore (r: foo); {r with x = 2; z = 3} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 72-73: - let f r = ignore (r: foo); {r with x = 2; z = 3} - ^ -Error: This record expression is expected to have type M.foo - The field z does not belong to type M.foo -# module M : - sig - type foo = M.foo = { x : int; y : int; } - type bar = M.bar = { x : int; y : int; z : int; } - type other = { a : int; b : int; } - end -# Characters 66-67: - let f r = ignore (r: foo); { r with x = 3; a = 4 } - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 73-74: - let f r = ignore (r: foo); { r with x = 3; a = 4 } - ^ -Error: This record expression is expected to have type M.foo - The field a does not belong to type M.foo -# Characters 39-40: - let r = {x=1; y=2} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 44-45: - let r = {x=1; y=2} - ^ -Warning 42: this use of y relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 67-68: - let r: other = {x=1; y=2} - ^ -Error: This record expression is expected to have type M.other - The field x does not belong to type M.other -# module A : sig type t = { x : int; } end -module B : sig type t = { x : int; } end -# Characters 20-23: - let f (r : B.t) = r.A.x;; (* fail *) - ^^^ -Error: The field A.x belongs to the record type A.t - but a field was expected belonging to the record type B.t -# Characters 88-91: - let a : t = {x=1;yyz=2} - ^^^ -Error: This record expression is expected to have type t - The field yyz does not belong to type t -Hint: Did you mean yyy? -# type t = A -type s = A -class f : t -> object end -# Characters 12-13: - class g = f A;; (* ok *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -class g : f -# class f : 'a -> 'a -> object end -# Characters 13-14: - class g = f (A : t) A;; (* warn with -principal *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 20-21: - class g = f (A : t) A;; (* warn with -principal *) - ^ -Warning 42: this use of A relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -class g : f -# Characters 199-200: - let y : t = {x = 0} - ^ -Warning 42: this use of x relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -Characters 114-120: - open M (* this open is unused, it isn't reported as shadowing 'x' *) - ^^^^^^ -Warning 33: unused open M. -module Shadow1 : - sig - type t = { x : int; } - module M : sig type s = { x : string; } end - val y : t - end -# Characters 97-103: - open M (* this open shadows label 'x' *) - ^^^^^^ -Warning 45: this open statement shadows the label x (which is later used) -Characters 149-157: - let y = {x = ""} - ^^^^^^^^ -Warning 41: these field labels belong to several types: M.s t -The first one was selected. Please disambiguate if this is wrong. -module Shadow2 : - sig - type t = { x : int; } - module M : sig type s = { x : string; } end - val y : M.s - end -# Characters 167-170: - let f (u : u) = match u with `Key {loc} -> loc - ^^^ -Warning 42: this use of loc relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -module P6235 : - sig - type t = { loc : string; } - type v = { loc : string; x : int; } - type u = [ `Key of t ] - val f : u -> string - end -# Characters 220-223: - |`Key {loc} -> loc - ^^^ -Warning 42: this use of loc relies on type-directed disambiguation, -it will not compile with OCaml 4.00 or earlier. -module P6235' : - sig - type t = { loc : string; } - type v = { loc : string; x : int; } - type u = [ `Key of t ] - val f : u -> string - end -# diff --git a/testsuite/tests/typing-warnings/unused_types.compilers.reference b/testsuite/tests/typing-warnings/unused_types.compilers.reference new file mode 100644 index 00000000..22014bcf --- /dev/null +++ b/testsuite/tests/typing-warnings/unused_types.compilers.reference @@ -0,0 +1,57 @@ +Characters 98-115: + type unused = int + ^^^^^^^^^^^^^^^^^ +Warning 34: unused type unused. +module Unused : sig end +Characters 68-93: + type nonrec unused = used + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 34: unused type unused. +module Unused_nonrec : sig end +Characters 40-65: + type unused = A of unused + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 34: unused type unused. +Characters 40-65: + type unused = A of unused + ^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 37: unused constructor A. +module Unused_rec : sig end +Characters 46-70: + exception Nobody_uses_me + ^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 38: unused exception Nobody_uses_me +module Unused_exception : sig end +Characters 96-110: + type t += Nobody_uses_me + ^^^^^^^^^^^^^^ +Warning 38: unused extension constructor Nobody_uses_me +module Unused_extension_constructor : sig type t = .. end +Characters 91-121: + exception Nobody_constructs_me + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 38: exception Nobody_constructs_me is never used to build values. +(However, this constructor appears in patterns.) +module Unused_exception_outside_patterns : sig val falsity : exn -> bool end +Characters 127-147: + type t += Nobody_constructs_me + ^^^^^^^^^^^^^^^^^^^^ +Warning 38: extension constructor Nobody_constructs_me is never used to build values. +(However, this constructor appears in patterns.) +module Unused_extension_outside_patterns : + sig type t = .. val falsity : t -> bool end +Characters 88-109: + exception Private_exn + ^^^^^^^^^^^^^^^^^^^^^ +Warning 38: exception Private_exn is never used to build values. +It is exported or rebound as a private extension. +module Unused_private_exception : sig type exn += private Private_exn end +Characters 124-135: + type t += Private_ext + ^^^^^^^^^^^ +Warning 38: extension constructor Private_ext is never used to build values. +It is exported or rebound as a private extension. +module Unused_private_extension : + sig type t = .. type t += private Private_ext end +module Pr7438 : sig end + diff --git a/testsuite/tests/typing-warnings/unused_types.ml b/testsuite/tests/typing-warnings/unused_types.ml index 791d9fd8..839d505b 100644 --- a/testsuite/tests/typing-warnings/unused_types.ml +++ b/testsuite/tests/typing-warnings/unused_types.ml @@ -1,3 +1,8 @@ +(* TEST + flags = " -w A -strict-sequence " + * toplevel +*) + module Unused : sig end = struct type unused = int diff --git a/testsuite/tests/typing-warnings/unused_types.ml.reference b/testsuite/tests/typing-warnings/unused_types.ml.reference deleted file mode 100644 index 1d318192..00000000 --- a/testsuite/tests/typing-warnings/unused_types.ml.reference +++ /dev/null @@ -1,58 +0,0 @@ - -# Characters 35-52: - type unused = int - ^^^^^^^^^^^^^^^^^ -Warning 34: unused type unused. -module Unused : sig end -# Characters 68-93: - type nonrec unused = used - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 34: unused type unused. -module Unused_nonrec : sig end -# Characters 40-65: - type unused = A of unused - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 34: unused type unused. -Characters 40-65: - type unused = A of unused - ^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 37: unused constructor A. -module Unused_rec : sig end -# Characters 46-70: - exception Nobody_uses_me - ^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 38: unused exception Nobody_uses_me -module Unused_exception : sig end -# Characters 96-110: - type t += Nobody_uses_me - ^^^^^^^^^^^^^^ -Warning 38: unused extension constructor Nobody_uses_me -module Unused_extension_constructor : sig type t = .. end -# Characters 91-121: - exception Nobody_constructs_me - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Warning 38: exception Nobody_constructs_me is never used to build values. -(However, this constructor appears in patterns.) -module Unused_exception_outside_patterns : sig val falsity : exn -> bool end -# Characters 127-147: - type t += Nobody_constructs_me - ^^^^^^^^^^^^^^^^^^^^ -Warning 38: extension constructor Nobody_constructs_me is never used to build values. -(However, this constructor appears in patterns.) -module Unused_extension_outside_patterns : - sig type t = .. val falsity : t -> bool end -# Characters 88-109: - exception Private_exn - ^^^^^^^^^^^^^^^^^^^^^ -Warning 38: exception Private_exn is never used to build values. -It is exported or rebound as a private extension. -module Unused_private_exception : sig type exn += private Private_exn end -# Characters 124-135: - type t += Private_ext - ^^^^^^^^^^^ -Warning 38: extension constructor Private_ext is never used to build values. -It is exported or rebound as a private extension. -module Unused_private_extension : - sig type t = .. type t += private Private_ext end -# module Pr7438 : sig end -# diff --git a/testsuite/tests/utils/Makefile b/testsuite/tests/utils/Makefile deleted file mode 100644 index f2d74860..00000000 --- a/testsuite/tests/utils/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Alain Frisch, LexiFi * -#* * -#* Copyright 2012 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -MODULES=testing misc identifiable numbers strongly_connected_components -INCLUDES= -I $(OTOPDIR)/utils -ADD_COMPFLAGS=$(INCLUDES) -CMO_FILES+="misc.cmo" - -include $(BASEDIR)/makefiles/Makefile.several -include $(BASEDIR)/makefiles/Makefile.common - -BYTECODE_ONLY=true diff --git a/testsuite/tests/utils/edit_distance.ml b/testsuite/tests/utils/edit_distance.ml index 294b02ce..3f3807fe 100644 --- a/testsuite/tests/utils/edit_distance.ml +++ b/testsuite/tests/utils/edit_distance.ml @@ -1,3 +1,10 @@ +(* TEST +include config +include testing +binary_modules = "misc identifiable numbers" +* bytecode +*) + let edit_distance = Misc.edit_distance let show_cutoff n = diff --git a/testsuite/tests/utils/ocamltests b/testsuite/tests/utils/ocamltests new file mode 100644 index 00000000..571dfa47 --- /dev/null +++ b/testsuite/tests/utils/ocamltests @@ -0,0 +1,3 @@ +edit_distance.ml +overflow_detection.ml +test_strongly_connected_components.ml diff --git a/testsuite/tests/utils/overflow_detection.ml b/testsuite/tests/utils/overflow_detection.ml new file mode 100644 index 00000000..ca5fa543 --- /dev/null +++ b/testsuite/tests/utils/overflow_detection.ml @@ -0,0 +1,45 @@ +(* TEST +include config +include testing +binary_modules = "misc identifiable numbers" +* bytecode +*) + +let print_int i = + if i = max_int then + "max_int" + else if i = min_int then + "min_int" + else + string_of_int i + +let test_no_overflow_add a b = + Printf.printf "Misc.no_overflow_add %s %s = %b\n" + (print_int a) + (print_int b) + (Misc.no_overflow_add a b) + +let test_no_overflow_sub a b = + Printf.printf "Misc.no_overflow_sub %s %s = %b\n" + (print_int a) + (print_int b) + (Misc.no_overflow_sub a b) + +let test_no_overflow_mul a b = + Printf.printf "Misc.no_overflow_mul %s %s = %b\n" + (print_int a) + (print_int b) + (Misc.no_overflow_mul a b) + +let cartesian_product l1 l2 = + List.concat + (l1 |> List.map (fun v1 -> + l2 |> List.map (fun v2 -> + (v1, v2)))) + +let () = + let ints = [ 0; 1; 2; max_int; -1; -2; min_int ] in + let int_pairs = cartesian_product ints ints in + int_pairs |> List.iter (fun (a, b) -> test_no_overflow_add a b); + int_pairs |> List.iter (fun (a, b) -> test_no_overflow_sub a b); + int_pairs |> List.iter (fun (a, b) -> test_no_overflow_mul a b) diff --git a/testsuite/tests/utils/overflow_detection.reference b/testsuite/tests/utils/overflow_detection.reference new file mode 100644 index 00000000..ce16f0b3 --- /dev/null +++ b/testsuite/tests/utils/overflow_detection.reference @@ -0,0 +1,149 @@ +Misc.no_overflow_add 0 0 = true +Misc.no_overflow_add 0 1 = true +Misc.no_overflow_add 0 2 = true +Misc.no_overflow_add 0 max_int = true +Misc.no_overflow_add 0 -1 = true +Misc.no_overflow_add 0 -2 = true +Misc.no_overflow_add 0 min_int = true +Misc.no_overflow_add 1 0 = true +Misc.no_overflow_add 1 1 = true +Misc.no_overflow_add 1 2 = true +Misc.no_overflow_add 1 max_int = false +Misc.no_overflow_add 1 -1 = true +Misc.no_overflow_add 1 -2 = true +Misc.no_overflow_add 1 min_int = true +Misc.no_overflow_add 2 0 = true +Misc.no_overflow_add 2 1 = true +Misc.no_overflow_add 2 2 = true +Misc.no_overflow_add 2 max_int = false +Misc.no_overflow_add 2 -1 = true +Misc.no_overflow_add 2 -2 = true +Misc.no_overflow_add 2 min_int = true +Misc.no_overflow_add max_int 0 = true +Misc.no_overflow_add max_int 1 = false +Misc.no_overflow_add max_int 2 = false +Misc.no_overflow_add max_int max_int = false +Misc.no_overflow_add max_int -1 = true +Misc.no_overflow_add max_int -2 = true +Misc.no_overflow_add max_int min_int = true +Misc.no_overflow_add -1 0 = true +Misc.no_overflow_add -1 1 = true +Misc.no_overflow_add -1 2 = true +Misc.no_overflow_add -1 max_int = true +Misc.no_overflow_add -1 -1 = true +Misc.no_overflow_add -1 -2 = true +Misc.no_overflow_add -1 min_int = false +Misc.no_overflow_add -2 0 = true +Misc.no_overflow_add -2 1 = true +Misc.no_overflow_add -2 2 = true +Misc.no_overflow_add -2 max_int = true +Misc.no_overflow_add -2 -1 = true +Misc.no_overflow_add -2 -2 = true +Misc.no_overflow_add -2 min_int = false +Misc.no_overflow_add min_int 0 = true +Misc.no_overflow_add min_int 1 = true +Misc.no_overflow_add min_int 2 = true +Misc.no_overflow_add min_int max_int = true +Misc.no_overflow_add min_int -1 = false +Misc.no_overflow_add min_int -2 = false +Misc.no_overflow_add min_int min_int = false +Misc.no_overflow_sub 0 0 = true +Misc.no_overflow_sub 0 1 = true +Misc.no_overflow_sub 0 2 = true +Misc.no_overflow_sub 0 max_int = true +Misc.no_overflow_sub 0 -1 = true +Misc.no_overflow_sub 0 -2 = true +Misc.no_overflow_sub 0 min_int = false +Misc.no_overflow_sub 1 0 = true +Misc.no_overflow_sub 1 1 = true +Misc.no_overflow_sub 1 2 = true +Misc.no_overflow_sub 1 max_int = true +Misc.no_overflow_sub 1 -1 = true +Misc.no_overflow_sub 1 -2 = true +Misc.no_overflow_sub 1 min_int = false +Misc.no_overflow_sub 2 0 = true +Misc.no_overflow_sub 2 1 = true +Misc.no_overflow_sub 2 2 = true +Misc.no_overflow_sub 2 max_int = true +Misc.no_overflow_sub 2 -1 = true +Misc.no_overflow_sub 2 -2 = true +Misc.no_overflow_sub 2 min_int = false +Misc.no_overflow_sub max_int 0 = true +Misc.no_overflow_sub max_int 1 = true +Misc.no_overflow_sub max_int 2 = true +Misc.no_overflow_sub max_int max_int = true +Misc.no_overflow_sub max_int -1 = false +Misc.no_overflow_sub max_int -2 = false +Misc.no_overflow_sub max_int min_int = false +Misc.no_overflow_sub -1 0 = true +Misc.no_overflow_sub -1 1 = true +Misc.no_overflow_sub -1 2 = true +Misc.no_overflow_sub -1 max_int = true +Misc.no_overflow_sub -1 -1 = true +Misc.no_overflow_sub -1 -2 = true +Misc.no_overflow_sub -1 min_int = true +Misc.no_overflow_sub -2 0 = true +Misc.no_overflow_sub -2 1 = true +Misc.no_overflow_sub -2 2 = true +Misc.no_overflow_sub -2 max_int = false +Misc.no_overflow_sub -2 -1 = true +Misc.no_overflow_sub -2 -2 = true +Misc.no_overflow_sub -2 min_int = true +Misc.no_overflow_sub min_int 0 = true +Misc.no_overflow_sub min_int 1 = false +Misc.no_overflow_sub min_int 2 = false +Misc.no_overflow_sub min_int max_int = false +Misc.no_overflow_sub min_int -1 = true +Misc.no_overflow_sub min_int -2 = true +Misc.no_overflow_sub min_int min_int = true +Misc.no_overflow_mul 0 0 = true +Misc.no_overflow_mul 0 1 = true +Misc.no_overflow_mul 0 2 = true +Misc.no_overflow_mul 0 max_int = true +Misc.no_overflow_mul 0 -1 = true +Misc.no_overflow_mul 0 -2 = true +Misc.no_overflow_mul 0 min_int = true +Misc.no_overflow_mul 1 0 = true +Misc.no_overflow_mul 1 1 = true +Misc.no_overflow_mul 1 2 = true +Misc.no_overflow_mul 1 max_int = true +Misc.no_overflow_mul 1 -1 = true +Misc.no_overflow_mul 1 -2 = true +Misc.no_overflow_mul 1 min_int = true +Misc.no_overflow_mul 2 0 = true +Misc.no_overflow_mul 2 1 = true +Misc.no_overflow_mul 2 2 = true +Misc.no_overflow_mul 2 max_int = false +Misc.no_overflow_mul 2 -1 = true +Misc.no_overflow_mul 2 -2 = true +Misc.no_overflow_mul 2 min_int = false +Misc.no_overflow_mul max_int 0 = true +Misc.no_overflow_mul max_int 1 = true +Misc.no_overflow_mul max_int 2 = false +Misc.no_overflow_mul max_int max_int = false +Misc.no_overflow_mul max_int -1 = true +Misc.no_overflow_mul max_int -2 = false +Misc.no_overflow_mul max_int min_int = false +Misc.no_overflow_mul -1 0 = true +Misc.no_overflow_mul -1 1 = true +Misc.no_overflow_mul -1 2 = true +Misc.no_overflow_mul -1 max_int = true +Misc.no_overflow_mul -1 -1 = true +Misc.no_overflow_mul -1 -2 = true +Misc.no_overflow_mul -1 min_int = false +Misc.no_overflow_mul -2 0 = true +Misc.no_overflow_mul -2 1 = true +Misc.no_overflow_mul -2 2 = true +Misc.no_overflow_mul -2 max_int = false +Misc.no_overflow_mul -2 -1 = true +Misc.no_overflow_mul -2 -2 = true +Misc.no_overflow_mul -2 min_int = false +Misc.no_overflow_mul min_int 0 = true +Misc.no_overflow_mul min_int 1 = true +Misc.no_overflow_mul min_int 2 = false +Misc.no_overflow_mul min_int max_int = false +Misc.no_overflow_mul min_int -1 = false +Misc.no_overflow_mul min_int -2 = false +Misc.no_overflow_mul min_int min_int = false + +All tests succeeded. diff --git a/testsuite/tests/utils/test_strongly_connected_components.ml b/testsuite/tests/utils/test_strongly_connected_components.ml index 8f3392e4..c818f383 100644 --- a/testsuite/tests/utils/test_strongly_connected_components.ml +++ b/testsuite/tests/utils/test_strongly_connected_components.ml @@ -1,3 +1,10 @@ +(* TEST +include config +include testing +binary_modules = "misc identifiable numbers strongly_connected_components" +* bytecode +*) + module Int = Numbers.Int module SCC = Strongly_connected_components.Make (Int) diff --git a/testsuite/tests/warnings/Makefile b/testsuite/tests/warnings/Makefile deleted file mode 100644 index 794e658b..00000000 --- a/testsuite/tests/warnings/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -#************************************************************************** -#* * -#* OCaml * -#* * -#* Xavier Clerc, SED, INRIA Rocquencourt * -#* * -#* Copyright 2010 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -BASEDIR=../.. -FLAGS=-w A - -run-all: - @$(OCAMLC) $(FLAGS) -c deprecated_module.mli - @$(OCAMLC) $(FLAGS) -c module_without_cmx.mli - @$(OCAMLC) $(FLAGS) -c w32.mli - @$(OCAMLC) $(FLAGS) -c w60.mli - @for file in *.ml; do \ - printf " ... testing '$$file':"; \ - F="`basename $$file .ml`"; \ - $(OCAMLC) $(FLAGS) -c $$file 2>$$F.result; \ - $(DIFF) $$F.reference $$F.result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - done; - @for file in *.opt.ml; do \ - printf " ... testing '$$file' with ocamlopt:"; \ - if $(BYTECODE_ONLY); then echo " => skipped"; else \ - F="`basename $$file .ml`"; \ - $(OCAMLOPT) $(FLAGS) -c $$file 2>$$F.opt_result; \ - $(DIFF) $$F.opt_reference $$F.opt_result >/dev/null \ - && echo " => passed" || echo " => failed"; \ - fi \ - done; - @for file in *.opt_backend.ml; do \ - printf " ... testing '$$file' with ocamlopt:"; \ - if $(BYTECODE_ONLY); then echo " => skipped"; else \ - F="`basename $$file .ml`"; \ - $(OCAMLOPT) $(FLAGS) -c $$file 2>$$F.$(BACKEND).opt_result; \ - $(DIFF) $$F.$(BACKEND).opt_reference $$F.$(BACKEND).opt_result \ - >/dev/null \ - && echo " => passed" || echo " => failed"; \ - fi \ - done; - -promote: defaultpromote - -clean: defaultclean - @rm -f *.result *.opt_result - -include $(BASEDIR)/makefiles/Makefile.common - -ifeq "$(FLAMBDA)" "true" -BACKEND=flambda -else -BACKEND=clambda -endif diff --git a/testsuite/tests/warnings/deprecated_module.compilers.reference b/testsuite/tests/warnings/deprecated_module.compilers.reference new file mode 100644 index 00000000..09a3a45a --- /dev/null +++ b/testsuite/tests/warnings/deprecated_module.compilers.reference @@ -0,0 +1,4 @@ +File "deprecated_module.ml", line 16, characters 8-11: +Warning 3: deprecated: module M +File "deprecated_module.ml", line 17, characters 8-9: +Warning 3: deprecated: module M diff --git a/testsuite/tests/warnings/deprecated_module.ml b/testsuite/tests/warnings/deprecated_module.ml index 092e9d09..b6a0121d 100755 --- a/testsuite/tests/warnings/deprecated_module.ml +++ b/testsuite/tests/warnings/deprecated_module.ml @@ -1,3 +1,11 @@ +(* TEST + +flags = "-w A" + +* bytecode + +*) + module M = struct type t = int diff --git a/testsuite/tests/warnings/deprecated_module.reference b/testsuite/tests/warnings/deprecated_module.reference deleted file mode 100644 index 9dcde99a..00000000 --- a/testsuite/tests/warnings/deprecated_module.reference +++ /dev/null @@ -1,4 +0,0 @@ -File "deprecated_module.ml", line 8, characters 8-11: -Warning 3: deprecated: module M -File "deprecated_module.ml", line 9, characters 8-9: -Warning 3: deprecated: module M diff --git a/testsuite/tests/warnings/deprecated_module_assigment.compilers.reference b/testsuite/tests/warnings/deprecated_module_assigment.compilers.reference new file mode 100644 index 00000000..6a635d9f --- /dev/null +++ b/testsuite/tests/warnings/deprecated_module_assigment.compilers.reference @@ -0,0 +1,72 @@ +File "deprecated_module_assigment.ml", line 17, characters 33-34: +Warning 3: deprecated: x +DEPRECATED + File "deprecated_module_assigment.ml", line 12, characters 2-41: + Definition + File "deprecated_module_assigment.ml", line 17, characters 15-26: + Expected signature +File "deprecated_module_assigment.ml", line 23, characters 13-14: +Warning 3: deprecated: x +DEPRECATED + File "deprecated_module_assigment.ml", line 12, characters 2-41: + Definition + File "deprecated_module_assigment.ml", line 21, characters 17-28: + Expected signature +File "deprecated_module_assigment.ml", line 33, characters 39-78: +Warning 3: deprecated: A + File "deprecated_module_assigment.ml", line 33, characters 55-70: + Definition + File "deprecated_module_assigment.ml", line 33, characters 27-28: + Expected signature +File "deprecated_module_assigment.ml", line 37, characters 2-20: +Warning 3: deprecated: A + File "deprecated_module_assigment.ml", line 36, characters 11-26: + Definition + File "deprecated_module_assigment.ml", line 37, characters 15-16: + Expected signature +File "deprecated_module_assigment.ml", line 45, characters 0-58: +Warning 3: deprecated: mutating field x + File "deprecated_module_assigment.ml", line 45, characters 17-53: + Definition + File "deprecated_module_assigment.ml", line 44, characters 14-28: + Expected signature +File "deprecated_module_assigment.ml", line 49, characters 2-31: +Warning 3: deprecated: mutating field x + File "deprecated_module_assigment.ml", line 48, characters 12-48: + Definition + File "deprecated_module_assigment.ml", line 49, characters 16-30: + Expected signature +File "deprecated_module_assigment.ml", line 54, characters 37-75: +Warning 3: deprecated: t + File "deprecated_module_assigment.ml", line 54, characters 44-71: + Definition + File "deprecated_module_assigment.ml", line 54, characters 18-30: + Expected signature +File "deprecated_module_assigment.ml", line 60, characters 0-52: +Warning 3: deprecated: c +FOO + File "deprecated_module_assigment.ml", line 60, characters 7-48: + Definition + File "deprecated_module_assigment.ml", line 59, characters 4-24: + Expected signature +File "deprecated_module_assigment.ml", line 64, characters 0-57: +Warning 3: deprecated: c +FOO + File "deprecated_module_assigment.ml", line 64, characters 7-53: + Definition + File "deprecated_module_assigment.ml", line 63, characters 4-29: + Expected signature +File "deprecated_module_assigment.ml", line 71, characters 0-55: +Warning 3: deprecated: S +FOO + File "deprecated_module_assigment.ml", line 71, characters 7-51: + Definition + File "deprecated_module_assigment.ml", line 70, characters 4-27: + Expected signature +File "deprecated_module_assigment.ml", line 82, characters 0-53: +Warning 3: deprecated: M +FOO + File "deprecated_module_assigment.ml", line 82, characters 7-49: + Definition + File "deprecated_module_assigment.ml", line 81, characters 4-22: + Expected signature diff --git a/testsuite/tests/warnings/deprecated_module_assigment.ml b/testsuite/tests/warnings/deprecated_module_assigment.ml index 25956372..93f0e305 100755 --- a/testsuite/tests/warnings/deprecated_module_assigment.ml +++ b/testsuite/tests/warnings/deprecated_module_assigment.ml @@ -1,3 +1,11 @@ +(* TEST + +flags = "-w A" + +* bytecode + +*) + (* Values *) module X : sig @@ -10,7 +18,7 @@ module Y : sig val x : int end = X module Z : sig val x : int [@@deprecated "..."] end = X -module F(A : sig val x : int end) = struct end +module F(A : sig val x : int end) = struct let _ = A.x end module B = F(X) diff --git a/testsuite/tests/warnings/deprecated_module_assigment.reference b/testsuite/tests/warnings/deprecated_module_assigment.reference deleted file mode 100644 index 5df8f12f..00000000 --- a/testsuite/tests/warnings/deprecated_module_assigment.reference +++ /dev/null @@ -1,72 +0,0 @@ -File "deprecated_module_assigment.ml", line 9, characters 33-34: -Warning 3: deprecated: x -DEPRECATED - File "deprecated_module_assigment.ml", line 4, characters 2-41: - Definition - File "deprecated_module_assigment.ml", line 9, characters 15-26: - Expected signature -File "deprecated_module_assigment.ml", line 15, characters 13-14: -Warning 3: deprecated: x -DEPRECATED - File "deprecated_module_assigment.ml", line 4, characters 2-41: - Definition - File "deprecated_module_assigment.ml", line 13, characters 17-28: - Expected signature -File "deprecated_module_assigment.ml", line 25, characters 39-78: -Warning 3: deprecated: A - File "deprecated_module_assigment.ml", line 25, characters 55-70: - Definition - File "deprecated_module_assigment.ml", line 25, characters 27-28: - Expected signature -File "deprecated_module_assigment.ml", line 29, characters 2-20: -Warning 3: deprecated: A - File "deprecated_module_assigment.ml", line 28, characters 11-26: - Definition - File "deprecated_module_assigment.ml", line 29, characters 15-16: - Expected signature -File "deprecated_module_assigment.ml", line 37, characters 0-58: -Warning 3: deprecated: mutating field x - File "deprecated_module_assigment.ml", line 37, characters 17-53: - Definition - File "deprecated_module_assigment.ml", line 36, characters 14-28: - Expected signature -File "deprecated_module_assigment.ml", line 41, characters 2-31: -Warning 3: deprecated: mutating field x - File "deprecated_module_assigment.ml", line 40, characters 12-48: - Definition - File "deprecated_module_assigment.ml", line 41, characters 16-30: - Expected signature -File "deprecated_module_assigment.ml", line 46, characters 37-75: -Warning 3: deprecated: t - File "deprecated_module_assigment.ml", line 46, characters 44-71: - Definition - File "deprecated_module_assigment.ml", line 46, characters 18-30: - Expected signature -File "deprecated_module_assigment.ml", line 52, characters 0-52: -Warning 3: deprecated: c -FOO - File "deprecated_module_assigment.ml", line 52, characters 7-48: - Definition - File "deprecated_module_assigment.ml", line 51, characters 4-24: - Expected signature -File "deprecated_module_assigment.ml", line 56, characters 0-57: -Warning 3: deprecated: c -FOO - File "deprecated_module_assigment.ml", line 56, characters 7-53: - Definition - File "deprecated_module_assigment.ml", line 55, characters 4-29: - Expected signature -File "deprecated_module_assigment.ml", line 63, characters 0-55: -Warning 3: deprecated: S -FOO - File "deprecated_module_assigment.ml", line 63, characters 7-51: - Definition - File "deprecated_module_assigment.ml", line 62, characters 4-27: - Expected signature -File "deprecated_module_assigment.ml", line 74, characters 0-53: -Warning 3: deprecated: M -FOO - File "deprecated_module_assigment.ml", line 74, characters 7-49: - Definition - File "deprecated_module_assigment.ml", line 73, characters 4-22: - Expected signature diff --git a/testsuite/tests/warnings/deprecated_module_use.compilers.reference b/testsuite/tests/warnings/deprecated_module_use.compilers.reference new file mode 100644 index 00000000..73772b73 --- /dev/null +++ b/testsuite/tests/warnings/deprecated_module_use.compilers.reference @@ -0,0 +1,14 @@ +File "deprecated_module_use.ml", line 18, characters 5-22: +Warning 3: deprecated: module Deprecated_module + + As you could guess, Deprecated_module is deprecated. + Please use something else! + +File "deprecated_module_use.ml", line 20, characters 9-12: +Warning 3: deprecated: module Deprecated_module.M +File "deprecated_module_use.ml", line 20, characters 9-12: +Warning 3: deprecated: Deprecated_module.M.t +File "deprecated_module_use.ml", line 22, characters 5-6: +Warning 3: deprecated: module Deprecated_module.M +File "deprecated_module_use.ml", line 23, characters 8-9: +Warning 3: deprecated: Deprecated_module.M.x diff --git a/testsuite/tests/warnings/deprecated_module_use.ml b/testsuite/tests/warnings/deprecated_module_use.ml index f04e6f52..adf01474 100755 --- a/testsuite/tests/warnings/deprecated_module_use.ml +++ b/testsuite/tests/warnings/deprecated_module_use.ml @@ -1,3 +1,20 @@ +(* TEST + +modules = "deprecated_module.mli deprecated_module.ml" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +flags = "-w a" +module = "deprecated_module.mli" +*** ocamlc.byte +module = "deprecated_module.ml" +**** ocamlc.byte +flags = "-w A" +module = "deprecated_module_use.ml" +***** check-ocamlc.byte-output + +*) + open Deprecated_module type s = M.t diff --git a/testsuite/tests/warnings/deprecated_module_use.reference b/testsuite/tests/warnings/deprecated_module_use.reference deleted file mode 100644 index a7615cd6..00000000 --- a/testsuite/tests/warnings/deprecated_module_use.reference +++ /dev/null @@ -1,14 +0,0 @@ -File "deprecated_module_use.ml", line 1, characters 5-22: -Warning 3: deprecated: module Deprecated_module - - As you could guess, Deprecated_module is deprecated. - Please use something else! - -File "deprecated_module_use.ml", line 3, characters 9-12: -Warning 3: deprecated: module Deprecated_module.M -File "deprecated_module_use.ml", line 3, characters 9-12: -Warning 3: deprecated: Deprecated_module.M.t -File "deprecated_module_use.ml", line 5, characters 5-6: -Warning 3: deprecated: module Deprecated_module.M -File "deprecated_module_use.ml", line 6, characters 8-9: -Warning 3: deprecated: Deprecated_module.M.x diff --git a/testsuite/tests/warnings/ocamltests b/testsuite/tests/warnings/ocamltests new file mode 100644 index 00000000..2f143cf8 --- /dev/null +++ b/testsuite/tests/warnings/ocamltests @@ -0,0 +1,22 @@ +deprecated_module_assigment.ml +deprecated_module.ml +deprecated_module_use.ml +w01.ml +w04_failure.ml +w04.ml +w06.ml +w32b.ml +w32.ml +w33.ml +w45.ml +w47_inline.ml +w50.ml +w51_bis.ml +w51.ml +w52.ml +w53.ml +w54.ml +w55.ml +w58.ml +w59.ml +w60.ml diff --git a/testsuite/tests/warnings/w01.compilers.reference b/testsuite/tests/warnings/w01.compilers.reference new file mode 100644 index 00000000..ea21e869 --- /dev/null +++ b/testsuite/tests/warnings/w01.compilers.reference @@ -0,0 +1,15 @@ +File "w01.ml", line 14, characters 12-14: +Warning 2: this is not the end of a comment. +File "w01.ml", line 20, characters 0-3: +Warning 5: this function application is partial, +maybe some arguments are missing. +File "w01.ml", line 30, characters 4-5: +Warning 8: this pattern-matching is not exhaustive. +Here is an example of a case that is not matched: +0 +File "w01.ml", line 35, characters 0-1: +Warning 10: this expression should have type unit. +File "w01.ml", line 19, characters 8-9: +Warning 27: unused variable y. +File "w01.ml", line 42, characters 2-3: +Warning 11: this match case is unused. diff --git a/testsuite/tests/warnings/w01.ml b/testsuite/tests/warnings/w01.ml index 08e2f291..91782259 100644 --- a/testsuite/tests/warnings/w01.ml +++ b/testsuite/tests/warnings/w01.ml @@ -1,3 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) (* C *) diff --git a/testsuite/tests/warnings/w01.reference b/testsuite/tests/warnings/w01.reference deleted file mode 100644 index 5221256f..00000000 --- a/testsuite/tests/warnings/w01.reference +++ /dev/null @@ -1,15 +0,0 @@ -File "w01.ml", line 4, characters 12-14: -Warning 2: this is not the end of a comment. -File "w01.ml", line 10, characters 0-3: -Warning 5: this function application is partial, -maybe some arguments are missing. -File "w01.ml", line 20, characters 4-5: -Warning 8: this pattern-matching is not exhaustive. -Here is an example of a case that is not matched: -0 -File "w01.ml", line 25, characters 0-1: -Warning 10: this expression should have type unit. -File "w01.ml", line 9, characters 8-9: -Warning 27: unused variable y. -File "w01.ml", line 32, characters 2-3: -Warning 11: this match case is unused. diff --git a/testsuite/tests/warnings/w04.compilers.reference b/testsuite/tests/warnings/w04.compilers.reference new file mode 100644 index 00000000..d746bd60 --- /dev/null +++ b/testsuite/tests/warnings/w04.compilers.reference @@ -0,0 +1,3 @@ +File "w04.ml", line 21, characters 10-40: +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type t. diff --git a/testsuite/tests/warnings/w04.ml b/testsuite/tests/warnings/w04.ml index e46b6bf7..fc33df31 100644 --- a/testsuite/tests/warnings/w04.ml +++ b/testsuite/tests/warnings/w04.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + [@@@ocaml.warning "+4"] type expr = E of int [@@unboxed] diff --git a/testsuite/tests/warnings/w04.reference b/testsuite/tests/warnings/w04.reference deleted file mode 100644 index df194ead..00000000 --- a/testsuite/tests/warnings/w04.reference +++ /dev/null @@ -1,3 +0,0 @@ -File "w04.ml", line 10, characters 10-40: -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type t. diff --git a/testsuite/tests/warnings/w04_failure.compilers.reference b/testsuite/tests/warnings/w04_failure.compilers.reference new file mode 100644 index 00000000..d4182ae4 --- /dev/null +++ b/testsuite/tests/warnings/w04_failure.compilers.reference @@ -0,0 +1,9 @@ +File "w04_failure.ml", line 20, characters 2-78: +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type repr. +File "w04_failure.ml", line 20, characters 2-78: +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type ab. +File "w04_failure.ml", line 20, characters 2-78: +Warning 4: this pattern-matching is fragile. +It will remain exhaustive when constructors are added to type xy. diff --git a/testsuite/tests/warnings/w04_failure.ml b/testsuite/tests/warnings/w04_failure.ml index 929226cd..98a84ff1 100644 --- a/testsuite/tests/warnings/w04_failure.ml +++ b/testsuite/tests/warnings/w04_failure.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + type ab = A | B type xy = X | Y diff --git a/testsuite/tests/warnings/w04_failure.reference b/testsuite/tests/warnings/w04_failure.reference deleted file mode 100644 index 8af70f40..00000000 --- a/testsuite/tests/warnings/w04_failure.reference +++ /dev/null @@ -1,9 +0,0 @@ -File "w04_failure.ml", line 9, characters 2-78: -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type repr. -File "w04_failure.ml", line 9, characters 2-78: -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type ab. -File "w04_failure.ml", line 9, characters 2-78: -Warning 4: this pattern-matching is fragile. -It will remain exhaustive when constructors are added to type xy. diff --git a/testsuite/tests/warnings/w06.compilers.reference b/testsuite/tests/warnings/w06.compilers.reference new file mode 100644 index 00000000..1c602821 --- /dev/null +++ b/testsuite/tests/warnings/w06.compilers.reference @@ -0,0 +1,4 @@ +File "w06.ml", line 16, characters 9-12: +Warning 6: label bar was omitted in the application of this function. +File "w06.ml", line 17, characters 9-12: +Warning 6: labels foo, baz were omitted in the application of this function. diff --git a/testsuite/tests/warnings/w06.ml b/testsuite/tests/warnings/w06.ml index 6e8a1bca..e8c64ffb 100644 --- a/testsuite/tests/warnings/w06.ml +++ b/testsuite/tests/warnings/w06.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + let foo ~bar = ignore bar (* one label *) let bar ~foo ~baz = ignore (foo, baz) (* two labels *) diff --git a/testsuite/tests/warnings/w06.reference b/testsuite/tests/warnings/w06.reference deleted file mode 100644 index b3019f4d..00000000 --- a/testsuite/tests/warnings/w06.reference +++ /dev/null @@ -1,4 +0,0 @@ -File "w06.ml", line 5, characters 9-12: -Warning 6: label bar was omitted in the application of this function. -File "w06.ml", line 6, characters 9-12: -Warning 6: labels foo, baz were omitted in the application of this function. diff --git a/testsuite/tests/warnings/w32.compilers.reference b/testsuite/tests/warnings/w32.compilers.reference new file mode 100644 index 00000000..2d5342db --- /dev/null +++ b/testsuite/tests/warnings/w32.compilers.reference @@ -0,0 +1,30 @@ +File "w32.ml", line 40, characters 24-25: +Warning 39: unused rec flag. +File "w32.ml", line 43, characters 24-25: +Warning 39: unused rec flag. +File "w32.ml", line 20, characters 4-5: +Warning 32: unused value h. +File "w32.ml", line 26, characters 4-5: +Warning 32: unused value j. +File "w32.ml", line 28, characters 4-5: +Warning 32: unused value k. +File "w32.ml", line 41, characters 4-5: +Warning 32: unused value r. +File "w32.ml", line 44, characters 20-21: +Warning 32: unused value t. +File "w32.ml", line 46, characters 24-25: +Warning 32: unused value u. +File "w32.ml", line 47, characters 4-5: +Warning 32: unused value v. +File "w32.ml", line 55, characters 22-23: +Warning 32: unused value g. +File "w32.ml", line 56, characters 22-23: +Warning 32: unused value h. +File "w32.ml", line 59, characters 22-23: +Warning 32: unused value k. +File "w32.ml", line 52, characters 0-174: +Warning 60: unused module M. +File "w32.ml", line 63, characters 18-29: +Warning 32: unused value x. +File "w32.ml", line 65, characters 18-29: +Warning 32: unused value x. diff --git a/testsuite/tests/warnings/w32.ml b/testsuite/tests/warnings/w32.ml index a3a17d3b..cab52568 100644 --- a/testsuite/tests/warnings/w32.ml +++ b/testsuite/tests/warnings/w32.ml @@ -1,3 +1,16 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "w32.mli" +*** ocamlc.byte +module = "w32.ml" +**** check-ocamlc.byte-output + +*) + (* from MPR#7624 *) let[@warning "-32"] f x = x @@ -45,3 +58,10 @@ module M = struct let j x = x and[@warning "+32"] k x = x end + +(* unused values in functor argument *) +module F (X : sig val x : int end) = struct end + +module G (X : sig val x : int end) = X + +module H (X : sig val x : int end) = X diff --git a/testsuite/tests/warnings/w32.mli b/testsuite/tests/warnings/w32.mli index 199e3508..8ffe03dd 100644 --- a/testsuite/tests/warnings/w32.mli +++ b/testsuite/tests/warnings/w32.mli @@ -7,3 +7,10 @@ val g : 'a -> 'a val n : 'a -> 'a val o : 'a -> 'a + +(* value in functor argument *) +module F (X : sig val x : int end) : sig end + +module G (X : sig val x : int end) : sig end + +module H (X : sig val x : int end) : sig val x : int end diff --git a/testsuite/tests/warnings/w32.reference b/testsuite/tests/warnings/w32.reference deleted file mode 100644 index 90401814..00000000 --- a/testsuite/tests/warnings/w32.reference +++ /dev/null @@ -1,26 +0,0 @@ -File "w32.ml", line 27, characters 24-25: -Warning 39: unused rec flag. -File "w32.ml", line 30, characters 24-25: -Warning 39: unused rec flag. -File "w32.ml", line 7, characters 4-5: -Warning 32: unused value h. -File "w32.ml", line 13, characters 4-5: -Warning 32: unused value j. -File "w32.ml", line 15, characters 4-5: -Warning 32: unused value k. -File "w32.ml", line 28, characters 4-5: -Warning 32: unused value r. -File "w32.ml", line 31, characters 20-21: -Warning 32: unused value t. -File "w32.ml", line 33, characters 24-25: -Warning 32: unused value u. -File "w32.ml", line 34, characters 4-5: -Warning 32: unused value v. -File "w32.ml", line 42, characters 22-23: -Warning 32: unused value g. -File "w32.ml", line 43, characters 22-23: -Warning 32: unused value h. -File "w32.ml", line 46, characters 22-23: -Warning 32: unused value k. -File "w32.ml", line 39, characters 0-174: -Warning 60: unused module M. diff --git a/testsuite/tests/warnings/w32b.compilers.reference b/testsuite/tests/warnings/w32b.compilers.reference new file mode 100644 index 00000000..9f8837bc --- /dev/null +++ b/testsuite/tests/warnings/w32b.compilers.reference @@ -0,0 +1,2 @@ +File "w32b.ml", line 13, characters 18-24: +Warning 34: unused type t. diff --git a/testsuite/tests/warnings/w32b.ml b/testsuite/tests/warnings/w32b.ml new file mode 100644 index 00000000..7f56659e --- /dev/null +++ b/testsuite/tests/warnings/w32b.ml @@ -0,0 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + +(* Check that [t] is considered unused without an .mli file (see GPR#1358) *) +module Q (M : sig type t end) = struct end diff --git a/testsuite/tests/warnings/w33.compilers.reference b/testsuite/tests/warnings/w33.compilers.reference new file mode 100644 index 00000000..0b1f4c4b --- /dev/null +++ b/testsuite/tests/warnings/w33.compilers.reference @@ -0,0 +1,4 @@ +File "w33.ml", line 19, characters 6-11: +Warning 33: unused open M. +File "w33.ml", line 27, characters 0-6: +Warning 33: unused open M. diff --git a/testsuite/tests/warnings/w33.ml b/testsuite/tests/warnings/w33.ml index 628fae3f..b6faa9af 100644 --- a/testsuite/tests/warnings/w33.ml +++ b/testsuite/tests/warnings/w33.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + (** Test unused opens, in particular in presence of pattern open *) diff --git a/testsuite/tests/warnings/w33.reference b/testsuite/tests/warnings/w33.reference deleted file mode 100644 index 9915965c..00000000 --- a/testsuite/tests/warnings/w33.reference +++ /dev/null @@ -1,4 +0,0 @@ -File "w33.ml", line 8, characters 6-11: -Warning 33: unused open M. -File "w33.ml", line 16, characters 0-6: -Warning 33: unused open M. diff --git a/testsuite/tests/warnings/w45.compilers.reference b/testsuite/tests/warnings/w45.compilers.reference new file mode 100644 index 00000000..9e74aed2 --- /dev/null +++ b/testsuite/tests/warnings/w45.compilers.reference @@ -0,0 +1,7 @@ +File "w45.ml", line 24, characters 2-9: +Warning 45: this open statement shadows the constructor X (which is later used) +File "w45.ml", line 26, characters 14-15: +Warning 41: X belongs to several types: T2.s T1.s +The first one was selected. Please disambiguate if this is wrong. +File "w45.ml", line 23, characters 2-9: +Warning 33: unused open T1. diff --git a/testsuite/tests/warnings/w45.ml b/testsuite/tests/warnings/w45.ml index efe89ffe..3442c745 100755 --- a/testsuite/tests/warnings/w45.ml +++ b/testsuite/tests/warnings/w45.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + module T1 = struct type t = A type s = X diff --git a/testsuite/tests/warnings/w45.reference b/testsuite/tests/warnings/w45.reference deleted file mode 100644 index 8c77ab05..00000000 --- a/testsuite/tests/warnings/w45.reference +++ /dev/null @@ -1,7 +0,0 @@ -File "w45.ml", line 13, characters 2-9: -Warning 45: this open statement shadows the constructor X (which is later used) -File "w45.ml", line 15, characters 14-15: -Warning 41: X belongs to several types: T2.s T1.s -The first one was selected. Please disambiguate if this is wrong. -File "w45.ml", line 12, characters 2-9: -Warning 33: unused open T1. diff --git a/testsuite/tests/warnings/w47_inline.compilers.reference b/testsuite/tests/warnings/w47_inline.compilers.reference new file mode 100644 index 00000000..e1735a8d --- /dev/null +++ b/testsuite/tests/warnings/w47_inline.compilers.reference @@ -0,0 +1,15 @@ +File "w47_inline.ml", line 15, characters 23-29: +Warning 47: illegal payload for attribute 'inline'. +It must be either empty, 'always' or 'never' +File "w47_inline.ml", line 16, characters 23-29: +Warning 47: illegal payload for attribute 'inline'. +It must be either empty, 'always' or 'never' +File "w47_inline.ml", line 17, characters 23-29: +Warning 47: illegal payload for attribute 'inline'. +It must be either empty, 'always' or 'never' +File "w47_inline.ml", line 18, characters 23-29: +Warning 47: illegal payload for attribute 'inline'. +It must be either empty, 'always' or 'never' +File "w47_inline.ml", line 23, characters 15-22: +Warning 47: illegal payload for attribute 'inlined'. +It must be either empty, 'always' or 'never' diff --git a/testsuite/tests/warnings/w47_inline.ml b/testsuite/tests/warnings/w47_inline.ml index 26794510..8ff34cc8 100644 --- a/testsuite/tests/warnings/w47_inline.ml +++ b/testsuite/tests/warnings/w47_inline.ml @@ -1,3 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) let a = (fun x -> x) [@inline] (* accepted *) let b = (fun x -> x) [@inline never] (* accepted *) diff --git a/testsuite/tests/warnings/w47_inline.reference b/testsuite/tests/warnings/w47_inline.reference deleted file mode 100644 index edc2d48b..00000000 --- a/testsuite/tests/warnings/w47_inline.reference +++ /dev/null @@ -1,15 +0,0 @@ -File "w47_inline.ml", line 13, characters 15-22: -Warning 47: illegal payload for attribute 'inlined'. -It must be either empty, 'always' or 'never' -File "w47_inline.ml", line 8, characters 23-29: -Warning 47: illegal payload for attribute 'inline'. -It must be either empty, 'always' or 'never' -File "w47_inline.ml", line 7, characters 23-29: -Warning 47: illegal payload for attribute 'inline'. -It must be either empty, 'always' or 'never' -File "w47_inline.ml", line 6, characters 23-29: -Warning 47: illegal payload for attribute 'inline'. -It must be either empty, 'always' or 'never' -File "w47_inline.ml", line 5, characters 23-29: -Warning 47: illegal payload for attribute 'inline'. -It must be either empty, 'always' or 'never' diff --git a/testsuite/tests/warnings/w50.compilers.reference b/testsuite/tests/warnings/w50.compilers.reference new file mode 100644 index 00000000..4628e0df --- /dev/null +++ b/testsuite/tests/warnings/w50.compilers.reference @@ -0,0 +1,4 @@ +File "w50.ml", line 13, characters 2-17: +Warning 60: unused module L. +File "w50.ml", line 17, characters 2-16: +Warning 60: unused module Y1. diff --git a/testsuite/tests/warnings/w50.ml b/testsuite/tests/warnings/w50.ml index 14877bbe..d0ac351c 100755 --- a/testsuite/tests/warnings/w50.ml +++ b/testsuite/tests/warnings/w50.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + module A : sig end = struct module L = List diff --git a/testsuite/tests/warnings/w50.reference b/testsuite/tests/warnings/w50.reference deleted file mode 100644 index db08d0aa..00000000 --- a/testsuite/tests/warnings/w50.reference +++ /dev/null @@ -1,4 +0,0 @@ -File "w50.ml", line 2, characters 2-17: -Warning 60: unused module L. -File "w50.ml", line 6, characters 2-16: -Warning 60: unused module Y1. diff --git a/testsuite/tests/warnings/w51.compilers.reference b/testsuite/tests/warnings/w51.compilers.reference new file mode 100644 index 00000000..95c98e67 --- /dev/null +++ b/testsuite/tests/warnings/w51.compilers.reference @@ -0,0 +1,2 @@ +File "w51.ml", line 14, characters 13-37: +Warning 51: expected tailcall diff --git a/testsuite/tests/warnings/w51.ml b/testsuite/tests/warnings/w51.ml index 25e08706..18d03ffe 100644 --- a/testsuite/tests/warnings/w51.ml +++ b/testsuite/tests/warnings/w51.ml @@ -1,3 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) let rec fact = function | 1 -> 1 diff --git a/testsuite/tests/warnings/w51.reference b/testsuite/tests/warnings/w51.reference deleted file mode 100644 index 5e3cf374..00000000 --- a/testsuite/tests/warnings/w51.reference +++ /dev/null @@ -1,2 +0,0 @@ -File "w51.ml", line 4, characters 13-37: -Warning 51: expected tailcall diff --git a/testsuite/tests/warnings/w51_bis.compilers.reference b/testsuite/tests/warnings/w51_bis.compilers.reference new file mode 100644 index 00000000..aa47c337 --- /dev/null +++ b/testsuite/tests/warnings/w51_bis.compilers.reference @@ -0,0 +1,2 @@ +File "w51_bis.ml", line 15, characters 12-48: +Warning 51: expected tailcall diff --git a/testsuite/tests/warnings/w51_bis.ml b/testsuite/tests/warnings/w51_bis.ml index 810fcdd4..58382556 100644 --- a/testsuite/tests/warnings/w51_bis.ml +++ b/testsuite/tests/warnings/w51_bis.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + let rec foldl op acc = function [] -> acc | x :: xs -> diff --git a/testsuite/tests/warnings/w51_bis.reference b/testsuite/tests/warnings/w51_bis.reference deleted file mode 100644 index ee5cab5a..00000000 --- a/testsuite/tests/warnings/w51_bis.reference +++ /dev/null @@ -1,2 +0,0 @@ -File "w51_bis.ml", line 4, characters 12-48: -Warning 51: expected tailcall diff --git a/testsuite/tests/warnings/w52.compilers.reference b/testsuite/tests/warnings/w52.compilers.reference new file mode 100644 index 00000000..546a14e0 --- /dev/null +++ b/testsuite/tests/warnings/w52.compilers.reference @@ -0,0 +1,12 @@ +File "w52.ml", line 12, characters 38-43: +Warning 52: Code should not depend on the actual values of +this constructor's arguments. They are only for information +and may change in future versions. (See manual section 9.5) +File "w52.ml", line 20, characters 7-17: +Warning 52: Code should not depend on the actual values of +this constructor's arguments. They are only for information +and may change in future versions. (See manual section 9.5) +File "w52.ml", line 25, characters 8-10: +Warning 52: Code should not depend on the actual values of +this constructor's arguments. They are only for information +and may change in future versions. (See manual section 9.5) diff --git a/testsuite/tests/warnings/w52.ml b/testsuite/tests/warnings/w52.ml new file mode 100644 index 00000000..58dec69d --- /dev/null +++ b/testsuite/tests/warnings/w52.ml @@ -0,0 +1,33 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + +let () = try () with Invalid_argument "Any" -> ();; + +type t = + | Warn of string [@ocaml.warn_on_literal_pattern] + | Without_warning of string + | Warn' of nativeint [@ocaml.warn_on_literal_pattern];; + +let f = function +| Warn "anything" -> () +| Warn _ | Warn' _ | Without_warning _ -> () +;; + +let g = function +| Warn' 0n -> () +| Warn _ | Warn' _ | Without_warning _ -> () +;; + + +let h = function +| Without_warning "outside" -> () +| Warn _ | Warn' _ | Without_warning _ -> () +;; diff --git a/testsuite/tests/warnings/w53.compilers.reference b/testsuite/tests/warnings/w53.compilers.reference new file mode 100644 index 00000000..0f37b0d6 --- /dev/null +++ b/testsuite/tests/warnings/w53.compilers.reference @@ -0,0 +1,26 @@ +File "w53.ml", line 12, characters 4-5: +Warning 32: unused value h. +File "w53.ml", line 12, characters 14-20: +Warning 53: the "inline" attribute cannot appear in this context +File "w53.ml", line 13, characters 14-26: +Warning 53: the "ocaml.inline" attribute cannot appear in this context +File "w53.ml", line 15, characters 14-21: +Warning 53: the "inlined" attribute cannot appear in this context +File "w53.ml", line 16, characters 14-27: +Warning 53: the "ocaml.inlined" attribute cannot appear in this context +File "w53.ml", line 19, characters 16-23: +Warning 53: the "inlined" attribute cannot appear in this context +File "w53.ml", line 21, characters 14-22: +Warning 53: the "tailcall" attribute cannot appear in this context +File "w53.ml", line 22, characters 14-28: +Warning 53: the "ocaml.tailcall" attribute cannot appear in this context +File "w53.ml", line 25, characters 16-24: +Warning 53: the "tailcall" attribute cannot appear in this context +File "w53.ml", line 33, characters 0-32: +Warning 53: the "inline" attribute cannot appear in this context +File "w53.ml", line 34, characters 0-39: +Warning 53: the "inline" attribute cannot appear in this context +File "w53.ml", line 40, characters 16-22: +Warning 53: the "inline" attribute cannot appear in this context +File "w53.ml", line 41, characters 17-29: +Warning 53: the "ocaml.inline" attribute cannot appear in this context diff --git a/testsuite/tests/warnings/w53.ml b/testsuite/tests/warnings/w53.ml index 9d77c3cc..4efdc2ab 100644 --- a/testsuite/tests/warnings/w53.ml +++ b/testsuite/tests/warnings/w53.ml @@ -1,3 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) let h x = x [@inline] (* rejected *) let h x = x [@ocaml.inline] (* rejected *) @@ -29,3 +39,5 @@ module F = (A [@inlined])(struct end) (* accepted *) module F' = (A [@ocaml.inlined])(struct end) (* accepted *) module G = (A [@inline])(struct end) (* rejected *) module G' = (A [@ocaml.inline])(struct end) (* rejected *) + +module H = Set.Make [@inlined] (Int32) (* GPR#1808 *) diff --git a/testsuite/tests/warnings/w53.reference b/testsuite/tests/warnings/w53.reference deleted file mode 100644 index 0f70e504..00000000 --- a/testsuite/tests/warnings/w53.reference +++ /dev/null @@ -1,26 +0,0 @@ -File "w53.ml", line 2, characters 4-5: -Warning 32: unused value h. -File "w53.ml", line 31, characters 17-29: -Warning 53: the "ocaml.inline" attribute cannot appear in this context -File "w53.ml", line 30, characters 16-22: -Warning 53: the "inline" attribute cannot appear in this context -File "w53.ml", line 24, characters 0-39: -Warning 53: the "inline" attribute cannot appear in this context -File "w53.ml", line 23, characters 0-32: -Warning 53: the "inline" attribute cannot appear in this context -File "w53.ml", line 15, characters 16-24: -Warning 53: the "tailcall" attribute cannot appear in this context -File "w53.ml", line 12, characters 14-28: -Warning 53: the "ocaml.tailcall" attribute cannot appear in this context -File "w53.ml", line 11, characters 14-22: -Warning 53: the "tailcall" attribute cannot appear in this context -File "w53.ml", line 9, characters 16-23: -Warning 53: the "inlined" attribute cannot appear in this context -File "w53.ml", line 6, characters 14-27: -Warning 53: the "ocaml.inlined" attribute cannot appear in this context -File "w53.ml", line 5, characters 14-21: -Warning 53: the "inlined" attribute cannot appear in this context -File "w53.ml", line 3, characters 14-26: -Warning 53: the "ocaml.inline" attribute cannot appear in this context -File "w53.ml", line 2, characters 14-20: -Warning 53: the "inline" attribute cannot appear in this context diff --git a/testsuite/tests/warnings/w54.compilers.reference b/testsuite/tests/warnings/w54.compilers.reference new file mode 100644 index 00000000..6a75df34 --- /dev/null +++ b/testsuite/tests/warnings/w54.compilers.reference @@ -0,0 +1,8 @@ +File "w54.ml", line 12, characters 33-39: +Warning 54: the "inline" attribute is used more than once on this expression +File "w54.ml", line 13, characters 51-63: +Warning 54: the "ocaml.inline" attribute is used more than once on this expression +File "w54.ml", line 15, characters 26-39: +Warning 54: the "ocaml.inlined" attribute is used more than once on this expression +File "w54.ml", line 19, characters 0-43: +Warning 54: the "inline" attribute is used more than once on this expression diff --git a/testsuite/tests/warnings/w54.ml b/testsuite/tests/warnings/w54.ml index 6ea66238..95bd04bd 100644 --- a/testsuite/tests/warnings/w54.ml +++ b/testsuite/tests/warnings/w54.ml @@ -1,3 +1,13 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) let f = (fun x -> x) [@inline] [@inline never] let g = (fun x -> x) [@inline] [@something_else] [@ocaml.inline] diff --git a/testsuite/tests/warnings/w54.reference b/testsuite/tests/warnings/w54.reference deleted file mode 100644 index 39c5d75d..00000000 --- a/testsuite/tests/warnings/w54.reference +++ /dev/null @@ -1,8 +0,0 @@ -File "w54.ml", line 9, characters 0-43: -Warning 54: the "inline" attribute is used more than once on this expression -File "w54.ml", line 5, characters 26-39: -Warning 54: the "ocaml.inlined" attribute is used more than once on this expression -File "w54.ml", line 3, characters 51-63: -Warning 54: the "ocaml.inline" attribute is used more than once on this expression -File "w54.ml", line 2, characters 33-39: -Warning 54: the "inline" attribute is used more than once on this expression diff --git a/testsuite/tests/warnings/w55.flambda.reference b/testsuite/tests/warnings/w55.flambda.reference new file mode 100644 index 00000000..f1a5b21a --- /dev/null +++ b/testsuite/tests/warnings/w55.flambda.reference @@ -0,0 +1,6 @@ +File "w55.ml", line 33, characters 10-26: +Warning 55: Cannot inline: [@inlined] attributes may not be used on partial applications +File "w55.ml", line 29, characters 10-27: +Warning 55: Cannot inline: [@inlined] attribute was not used on this function application (the optimizer did not know what function was being applied) +File "w55.ml", line 39, characters 12-30: +Warning 55: Cannot inline: [@inlined] attribute was not used on this function application (the optimizer did not know what function was being applied) diff --git a/testsuite/tests/warnings/w55.ml b/testsuite/tests/warnings/w55.ml new file mode 100644 index 00000000..6013ced4 --- /dev/null +++ b/testsuite/tests/warnings/w55.ml @@ -0,0 +1,42 @@ +(* TEST + +flags = "-w A" +compile_only = "true" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output + +* no-flambda +** setup-ocamlopt.byte-build-env +*** ocamlopt.byte +**** check-ocamlopt.byte-output + +* flambda +compiler_reference = "${test_source_directory}/w55.flambda.reference" +** setup-ocamlopt.byte-build-env +*** ocamlopt.byte +**** check-ocamlopt.byte-output + +*) + +let f = (fun x -> x + 1) [@inline never] + +let g x = (f [@inlined]) x + +let h = ref f + +let i x = (!h [@inlined]) x + +let j x y = x + y + +let h x = (j [@inlined]) x + +let a x = + let b = x + 1 in + fun y -> y + b + +let b x y = (a [@inlined]) x y + +let c x = x + 1 [@@inline never] +let d x = (c [@inlined]) x diff --git a/testsuite/tests/warnings/w55.native.reference b/testsuite/tests/warnings/w55.native.reference new file mode 100644 index 00000000..31315b26 --- /dev/null +++ b/testsuite/tests/warnings/w55.native.reference @@ -0,0 +1,12 @@ +File "w55.ml", line 25, characters 10-26: +Warning 55: Cannot inline: Function information unavailable +File "w55.ml", line 29, characters 10-27: +Warning 55: Cannot inline: Unknown function +File "w55.ml", line 33, characters 10-26: +Warning 55: Cannot inline: Partial application +File "w55.ml", line 39, characters 12-30: +Warning 55: Cannot inline: Over-application +File "w55.ml", line 39, characters 12-30: +Warning 55: Cannot inline: Function information unavailable +File "w55.ml", line 42, characters 10-26: +Warning 55: Cannot inline: Function information unavailable diff --git a/testsuite/tests/warnings/w55.opt_backend.clambda.opt_reference b/testsuite/tests/warnings/w55.opt_backend.clambda.opt_reference deleted file mode 100644 index 933e5d2a..00000000 --- a/testsuite/tests/warnings/w55.opt_backend.clambda.opt_reference +++ /dev/null @@ -1,12 +0,0 @@ -File "w55.opt_backend.ml", line 4, characters 10-26: -Warning 55: Cannot inline: Function information unavailable -File "w55.opt_backend.ml", line 8, characters 10-27: -Warning 55: Cannot inline: Unknown function -File "w55.opt_backend.ml", line 12, characters 10-26: -Warning 55: Cannot inline: Partial application -File "w55.opt_backend.ml", line 18, characters 12-30: -Warning 55: Cannot inline: Over-application -File "w55.opt_backend.ml", line 18, characters 12-30: -Warning 55: Cannot inline: Function information unavailable -File "w55.opt_backend.ml", line 21, characters 10-26: -Warning 55: Cannot inline: Function information unavailable diff --git a/testsuite/tests/warnings/w55.opt_backend.flambda.opt_reference b/testsuite/tests/warnings/w55.opt_backend.flambda.opt_reference deleted file mode 100644 index b1b51205..00000000 --- a/testsuite/tests/warnings/w55.opt_backend.flambda.opt_reference +++ /dev/null @@ -1,6 +0,0 @@ -File "w55.opt_backend.ml", line 12, characters 10-26: -Warning 55: Cannot inline: [@inlined] attributes may not be used on partial applications -File "w55.opt_backend.ml", line 8, characters 10-27: -Warning 55: Cannot inline: [@inlined] attribute was not used on this function application (the optimizer did not know what function was being applied) -File "w55.opt_backend.ml", line 18, characters 12-30: -Warning 55: Cannot inline: [@inlined] attribute was not used on this function application (the optimizer did not know what function was being applied) diff --git a/testsuite/tests/warnings/w55.opt_backend.ml b/testsuite/tests/warnings/w55.opt_backend.ml deleted file mode 100644 index aef2af50..00000000 --- a/testsuite/tests/warnings/w55.opt_backend.ml +++ /dev/null @@ -1,21 +0,0 @@ - -let f = (fun x -> x + 1) [@inline never] - -let g x = (f [@inlined]) x - -let h = ref f - -let i x = (!h [@inlined]) x - -let j x y = x + y - -let h x = (j [@inlined]) x - -let a x = - let b = x + 1 in - fun y -> y + b - -let b x y = (a [@inlined]) x y - -let c x = x + 1 [@@inline never] -let d x = (c [@inlined]) x diff --git a/testsuite/tests/warnings/w55.opt_backend.reference b/testsuite/tests/warnings/w55.opt_backend.reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/warnings/w58.ml b/testsuite/tests/warnings/w58.ml new file mode 100644 index 00000000..4e59ca5c --- /dev/null +++ b/testsuite/tests/warnings/w58.ml @@ -0,0 +1,22 @@ +(* TEST + +flags = "-w A" +files = "module_without_cmx.mli" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +module = "module_without_cmx.mli" +*** ocamlc.byte +module = "w58.ml" +**** check-ocamlc.byte-output + +* setup-ocamlopt.byte-build-env +** ocamlopt.byte +module = "module_without_cmx.mli" +*** ocamlopt.byte +module = "w58.ml" +**** check-ocamlopt.byte-output + +*) + +let () = print_endline (Module_without_cmx.id "Hello World") diff --git a/testsuite/tests/warnings/w58.opt.opt_reference b/testsuite/tests/warnings/w58.native.reference similarity index 100% rename from testsuite/tests/warnings/w58.opt.opt_reference rename to testsuite/tests/warnings/w58.native.reference diff --git a/testsuite/tests/warnings/w58.opt.ml b/testsuite/tests/warnings/w58.opt.ml deleted file mode 100644 index 8f7bfd27..00000000 --- a/testsuite/tests/warnings/w58.opt.ml +++ /dev/null @@ -1,2 +0,0 @@ - -let () = print_endline (Module_without_cmx.id "Hello World") diff --git a/testsuite/tests/warnings/w58.opt.reference b/testsuite/tests/warnings/w58.opt.reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/warnings/w59.flambda.reference b/testsuite/tests/warnings/w59.flambda.reference new file mode 100644 index 00000000..c8f62751 --- /dev/null +++ b/testsuite/tests/warnings/w59.flambda.reference @@ -0,0 +1,20 @@ +File "w59.ml", line 46, characters 2-43: +Warning 59: A potential assignment to a non-mutable value was detected +in this source file. Such assignments may generate incorrect code +when using Flambda. +File "w59.ml", line 47, characters 2-43: +Warning 59: A potential assignment to a non-mutable value was detected +in this source file. Such assignments may generate incorrect code +when using Flambda. +File "w59.ml", line 48, characters 2-43: +Warning 59: A potential assignment to a non-mutable value was detected +in this source file. Such assignments may generate incorrect code +when using Flambda. +File "w59.ml", line 49, characters 2-43: +Warning 59: A potential assignment to a non-mutable value was detected +in this source file. Such assignments may generate incorrect code +when using Flambda. +File "w59.ml", line 56, characters 2-7: +Warning 59: A potential assignment to a non-mutable value was detected +in this source file. Such assignments may generate incorrect code +when using Flambda. diff --git a/testsuite/tests/warnings/w59.ml b/testsuite/tests/warnings/w59.ml new file mode 100644 index 00000000..119e3638 --- /dev/null +++ b/testsuite/tests/warnings/w59.ml @@ -0,0 +1,65 @@ +(* TEST + +flags = "-w A" +compile_only = "true" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +*** check-ocamlc.byte-output + +* no-flambda +** setup-ocamlopt.byte-build-env +*** ocamlopt.byte +**** check-ocamlopt.byte-output + +* flambda +compiler_reference = "${test_source_directory}/w59.flambda.reference" +** setup-ocamlopt.byte-build-env +*** ocamlopt.byte +**** check-ocamlopt.byte-output + +*) + +(* Check that the warning 59 (assignment to immutable value) does not + trigger on those examples *) +let a = Lazy.force (lazy "a") +let b = Lazy.force (lazy 1) +let c = Lazy.force (lazy 3.14) +let d = Lazy.force (lazy 'a') +let e = Lazy.force (lazy (fun x -> x+1)) +let rec f (x:int) : int = g x and g x = f x +let h = Lazy.force (lazy f) +let i = Lazy.force (lazy g) +let j = Lazy.force (lazy 1L) +let k = Lazy.force (lazy (1,2)) +let l = Lazy.force (lazy [|3.14|]) +let m = Lazy.force (lazy (Sys.opaque_identity 3.14)) +let n = Lazy.force (lazy None) + +(* Check that obviously wrong code is reported *) +let o = (1,2) +let p = fun x -> x +let q = 3.14 +let r = 1 + +let () = + Obj.set_field (Obj.repr o) 0 (Obj.repr 3); + Obj.set_field (Obj.repr p) 0 (Obj.repr 3); + Obj.set_field (Obj.repr q) 0 (Obj.repr 3); + Obj.set_field (Obj.repr r) 0 (Obj.repr 3) + +let set v = + Obj.set_field (Obj.repr v) 0 (Obj.repr 3) + [@@inline] + +let () = + set o + +(* Sys.opaque_identity hides all information and shouldn't warn *) + +let opaque = Sys.opaque_identity (1,2) +let set_opaque = + Obj.set_field + (Obj.repr opaque) + 0 + (Obj.repr 3) diff --git a/testsuite/tests/warnings/w59.opt_backend.clambda.opt_reference b/testsuite/tests/warnings/w59.opt_backend.clambda.opt_reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/warnings/w59.opt_backend.flambda.opt_reference b/testsuite/tests/warnings/w59.opt_backend.flambda.opt_reference deleted file mode 100644 index b757eafd..00000000 --- a/testsuite/tests/warnings/w59.opt_backend.flambda.opt_reference +++ /dev/null @@ -1,20 +0,0 @@ -File "w59.opt_backend.ml", line 25, characters 2-43: -Warning 59: A potential assignment to a non-mutable value was detected -in this source file. Such assignments may generate incorrect code -when using Flambda. -File "w59.opt_backend.ml", line 26, characters 2-43: -Warning 59: A potential assignment to a non-mutable value was detected -in this source file. Such assignments may generate incorrect code -when using Flambda. -File "w59.opt_backend.ml", line 27, characters 2-43: -Warning 59: A potential assignment to a non-mutable value was detected -in this source file. Such assignments may generate incorrect code -when using Flambda. -File "w59.opt_backend.ml", line 28, characters 2-43: -Warning 59: A potential assignment to a non-mutable value was detected -in this source file. Such assignments may generate incorrect code -when using Flambda. -File "w59.opt_backend.ml", line 35, characters 2-7: -Warning 59: A potential assignment to a non-mutable value was detected -in this source file. Such assignments may generate incorrect code -when using Flambda. diff --git a/testsuite/tests/warnings/w59.opt_backend.ml b/testsuite/tests/warnings/w59.opt_backend.ml deleted file mode 100644 index 91e51474..00000000 --- a/testsuite/tests/warnings/w59.opt_backend.ml +++ /dev/null @@ -1,44 +0,0 @@ - -(* Check that the warning 59 (assignment to immutable value) does not - trigger on those examples *) -let a = Lazy.force (lazy "a") -let b = Lazy.force (lazy 1) -let c = Lazy.force (lazy 3.14) -let d = Lazy.force (lazy 'a') -let e = Lazy.force (lazy (fun x -> x+1)) -let rec f (x:int) : int = g x and g x = f x -let h = Lazy.force (lazy f) -let i = Lazy.force (lazy g) -let j = Lazy.force (lazy 1L) -let k = Lazy.force (lazy (1,2)) -let l = Lazy.force (lazy [|3.14|]) -let m = Lazy.force (lazy (Sys.opaque_identity 3.14)) -let n = Lazy.force (lazy None) - -(* Check that obviously wrong code is reported *) -let o = (1,2) -let p = fun x -> x -let q = 3.14 -let r = 1 - -let () = - Obj.set_field (Obj.repr o) 0 (Obj.repr 3); - Obj.set_field (Obj.repr p) 0 (Obj.repr 3); - Obj.set_field (Obj.repr q) 0 (Obj.repr 3); - Obj.set_field (Obj.repr r) 0 (Obj.repr 3) - -let set v = - Obj.set_field (Obj.repr v) 0 (Obj.repr 3) - [@@inline] - -let () = - set o - -(* Sys.opaque_identity hide all information and shouldn't warn *) - -let opaque = Sys.opaque_identity (1,2) -let set_opaque = - Obj.set_field - (Obj.repr opaque) - 0 - (Obj.repr 3) diff --git a/testsuite/tests/warnings/w59.opt_backend.reference b/testsuite/tests/warnings/w59.opt_backend.reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/warnings/w60.ml b/testsuite/tests/warnings/w60.ml index 01aed6f8..c7007afa 100755 --- a/testsuite/tests/warnings/w60.ml +++ b/testsuite/tests/warnings/w60.ml @@ -1,3 +1,14 @@ +(* TEST + +flags = "-w A" + +* setup-ocamlc.byte-build-env +** ocamlc.byte +compile_only = "true" +*** check-ocamlc.byte-output + +*) + (* PR#7314 *) module type Comparable = sig diff --git a/testsuite/tests/warnings/w60.reference b/testsuite/tests/warnings/w60.reference deleted file mode 100644 index e69de29b..00000000 diff --git a/testsuite/tests/win-unicode/Makefile b/testsuite/tests/win-unicode/Makefile index bc4adfad..def3d939 100644 --- a/testsuite/tests/win-unicode/Makefile +++ b/testsuite/tests/win-unicode/Makefile @@ -24,5 +24,11 @@ include $(BASEDIR)/makefiles/Makefile.common GENERATED_SOURCES=symlink_tests.precheck +ifeq ($(CCOMPTYPE),msvc) +CCOMP=set -o pipefail ; $(CC) $(CFLAGS) $(CPPFLAGS) /Fe$(1) $(addprefix /link ,$(LDFLAGS)) | tail -n +2 +else +CCOMP=$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $(1) +endif + %.exe: %.c - @$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(if $(filter msvc,$(CCOMPTYPE)),/Fe$*.exe,-o$*.exe) $*.c + @$(call CCOMP,$*.exe $*.c) diff --git a/testsuite/tools/Makefile b/testsuite/tools/Makefile index 8c9dd05a..2abced57 100644 --- a/testsuite/tools/Makefile +++ b/testsuite/tools/Makefile @@ -21,7 +21,7 @@ LIBRARIES=../../compilerlibs/ocamlcommon \ ../../compilerlibs/ocamlbytecomp \ ../../compilerlibs/ocamltoplevel -$(PROG): $(MAIN).cmo +$(PROG): $(MAIN).cmo $(LIBRARIES:=.cma) $(OCAMLC) -linkall -o $(PROG) $(LIBRARIES:=.cma) $(MAIN).cmo include $(BASEDIR)/makefiles/Makefile.common diff --git a/testsuite/tools/expect_test.ml b/testsuite/tools/expect_test.ml index 42c3027a..497328cf 100644 --- a/testsuite/tools/expect_test.ml +++ b/testsuite/tools/expect_test.ml @@ -132,11 +132,18 @@ let split_chunks phrases = module Compiler_messages = struct let print_loc ppf (loc : Location.t) = let startchar = loc.loc_start.pos_cnum - loc.loc_start.pos_bol in - let endchar = loc.loc_end.pos_cnum - loc.loc_start.pos_cnum + startchar in + let endchar = loc.loc_end.pos_cnum - loc.loc_start.pos_bol in Format.fprintf ppf "Line _"; if startchar >= 0 then Format.fprintf ppf ", characters %d-%d" startchar endchar; - Format.fprintf ppf ":@," + Format.fprintf ppf ":@."; + if startchar >= 0 then + begin match !Location.input_lexbuf with + | None -> () + | Some lexbuf -> + Location.show_code_at_location ppf lexbuf loc + end; + () let capture ppf ~f = Misc.protect_refs @@ -182,6 +189,7 @@ let parse_contents ~fname contents = let lexbuf = Lexing.from_string contents in Location.init lexbuf fname; Location.input_name := fname; + Location.input_lexbuf := Some lexbuf; Parse.use_file lexbuf let eval_expectation expectation ~output = @@ -245,8 +253,15 @@ let eval_expect_file _fname ~file_contents = try exec_phrase ppf phrase with exn -> - Location.report_exception ppf exn; - false) + let bt = Printexc.get_raw_backtrace () in + begin try Location.report_exception ppf exn + with _ -> + Format.fprintf ppf "Uncaught exception: %s\n%s\n" + (Printexc.to_string exn) + (Printexc.raw_backtrace_to_string bt) + end; + false + ) in Format.pp_print_flush ppf (); let len = Buffer.length buf in @@ -313,7 +328,7 @@ let process_expect_file fname = let correction = eval_expect_file fname ~file_contents in write_corrected ~file:corrected_fname ~file_contents correction -let repo_root = ref "" +let repo_root = ref None let main fname = Toploop.override_sys_argv @@ -321,25 +336,97 @@ let main fname = ~len:(Array.length Sys.argv - !Arg.current)); (* Ignore OCAMLRUNPARAM=b to be reproducible *) Printexc.record_backtrace false; - List.iter [ "stdlib" ] ~f:(fun s -> - Topdirs.dir_directory (Filename.concat !repo_root s)); + if not !Clflags.no_std_include then begin + match !repo_root with + | None -> () + | Some dir -> + (* If we pass [-repo-root], use the stdlib from inside the + compiler, not the installed one. We use + [Compenv.last_include_dirs] to make sure that the stdlib + directory is the last one. *) + Clflags.no_std_include := true; + Compenv.last_include_dirs := [Filename.concat dir "stdlib"] + end; + Compmisc.init_path false; Toploop.initialize_toplevel_env (); Sys.interactive := false; process_expect_file fname; exit 0 +module Options = Main_args.Make_bytetop_options (struct + let set r () = r := true + let clear r () = r := false + open Clflags + let _absname = set Location.absname + let _I dir = + let dir = Misc.expand_directory Config.standard_library dir in + include_dirs := dir :: !include_dirs + let _init s = init_file := Some s + let _noinit = set noinit + let _labels = clear classic + let _alias_deps = clear transparent_modules + let _no_alias_deps = set transparent_modules + let _app_funct = set applicative_functors + let _no_app_funct = clear applicative_functors + let _noassert = set noassert + let _nolabels = set classic + let _noprompt = set noprompt + let _nopromptcont = set nopromptcont + let _nostdlib = set no_std_include + let _open s = open_modules := s :: !open_modules + let _ppx _s = (* disabled *) () + let _principal = set principal + let _no_principal = clear principal + let _rectypes = set recursive_types + let _no_rectypes = clear recursive_types + let _safe_string = clear unsafe_string + let _short_paths = clear real_paths + let _stdin () = (* disabled *) () + let _strict_sequence = set strict_sequence + let _no_strict_sequence = clear strict_sequence + let _strict_formats = set strict_formats + let _no_strict_formats = clear strict_formats + let _unboxed_types = set unboxed_types + let _no_unboxed_types = clear unboxed_types + let _unsafe = set fast + let _unsafe_string = set unsafe_string + let _version () = (* disabled *) () + let _vnum () = (* disabled *) () + let _no_version = set noversion + let _w s = Warnings.parse_options false s + let _warn_error s = Warnings.parse_options true s + let _warn_help = Warnings.help_warnings + let _dparsetree = set dump_parsetree + let _dtypedtree = set dump_typedtree + let _dno_unique_ids = clear unique_ids + let _dunique_ids = set unique_ids + let _dsource = set dump_source + let _drawlambda = set dump_rawlambda + let _dlambda = set dump_lambda + let _dflambda = set dump_flambda + let _dtimings () = profile_columns := [ `Time ] + let _dprofile () = profile_columns := Profile.all_columns + let _dinstr = set dump_instr + + let _args = Arg.read_arg + let _args0 = Arg.read_arg0 + + let anonymous s = main s +end);; + let args = Arg.align - [ "-repo-root", Set_string repo_root, - " root of the OCaml repository" - ; "-principal", Set Clflags.principal, - " Evaluate the file with -principal set" - ] + ( [ "-repo-root", Arg.String (fun s -> repo_root := Some s), + " root of the OCaml repository. This causes the tool to use \ + the stdlib from the current source tree rather than the installed one." + ] @ Options.list + ) let usage = "Usage: expect_test [script-file [arguments]]\n\ options are:" let () = + Clflags.color := Some Misc.Color.Never; Clflags.error_size := 0; try Arg.parse args main usage; diff --git a/tools/Makefile b/tools/Makefile index 92d9e99e..78d2a106 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,17 +15,13 @@ MAKEFLAGS := -r -R include ../config/Makefile -INSTALL_BINDIR:=$(DESTDIR)$(BINDIR) -INSTALL_LIBDIR:=$(DESTDIR)$(LIBDIR) -INSTALL_COMPLIBDIR:=$(DESTDIR)$(COMPLIBDIR) -INSTALL_STUBLIBDIR:=$(DESTDIR)$(STUBLIBDIR) -INSTALL_MANDIR:=$(DESTDIR)$(MANDIR) +include ../Makefile.common ifeq ($(SYSTEM),unix) override define shellquote $i := $$(subst ",\",$$(subst $$$$,\$$$$,$$(subst `,\`,$i)))#")# endef -$(foreach i,BINDIR LIBDIR COMPLIBDIR STUBLIBDIR MANDIR,$(eval $(shellquote))) +$(foreach i,BINDIR LIBDIR STUBLIBDIR MANDIR,$(eval $(shellquote))) endif CAMLRUN ?= ../boot/ocamlrun @@ -128,6 +124,7 @@ clean:: CSLPROF=ocamlprof.cmo CSLPROF_IMPORTS=misc.cmo config.cmo identifiable.cmo numbers.cmo \ arg_helper.cmo clflags.cmo terminfo.cmo \ + build_path_prefix_map.cmo \ warnings.cmo location.cmo longident.cmo docstrings.cmo \ syntaxerr.cmo ast_helper.cmo parser.cmo lexer.cmo parse.cmo @@ -142,10 +139,14 @@ $(call byte_and_opt,ocamloptp,$(ocamlcp_cmos) ocamloptp.cmo,) opt:: profiling.cmx install:: - cp -- profiling.cmi profiling.cmo profiling.cmt profiling.cmti "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) \ + profiling.cmi profiling.cmo profiling.cmt profiling.cmti \ + "$(INSTALL_LIBDIR)" installopt:: - cp -- profiling.cmx profiling.$(O) "$(INSTALL_LIBDIR)" + $(INSTALL_DATA) \ + profiling.cmx profiling.$(O) \ + "$(INSTALL_LIBDIR)" # To help building mixed-mode libraries (OCaml + C) @@ -178,7 +179,7 @@ $(call byte_and_opt,ocamlmktop,$(OCAMLMKTOP_IMPORTS) $(OCAMLMKTOP),) # Converter olabl/ocaml 2.99 to ocaml 3 OCAML299TO3= lexer299.cmo ocaml299to3.cmo -LIBRARY3= misc.cmo warnings.cmo location.cmo +LIBRARY3= misc.cmo warnings.cmo build_path_prefix_map.cmo location.cmo ocaml299to3: $(OCAML299TO3) $(CAMLC) $(LINKFLAGS) -o ocaml299to3 $(LIBRARY3) $(OCAML299TO3) @@ -187,7 +188,7 @@ lexer299.ml: lexer299.mll $(CAMLLEX) lexer299.mll #install:: -# cp ocaml299to3 "$(INSTALL_BINDIR)/ocaml299to3$(EXE)" +# $(INSTALL_PROG) ocaml299to3 "$(INSTALL_BINDIR)/ocaml299to3$(EXE)" clean:: rm -f ocaml299to3 lexer299.ml @@ -203,7 +204,7 @@ lexer301.ml: lexer301.mll $(CAMLLEX) lexer301.mll #install:: -# cp scrapelabels "$(INSTALL_LIBDIR)" +# $(INSTALL_PROG) scrapelabels "$(INSTALL_LIBDIR)" clean:: rm -f scrapelabels lexer301.ml @@ -212,6 +213,7 @@ clean:: ADDLABELS_IMPORTS=misc.cmo config.cmo arg_helper.cmo clflags.cmo \ identifiable.cmo numbers.cmo terminfo.cmo \ + build_path_prefix_map.cmo \ warnings.cmo location.cmo longident.cmo docstrings.cmo \ syntaxerr.cmo ast_helper.cmo parser.cmo lexer.cmo parse.cmo @@ -220,7 +222,7 @@ addlabels: addlabels.cmo $(ADDLABELS_IMPORTS) addlabels.cmo #install:: -# cp addlabels "$(INSTALL_LIBDIR)" +# $(INSTALL_PROG) addlabels "$(INSTALL_LIBDIR)" ifeq ($(UNIX_OR_WIN32),unix) LN := ln -sf @@ -231,9 +233,9 @@ endif install:: for i in $(install_files); \ do \ - cp -- "$$i" "$(INSTALL_BINDIR)/$$i.byte$(EXE)" && \ + $(INSTALL_PROG) "$$i" "$(INSTALL_BINDIR)/$$i.byte$(EXE)" && \ if test -f "$$i".opt; then \ - cp -- "$$i.opt" "$(INSTALL_BINDIR)/$$i.opt$(EXE)" && \ + $(INSTALL_PROG) "$$i.opt" "$(INSTALL_BINDIR)/$$i.opt$(EXE)" && \ (cd "$(INSTALL_BINDIR)/" && $(LN) "$$i.opt$(EXE)" "$$i$(EXE)"); \ else \ (cd "$(INSTALL_BINDIR)/" && $(LN) "$$i.byte$(EXE)" "$$i$(EXE)"); \ @@ -277,9 +279,9 @@ $(call byte_and_opt,read_cmt,$(READ_CMT),) install:: if test -f read_cmt.opt; then \ - cp read_cmt.opt "$(INSTALL_BINDIR)/ocamlcmt$(EXE)"; \ + $(INSTALL_PROG) read_cmt.opt "$(INSTALL_BINDIR)/ocamlcmt$(EXE)"; \ else \ - cp read_cmt "$(INSTALL_BINDIR)/ocamlcmt$(EXE)"; \ + $(INSTALL_PROG) read_cmt "$(INSTALL_BINDIR)/ocamlcmt$(EXE)"; \ fi @@ -287,9 +289,9 @@ install:: DUMPOBJ=opnames.cmo dumpobj.cmo -$(call byte_and_opt,dumpobj,misc.cmo identifiable.cmo numbers.cmo tbl.cmo \ - config.cmo ident.cmo opcodes.cmo bytesections.cmo \ - $(DUMPOBJ),) +$(call byte_and_opt,dumpobj,misc.cmo config.cmo identifiable.cmo \ + numbers.cmo arg_helper.cmo clflags.cmo tbl.cmo \ + ident.cmo opcodes.cmo bytesections.cmo $(DUMPOBJ),) make_opcodes.ml: make_opcodes.mll $(CAMLLEX) make_opcodes.mll @@ -327,7 +329,8 @@ OBJINFO=../compilerlibs/ocamlcommon.cma \ $(call byte_and_opt,ocamlobjinfo,$(OBJINFO),objinfo_helper$(EXE)) install:: - cp objinfo_helper$(EXE) "$(INSTALL_LIBDIR)/objinfo_helper$(EXE)" + $(INSTALL_PROG) \ + objinfo_helper$(EXE) "$(INSTALL_LIBDIR)/objinfo_helper$(EXE)" # Scan object files for required primitives $(call byte_and_opt,primreq,config.cmo primreq.cmo,) @@ -369,7 +372,9 @@ $(call byte_and_opt,cmpbyt,$(CMPBYT),) ifeq "$(RUNTIMEI)" "true" install:: - cp ocaml-instr-graph ocaml-instr-report "$(INSTALL_BINDIR)/" + $(INSTALL_PROG) \ + ocaml-instr-graph ocaml-instr-report \ + "$(INSTALL_BINDIR)/" endif # Common stuff diff --git a/tools/ci-build b/tools/ci-build deleted file mode 100755 index a7489264..00000000 --- a/tools/ci-build +++ /dev/null @@ -1,239 +0,0 @@ -#!/bin/sh -#************************************************************************** -#* * -#* OCaml * -#* * -#* Damien Doligez, projet Gallium, INRIA Rocquencourt * -#* * -#* Copyright 2014 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -# This script is run on our continuous-integration servers to recompile -# from scratch and run the test suite. - -# To know the slave's architecture, this script looks at the OCAML_ARCH -# environment variable. For a given node NODe, this variable can be defined -# in Jenkins at the following address: -# https://ci.inria.fr/ocaml/computer/NODE/configure - -# Other environments variables that are honored: -# OCAML_CONFIGURE_OPTIONS additional options for configure -# OCAML_JOBS number of jobs to run in parallel (make -j) - -# Command-line arguments: -# -conf configure-option add configure-option to configure cmd line -# -patch1 file-name apply patch with -p1 -# -no-native do not build "opt" and "opt.opt" -# -jNN pass "-jNN" option to make for parallel builds - -error () { - echo "$1" >&2 - exit 3 -} - -arch_error() { - configure_url="https://ci.inria.fr/ocaml/computer/${NODE_NAME}/configure" - msg="Unknown architecture. Make sure the OCAML_ARCH environemnt" - msg="$msg variable has been defined." - msg="$msg\nSee ${configure_url}" - error "$msg" -} - -# Kill a task on Windows -# Errors are ignored -kill_task() -{ - task=$1 - taskkill /f /im ${task} || true -} - -quote1 () { - printf "'%s'" "`printf %s "$1" | sed -e "s/'/'\\\\\\\\''/g"`"; -} - -######################################################################### -# be verbose -set -x - -######################################################################### -# Save the current directory (on cygwin, /etc/profile changes it) -jenkinsdir="$(pwd)" -echo jenkinsdir=${jenkinsdir} - -######################################################################### -# If we are called from a Windows batch script, we must set up the -# Unix environment variables (e.g. PATH). - -case "${OCAML_ARCH}" in - bsd|macos|linux) ;; - cygwin|mingw|mingw64) - . /etc/profile - . "$HOME/.profile" - ;; - msvc) - . /etc/profile - . "$HOME/.profile" - . "$HOME/.msenv32" - ;; - msvc64) - . /etc/profile - . "$HOME/.profile" - . "$HOME/.msenv64" - ;; - *) arch_error;; -esac - -######################################################################### - -# be considerate towards other potential users of the test machine -case "${OCAML_ARCH}" in - bsd|macos|linux) renice 10 $$ ;; -esac - -# be verbose and stop on error -set -ex - -######################################################################### -# set up variables - -# default values -make=make -instdir="$HOME/ocaml-tmp-install" -configure=unix -confoptions="${OCAML_CONFIGURE_OPTIONS}" -make_native=true -cleanup=false -check_make_alldepend=false -dorebase=false -jobs='' - -case "${OCAML_ARCH}" in - bsd) make=gmake ;; - macos) ;; - linux) - confoptions="${confoptions} -with-instrumented-runtime" - check_make_alldepend=true - ;; - cygwin) - cleanup=true - check_make_alldepend=true - dorebase=true - ;; - mingw) - instdir='C:/ocamlmgw' - configure=nt - cleanup=true - check_make_alldepend=true - ;; - mingw64) - instdir='C:/ocamlmgw64' - configure=nt - cleanup=true - check_make_alldepend=true - ;; - msvc) - instdir='C:/ocamlms' - configure=nt - cleanup=true - ;; - msvc64) - instdir='C:/ocamlms64' - configure=nt - cleanup=true - ;; - *) arch_error;; -esac - -# Make sure two builds won't use the same install directory -instdir="$instdir-$$" - -case "${OCAML_JOBS}" in - [1-9]|[1-9][0-9]) jobs="-j${OCAML_JOBS}" ;; -esac - -######################################################################### -# On Windows, cleanup processes that may remain from previous run - -if $cleanup; then - tasks="tee ocamlrun program" - for task in ${tasks}; do kill_task ${task}.exe; done -fi - -######################################################################### -# Go to the right directory - -pwd -cd "$jenkinsdir" - -######################################################################### -# parse optional command-line arguments (has to be done after the "cd") - -while [ $# -gt 0 ]; do - case $1 in - -conf) confoptions="$confoptions `quote1 "$2"`"; shift;; - -patch1) patch -f -p1 <"$2"; shift;; - -no-native) make_native=false;; - -j[1-9]|-j[1-9][0-9]) jobs="$1";; - *) error "unknown option $1";; - esac - shift -done - -######################################################################### -# Do the work - -# Tell gcc to use only ASCII in its diagnostic outputs. -export LC_ALL=C - -$make -s distclean || : - -# `make distclean` does not clean the files from previous versions that -# are not produced by the current version, so use `git clean` in addition. -git clean -f -d -x - -case $configure in - unix) - confoptions="$confoptions -with-debug-runtime" - if $flambda; then - confoptions="$confoptions -flambda" - fi - eval "./configure -prefix '$instdir' $confoptions" - ;; - nt) - cp config/m-nt.h byterun/caml/m.h - cp config/s-nt.h byterun/caml/s.h - cp config/Makefile.${OCAML_ARCH} config/Makefile - sed -i "s%PREFIX=\(.\+\)%PREFIX=${instdir}%" config/Makefile - sed -i 's%RUNTIMED=.\+%RUNTIMED=true%' config/Makefile - if $flambda; then - sed -i 's%FLAMBDA=.\+%FLAMBDA=true%' config/Makefile - fi - ;; - *) error "internal error";; -esac - -$make $jobs coldstart -$make $jobs core -$make $jobs coreboot -$make $jobs world -if $make_native; then - $make $jobs opt - $make $jobs opt.opt - if $check_make_alldepend; then $make alldepend; fi -fi -if $dorebase; then - # temporary solution to the cygwin fork problem - rebase -b 0x7cd20000 otherlibs/unix/dllunix.so - rebase -b 0x7cdc0000 otherlibs/systhreads/dllthreads.so -fi -$make install - -rm -rf "$instdir" -cd testsuite -$make all diff --git a/tools/ci-build-other-configs b/tools/ci-build-other-configs deleted file mode 100755 index ac655815..00000000 --- a/tools/ci-build-other-configs +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -#************************************************************************** -#* * -#* OCaml * -#* * -#* Sebastien Hinderer, projet Gallium, INRIA Paris * -#* * -#* Copyright 2017 Institut National de Recherche en Informatique et * -#* en Automatique. * -#* * -#* All rights reserved. This file is distributed under the terms of * -#* the GNU Lesser General Public License version 2.1, with the * -#* special exception on linking described in the file LICENSE. * -#* * -#************************************************************************** - -# Commands to run for the 'other-configs' job on Inria's CI - -./tools/ci-build -conf -no-native-compiler -no-native -./tools/ci-build -conf -no-naked-pointers -./tools/ci-build -conf -flambda -conf -no-naked-pointers diff --git a/tools/ci/appveyor/appveyor_build.cmd b/tools/ci/appveyor/appveyor_build.cmd new file mode 100644 index 00000000..89cb8770 --- /dev/null +++ b/tools/ci/appveyor/appveyor_build.cmd @@ -0,0 +1,113 @@ +@rem *********************************************************************** +@rem * * +@rem * OCaml * +@rem * * +@rem * David Allsopp, OCaml Labs, Cambridge. * +@rem * * +@rem * Copyright 2017 MetaStack Solutions Ltd. * +@rem * * +@rem * All rights reserved. This file is distributed under the terms of * +@rem * the GNU Lesser General Public License version 2.1, with the * +@rem * special exception on linking described in the file LICENSE. * +@rem * * +@rem *********************************************************************** + +@rem BE CAREFUL ALTERING THIS FILE TO ENSURE THAT ERRORS PROPAGATE +@rem IF A COMMAND SHOULD FAIL IT PROBABLY NEEDS TO END WITH +@rem || exit /b 1 +@rem BASICALLY, DO THE TESTING IN BASH... + +@rem Do not call setlocal! +@echo off + +goto %1 + +goto :EOF + +:SaveVars +set OCAML_PREV_PATH=%PATH% +set OCAML_PREV_LIB=%LIB% +set OCAML_PREV_INCLUDE=%INCLUDE% +goto :EOF + +:RestoreVars +set PATH=%OCAML_PREV_PATH% +set LIB=%OCAML_PREV_LIB% +set INCLUDE=%OCAML_PREV_INCLUDE% +goto :EOF + +:CheckPackage +"%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %1" | findstr %1 > nul +if %ERRORLEVEL% equ 1 ( + echo Cygwin package %1 will be installed + set CYGWIN_INSTALL_PACKAGES=%CYGWIN_INSTALL_PACKAGES%,%1 +) +goto :EOF + +:UpgradeCygwin +if "%CYGWIN_INSTALL_PACKAGES%" neq "" "%CYG_ROOT%\setup-x86_64.exe" --quiet-mode --no-shortcuts --no-startmenu --no-desktop --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages %CYGWIN_INSTALL_PACKAGES:~1% > nul +for %%P in (%CYGWIN_COMMANDS%) do "%CYG_ROOT%\bin\%%P.exe" --version > nul || set CYGWIN_UPGRADE_REQUIRED=1 +"%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %CYGWIN_PACKAGES%" +if %CYGWIN_UPGRADE_REQUIRED% equ 1 ( + echo Cygwin package upgrade required - please go and drink coffee + "%CYG_ROOT%\setup-x86_64.exe" --quiet-mode --no-shortcuts --no-startmenu --no-desktop --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --upgrade-also > nul + "%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %CYGWIN_PACKAGES%" +) +goto :EOF + +:install +chcp 65001 > nul +rem This must be kept in sync with appveyor_build.sh +set BUILD_PREFIX=🐫реализация +git worktree add "..\%BUILD_PREFIX%-msvc64" -b appveyor-build-msvc64 +git worktree add "..\%BUILD_PREFIX%-mingw32" -b appveyor-build-mingw32 +git worktree add "..\%BUILD_PREFIX%-msvc32" -b appveyor-build-msvc32 +cd "..\%BUILD_PREFIX%-mingw32" +git submodule update --init flexdll + +cd "%APPVEYOR_BUILD_FOLDER%" +appveyor DownloadFile "https://github.com/alainfrisch/flexdll/archive/0.37.tar.gz" -FileName "flexdll.tar.gz" || exit /b 1 +appveyor DownloadFile "https://github.com/alainfrisch/flexdll/releases/download/0.37/flexdll-bin-0.37.zip" -FileName "flexdll.zip" || exit /b 1 +rem flexdll.zip is processed here, rather than in appveyor_build.sh because the +rem unzip command comes from MSYS2 (via Git for Windows) and it has to be +rem invoked via cmd /c in a bash script which is weird(er). +mkdir "%APPVEYOR_BUILD_FOLDER%\..\flexdll" +move flexdll.zip "%APPVEYOR_BUILD_FOLDER%\..\flexdll" +cd "%APPVEYOR_BUILD_FOLDER%\..\flexdll" && unzip -q flexdll.zip + +rem CYGWIN_PACKAGES is the list of required Cygwin packages (cygwin is included +rem in the list just so that the Cygwin version is always displayed on the log). +rem CYGWIN_COMMANDS is a corresponding command to run with --version to test +rem whether the package works. This is used to verify whether the installation +rem needs upgrading. +set CYGWIN_PACKAGES=cygwin make diffutils mingw64-i686-gcc-core +set CYGWIN_COMMANDS=cygcheck make diff i686-w64-mingw32-gcc + +set CYGWIN_INSTALL_PACKAGES= +set CYGWIN_UPGRADE_REQUIRED=0 + +for %%P in (%CYGWIN_PACKAGES%) do call :CheckPackage %%P +call :UpgradeCygwin + +"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/tools/ci/appveyor/appveyor_build.sh install" || exit /b 1 + +call :SaveVars +goto :EOF + +:build +rem Run the msvc64 and mingw32 builds +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/tools/ci/appveyor/appveyor_build.sh" || exit /b 1 + +rem Reconfigure the environment and run the msvc32 partial build +call :RestoreVars +call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x86 +"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/tools/ci/appveyor/appveyor_build.sh msvc32-only" || exit /b 1 +goto :EOF + +:test +rem Reconfigure the environment for the msvc64 build +call :RestoreVars +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +"%CYG_ROOT%\bin\bash.exe" -lec "$APPVEYOR_BUILD_FOLDER/tools/ci/appveyor/appveyor_build.sh test" || exit /b 1 +goto :EOF diff --git a/appveyor_build.sh b/tools/ci/appveyor/appveyor_build.sh similarity index 100% rename from appveyor_build.sh rename to tools/ci/appveyor/appveyor_build.sh diff --git a/tools/ci/inria/main b/tools/ci/inria/main new file mode 100755 index 00000000..11e41fee --- /dev/null +++ b/tools/ci/inria/main @@ -0,0 +1,240 @@ +#!/bin/sh +#************************************************************************** +#* * +#* OCaml * +#* * +#* Damien Doligez, projet Gallium, INRIA Rocquencourt * +#* * +#* Copyright 2014 Institut National de Recherche en Informatique et * +#* en Automatique. * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# This script is run on our continuous-integration servers to recompile +# from scratch and run the test suite. + +# To know the slave's architecture, this script looks at the OCAML_ARCH +# environment variable. For a given node NODe, this variable can be defined +# in Jenkins at the following address: +# https://ci.inria.fr/ocaml/computer/NODE/configure + +# Other environments variables that are honored: +# OCAML_CONFIGURE_OPTIONS additional options for configure +# OCAML_JOBS number of jobs to run in parallel (make -j) + +# Command-line arguments: +# -conf configure-option add configure-option to configure cmd line +# -patch1 file-name apply patch with -p1 +# -no-native do not build "opt" and "opt.opt" +# -jNN pass "-jNN" option to make for parallel builds + +error () { + echo "$1" >&2 + exit 3 +} + +arch_error() { + configure_url="https://ci.inria.fr/ocaml/computer/${NODE_NAME}/configure" + msg="Unknown architecture. Make sure the OCAML_ARCH environemnt" + msg="$msg variable has been defined." + msg="$msg\nSee ${configure_url}" + error "$msg" +} + +# Kill a task on Windows +# Errors are ignored +kill_task() +{ + task=$1 + taskkill /f /im ${task} /t || true +} + +quote1 () { + printf "'%s'" "`printf %s "$1" | sed -e "s/'/'\\\\\\\\''/g"`"; +} + +######################################################################### +# be verbose +set -x + +######################################################################### +# Save the current directory (on cygwin, /etc/profile changes it) +jenkinsdir="$(pwd)" +echo jenkinsdir=${jenkinsdir} + +######################################################################### +# If we are called from a Windows batch script, we must set up the +# Unix environment variables (e.g. PATH). + +case "${OCAML_ARCH}" in + bsd|macos|linux) ;; + cygwin|mingw|mingw64) + . /etc/profile + . "$HOME/.profile" + ;; + msvc) + . /etc/profile + . "$HOME/.profile" + . "$HOME/.msenv32" + ;; + msvc64) + . /etc/profile + . "$HOME/.profile" + . "$HOME/.msenv64" + ;; + *) arch_error;; +esac + +######################################################################### + +# be considerate towards other potential users of the test machine +case "${OCAML_ARCH}" in + bsd|macos|linux) renice 10 $$ ;; +esac + +# be verbose and stop on error +set -ex + +######################################################################### +# set up variables + +# default values +make=make +instdir="$HOME/ocaml-tmp-install" +configure=unix +confoptions="${OCAML_CONFIGURE_OPTIONS}" +make_native=true +cleanup=false +check_make_alldepend=false +dorebase=false +jobs='' + +case "${OCAML_ARCH}" in + bsd) make=gmake ;; + macos) ;; + linux) + confoptions="${confoptions} -with-instrumented-runtime" + check_make_alldepend=true + ;; + cygwin) + cleanup=true + check_make_alldepend=true + dorebase=true + ;; + mingw) + instdir='C:/ocamlmgw' + configure=nt + cleanup=true + check_make_alldepend=true + ;; + mingw64) + instdir='C:/ocamlmgw64' + configure=nt + cleanup=true + check_make_alldepend=true + ;; + msvc) + instdir='C:/ocamlms' + configure=nt + cleanup=true + ;; + msvc64) + instdir='C:/ocamlms64' + configure=nt + cleanup=true + ;; + *) arch_error;; +esac + +# Make sure two builds won't use the same install directory +instdir="$instdir-$$" + +case "${OCAML_JOBS}" in + [1-9]|[1-9][0-9]) jobs="-j${OCAML_JOBS}" ;; +esac + +######################################################################### +# On Windows, cleanup processes that may remain from previous run + +if $cleanup; then + tasks="tee ocamlrun program ocamltest ocamltest.opt" + for task in ${tasks}; do kill_task ${task}.exe; done +fi + +######################################################################### +# Go to the right directory + +pwd +cd "$jenkinsdir" + +######################################################################### +# parse optional command-line arguments (has to be done after the "cd") + +while [ $# -gt 0 ]; do + case $1 in + -conf) confoptions="$confoptions `quote1 "$2"`"; shift;; + -patch1) patch -f -p1 <"$2"; shift;; + -no-native) make_native=false;; + -j[1-9]|-j[1-9][0-9]) jobs="$1";; + *) error "unknown option $1";; + esac + shift +done + +######################################################################### +# Do the work + +# Tell gcc to use only ASCII in its diagnostic outputs. +export LC_ALL=C + +$make -s distclean || : + +# `make distclean` does not clean the files from previous versions that +# are not produced by the current version, so use `git clean` in addition. +git clean -f -d -x + +case $configure in + unix) + confoptions="$confoptions -with-debug-runtime" + if $flambda; then + confoptions="$confoptions -flambda -with-flambda-invariants" + fi + eval "./configure -prefix '$instdir' $confoptions" + ;; + nt) + cp config/m-nt.h byterun/caml/m.h + cp config/s-nt.h byterun/caml/s.h + cp config/Makefile.${OCAML_ARCH} config/Makefile + sed -i "s%PREFIX=\(.\+\)%PREFIX=${instdir}%" config/Makefile + sed -i 's%RUNTIMED=.\+%RUNTIMED=true%' config/Makefile + if $flambda; then + sed -i 's%FLAMBDA=.\+%FLAMBDA=true%' config/Makefile + fi + ;; + *) error "internal error";; +esac + +if $make_native; then + $make $jobs world.opt + if $check_make_alldepend; then $make alldepend; fi +else + $make $jobs world +fi +if $dorebase; then + # temporary solution to the cygwin fork problem + # see https://github.com/alainfrisch/flexdll/issues/50 + rebase -b 0x7cd20000 otherlibs/unix/dllunix.so + rebase -b 0x7cdc0000 otherlibs/systhreads/dllthreads.so +fi +$make install + +rm -rf "$instdir" +cd testsuite +if test -n "$jobs" && test -x /usr/bin/parallel +then PARALLEL="$jobs $PARALLEL" $make parallel +else $make all +fi diff --git a/tools/ci/inria/other-configs b/tools/ci/inria/other-configs new file mode 100755 index 00000000..c9ef0e98 --- /dev/null +++ b/tools/ci/inria/other-configs @@ -0,0 +1,29 @@ +#!/bin/sh +#************************************************************************** +#* * +#* OCaml * +#* * +#* Sebastien Hinderer, projet Gallium, INRIA Paris * +#* * +#* Copyright 2017 Institut National de Recherche en Informatique et * +#* en Automatique. * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +# Commands to run for the 'other-configs' job on Inria's CI + +# Stop on error +set -e + +mainjob=./tools/ci/inria/main +main="${mainjob} -j8" + +${main} -conf -no-native-compiler -no-native +${main} -conf -no-naked-pointers +${main} -conf -no-flat-float-array +${main} -conf -flambda -conf -no-naked-pointers +OCAMLRUNPARAM="c=1" ${main} diff --git a/tools/ci/travis/travis-ci.sh b/tools/ci/travis/travis-ci.sh new file mode 100755 index 00000000..c4dbab84 --- /dev/null +++ b/tools/ci/travis/travis-ci.sh @@ -0,0 +1,160 @@ +#!/bin/bash +#************************************************************************** +#* * +#* OCaml * +#* * +#* Anil Madhavapeddy, OCaml Labs * +#* * +#* Copyright 2014 Institut National de Recherche en Informatique et * +#* en Automatique. * +#* * +#* All rights reserved. This file is distributed under the terms of * +#* the GNU Lesser General Public License version 2.1, with the * +#* special exception on linking described in the file LICENSE. * +#* * +#************************************************************************** + +PREFIX=~/local + +MAKE=make SHELL=dash + +# TRAVIS_COMMIT_RANGE has the form ... +# TRAVIS_CUR_HEAD is +# TRAVIS_PR_HEAD is +# +# The following diagram illustrates the relationship between +# the commits: +# +# (trunk) (pr branch) +# TRAVIS_CUR_HEAD TRAVIS_PR_HEAD +# | / +# ... ... +# | / +# TRAVIS_MERGE_BASE +# +echo TRAVIS_COMMIT_RANGE=$TRAVIS_COMMIT_RANGE +TRAVIS_CUR_HEAD=${TRAVIS_COMMIT_RANGE%%...*} +TRAVIS_PR_HEAD=${TRAVIS_COMMIT_RANGE##*...} +case $TRAVIS_EVENT_TYPE in + # If this is not a pull request then TRAVIS_COMMIT_RANGE may be empty. + pull_request) + TRAVIS_MERGE_BASE=$(git merge-base $TRAVIS_CUR_HEAD $TRAVIS_PR_HEAD);; +esac + +BuildAndTest () { + mkdir -p $PREFIX + cat< /dev/null && CheckNoChangesMessage || echo pass +} + +CheckNoChangesMessage () { + API_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/issues/$TRAVIS_PULL_REQUEST/labels + if test -n "$(git log --grep="[Nn]o [Cc]hange.* needed" --max-count=1 \ + ${TRAVIS_MERGE_BASE}..${TRAVIS_PR_HEAD})" + then echo pass + elif test -n "$(curl $API_URL | grep 'no-change-entry-needed')" + then echo pass + else exit 1 + fi +} + +CheckTestsuiteModified () { + cat< /dev/null && exit 1 || echo pass +} + +case $CI_KIND in +build) BuildAndTest;; +changes) + case $TRAVIS_EVENT_TYPE in + pull_request) CheckChangesModified;; + esac;; +tests) + case $TRAVIS_EVENT_TYPE in + pull_request) CheckTestsuiteModified;; + esac;; +*) echo unknown CI kind + exit 1 + ;; +esac diff --git a/tools/dumpobj.ml b/tools/dumpobj.ml index 49450511..5d2e43aa 100644 --- a/tools/dumpobj.ml +++ b/tools/dumpobj.ml @@ -335,7 +335,8 @@ let op_shapes = [ opGETVECTITEM, Nothing; opSETVECTITEM, Nothing; opGETSTRINGCHAR, Nothing; - opSETSTRINGCHAR, Nothing; + opGETBYTESCHAR, Nothing; + opSETBYTESCHAR, Nothing; opBRANCH, Disp; opBRANCHIF, Disp; opBRANCHIFNOT, Disp; diff --git a/tools/make-version-header.sh b/tools/make-version-header.sh index ce3b70c6..707d04fa 100755 --- a/tools/make-version-header.sh +++ b/tools/make-version-header.sh @@ -39,7 +39,7 @@ case $# in esac major="`echo "$version" | sed -n -e '1s/^\([0-9]*\)\..*/\1/p'`" -minor="`echo "$version" | sed -n -e '1s/^[0-9]*\.\([0-9]*\).*/\1/p'`" +minor="`echo "$version" | sed -n -e '1s/^[0-9]*\.0*\([0-9]*\).*/\1/p'`" patchlvl="`echo "$version" | sed -n -e '1s/^[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/p'`" suffix="`echo "$version" | sed -n -e '1s/^[^+]*+\(.*\)/\1/p'`" diff --git a/tools/objinfo.ml b/tools/objinfo.ml index 6f0dfaac..0e780991 100644 --- a/tools/objinfo.ml +++ b/tools/objinfo.ml @@ -23,9 +23,12 @@ open Misc open Config open Cmo_format -(* Command line option to prevent printing approximation and function code *) +(* Command line options to prevent printing approximation, + function code and CRC + *) let no_approx = ref false let no_code = ref false +let no_crc = ref false let input_stringlist ic len = let get_string_list sect len = @@ -41,12 +44,15 @@ let input_stringlist ic len = get_string_list sect len let dummy_crc = String.make 32 '-' +let null_crc = String.make 32 '0' + +let string_of_crc crc = if !no_crc then null_crc else Digest.to_hex crc let print_name_crc (name, crco) = let crc = match crco with None -> dummy_crc - | Some crc -> Digest.to_hex crc + | Some crc -> string_of_crc crc in printf "\t%s\t%s\n" crc name @@ -107,11 +113,11 @@ let print_cmt_infos cmt = printf "cmt interface digest: %s\n" (match cmt.cmt_interface_digest with | None -> "" - | Some crc -> Digest.to_hex crc) + | Some crc -> string_of_crc crc) let print_general_infos name crc defines cmi cmx = printf "Name: %s\n" name; - printf "CRC of implementation: %s\n" (Digest.to_hex crc); + printf "CRC of implementation: %s\n" (string_of_crc crc); printf "Globals defined:\n"; List.iter print_line defines; printf "Interfaces imported:\n"; @@ -150,7 +156,7 @@ let print_cmx_infos (ui, crc) = Compilation_unit.set_current cu; let root_symbols = List.map (fun s -> - Symbol.unsafe_create cu (Linkage_name.create ("caml"^s))) + Symbol.of_global_linkage cu (Linkage_name.create ("caml"^s))) ui.ui_defines in Format.printf "approximations@ %a@.@." @@ -323,6 +329,7 @@ let dump_obj filename = let arg_list = [ "-no-approx", Arg.Set no_approx, " Do not print module approximation information"; "-no-code", Arg.Set no_code, " Do not print code from exported flambda functions"; + "-null-crc", Arg.Set no_crc, " Print a null CRC for imported interfaces"; "-args", Arg.Expand Arg.read_arg, " Read additional newline separated command line arguments \n\ \ from "; diff --git a/tools/ocamlcp.ml b/tools/ocamlcp.ml index 0aeaf2ce..eed29359 100644 --- a/tools/ocamlcp.ml +++ b/tools/ocamlcp.ml @@ -118,6 +118,8 @@ module Options = Main_args.Make_bytecomp_options (struct let _color s = option_with_arg "-color" s let _where = option "-where" let _nopervasives = option "-nopervasives" + let _dno_unique_ids = option "-dno-unique-ids" + let _dunique_ids = option "-dunique-ids" let _dsource = option "-dsource" let _dparsetree = option "-dparsetree" let _dtypedtree = option "-dtypedtree" diff --git a/tools/ocamloptp.ml b/tools/ocamloptp.ml index 4683cc03..fbeee6de 100644 --- a/tools/ocamloptp.ml +++ b/tools/ocamloptp.ml @@ -146,6 +146,8 @@ module Options = Main_args.Make_optcomp_options (struct let _linscan = option "-linscan" let _nopervasives = option "-nopervasives" + let _dno_unique_ids = option "-dno-unique_ids" + let _dunique_ids = option "-dunique_ids" let _dsource = option "-dsource" let _dparsetree = option "-dparsetree" let _dtypedtree = option "-dtypedtree" @@ -155,6 +157,7 @@ module Options = Main_args.Make_optcomp_options (struct let _dclambda = option "-dclambda" let _drawflambda = option "-drawflambda" let _dflambda = option "-dflambda" + let _dflambda_invariants = option "-dflambda-invariants" let _dflambda_no_invariants = option "-dflambda-no-invariants" let _dflambda_let stamp = option_with_int "-dflambda-let" stamp let _dflambda_verbose = option "-dflambda-verbose" diff --git a/toplevel/opttoploop.ml b/toplevel/opttoploop.ml index d5a45ee1..cd6d91da 100644 --- a/toplevel/opttoploop.ml +++ b/toplevel/opttoploop.ml @@ -82,7 +82,7 @@ let toplevel_value id = let close_phrase lam = let open Lambda in - IdentSet.fold (fun id l -> + Ident.Set.fold (fun id l -> let glb, pos = toplevel_value id in let glob = Lprim (Pfield pos, @@ -329,7 +329,7 @@ let execute_phrase print_outcome ppf phr = else Compilenv.record_global_approx_toplevel (); if print_outcome then - Printtyp.wrap_printing_env oldenv (fun () -> + Printtyp.wrap_printing_env ~error:false oldenv (fun () -> match str.str_items with | [] -> Ophr_signature [] | _ -> diff --git a/toplevel/opttopmain.ml b/toplevel/opttopmain.ml index f199d44d..423d68c2 100644 --- a/toplevel/opttopmain.ml +++ b/toplevel/opttopmain.ml @@ -174,6 +174,7 @@ module Options = Main_args.Make_opttop_options (struct let _dflambda_verbose () = set dump_flambda (); set dump_flambda_verbose () + let _dflambda_invariants = set flambda_invariant_checks let _dflambda_no_invariants = clear flambda_invariant_checks let _labels = clear classic let _alias_deps = clear transparent_modules @@ -210,6 +211,8 @@ module Options = Main_args.Make_opttop_options (struct let _warn_error s = Warnings.parse_options true s let _warn_help = Warnings.help_warnings + let _dno_unique_ids = clear unique_ids + let _dunique_ids = set unique_ids let _dsource = set dump_source let _dparsetree = set dump_parsetree let _dtypedtree = set dump_typedtree diff --git a/toplevel/topdirs.ml b/toplevel/topdirs.ml index c956513b..ec61f572 100644 --- a/toplevel/topdirs.ml +++ b/toplevel/topdirs.ml @@ -508,7 +508,7 @@ let show_prim to_sig ppf lid = in let id = Ident.create_persistent s in let sg = to_sig env loc id lid in - Printtyp.wrap_printing_env env + Printtyp.wrap_printing_env ~error:false env (fun () -> fprintf ppf "@[%a@]@." Printtyp.signature sg) with | Not_found -> diff --git a/toplevel/toploop.ml b/toplevel/toploop.ml index e832fde5..bd8720a6 100644 --- a/toplevel/toploop.ml +++ b/toplevel/toploop.ml @@ -262,7 +262,7 @@ let execute_phrase print_outcome ppf phr = match res with | Result v -> if print_outcome then - Printtyp.wrap_printing_env oldenv (fun () -> + Printtyp.wrap_printing_env ~error:false oldenv (fun () -> match str.str_items with | [ { str_desc = (Tstr_eval (exp, _) diff --git a/toplevel/topmain.ml b/toplevel/topmain.ml index 083b427e..4b1a06a6 100644 --- a/toplevel/topmain.ml +++ b/toplevel/topmain.ml @@ -139,6 +139,8 @@ module Options = Main_args.Make_bytetop_options (struct let _warn_help = Warnings.help_warnings let _dparsetree = set dump_parsetree let _dtypedtree = set dump_typedtree + let _dno_unique_ids = clear unique_ids + let _dunique_ids = set unique_ids let _dsource = set dump_source let _drawlambda = set dump_rawlambda let _dlambda = set dump_lambda diff --git a/typing/btype.ml b/typing/btype.ml index d94693b1..c4f03ac3 100644 --- a/typing/btype.ml +++ b/typing/btype.ml @@ -44,7 +44,7 @@ let pivot_level = 2 * lowest_level - 1 let new_id = ref (-1) let newty2 level desc = - incr new_id; { desc; level; id = !new_id } + incr new_id; { desc; level; scope = None; id = !new_id } let newgenty desc = newty2 generic_level desc let newgenvar ?name () = newgenty (Tvar name) (* @@ -72,6 +72,7 @@ type change = Ctype of type_expr * type_desc | Ccompress of type_expr * type_desc * type_desc | Clevel of type_expr * int + | Cscope of type_expr * int option | Cname of (Path.t * type_expr list) option ref * (Path.t * type_expr list) option | Crow of row_field option ref * row_field option @@ -582,7 +583,7 @@ let memorize_abbrev mem priv path v v' = let rec forget_abbrev_rec mem path = match mem with Mnil -> - assert false + mem | Mcons (_, path', _, _, rem) when Path.same path path' -> rem | Mcons (priv, path', v, v', rem) -> @@ -639,6 +640,7 @@ let undo_change = function Ctype (ty, desc) -> ty.desc <- desc | Ccompress (ty, desc, _) -> ty.desc <- desc | Clevel (ty, level) -> ty.level <- level + | Cscope (ty, scope) -> ty.scope <- scope | Cname (r, v) -> r := v | Crow (r, v) -> r := v | Ckind (r, v) -> r := v @@ -672,6 +674,9 @@ let link_type ty ty' = let set_level ty level = if ty.id <= !last_snapshot then log_change (Clevel (ty, ty.level)); ty.level <- level +let set_scope ty scope = + if ty.id <= !last_snapshot then log_change (Cscope (ty, ty.scope)); + ty.scope <- scope let set_univar rty ty = log_change (Cuniv (rty, !rty)); rty := Some ty let set_name nm v = diff --git a/typing/btype.mli b/typing/btype.mli index aaa426a8..630f2598 100644 --- a/typing/btype.mli +++ b/typing/btype.mli @@ -198,6 +198,7 @@ val link_type: type_expr -> type_expr -> unit (* Set the desc field of [t1] to [Tlink t2], logging the old value if there is an active snapshot *) val set_level: type_expr -> int -> unit +val set_scope: type_expr -> int option -> unit val set_name: (Path.t * type_expr list) option ref -> (Path.t * type_expr list) option -> unit diff --git a/typing/cmt_format.ml b/typing/cmt_format.ml index fda1a4a5..e0cc55ad 100644 --- a/typing/cmt_format.ml +++ b/typing/cmt_format.ml @@ -182,7 +182,7 @@ let save_cmt filename modname binary_annots sourcefile initial_env cmi = cmt_comments = Lexer.comments (); cmt_args = Sys.argv; cmt_sourcefile = sourcefile; - cmt_builddir = Sys.getcwd (); + cmt_builddir = Location.rewrite_absolute_path (Sys.getcwd ()); cmt_loadpath = !Config.load_path; cmt_source_digest = source_digest; cmt_initial_env = if need_to_clear_env then diff --git a/typing/ctype.ml b/typing/ctype.ml index df46de1f..f24e46d1 100644 --- a/typing/ctype.ml +++ b/typing/ctype.ml @@ -291,6 +291,16 @@ let associate_fields fields1 fields2 = in associate [] [] [] (fields1, fields2) +let rec has_dummy_method ty = + match repr ty with + {desc = Tfield (m, _, _, ty2)} -> + m = dummy_method || has_dummy_method ty2 + | _ -> false + +let is_self_type = function + | Tobject (ty, _) -> has_dummy_method ty + | _ -> false + (**** Check whether an object is open ****) (* +++ The abbreviation should eventually be expanded *) @@ -319,6 +329,7 @@ let close_object ty = match ty.desc with Tvar _ -> link_type ty (newty2 ty.level Tnil) + | Tfield(lab, _, _, _) when lab = dummy_method -> raise (Unify []) | Tfield(_, _, _, ty') -> close ty' | _ -> assert false in @@ -673,15 +684,8 @@ let forward_try_expand_once = (* Forward declaration *) module M = struct type t let _ = (x : t list ref) end (without this constraint, the type system would actually be unsound.) *) -let get_level env p = - try - match (Env.find_type p env).type_newtype_level with - | None -> Path.binding_time p - | Some (x, _) -> x - with - | Not_found -> - (* no newtypes in predef *) - Path.binding_time p +let get_path_scope p = + Path.binding_time p let rec normalize_package_path env p = let t = @@ -699,25 +703,55 @@ let rec normalize_package_path env p = normalize_package_path env (Path.Pdot (p1', s, n)) | _ -> p +let check_scope_escape level ty = + let rec aux ty = + let ty = repr ty in + if ty.level >= lowest_level then begin + ty.level <- pivot_level - ty.level; + begin match ty.scope with + Some lv -> + let var = newvar2 level in + if level < lv then raise (Unify [(ty,ty); (var, var)]) + | None -> () + end; + iter_type_expr aux ty + end + in + try + aux ty; + unmark_type ty + with Unify trace -> + let var = newvar2 level in + raise (Unify ((ty, ty) :: (var, var) :: trace)) + +let update_scope scope ty = + match scope with + | None -> () + | Some lvl -> + let ty = repr ty in + let scope = + match ty.scope with + | None -> lvl + | Some lvl' -> max lvl lvl' + in + if ty.level < scope then raise (Unify [(ty, newvar2 ty.level)]); + set_scope ty (Some scope) + let rec update_level env level expand ty = let ty = repr ty in if ty.level > level then begin - begin match Env.gadt_instance_level env ty with + begin match ty.scope with Some lv -> if level < lv then raise (Unify [(ty, newvar2 level)]) | None -> () end; match ty.desc with - Tconstr(p, _tl, _abbrev) when level < get_level env p -> + Tconstr(p, _tl, _abbrev) when level < get_path_scope p -> (* Try first to replace an abbreviation by its expansion. *) begin try - (* if is_newtype env p then raise Cannot_expand; *) link_type ty (!forward_try_expand_once env ty); update_level env level expand ty with Cannot_expand -> - (* +++ Levels should be restored... *) - (* Format.printf "update_level: %i < %i@." level (get_level env p); *) - if level < get_level env p then raise (Unify [(ty, newvar2 level)]); - iter_type_expr (update_level env level expand) ty + raise (Unify [(ty, newvar2 level)]) end | Tconstr(_, _ :: _, _) when expand -> begin try @@ -726,20 +760,20 @@ let rec update_level env level expand ty = with Cannot_expand -> set_level ty level; iter_type_expr (update_level env level expand) ty - end + end | Tpackage (p, nl, tl) when level < Path.binding_time p -> let p' = normalize_package_path env p in if Path.same p p' then raise (Unify [(ty, newvar2 level)]); log_type ty; ty.desc <- Tpackage (p', nl, tl); update_level env level expand ty | Tobject(_, ({contents=Some(p, _tl)} as nm)) - when level < get_level env p -> + when level < get_path_scope p -> set_name nm None; update_level env level expand ty | Tvariant row -> let row = row_repr row in begin match row.row_name with - | Some (p, _tl) when level < get_level env p -> + | Some (p, _tl) when level < get_path_scope p -> log_type ty; ty.desc <- Tvariant {row with row_name = None} | _ -> () @@ -930,8 +964,8 @@ let abbreviations = ref (ref Mnil) (* partial: we may not wish to copy the non generic types before we call type_pat *) -let rec copy ?env ?partial ?keep_names ty = - let copy = copy ?env ?partial ?keep_names in +let rec copy ?partial ?keep_names ty = + let copy = copy ?partial ?keep_names in let ty = repr ty in match ty.desc with Tsubst ty -> ty @@ -952,14 +986,7 @@ let rec copy ?env ?partial ?keep_names ty = let desc = ty.desc in save_desc ty desc; let t = newvar() in (* Stub *) - begin match env with - Some env when Env.has_local_constraints env -> - begin match Env.gadt_instance_level env ty with - Some lv -> Env.add_gadt_instances env lv [t] - | None -> () - end - | _ -> () - end; + set_scope t ty.scope; ty.desc <- Tsubst t; t.desc <- begin match desc with @@ -995,7 +1022,7 @@ let rec copy ?env ?partial ?keep_names ty = Tlink ty2 | _ -> (* If the row variable is not generic, we must keep it *) - let keep = more.level <> generic_level in + let keep = more.level <> generic_level && partial = None in let more' = match more.desc with Tsubst ty -> ty @@ -1060,19 +1087,13 @@ let simple_copy t = copy t (**** Variants of instantiations ****) -let gadt_env env = - if Env.has_local_constraints env - then Some env - else None - -let instance ?partial env sch = - let env = gadt_env env in +let instance ?partial sch = let partial = match partial with None -> None | Some keep -> Some (compute_univars sch, keep) in - let ty = copy ?env ?partial sch in + let ty = copy ?partial sch in cleanup_types (); ty @@ -1081,16 +1102,15 @@ let instance_def sch = cleanup_types (); ty -let generic_instance env sch = +let generic_instance sch = let old = !current_level in current_level := generic_level; - let ty = instance env sch in + let ty = instance sch in current_level := old; ty -let instance_list env schl = - let env = gadt_env env in - let tyl = List.map (fun t -> copy ?env t) schl in +let instance_list schl = + let tyl = List.map (fun t -> copy t) schl in cleanup_types (); tyl @@ -1109,7 +1129,7 @@ let get_new_abstract_name s = if index = 0 && s <> "" && s.[String.length s - 1] <> '$' then s else Printf.sprintf "%s%d" s index -let new_declaration newtype manifest = +let new_declaration expansion_scope manifest = { type_params = []; type_arity = 0; @@ -1117,7 +1137,8 @@ let new_declaration newtype manifest = type_private = Public; type_manifest = manifest; type_variance = []; - type_newtype_level = newtype; + type_is_newtype = true; + type_expansion_scope = expansion_scope; type_loc = Location.none; type_attributes = []; type_immediate = false; @@ -1127,9 +1148,9 @@ let new_declaration newtype manifest = let instance_constructor ?in_pattern cstr = begin match in_pattern with | None -> () - | Some (env, newtype_lev) -> + | Some (env, expansion_scope) -> let process existential = - let decl = new_declaration (Some (newtype_lev, newtype_lev)) None in + let decl = new_declaration (Some expansion_scope) None in let name = match repr existential with {desc = Tvar (Some name)} -> "$" ^ cstr.cstr_name ^ "_'" ^ name @@ -1390,7 +1411,7 @@ let check_abbrev_env env = let expand_abbrev_gen kind find_type_expansion env ty = check_abbrev_env env; match ty with - {desc = Tconstr (path, args, abbrev); level = level} -> + {desc = Tconstr (path, args, abbrev); level = level; scope} -> let lookup_abbrev = proper_abbrevs path args abbrev in begin match find_expans kind path !lookup_abbrev with Some ty' -> @@ -1405,6 +1426,14 @@ let expand_abbrev_gen kind find_type_expansion env ty = typing error *) () end; + begin try + update_scope scope ty'; + with Unify _ -> + (* XXX This should not happen. + However, levels are not correctly restored after a + typing error *) + () + end; let ty' = repr ty' in (* assert (ty != ty'); *) (* PR#7324 *) ty' @@ -1422,11 +1451,12 @@ let expand_abbrev_gen kind find_type_expansion env ty = (* For gadts, remember type as non exportable *) (* The ambiguous level registered for ty' should be the highest *) if !trace_gadt_instances then begin - match max lv (Env.gadt_instance_level env ty) with + match max lv ty.scope with None -> () | Some lv -> if level < lv then raise (Unify [(ty, newvar2 level)]); - Env.add_gadt_instances env lv [ty; ty'] + set_scope ty (Some lv); + set_scope ty' (Some lv) end; ty' end @@ -1471,14 +1501,6 @@ let rec try_expand_head try_once env ty = try try_expand_head try_once env ty' with Cannot_expand -> ty' -let try_expand_head try_once env ty = - let ty' = try_expand_head try_once env ty in - begin match Env.gadt_instance_level env ty' with - None -> () - | Some lv -> Env.add_gadt_instance_chain env lv ty - end; - ty' - (* Unsafe full expansion, may raise Unify. *) let expand_head_unif env ty = try try_expand_head try_expand_once env ty with Cannot_expand -> repr ty @@ -1664,7 +1686,7 @@ let rec local_non_recursive_abbrev strict visited env p ty = begin try (* try expanding, since [p] could be hidden *) local_non_recursive_abbrev strict visited env p - (try_expand_head try_expand_once env ty) + (try_expand_head try_expand_once_opt env ty) with Cannot_expand -> let params = try (Env.find_type p' env).type_params @@ -1828,6 +1850,29 @@ let enter_poly env univar_pairs t1 tl1 t2 tl2 f = let univar_pairs = ref [] +(* assumption: [ty] is fully generalized. *) +let reify_univars ty = + let rec subst_univar vars ty = + let ty = repr ty in + if ty.level >= lowest_level then begin + ty.level <- pivot_level - ty.level; + match ty.desc with + | Tvar name -> + save_desc ty ty.desc; + let t = newty2 ty.level (Tunivar name) in + vars := t :: !vars; + ty.desc <- Tsubst t + | _ -> + iter_type_expr (subst_univar vars) ty + end + in + let vars = ref [] in + subst_univar vars ty; + unmark_type ty; + let ty = copy ty in + cleanup_types (); + newty2 ty.level (Tpoly(repr ty, !vars)) + (*****************) (* Unification *) @@ -1898,26 +1943,19 @@ let deep_occur t0 ty = information is indeed lost, but it probably does not worth it. *) -let newtype_level = ref None - -let get_newtype_level () = - match !newtype_level with - | None -> assert false - | Some x -> x - (* a local constraint can be added only if the rhs of the constraint does not contain any Tvars. They need to be removed using this function *) let reify env t = - let newtype_level = get_newtype_level () in let create_fresh_constr lev name = - let decl = new_declaration (Some (newtype_level, newtype_level)) None in let name = match name with Some s -> "$'"^s | _ -> "$" in let path = Path.Pident (Ident.create (get_new_abstract_name name)) in + let binding_time = Ident.current_time () in + let decl = new_declaration (Some binding_time) None in let new_env = Env.add_local_type path decl !env in let t = newty2 lev (Tconstr (path,[],ref Mnil)) in env := new_env; - t + t, binding_time in let visited = ref TypeSet.empty in let rec iterator ty = @@ -1926,9 +1964,9 @@ let reify env t = visited := TypeSet.add ty !visited; match ty.desc with Tvar o -> - let t = create_fresh_constr ty.level o in + let t, binding_time = create_fresh_constr ty.level o in link_type ty t; - if ty.level < newtype_level then + if ty.level < binding_time then raise (Unify [t, newvar2 ty.level]) | Tvariant r -> let r = row_repr r in @@ -1937,11 +1975,11 @@ let reify env t = let m = r.row_more in match m.desc with Tvar o -> - let t = create_fresh_constr m.level o in + let t, binding_time = create_fresh_constr m.level o in let row = {r with row_fields=[]; row_fixed=true; row_more = t} in link_type m (newty2 m.level (Tvariant row)); - if m.level < newtype_level then + if m.level < binding_time then raise (Unify [t, newvar2 m.level]) | _ -> assert false end; @@ -1957,14 +1995,14 @@ let reify env t = let is_newtype env p = try let decl = Env.find_type p env in - decl.type_newtype_level <> None && + decl.type_expansion_scope <> None && decl.type_kind = Type_abstract && decl.type_private = Public with Not_found -> false let non_aliasable p decl = (* in_pervasives p || (subsumed by in_current_module) *) - in_current_module p && decl.type_newtype_level = None + in_current_module p && not decl.type_is_newtype let is_instantiable env p = try @@ -2025,7 +2063,9 @@ let rec mcomp type_pairs env t1 t2 = with Not_found -> TypePairs.add type_pairs (t1', t2') (); match (t1'.desc, t2'.desc) with - (Tvar _, Tvar _) -> assert false + | (Tvar _, _) + | (_, Tvar _) -> + () | (Tarrow (l1, t1, u1, _), Tarrow (l2, t2, u2, _)) when l1 = l2 || not (is_optional l1 || is_optional l2) -> mcomp type_pairs env t1 t2; @@ -2205,19 +2245,28 @@ let find_lowest_level ty = end in find ty; unmark_type ty; !lowest -let find_newtype_level env path = - try match (Env.find_type path env).type_newtype_level with - Some x -> x - | None -> raise Not_found - with Not_found -> let lev = Path.binding_time path in (lev, lev) +let find_expansion_scope env path = + match (Env.find_type path env).type_expansion_scope with + | Some x -> x + | None -> assert false + +let gadt_equations_level = ref None + +let get_gadt_equations_level () = + match !gadt_equations_level with + | None -> assert false + | Some x -> x let add_gadt_equation env source destination = + (* Format.eprintf "@[add_gadt_equation %s %a@]@." + (Path.name source) !Btype.print_raw destination; *) if local_non_recursive_abbrev !env source destination then begin let destination = duplicate_type destination in - let source_lev = find_newtype_level !env source in - let decl = new_declaration (Some source_lev) (Some destination) in - let newtype_level = get_newtype_level () in - env := Env.add_local_constraint source decl newtype_level !env; + let expansion_scope = + max (Path.binding_time source) (get_gadt_equations_level ()) + in + let decl = new_declaration (Some expansion_scope) (Some destination) in + env := Env.add_local_type source decl !env; cleanup_abbrev () end @@ -2248,7 +2297,7 @@ let nondep_instance env level id ty = if level = generic_level then duplicate_type ty else let old = !current_level in current_level := level; - let ty = instance env ty in + let ty = instance ty in current_level := old; ty @@ -2318,7 +2367,8 @@ let unify1_var env t1 t2 = let d1 = t1.desc in link_type t1 t2; try - update_level env t1.level t2 + update_level env t1.level t2; + update_scope t1.scope t2 with Unify _ as e -> t1.desc <- d1; raise e @@ -2345,6 +2395,7 @@ let rec unify (env:Env.t ref) t1 t2 = | (Tunivar _, Tunivar _) -> unify_univar t1 t2 !univar_pairs; update_level !env t1.level t2; + update_scope t1.scope t2; link_type t1 t2 | (Tconstr (p1, [], a1), Tconstr (p2, [], a2)) when Path.same p1 p2 (* && actual_mode !env = Old *) @@ -2354,13 +2405,14 @@ let rec unify (env:Env.t ref) t1 t2 = && not (has_cached_expansion p1 !a1 || has_cached_expansion p2 !a2) -> update_level !env t1.level t2; + update_scope t1.scope t2; link_type t1 t2 | (Tconstr (p1, [], _), Tconstr (p2, [], _)) when Env.has_local_constraints !env && is_newtype !env p1 && is_newtype !env p2 -> (* Do not use local constraints more than necessary *) begin try - if find_newtype_level !env p1 < find_newtype_level !env p2 then + if find_expansion_scope !env p1 > find_expansion_scope !env p2 then unify env t1 (try_expand_once !env t2) else unify env (try_expand_once !env t1) t2 @@ -2383,19 +2435,14 @@ and unify2 env t1 t2 = let t1' = expand_head_unif !env t1 in let t2' = expand_head_unif !env t2 in let lv = min t1'.level t2'.level in + let scope = max t1'.scope t2'.scope in update_level !env lv t2; update_level !env lv t1; + update_scope scope t2; + update_scope scope t1; if unify_eq t1' t2' then () else let t1 = repr t1 and t2 = repr t2 in - if !trace_gadt_instances then begin - (* All types in chains already have the same ambiguity levels *) - let ilevel t = - match Env.gadt_instance_level !env t with None -> 0 | Some lv -> lv in - let lv1 = ilevel t1 and lv2 = ilevel t2 in - if lv1 > lv2 then Env.add_gadt_instance_chain !env lv1 t2 else - if lv2 > lv1 then Env.add_gadt_instance_chain !env lv2 t1 - end; let t1, t2 = if !Clflags.principal && (find_lowest_level t1' < lv || find_lowest_level t2' < lv) then @@ -2435,7 +2482,9 @@ and unify3 env t1 t1' t2 t2' = begin match !umode with | Expression -> occur !env t1' t2'; - link_type t1' t2 + if is_self_type d1 (* PR#7711: do not abbreviate self type *) + then link_type t1' t2' + else link_type t1' t2 | Pattern -> add_type_equality t1' t2' end; @@ -2483,7 +2532,7 @@ and unify3 env t1 t1' t2 t2' = when is_instantiable !env path && is_instantiable !env path' && !generate_equations -> let source, destination = - if find_newtype_level !env path > find_newtype_level !env path' + if get_path_scope path > get_path_scope path' then path , t2' else path', t1' in @@ -2604,7 +2653,10 @@ and unify_fields env ty1 ty2 = (* Optimization *) (fun (n, k1, t1, k2, t2) -> unify_kind k1 k2; try - if !trace_gadt_instances then update_level !env va.level t1; + if !trace_gadt_instances then begin + update_level !env va.level t1; + update_scope va.scope t1 + end; unify env t1 t2 with Unify trace -> raise (Unify ((newty (Tfield(n, k1, t1, newty Tnil)), @@ -2694,6 +2746,7 @@ and unify_row env row1 row2 = else let ty = newgenty (Tvariant {row0 with row_fields = rest}) in update_level !env rm.level ty; + update_scope rm.scope ty; link_type rm ty in let md1 = rm1.desc and md2 = rm2.desc in @@ -2762,7 +2815,11 @@ and unify_row_field env fixed1 fixed2 more l f1 f2 = | (tu::_, []) | ([], tu::_) -> occur_univar !env tu end; (* Is this handling of levels really principal? *) - List.iter (update_level !env (repr more).level) (tl1' @ tl2'); + List.iter (fun ty -> + let rm = repr more in + update_level !env rm.level ty; + update_scope rm.scope ty; + ) (tl1' @ tl2'); let e = ref None in let f1' = Reither(c1 || c2, tl1', m1 || m2, e) and f2' = Reither(c1 || c2, tl2', m1 || m2, e) in @@ -2772,12 +2829,16 @@ and unify_row_field env fixed1 fixed2 more l f1 f2 = | Rabsent, Rabsent -> () | Reither(false, tl, _, e1), Rpresent(Some t2) when not fixed1 -> set_row_field e1 f2; - update_level !env (repr more).level t2; + let rm = repr more in + update_level !env rm.level t2; + update_scope rm.scope t2; (try List.iter (fun t1 -> unify env t1 t2) tl with exn -> e1 := None; raise exn) | Rpresent(Some t1), Reither(false, tl, _, e2) when not fixed2 -> set_row_field e2 f1; - update_level !env (repr more).level t1; + let rm = repr more in + update_level !env rm.level t1; + update_scope rm.scope t1; (try List.iter (unify env t1) tl with exn -> e2 := None; raise exn) | Reither(true, [], _, e1), Rpresent None when not fixed1 -> @@ -2799,16 +2860,16 @@ let unify env ty1 ty2 = undo_compress snap; raise (Unification_recursive_abbrev (expand_trace !env [(ty1,ty2)])) -let unify_gadt ~newtype_level:lev (env:Env.t ref) ty1 ty2 = +let unify_gadt ~equations_level:lev (env:Env.t ref) ty1 ty2 = try univar_pairs := []; - newtype_level := Some lev; + gadt_equations_level := Some lev; set_mode_pattern ~generate:true ~injective:true (fun () -> unify env ty1 ty2); - newtype_level := None; + gadt_equations_level := None; TypePairs.clear unify_eq_set; with e -> - newtype_level := None; + gadt_equations_level := None; TypePairs.clear unify_eq_set; raise e @@ -2823,6 +2884,7 @@ let unify_var env t1 t2 = begin try occur env t1 t2; update_level env t1.level t2; + update_scope t1.scope t2; link_type t1 t2; reset_trace_gadt_instances reset_tracing; with Unify trace -> @@ -2909,6 +2971,7 @@ let filter_method env name priv ty = let ty1 = newvar () in let ty' = newobj ty1 in update_level env ty.level ty'; + update_scope ty.scope ty'; link_type ty ty'; filter_method_field env name priv ty1 | Tobject(f, _) -> @@ -2973,6 +3036,7 @@ let rec moregen inst_nongen type_pairs env t1 t2 = match (t1.desc, t2.desc) with (Tvar _, _) when may_instantiate inst_nongen t1 -> moregen_occur env t1.level t2; + update_scope t1.scope t2; occur env t1 t2; link_type t1 t2 | (Tconstr (p1, [], _), Tconstr (p2, [], _)) when Path.same p1 p2 -> @@ -2990,6 +3054,7 @@ let rec moregen inst_nongen type_pairs env t1 t2 = match (t1'.desc, t2'.desc) with (Tvar _, _) when may_instantiate inst_nongen t1' -> moregen_occur env t1'.level t2; + update_scope t1'.scope t2; link_type t1' t2 | (Tarrow (l1, t1, u1, _), Tarrow (l2, t2, u2, _)) when l1 = l2 || !Clflags.classic && not (is_optional l1 || is_optional l2) -> @@ -3081,6 +3146,7 @@ and moregen_row inst_nongen type_pairs env row1 row2 = newgenty (Tvariant {row2 with row_fields = r2; row_name = None}) in moregen_occur env rm1.level ext; + update_scope rm1.scope ext; link_type rm1 ext | Tconstr _, Tconstr _ -> moregen inst_nongen type_pairs env rm1 rm2 @@ -3140,10 +3206,10 @@ let moregeneral env inst_nongen pat_sch subj_sch = then copied with [duplicate_type]. That way, its levels won't be changed. *) - let subj = duplicate_type (instance env subj_sch) in + let subj = duplicate_type (instance subj_sch) in current_level := generic_level; (* Duplicate generic variables *) - let patt = instance env pat_sch in + let patt = instance pat_sch in let res = try moregen inst_nongen (TypePairs.create 13) env patt subj; true with Unify _ -> false @@ -3482,7 +3548,7 @@ let match_class_types ?(trace=true) env pat_sch subj_sch = | _ -> CM_Hide_public lab::err end in - if Concr.mem lab sign1.csig_concr then err + if lab = dummy_method || Concr.mem lab sign1.csig_concr then err else CM_Hide_virtual ("method", lab) :: err) miss1 [] in @@ -4417,7 +4483,8 @@ let nondep_type_decl env mid id is_covariant decl = type_manifest = tm; type_private = priv; type_variance = decl.type_variance; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = decl.type_loc; type_attributes = decl.type_attributes; type_immediate = decl.type_immediate; diff --git a/typing/ctype.mli b/typing/ctype.mli index 00daacd5..e22d2694 100644 --- a/typing/ctype.mli +++ b/typing/ctype.mli @@ -109,16 +109,21 @@ val limited_generalize: type_expr -> type_expr -> unit (* Only generalize some part of the type Make the remaining of the type non-generalizable *) -val instance: ?partial:bool -> Env.t -> type_expr -> type_expr +val check_scope_escape : int -> type_expr -> unit + (* [check_scope_escape lvl ty] ensures that [ty] could be raised + to the level [lvl] without any scope escape. + Raises [Unify] otherwise *) + +val instance: ?partial:bool -> type_expr -> type_expr (* Take an instance of a type scheme *) (* partial=None -> normal partial=false -> newvar() for non generic subterms partial=true -> newty2 ty.level Tvar for non generic subterms *) val instance_def: type_expr -> type_expr (* use defaults *) -val generic_instance: Env.t -> type_expr -> type_expr +val generic_instance: type_expr -> type_expr (* Same as instance, but new nodes at generic_level *) -val instance_list: Env.t -> type_expr list -> type_expr list +val instance_list: type_expr list -> type_expr list (* Take an instance of a list of type schemes *) val instance_constructor: ?in_pattern:Env.t ref * int -> @@ -164,7 +169,7 @@ val enforce_constraints: Env.t -> type_expr -> unit val unify: Env.t -> type_expr -> type_expr -> unit (* Unify the two types given. Raise [Unify] if not possible. *) -val unify_gadt: newtype_level:int -> Env.t ref -> type_expr -> type_expr -> unit +val unify_gadt: equations_level:int -> Env.t ref -> type_expr -> type_expr -> unit (* Unify the two types given and update the environment with the local constraints. Raise [Unify] if not possible. *) val unify_var: Env.t -> type_expr -> type_expr -> unit @@ -194,6 +199,9 @@ val matches: Env.t -> type_expr -> type_expr -> bool (* Same as [moregeneral false], implemented using the two above functions and backtracking. Ignore levels *) +val reify_univars : Types.type_expr -> Types.type_expr + (* Replaces all the variables of a type by a univar. *) + type class_match_failure = CM_Virtual_class | CM_Parameter_arity_mismatch of int * int @@ -290,3 +298,5 @@ val maybe_pointer_type : Env.t -> type_expr -> bool val package_subtype : (Env.t -> Path.t -> Longident.t list -> type_expr list -> Path.t -> Longident.t list -> type_expr list -> bool) ref + +val mcomp : Env.t -> type_expr -> type_expr -> unit diff --git a/typing/datarepr.ml b/typing/datarepr.ml index bce6ff21..7bef64c9 100644 --- a/typing/datarepr.ml +++ b/typing/datarepr.ml @@ -85,7 +85,8 @@ let constructor_args priv cd_args cd_res path rep = type_private = priv; type_manifest = None; type_variance = List.map (fun _ -> Variance.full) type_params; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = Location.none; type_attributes = []; type_immediate = false; @@ -176,7 +177,7 @@ let extension_descr path_ext ext = cstr_inlined; } -let none = {desc = Ttuple []; level = -1; id = -1} +let none = {desc = Ttuple []; level = -1; scope = None; id = -1} (* Clearly ill-formed type *) let dummy_label = { lbl_name = ""; lbl_res = none; lbl_arg = none; lbl_mut = Immutable; diff --git a/typing/env.ml b/typing/env.ml index 4d51aa9b..cf5207ee 100644 --- a/typing/env.ml +++ b/typing/env.ml @@ -161,7 +161,7 @@ type summary = | Env_modtype of summary * Ident.t * modtype_declaration | Env_class of summary * Ident.t * class_declaration | Env_cltype of summary * Ident.t * class_type_declaration - | Env_open of summary * Path.t + | Env_open of summary * StringSet.t * Path.t | Env_functor_arg of summary * Ident.t | Env_constraints of summary * type_declaration PathMap.t | Env_copy_types of summary * string list @@ -333,7 +333,7 @@ module IdTbl = | None -> raise exn end - let rec find_name mark name tbl = + let rec find_name ~mark name tbl = try let (id, desc) = Ident.find_name name tbl.current in Pident id, desc @@ -346,20 +346,18 @@ module IdTbl = if mark then begin match using with | None -> () | Some f -> - begin try f name (Some (snd (find_name false name next), snd res)) + begin try f name (Some (snd (find_name ~mark:false name next), snd res)) with Not_found -> f name None end end; res with Not_found -> - find_name mark name next + find_name ~mark name next end | None -> raise exn end - let find_name name tbl = find_name true name tbl - let rec update name f tbl = try let (id, desc) = Ident.find_name name tbl.current in @@ -438,7 +436,6 @@ type type_descriptions = constructor_description list * label_description list let in_signature_flag = 0x01 -let implicit_coercion_flag = 0x02 type t = { values: value_description IdTbl.t; @@ -453,7 +450,6 @@ type t = { functor_args: unit Ident.tbl; summary: summary; local_constraints: type_declaration PathMap.t; - gadt_instances: (int * TypeSet.t ref) list; flags: int; } @@ -496,7 +492,6 @@ and functor_components = { let copy_local ~from env = { env with local_constraints = from.local_constraints; - gadt_instances = from.gadt_instances; flags = from.flags } let same_constr = ref (fun _ _ _ -> assert false) @@ -536,7 +531,7 @@ let empty = { modules = IdTbl.empty; modtypes = IdTbl.empty; components = IdTbl.empty; classes = IdTbl.empty; cltypes = IdTbl.empty; - summary = Env_empty; local_constraints = PathMap.empty; gadt_instances = []; + summary = Env_empty; local_constraints = PathMap.empty; flags = 0; functor_args = Ident.empty; } @@ -548,11 +543,7 @@ let in_signature b env = in {env with flags} -let implicit_coercion env = - {env with flags = env.flags lor implicit_coercion_flag} - let is_in_signature env = env.flags land in_signature_flag <> 0 -let is_implicit_coercion env = env.flags land implicit_coercion_flag <> 0 let is_ident = function Pident _ -> true @@ -653,9 +644,6 @@ let persistent_structures = let crc_units = Consistbl.create() -module StringSet = - Set.Make(struct type t = string let compare = String.compare end) - let imported_units = ref StringSet.empty let add_import s = @@ -777,17 +765,17 @@ let find_pers_struct check name = acknowledge_pers_struct check name ps (* Emits a warning if there is no valid cmi for name *) -let check_pers_struct name = +let check_pers_struct ~loc name = try ignore (find_pers_struct false name) with | Not_found -> let warn = Warnings.No_cmi_file(name, None) in - Location.prerr_warning Location.none warn + Location.prerr_warning loc warn | Cmi_format.Error err -> let msg = Format.asprintf "%a" Cmi_format.report_error err in let warn = Warnings.No_cmi_file(name, Some msg) in - Location.prerr_warning Location.none warn + Location.prerr_warning loc warn | Error err -> let msg = match err with @@ -808,7 +796,7 @@ let check_pers_struct name = | Illegal_value_name _ -> assert false in let warn = Warnings.No_cmi_file(name, Some msg) in - Location.prerr_warning Location.none warn + Location.prerr_warning loc warn let read_pers_struct modname filename = read_pers_struct true modname filename @@ -816,7 +804,7 @@ let read_pers_struct modname filename = let find_pers_struct name = find_pers_struct true name -let check_pers_struct name = +let check_pers_struct ~loc name = if not (Hashtbl.mem persistent_structures name) then begin (* PR#6843: record the weak dependency ([add_import]) regardless of whether the check succeeds, to help make builds more @@ -824,7 +812,7 @@ let check_pers_struct name = add_import name; if (Warnings.is_active (Warnings.No_cmi_file("", None))) then !add_delayed_check_forward - (fun () -> check_pers_struct name) + (fun () -> check_pers_struct ~loc name) end let reset_cache () = @@ -1063,7 +1051,7 @@ let find_type_expansion path env = | Some body when decl.type_private = Public || decl.type_kind <> Type_abstract || Btype.has_constr_row body -> - (decl.type_params, body, may_map snd decl.type_newtype_level) + (decl.type_params, body, decl.type_expansion_scope) (* The manifest type of Private abstract data types without private row are still considered unknown to the type system. Hence, this case is caught by the following clause that also handles @@ -1079,7 +1067,8 @@ let find_type_expansion_opt path env = match decl.type_manifest with (* The manifest type of Private abstract data types can still get an approximation using their manifest type. *) - | Some body -> (decl.type_params, body, may_map snd decl.type_newtype_level) + | Some body -> + (decl.type_params, body, decl.type_expansion_scope) | _ -> raise Not_found let find_modtype_expansion path env = @@ -1107,23 +1096,22 @@ let report_deprecated ?loc p deprecated = Location.deprecated loc (Printf.sprintf "module %s%s" (Path.name p) txt) | _ -> () -let mark_module_used env name loc = - if not (is_implicit_coercion env) then - try Hashtbl.find module_declarations (name, loc) () - with Not_found -> () +let mark_module_used name loc = + try Hashtbl.find module_declarations (name, loc) () + with Not_found -> () -let rec lookup_module_descr_aux ?loc lid env = +let rec lookup_module_descr_aux ?loc ~mark lid env = match lid with Lident s -> begin try - IdTbl.find_name s env.components + IdTbl.find_name ~mark s env.components with Not_found -> if s = !current_unit then raise Not_found; let ps = find_pers_struct s in (Pident(Ident.create_persistent s), ps.ps_comps) end | Ldot(l, s) -> - let (p, descr) = lookup_module_descr ?loc l env in + let (p, descr) = lookup_module_descr ?loc ~mark l env in begin match get_components descr with Structure_comps c -> let (descr, pos) = Tbl.find_str s c.comp_components in @@ -1132,21 +1120,23 @@ let rec lookup_module_descr_aux ?loc lid env = raise Not_found end | Lapply(l1, l2) -> - let (p1, desc1) = lookup_module_descr ?loc l1 env in - let p2 = lookup_module ~load:true ?loc l2 env in + let (p1, desc1) = lookup_module_descr ?loc ~mark l1 env in + let p2 = lookup_module ~load:true ~mark ?loc l2 env in let {md_type=mty2} = find_module p2 env in begin match get_components desc1 with Functor_comps f -> let loc = match loc with Some l -> l | None -> Location.none in - Misc.may (!check_modtype_inclusion ~loc env mty2 p2) f.fcomp_arg; + (match f.fcomp_arg with + | None -> raise Not_found (* PR#7611 *) + | Some arg -> !check_modtype_inclusion ~loc env mty2 p2 arg); (Papply(p1, p2), !components_of_functor_appl' f env p1 p2) | Structure_comps _ -> raise Not_found end -and lookup_module_descr ?loc lid env = - let (p, comps) as res = lookup_module_descr_aux ?loc lid env in - mark_module_used env (Path.last p) comps.loc; +and lookup_module_descr ?loc ~mark lid env = + let (p, comps) as res = lookup_module_descr_aux ?loc ~mark lid env in + if mark then mark_module_used (Path.last p) comps.loc; (* Format.printf "USE module %s at %a@." (Path.last p) Location.print comps.loc; @@ -1154,15 +1144,15 @@ and lookup_module_descr ?loc lid env = report_deprecated ?loc p comps.deprecated; res -and lookup_module ~load ?loc lid env : Path.t = +and lookup_module ~load ?loc ~mark lid env : Path.t = match lid with Lident s -> begin try - let (p, data) = IdTbl.find_name s env.modules in + let (p, data) = IdTbl.find_name ~mark s env.modules in let {md_loc; md_attributes; md_type} = EnvLazy.force subst_modtype_maker data in - mark_module_used env s md_loc; + if mark then mark_module_used s md_loc; begin match md_type with | Mty_ident (Path.Pident id) when Ident.name id = "#recmod#" -> (* see #5965 *) @@ -1175,7 +1165,10 @@ and lookup_module ~load ?loc lid env : Path.t = with Not_found -> if s = !current_unit then raise Not_found; let p = Pident(Ident.create_persistent s) in - if !Clflags.transparent_modules && not load then check_pers_struct s + if !Clflags.transparent_modules && not load + then + let loc = match loc with Some l -> l | None -> Location.none in + check_pers_struct ~loc s else begin let ps = find_pers_struct s in report_deprecated ?loc p ps.ps_comps.deprecated @@ -1183,12 +1176,12 @@ and lookup_module ~load ?loc lid env : Path.t = p end | Ldot(l, s) -> - let (p, descr) = lookup_module_descr ?loc l env in + let (p, descr) = lookup_module_descr ?loc ~mark l env in begin match get_components descr with Structure_comps c -> let (_data, pos) = Tbl.find_str s c.comp_modules in let (comps, _) = Tbl.find_str s c.comp_components in - mark_module_used env s comps.loc; + if mark then mark_module_used s comps.loc; let p = Pdot(p, s, pos) in report_deprecated ?loc p comps.deprecated; p @@ -1196,25 +1189,27 @@ and lookup_module ~load ?loc lid env : Path.t = raise Not_found end | Lapply(l1, l2) -> - let (p1, desc1) = lookup_module_descr ?loc l1 env in - let p2 = lookup_module ~load:true ?loc l2 env in + let (p1, desc1) = lookup_module_descr ?loc ~mark l1 env in + let p2 = lookup_module ~load:true ?loc ~mark l2 env in let {md_type=mty2} = find_module p2 env in let p = Papply(p1, p2) in begin match get_components desc1 with Functor_comps f -> let loc = match loc with Some l -> l | None -> Location.none in - Misc.may (!check_modtype_inclusion ~loc env mty2 p2) f.fcomp_arg; + (match f.fcomp_arg with + | None -> raise Not_found (* PR#7611 *) + | Some arg -> (!check_modtype_inclusion ~loc env mty2 p2) arg); p | Structure_comps _ -> raise Not_found end -let lookup proj1 proj2 ?loc lid env = +let lookup proj1 proj2 ?loc ~mark lid env = match lid with Lident s -> - IdTbl.find_name s (proj1 env) + IdTbl.find_name ~mark s (proj1 env) | Ldot(l, s) -> - let (p, desc) = lookup_module_descr ?loc l env in + let (p, desc) = lookup_module_descr ?loc ~mark l env in begin match get_components desc with Structure_comps c -> let (data, pos) = Tbl.find_str s (proj2 c) in @@ -1225,7 +1220,7 @@ let lookup proj1 proj2 ?loc lid env = | Lapply _ -> raise Not_found -let lookup_all_simple proj1 proj2 shadow ?loc lid env = +let lookup_all_simple proj1 proj2 shadow ?loc ~mark lid env = match lid with Lident s -> let xl = TycompTbl.find_all s (proj1 env) in @@ -1238,7 +1233,7 @@ let lookup_all_simple proj1 proj2 shadow ?loc lid env = in do_shadow xl | Ldot(l, s) -> - let (_p, desc) = lookup_module_descr ?loc l env in + let (_p, desc) = lookup_module_descr ?loc ~mark l env in begin match get_components desc with Structure_comps c -> let comps = @@ -1284,26 +1279,22 @@ let copy_types l env = let values = List.fold_left (fun env s -> IdTbl.update s f env) env.values l in {env with values; summary = Env_copy_types (env.summary, l)} -let mark_value_used env name vd = - if not (is_implicit_coercion env) then - try Hashtbl.find value_declarations (name, vd.val_loc) () - with Not_found -> () +let mark_value_used name vd = + try Hashtbl.find value_declarations (name, vd.val_loc) () + with Not_found -> () -let mark_type_used env name vd = - if not (is_implicit_coercion env) then - try Hashtbl.find type_declarations (name, vd.type_loc) () - with Not_found -> () +let mark_type_used name vd = + try Hashtbl.find type_declarations (name, vd.type_loc) () + with Not_found -> () -let mark_constructor_used usage env name vd constr = - if not (is_implicit_coercion env) then - try Hashtbl.find used_constructors (name, vd.type_loc, constr) usage - with Not_found -> () +let mark_constructor_used usage name vd constr = + try Hashtbl.find used_constructors (name, vd.type_loc, constr) usage + with Not_found -> () -let mark_extension_used usage env ext name = - if not (is_implicit_coercion env) then - let ty_name = Path.last ext.ext_type_path in - try Hashtbl.find used_constructors (ty_name, ext.ext_loc, name) usage - with Not_found -> () +let mark_extension_used usage ext name = + let ty_name = Path.last ext.ext_type_path in + try Hashtbl.find used_constructors (ty_name, ext.ext_loc, name) usage + with Not_found -> () let set_value_used_callback name vd callback = let key = (name, vd.val_loc) in @@ -1327,20 +1318,20 @@ let set_type_used_callback name td callback = in Hashtbl.replace type_declarations key (fun () -> callback old) -let lookup_value ?loc lid env = - let (_, desc) as r = lookup_value ?loc lid env in - mark_value_used env (Longident.last lid) desc; +let lookup_value ?loc ?(mark = true) lid env = + let (_, desc) as r = lookup_value ?loc ~mark lid env in + if mark then mark_value_used (Longident.last lid) desc; r -let lookup_type ?loc lid env = - let (path, (decl, _)) = lookup_type ?loc lid env in - mark_type_used env (Longident.last lid) decl; +let lookup_type ?loc ?(mark = true) lid env = + let (path, (decl, _)) = lookup_type ?loc ~mark lid env in + if mark then mark_type_used (Longident.last lid) decl; path let mark_type_path env path = try let decl = find_type path env in - mark_type_used env (Path.last path) decl + mark_type_used (Path.last path) decl with Not_found -> () let ty_path t = @@ -1348,32 +1339,35 @@ let ty_path t = | {desc=Tconstr(path, _, _)} -> path | _ -> assert false -let lookup_constructor ?loc lid env = - match lookup_all_constructors ?loc lid env with +let lookup_constructor ?loc ?(mark = true) lid env = + match lookup_all_constructors ?loc ~mark lid env with [] -> raise Not_found | (desc, use) :: _ -> - mark_type_path env (ty_path desc.cstr_res); - use (); + if mark then begin + mark_type_path env (ty_path desc.cstr_res); + use () + end; desc let is_lident = function Lident _ -> true | _ -> false -let lookup_all_constructors ?loc lid env = +let lookup_all_constructors ?loc ?(mark = true) lid env = try - let cstrs = lookup_all_constructors ?loc lid env in + let cstrs = lookup_all_constructors ?loc ~mark lid env in let wrap_use desc use () = - mark_type_path env (ty_path desc.cstr_res); - use () + if mark then begin + mark_type_path env (ty_path desc.cstr_res); + use () + end in List.map (fun (cstr, use) -> (cstr, wrap_use cstr use)) cstrs with Not_found when is_lident lid -> [] let mark_constructor usage env name desc = - if not (is_implicit_coercion env) - then match desc.cstr_tag with + match desc.cstr_tag with | Cstr_extension _ -> begin let ty_path = ty_path desc.cstr_res in @@ -1385,36 +1379,46 @@ let mark_constructor usage env name desc = let ty_path = ty_path desc.cstr_res in let ty_decl = try find_type ty_path env with Not_found -> assert false in let ty_name = Path.last ty_path in - mark_constructor_used usage env ty_name ty_decl name + mark_constructor_used usage ty_name ty_decl name -let lookup_label ?loc lid env = - match lookup_all_labels ?loc lid env with +let lookup_label ?loc ?(mark = true) lid env = + match lookup_all_labels ?loc ~mark lid env with [] -> raise Not_found | (desc, use) :: _ -> - mark_type_path env (ty_path desc.lbl_res); - use (); + if mark then begin + mark_type_path env (ty_path desc.lbl_res); + use () + end; desc -let lookup_all_labels ?loc lid env = +let lookup_all_labels ?loc ?(mark = true) lid env = try - let lbls = lookup_all_labels ?loc lid env in + let lbls = lookup_all_labels ?loc ~mark lid env in let wrap_use desc use () = - mark_type_path env (ty_path desc.lbl_res); - use () + if mark then begin + mark_type_path env (ty_path desc.lbl_res); + use () + end in List.map (fun (lbl, use) -> (lbl, wrap_use lbl use)) lbls with Not_found when is_lident lid -> [] -let lookup_class ?loc lid env = - let (_, desc) as r = lookup_class ?loc lid env in +let lookup_module ~load ?loc ?(mark = true) lid env = + lookup_module ~load ?loc ~mark lid env + +let lookup_modtype ?loc ?(mark = true) lid env = + lookup_modtype ?loc ~mark lid env + +let lookup_class ?loc ?(mark = true) lid env = + let (_, desc) as r = lookup_class ?loc ~mark lid env in (* special support for Typeclass.unbound_class *) - if Path.name desc.cty_path = "" then ignore (lookup_type ?loc lid env) - else mark_type_path env desc.cty_path; + if Path.name desc.cty_path = "" then ignore (lookup_type ?loc ~mark lid env) + else if mark then mark_type_path env desc.cty_path; r -let lookup_cltype ?loc lid env = - let (_, desc) as r = lookup_cltype ?loc lid env in +let lookup_cltype ?loc ?(mark = true) lid env = + let (_, desc) as r = lookup_cltype ?loc ~mark lid env in if Path.name desc.clty_path = "" then ignore (lookup_type ?loc lid env) else mark_type_path env desc.clty_path; mark_type_path env desc.clty_path; @@ -1521,52 +1525,6 @@ let find_shadowed_types path env = (find_shadowed (fun env -> env.types) (fun comps -> comps.comp_types) path env) - -(* GADT instance tracking *) - -let add_gadt_instance_level lv env = - {env with - gadt_instances = (lv, ref TypeSet.empty) :: env.gadt_instances} - -let is_Tlink = function {desc = Tlink _} -> true | _ -> false - -let gadt_instance_level env t = - let rec find_instance = function - [] -> None - | (lv, r) :: rem -> - if TypeSet.exists is_Tlink !r then - (* Should we use set_typeset ? *) - r := TypeSet.fold (fun ty -> TypeSet.add (repr ty)) !r TypeSet.empty; - if TypeSet.mem t !r then Some lv else find_instance rem - in find_instance env.gadt_instances - -let add_gadt_instances env lv tl = - let r = - try List.assoc lv env.gadt_instances with Not_found -> assert false in - (* Format.eprintf "Added"; - List.iter (fun ty -> Format.eprintf "@ %a" !Btype.print_raw ty) tl; - Format.eprintf "@."; *) - set_typeset r (List.fold_right TypeSet.add tl !r) - -(* Only use this after expand_head! *) -let add_gadt_instance_chain env lv t = - let r = - try List.assoc lv env.gadt_instances with Not_found -> assert false in - let rec add_instance t = - let t = repr t in - if not (TypeSet.mem t !r) then begin - (* Format.eprintf "@ %a" !Btype.print_raw t; *) - set_typeset r (TypeSet.add t !r); - match t.desc with - Tconstr (p, _, memo) -> - may add_instance (find_expans Private p !memo) - | _ -> () - end - in - (* Format.eprintf "Added chain"; *) - add_instance t - (* Format.eprintf "@." *) - (* Expand manifest module type names at the top of the given module type *) let rec scrape_alias env ?path mty = @@ -1968,14 +1926,6 @@ let add_local_type path info env = { env with local_constraints = PathMap.add path info env.local_constraints } -let add_local_constraint path info elv env = - match info with - {type_manifest = Some _; type_newtype_level = Some (lv, _)} -> - (* elv is the expansion level, lv is the definition level *) - let info = {info with type_newtype_level = Some (lv, elv)} in - add_local_type path info env - | _ -> assert false - (* Insertion of bindings by name *) @@ -2016,13 +1966,37 @@ let rec add_signature sg env = (* Open a signature path *) -let add_components slot root env0 comps = +let add_components ?filter_modules slot root env0 comps = let add_l w comps env0 = TycompTbl.add_open slot w comps env0 in let add w comps env0 = IdTbl.add_open slot w root comps env0 in + let skipped_modules = ref StringSet.empty in + let filter tbl env0_tbl = + match filter_modules with + | None -> tbl + | Some f -> + Tbl.fold (fun m x acc -> + if f m then + Tbl.add m x acc + else begin + assert + (match IdTbl.find_name m env0_tbl~mark:false with + | (_ : _ * _) -> false + | exception _ -> true); + skipped_modules := StringSet.add m !skipped_modules; + acc + end) + tbl Tbl.empty + in + + let filter_and_add w comps env0 = + let comps = filter comps env0 in + add w comps env0 + in + let constrs = add_l (fun x -> `Constructor x) comps.comp_constrs env0.constrs in @@ -2046,15 +2020,15 @@ let add_components slot root env0 comps = add (fun x -> `Class_type x) comps.comp_cltypes env0.cltypes in let components = - add (fun x -> `Component x) comps.comp_components env0.components + filter_and_add (fun x -> `Component x) comps.comp_components env0.components in let modules = - add (fun x -> `Module x) comps.comp_modules env0.modules + filter_and_add (fun x -> `Module x) comps.comp_modules env0.modules in { env0 with - summary = Env_open(env0.summary, root); + summary = Env_open(env0.summary, !skipped_modules, root); constrs; labels; values; @@ -2066,10 +2040,11 @@ let add_components slot root env0 comps = modules; } -let open_signature slot root env0 = +let open_signature ?filter_modules slot root env0 = match get_components (find_module_descr root env0) with | Functor_comps _ -> None - | Structure_comps comps -> Some (add_components slot root env0 comps) + | Structure_comps comps -> + Some (add_components ?filter_modules slot root env0 comps) (* Open a signature from a file *) @@ -2079,9 +2054,28 @@ let open_pers_signature name env = | Some env -> env | None -> assert false (* a compilation unit cannot refer to a functor *) +let open_signature_of_initially_opened_module root env = + let load_path = !Config.load_path in + let filter_modules m = + match Misc.find_in_path_uncap load_path (m ^ ".cmi") with + | (_ : string) -> false + | exception Not_found -> true + in + open_signature None root env ~filter_modules + +let open_signature_from_env_summary root env ~hidden_submodules = + let filter_modules = + if StringSet.is_empty hidden_submodules then + None + else + Some (fun m -> not (StringSet.mem m hidden_submodules)) + in + open_signature None root env ?filter_modules + let open_signature ?(used_slot = ref false) - ?(loc = Location.none) ?(toplevel = false) ovf root env = + ?(loc = Location.none) ?(toplevel = false) + ovf root env = if not toplevel && ovf = Asttypes.Fresh && not loc.Location.loc_ghost && (Warnings.is_active (Warnings.Unused_open "") || Warnings.is_active (Warnings.Open_shadow_identifier ("", "")) @@ -2203,7 +2197,7 @@ let find_all proj1 proj2 f lid env acc = (fun name (p, data) acc -> f name p data acc) (proj1 env) acc | Some l -> - let p, desc = lookup_module_descr l env in + let p, desc = lookup_module_descr ~mark:true l env in begin match get_components desc with Structure_comps c -> Tbl.fold @@ -2220,7 +2214,7 @@ let find_all_simple_list proj1 proj2 f lid env acc = (fun data acc -> f data acc) (proj1 env) acc | Some l -> - let (_p, desc) = lookup_module_descr l env in + let (_p, desc) = lookup_module_descr ~mark:true l env in begin match get_components desc with Structure_comps c -> Tbl.fold @@ -2256,7 +2250,7 @@ let fold_modules f lid env acc = persistent_structures acc | Some l -> - let p, desc = lookup_module_descr l env in + let p, desc = lookup_module_descr ~mark:true l env in begin match get_components desc with Structure_comps c -> Tbl.fold diff --git a/typing/env.mli b/typing/env.mli index f96c76b7..0110504a 100644 --- a/typing/env.mli +++ b/typing/env.mli @@ -29,7 +29,9 @@ type summary = | Env_modtype of summary * Ident.t * modtype_declaration | Env_class of summary * Ident.t * class_declaration | Env_cltype of summary * Ident.t * class_type_declaration - | Env_open of summary * Path.t + | Env_open of summary * Misc.StringSet.t * Path.t + (** The string set argument of [Env_open] represents a list of module names + to skip, i.e. that won't be imported in the toplevel namespace. *) | Env_functor_arg of summary * Ident.t | Env_constraints of summary * type_declaration PathMap.t | Env_copy_types of summary * string list @@ -89,40 +91,41 @@ val get_required_globals: unit -> Ident.t list val add_required_global: Ident.t -> unit val has_local_constraints: t -> bool -val add_gadt_instance_level: int -> t -> t -val gadt_instance_level: t -> type_expr -> int option -val add_gadt_instances: t -> int -> type_expr list -> unit -val add_gadt_instance_chain: t -> int -> type_expr -> unit (* Lookup by long identifiers *) (* ?loc is used to report 'deprecated module' warnings *) val lookup_value: - ?loc:Location.t -> Longident.t -> t -> Path.t * value_description + ?loc:Location.t -> ?mark:bool -> + Longident.t -> t -> Path.t * value_description val lookup_constructor: - ?loc:Location.t -> Longident.t -> t -> constructor_description + ?loc:Location.t -> ?mark:bool -> Longident.t -> t -> constructor_description val lookup_all_constructors: - ?loc:Location.t -> + ?loc:Location.t -> ?mark:bool -> Longident.t -> t -> (constructor_description * (unit -> unit)) list val lookup_label: - ?loc:Location.t -> Longident.t -> t -> label_description + ?loc:Location.t -> ?mark:bool -> + Longident.t -> t -> label_description val lookup_all_labels: - ?loc:Location.t -> + ?loc:Location.t -> ?mark:bool -> Longident.t -> t -> (label_description * (unit -> unit)) list val lookup_type: - ?loc:Location.t -> Longident.t -> t -> Path.t + ?loc:Location.t -> ?mark:bool -> Longident.t -> t -> Path.t (* Since 4.04, this function no longer returns [type_description]. To obtain it, you should either call [Env.find_type], or replace it by [Typetexp.find_type] *) val lookup_module: - load:bool -> ?loc:Location.t -> Longident.t -> t -> Path.t + load:bool -> ?loc:Location.t -> ?mark:bool -> Longident.t -> t -> Path.t val lookup_modtype: - ?loc:Location.t -> Longident.t -> t -> Path.t * modtype_declaration + ?loc:Location.t -> ?mark:bool -> + Longident.t -> t -> Path.t * modtype_declaration val lookup_class: - ?loc:Location.t -> Longident.t -> t -> Path.t * class_declaration + ?loc:Location.t -> ?mark:bool -> + Longident.t -> t -> Path.t * class_declaration val lookup_cltype: - ?loc:Location.t -> Longident.t -> t -> Path.t * class_type_declaration + ?loc:Location.t -> ?mark:bool -> + Longident.t -> t -> Path.t * class_type_declaration val copy_types: string list -> t -> t (* Used only in Typecore.duplicate_ident_types. *) @@ -144,7 +147,6 @@ val add_module_declaration: ?arg:bool -> check:bool -> Ident.t -> val add_modtype: Ident.t -> modtype_declaration -> t -> t val add_class: Ident.t -> class_declaration -> t -> t val add_cltype: Ident.t -> class_type_declaration -> t -> t -val add_local_constraint: Path.t -> type_declaration -> int -> t -> t val add_local_type: Path.t -> type_declaration -> t -> t (* Insertion of all fields of a signature. *) @@ -157,9 +159,27 @@ val add_signature: signature -> t -> t not a structure. *) val open_signature: ?used_slot:bool ref -> - ?loc:Location.t -> ?toplevel:bool -> Asttypes.override_flag -> Path.t -> + ?loc:Location.t -> ?toplevel:bool -> + Asttypes.override_flag -> Path.t -> t -> t option +(* Similar to [open_signature], except that modules from the load path + have precedence over sub-modules of the opened module. + + For instance, if opening a module [M] with a sub-module [X]: + - if the load path contains a [x.cmi] file, then resolving [X] in the + new environment yields the same result as resolving [X] in the + old environment + - otherwise, in the new environment [X] resolves to [M.X] +*) +val open_signature_of_initially_opened_module: + Path.t -> t -> t option + +(* Similar to [open_signature] except that sub-modules of the opened modules + that are in [hidden_submodules] are not added to the environment. *) +val open_signature_from_env_summary: + Path.t -> t -> hidden_submodules:Misc.StringSet.t -> t option + val open_pers_signature: string -> t -> t (* Insertion by name *) @@ -245,20 +265,19 @@ open Format val report_error: formatter -> error -> unit -val mark_value_used: t -> string -> value_description -> unit -val mark_module_used: t -> string -> Location.t -> unit -val mark_type_used: t -> string -> type_declaration -> unit +val mark_value_used: string -> value_description -> unit +val mark_module_used: string -> Location.t -> unit +val mark_type_used: string -> type_declaration -> unit type constructor_usage = Positive | Pattern | Privatize val mark_constructor_used: - constructor_usage -> t -> string -> type_declaration -> string -> unit + constructor_usage -> string -> type_declaration -> string -> unit val mark_constructor: constructor_usage -> t -> string -> constructor_description -> unit val mark_extension_used: - constructor_usage -> t -> extension_constructor -> string -> unit + constructor_usage -> extension_constructor -> string -> unit val in_signature: bool -> t -> t -val implicit_coercion: t -> t val is_in_signature: t -> bool diff --git a/typing/envaux.ml b/typing/envaux.ml index c78f152b..caa67f38 100644 --- a/typing/envaux.ml +++ b/typing/envaux.ml @@ -60,10 +60,11 @@ let rec env_from_summary sum subst = | Env_cltype (s, id, desc) -> Env.add_cltype id (Subst.cltype_declaration subst desc) (env_from_summary s subst) - | Env_open(s, path) -> + | Env_open(s, hidden_submodules, path) -> let env = env_from_summary s subst in let path' = Subst.module_path subst path in - begin match Env.open_signature Asttypes.Override path' env with + begin match Env.open_signature_from_env_summary path' env + ~hidden_submodules with | Some env -> env | None -> assert false end diff --git a/typing/ident.ml b/typing/ident.ml index c5556cb8..1235b058 100644 --- a/typing/ident.ml +++ b/typing/ident.ml @@ -15,7 +15,7 @@ open Format -type t = { stamp: int; name: string; mutable flags: int } +type t = { stamp: int; name: string; flags: int } let global_flag = 1 let predef_exn_flag = 2 @@ -30,7 +30,8 @@ let create s = let create_predef_exn s = incr currentstamp; - { name = s; stamp = !currentstamp; flags = predef_exn_flag } + { name = s; stamp = !currentstamp; + flags = predef_exn_flag lor global_flag } let create_persistent s = { name = s; stamp = 0; flags = global_flag } @@ -41,6 +42,8 @@ let rename i = let name i = i.name +let with_name i name = { i with name; } + let unique_name i = i.name ^ "_" ^ string_of_int i.stamp let unique_toplevel_name i = i.name ^ "/" ^ string_of_int i.stamp @@ -72,9 +75,6 @@ let reinit () = let hide i = { i with stamp = -1 } -let make_global i = - i.flags <- i.flags lor global_flag - let global i = (i.flags land global_flag) <> 0 @@ -85,7 +85,11 @@ let print ppf i = match i.stamp with | 0 -> fprintf ppf "%s!" i.name | -1 -> fprintf ppf "%s#" i.name - | n -> fprintf ppf "%s/%i%s" i.name n (if global i then "g" else "") + | n -> + let stampstr = + if !Clflags.unique_ids then Printf.sprintf "/%i" n else "" + in + fprintf ppf "%s%s%s" i.name stampstr (if global i then "g" else "") type 'a tbl = Empty diff --git a/typing/ident.mli b/typing/ident.mli index c2983edb..e34ce37f 100644 --- a/typing/ident.mli +++ b/typing/ident.mli @@ -15,7 +15,7 @@ (* Identifiers (unique names) *) -type t = { stamp: int; name: string; mutable flags: int } +type t include Identifiable.S with type t := t (* Notes: @@ -30,6 +30,7 @@ val create_persistent: string -> t val create_predef_exn: string -> t val rename: t -> t val name: t -> string +val with_name: t -> string -> t val unique_name: t -> string val unique_toplevel_name: t -> string val persistent: t -> bool @@ -46,7 +47,6 @@ val hide: t -> t When put in a 'a tbl, this identifier can only be looked up by name. *) -val make_global: t -> unit val global: t -> bool val is_predef_exn: t -> bool diff --git a/typing/includeclass.ml b/typing/includeclass.ml index 59e363ca..5501631a 100644 --- a/typing/includeclass.ml +++ b/typing/includeclass.ml @@ -63,7 +63,7 @@ let include_err ppf = (function ppf -> fprintf ppf "but is expected to have type") | CM_Class_type_mismatch (env, cty1, cty2) -> - Printtyp.wrap_printing_env env (fun () -> + Printtyp.wrap_printing_env ~error:true env (fun () -> fprintf ppf "@[The class type@;<1 2>%a@ %s@;<1 2>%a@]" Printtyp.class_type cty1 diff --git a/typing/includecore.ml b/typing/includecore.ml index 4982a8a5..9ee520f3 100644 --- a/typing/includecore.ml +++ b/typing/includecore.ml @@ -249,7 +249,7 @@ and compare_records ~loc env params1 params2 n [Field_type ld1.ld_id] end -let type_declarations ?(equality = false) ~loc env name decl1 id decl2 = +let type_declarations ?(equality = false) ~loc env ~mark name decl1 id decl2 = Builtin_attributes.check_deprecated_inclusion ~def:decl1.type_loc ~use:decl2.type_loc @@ -288,23 +288,28 @@ let type_declarations ?(equality = false) ~loc env name decl1 id decl2 = let err = match (decl1.type_kind, decl2.type_kind) with (_, Type_abstract) -> [] | (Type_variant cstrs1, Type_variant cstrs2) -> - let mark cstrs usage name decl = - List.iter - (fun c -> - Env.mark_constructor_used usage env name decl - (Ident.name c.Types.cd_id)) - cstrs - in - let usage = - if decl1.type_private = Private || decl2.type_private = Public - then Env.Positive else Env.Privatize - in - mark cstrs1 usage name decl1; - if equality then mark cstrs2 Env.Positive (Ident.name id) decl2; - compare_variants ~loc env decl1.type_params decl2.type_params 1 cstrs1 cstrs2 + if mark then begin + let mark cstrs usage name decl = + List.iter + (fun c -> + Env.mark_constructor_used usage name decl + (Ident.name c.Types.cd_id)) + cstrs + in + let usage = + if decl1.type_private = Private || decl2.type_private = Public + then Env.Positive else Env.Privatize + in + mark cstrs1 usage name decl1; + if equality then mark cstrs2 Env.Positive (Ident.name id) decl2 + end; + compare_variants ~loc env decl1.type_params + decl2.type_params 1 cstrs1 cstrs2 | (Type_record(labels1,rep1), Type_record(labels2,rep2)) -> - let err = compare_records ~loc env decl1.type_params decl2.type_params - 1 labels1 labels2 in + let err = + compare_records ~loc env decl1.type_params + decl2.type_params 1 labels1 labels2 + in if err <> [] || rep1 = rep2 then err else [Record_representation (rep2 = Record_float)] | (Type_open, Type_open) -> [] @@ -343,12 +348,14 @@ let type_declarations ?(equality = false) ~loc env name decl1 id decl2 = (* Inclusion between extension constructors *) -let extension_constructors ~loc env id ext1 ext2 = - let usage = - if ext1.ext_private = Private || ext2.ext_private = Public - then Env.Positive else Env.Privatize - in - Env.mark_extension_used usage env ext1 (Ident.name id); +let extension_constructors ~loc env ~mark id ext1 ext2 = + if mark then begin + let usage = + if ext1.ext_private = Private || ext2.ext_private = Public + then Env.Positive else Env.Privatize + in + Env.mark_extension_used usage ext1 (Ident.name id) + end; let ty1 = Btype.newgenty (Tconstr(ext1.ext_type_path, ext1.ext_type_params, ref Mnil)) in diff --git a/typing/includecore.mli b/typing/includecore.mli index e3b8cac1..5193a9d0 100644 --- a/typing/includecore.mli +++ b/typing/includecore.mli @@ -43,12 +43,11 @@ val value_descriptions: val type_declarations: ?equality:bool -> loc:Location.t -> - Env.t -> string -> + Env.t -> mark:bool -> string -> type_declaration -> Ident.t -> type_declaration -> type_mismatch list val extension_constructors: - loc:Location.t -> - Env.t -> Ident.t -> + loc:Location.t -> Env.t -> mark:bool -> Ident.t -> extension_constructor -> extension_constructor -> bool (* val class_types: diff --git a/typing/includemod.ml b/typing/includemod.ml index 9b12e778..c1a691a2 100644 --- a/typing/includemod.ml +++ b/typing/includemod.ml @@ -47,15 +47,32 @@ type error = pos list * Env.t * symptom exception Error of error list +type mark = + | Mark_both + | Mark_positive + | Mark_negative + | Mark_neither + +let negate_mark = function + | Mark_both -> Mark_both + | Mark_positive -> Mark_negative + | Mark_negative -> Mark_positive + | Mark_neither -> Mark_neither + +let mark_positive = function + | Mark_both | Mark_positive -> true + | Mark_negative | Mark_neither -> false + (* All functions "blah env x1 x2" check that x1 is included in x2, i.e. that x1 is the type of an implementation that fulfills the specification x2. If not, Error is raised with a backtrace of the error. *) (* Inclusion between value descriptions *) -let value_descriptions ~loc env cxt subst id vd1 vd2 = +let value_descriptions ~loc env ~mark cxt subst id vd1 vd2 = Cmt_format.record_value_dependency vd1 vd2; - Env.mark_value_used env (Ident.name id) vd1; + if mark_positive mark then + Env.mark_value_used (Ident.name id) vd1; let vd2 = Subst.value_description subst vd2 in try Includecore.value_descriptions ~loc env (Ident.name id) vd1 vd2 @@ -64,20 +81,24 @@ let value_descriptions ~loc env cxt subst id vd1 vd2 = (* Inclusion between type declarations *) -let type_declarations ~loc env ?(old_env=env) cxt subst id decl1 decl2 = - Env.mark_type_used env (Ident.name id) decl1; +let type_declarations ~loc env ~mark ?(old_env=env) cxt subst id decl1 decl2 = + let mark = mark_positive mark in + if mark then + Env.mark_type_used (Ident.name id) decl1; let decl2 = Subst.type_declaration subst decl2 in let err = - Includecore.type_declarations ~loc env (Ident.name id) decl1 id decl2 + Includecore.type_declarations ~loc env ~mark + (Ident.name id) decl1 id decl2 in if err <> [] then raise(Error[cxt, old_env, Type_declarations(id, decl1, decl2, err)]) (* Inclusion between extension constructors *) -let extension_constructors ~loc env cxt subst id ext1 ext2 = +let extension_constructors ~loc env ~mark cxt subst id ext1 ext2 = + let mark = mark_positive mark in let ext2 = Subst.extension_constructor subst ext2 in - if Includecore.extension_constructors ~loc env id ext1 ext2 + if Includecore.extension_constructors ~loc env ~mark id ext1 ext2 then () else raise(Error[cxt, env, Extension_constructors(id, ext1, ext2)]) @@ -213,9 +234,9 @@ let simplify_structure_coercion cc id_pos_list = Return the restriction that transforms a value of the smaller type into a value of the bigger type. *) -let rec modtypes ~loc env cxt subst mty1 mty2 = +let rec modtypes ~loc env ~mark cxt subst mty1 mty2 = try - try_modtypes ~loc env cxt subst mty1 mty2 + try_modtypes ~loc env ~mark cxt subst mty1 mty2 with Dont_match -> raise(Error[cxt, env, Module_types(mty1, Subst.modtype subst mty2)]) @@ -227,7 +248,7 @@ let rec modtypes ~loc env cxt subst mty1 mty2 = raise(Error((cxt, env, Module_types(mty1, Subst.modtype subst mty2)) :: reasons)) -and try_modtypes ~loc env cxt subst mty1 mty2 = +and try_modtypes ~loc env ~mark cxt subst mty1 mty2 = match (mty1, mty2) with | (Mty_alias(pres1, p1), Mty_alias(pres2, p2)) -> begin if Env.is_functor_arg p2 env then @@ -261,29 +282,36 @@ and try_modtypes ~loc env cxt subst mty1 mty2 = Mtype.strengthen ~aliasable:true env (expand_module_alias env cxt p1) p1 in - let cc = modtypes ~loc env cxt subst mty1 mty2 in + let cc = modtypes ~loc env ~mark cxt subst mty1 mty2 in match pres1 with | Mta_present -> cc | Mta_absent -> Tcoerce_alias (p1, cc) end | (Mty_ident p1, _) when may_expand_module_path env p1 -> - try_modtypes ~loc env cxt subst (expand_module_path env cxt p1) mty2 + try_modtypes ~loc env ~mark cxt subst + (expand_module_path env cxt p1) mty2 | (_, Mty_ident _) -> - try_modtypes2 ~loc env cxt mty1 (Subst.modtype subst mty2) + try_modtypes2 ~loc env ~mark cxt mty1 (Subst.modtype subst mty2) | (Mty_signature sig1, Mty_signature sig2) -> - signatures ~loc env cxt subst sig1 sig2 + signatures ~loc env ~mark cxt subst sig1 sig2 | (Mty_functor(param1, None, res1), Mty_functor(_param2, None, res2)) -> - begin match modtypes ~loc env (Body param1::cxt) subst res1 res2 with - Tcoerce_none -> Tcoerce_none + begin + match modtypes ~loc env ~mark (Body param1::cxt) subst res1 res2 with + | Tcoerce_none -> Tcoerce_none | cc -> Tcoerce_functor (Tcoerce_none, cc) - end + end | (Mty_functor(param1, Some arg1, res1), Mty_functor(param2, Some arg2, res2)) -> let arg2' = Subst.modtype subst arg2 in - let cc_arg = modtypes ~loc env (Arg param1::cxt) Subst.identity arg2' arg1 in + let cc_arg = + modtypes ~loc env ~mark:(negate_mark mark) + (Arg param1::cxt) Subst.identity arg2' arg1 + in let cc_res = - modtypes ~loc (Env.add_module param1 arg2' env) (Body param1::cxt) - (Subst.add_module param2 (Pident param1) subst) res1 res2 in + modtypes ~loc (Env.add_module param1 arg2' env) ~mark + (Body param1::cxt) (Subst.add_module param2 (Pident param1) subst) + res1 res2 + in begin match (cc_arg, cc_res) with (Tcoerce_none, Tcoerce_none) -> Tcoerce_none | _ -> Tcoerce_functor(cc_arg, cc_res) @@ -291,7 +319,7 @@ and try_modtypes ~loc env cxt subst mty1 mty2 = | (_, _) -> raise Dont_match -and try_modtypes2 ~loc env cxt mty1 mty2 = +and try_modtypes2 ~loc env ~mark cxt mty1 mty2 = (* mty2 is an identifier *) match (mty1, mty2) with (Mty_ident p1, Mty_ident p2) @@ -299,13 +327,14 @@ and try_modtypes2 ~loc env cxt mty1 mty2 = (Env.normalize_path_prefix None env p2) -> Tcoerce_none | (_, Mty_ident p2) when may_expand_module_path env p2 -> - try_modtypes ~loc env cxt Subst.identity mty1 (expand_module_path env cxt p2) + try_modtypes ~loc env ~mark cxt Subst.identity + mty1 (expand_module_path env cxt p2) | (_, _) -> raise Dont_match (* Inclusion between signatures *) -and signatures ~loc env cxt subst sig1 sig2 = +and signatures ~loc env ~mark cxt subst sig1 sig2 = (* Environment used to check inclusion of components *) let new_env = Env.add_signature sig1 (Env.in_signature true env) in @@ -344,7 +373,7 @@ and signatures ~loc env cxt subst sig1 sig2 = begin match unpaired with [] -> let cc = - signature_components ~loc env new_env cxt subst + signature_components ~loc env ~mark new_env cxt subst (List.rev paired) in if len1 = len2 then (* see PR#5098 *) @@ -393,28 +422,32 @@ and signatures ~loc env cxt subst sig1 sig2 = (* Inclusion between signature components *) -and signature_components ~loc old_env env cxt subst paired = - let comps_rec rem = signature_components ~loc old_env env cxt subst rem in +and signature_components ~loc old_env ~mark env cxt subst paired = + let comps_rec rem = + signature_components ~loc old_env ~mark env cxt subst rem + in match paired with [] -> [] | (Sig_value(id1, valdecl1), Sig_value(_id2, valdecl2), pos) :: rem -> - let cc = value_descriptions ~loc env cxt subst id1 valdecl1 valdecl2 in + let cc = + value_descriptions ~loc env ~mark cxt subst id1 valdecl1 valdecl2 + in begin match valdecl2.val_kind with Val_prim _ -> comps_rec rem | _ -> (pos, cc) :: comps_rec rem end | (Sig_type(id1, tydecl1, _), Sig_type(_id2, tydecl2, _), _pos) :: rem -> - type_declarations ~loc ~old_env env cxt subst id1 tydecl1 tydecl2; + type_declarations ~loc ~old_env env ~mark cxt subst id1 tydecl1 tydecl2; comps_rec rem | (Sig_typext(id1, ext1, _), Sig_typext(_id2, ext2, _), pos) :: rem -> - extension_constructors ~loc env cxt subst id1 ext1 ext2; + extension_constructors ~loc env ~mark cxt subst id1 ext1 ext2; (pos, Tcoerce_none) :: comps_rec rem | (Sig_module(id1, mty1, _), Sig_module(_id2, mty2, _), pos) :: rem -> - let cc = module_declarations ~loc env cxt subst id1 mty1 mty2 in + let cc = module_declarations ~loc env ~mark cxt subst id1 mty1 mty2 in (pos, cc) :: comps_rec rem | (Sig_modtype(id1, info1), Sig_modtype(_id2, info2), _pos) :: rem -> - modtype_infos ~loc env cxt subst id1 info1 info2; + modtype_infos ~loc env ~mark cxt subst id1 info1 info2; comps_rec rem | (Sig_class(id1, decl1, _), Sig_class(_id2, decl2, _), pos) :: rem -> class_declarations ~old_env env cxt subst id1 decl1 decl2; @@ -426,7 +459,7 @@ and signature_components ~loc old_env env cxt subst paired = | _ -> assert false -and module_declarations ~loc env cxt subst id1 md1 md2 = +and module_declarations ~loc env ~mark cxt subst id1 md1 md2 = Builtin_attributes.check_deprecated_inclusion ~def:md1.md_loc ~use:md2.md_loc @@ -434,13 +467,14 @@ and module_declarations ~loc env cxt subst id1 md1 md2 = md1.md_attributes md2.md_attributes (Ident.name id1); let p1 = Pident id1 in - Env.mark_module_used env (Ident.name id1) md1.md_loc; - modtypes ~loc env (Module id1::cxt) subst + if mark_positive mark then + Env.mark_module_used (Ident.name id1) md1.md_loc; + modtypes ~loc env ~mark (Module id1::cxt) subst (Mtype.strengthen ~aliasable:true env md1.md_type p1) md2.md_type (* Inclusion between module type specifications *) -and modtype_infos ~loc env cxt subst id info1 info2 = +and modtype_infos ~loc env ~mark cxt subst id info1 info2 = Builtin_attributes.check_deprecated_inclusion ~def:info1.mtd_loc ~use:info2.mtd_loc @@ -454,16 +488,16 @@ and modtype_infos ~loc env cxt subst id info1 info2 = (None, None) -> () | (Some _, None) -> () | (Some mty1, Some mty2) -> - check_modtype_equiv ~loc env cxt' mty1 mty2 + check_modtype_equiv ~loc env ~mark cxt' mty1 mty2 | (None, Some mty2) -> - check_modtype_equiv ~loc env cxt' (Mty_ident(Pident id)) mty2 + check_modtype_equiv ~loc env ~mark cxt' (Mty_ident(Pident id)) mty2 with Error reasons -> raise(Error((cxt, env, Modtype_infos(id, info1, info2)) :: reasons)) -and check_modtype_equiv ~loc env cxt mty1 mty2 = +and check_modtype_equiv ~loc env ~mark cxt mty1 mty2 = match - (modtypes ~loc env cxt Subst.identity mty1 mty2, - modtypes ~loc env cxt Subst.identity mty2 mty1) + (modtypes ~loc env ~mark cxt Subst.identity mty1 mty2, + modtypes ~loc env ~mark:(negate_mark mark) cxt Subst.identity mty2 mty1) with (Tcoerce_none, Tcoerce_none) -> () | (_c1, _c2) -> @@ -482,33 +516,34 @@ let can_alias env path = no_apply path && not (Env.is_functor_arg path env) let check_modtype_inclusion ~loc env mty1 path1 mty2 = - try - let aliasable = can_alias env path1 in - ignore(modtypes ~loc env [] Subst.identity - (Mtype.strengthen ~aliasable env mty1 path1) mty2) - with Error _ -> - raise Not_found + let aliasable = can_alias env path1 in + ignore(modtypes ~loc env ~mark:Mark_both [] Subst.identity + (Mtype.strengthen ~aliasable env mty1 path1) mty2) -let _ = Env.check_modtype_inclusion := check_modtype_inclusion +let () = + Env.check_modtype_inclusion := (fun ~loc a b c d -> + try (check_modtype_inclusion ~loc a b c d : unit) + with Error _ -> raise Not_found) (* Check that an implementation of a compilation unit meets its interface. *) -let compunit env impl_name impl_sig intf_name intf_sig = +let compunit env ?(mark=Mark_both) impl_name impl_sig intf_name intf_sig = try - signatures ~loc:(Location.in_file impl_name) env [] Subst.identity - impl_sig intf_sig + signatures ~loc:(Location.in_file impl_name) env ~mark [] + Subst.identity impl_sig intf_sig with Error reasons -> raise(Error(([], Env.empty,Interface_mismatch(impl_name, intf_name)) :: reasons)) (* Hide the context and substitution parameters to the outside world *) -let modtypes ~loc env mty1 mty2 = modtypes ~loc env [] Subst.identity mty1 mty2 -let signatures env sig1 sig2 = - signatures ~loc:Location.none env [] Subst.identity sig1 sig2 -let type_declarations ~loc env id decl1 decl2 = - type_declarations ~loc env [] Subst.identity id decl1 decl2 +let modtypes ~loc env ?(mark=Mark_both) mty1 mty2 = + modtypes ~loc env ~mark [] Subst.identity mty1 mty2 +let signatures env ?(mark=Mark_both) sig1 sig2 = + signatures ~loc:Location.none env ~mark [] Subst.identity sig1 sig2 +let type_declarations ~loc env ?(mark=Mark_both) id decl1 decl2 = + type_declarations ~loc env ~mark [] Subst.identity id decl1 decl2 (* let modtypes env m1 m2 = @@ -639,7 +674,7 @@ let context ppf cxt = fprintf ppf "@[At position@ %a@]@ " context cxt let include_err ppf (cxt, env, err) = - Printtyp.wrap_printing_env env (fun () -> + Printtyp.wrap_printing_env ~error:true env (fun () -> fprintf ppf "@[%a%a@]" context (List.rev cxt) include_err err) let buffer = ref Bytes.empty diff --git a/typing/includemod.mli b/typing/includemod.mli index d5d3cbfc..2909ee99 100644 --- a/typing/includemod.mli +++ b/typing/includemod.mli @@ -19,17 +19,37 @@ open Typedtree open Types open Format +(** Type describing which arguments of an inclusion to consider as used + for the usage warnings. [Mark_both] is the default. *) +type mark = + | Mark_both + (** Mark definitions used from both arguments *) + | Mark_positive + (** Mark definitions used from the positive (first) argument *) + | Mark_negative + (** Mark definitions used from the negative (second) argument *) + | Mark_neither + (** Do not mark definitions used from either argument *) + val modtypes: - loc:Location.t -> Env.t -> + loc:Location.t -> Env.t -> ?mark:mark -> module_type -> module_type -> module_coercion -val signatures: Env.t -> signature -> signature -> module_coercion +val check_modtype_inclusion : + loc:Location.t -> Env.t -> Types.module_type -> Path.t -> Types.module_type -> unit +(** [check_modtype_inclusion ~loc env mty1 path1 mty2] checks that the + functor application F(M) is well typed, where mty2 is the type of + the argument of F and path1/mty1 is the path/unstrenghened type of M. *) + +val signatures: Env.t -> ?mark:mark -> + signature -> signature -> module_coercion val compunit: - Env.t -> string -> signature -> string -> signature -> module_coercion + Env.t -> ?mark:mark -> string -> signature -> + string -> signature -> module_coercion val type_declarations: - loc:Location.t -> Env.t -> + loc:Location.t -> Env.t -> ?mark:mark -> Ident.t -> type_declaration -> type_declaration -> unit val print_coercion: formatter -> module_coercion -> unit diff --git a/typing/mtype.ml b/typing/mtype.ml index 479f12e3..c923fd33 100644 --- a/typing/mtype.ml +++ b/typing/mtype.ml @@ -107,6 +107,43 @@ and strengthen_decl ~aliasable env md p = let () = Env.strengthen := strengthen +let rec make_aliases_absent mty = + match mty with + | Mty_alias(_, p) -> + Mty_alias(Mta_absent, p) + | Mty_signature sg -> + Mty_signature(make_aliases_absent_sig sg) + | Mty_functor(param, arg, res) -> + Mty_functor(param, arg, make_aliases_absent res) + | mty -> + mty + +and make_aliases_absent_sig sg = + match sg with + [] -> [] + | Sig_module(id, md, rs) :: rem -> + let str = + { md with md_type = make_aliases_absent md.md_type } + in + Sig_module(id, str, rs) :: make_aliases_absent_sig rem + | sigelt :: rem -> + sigelt :: make_aliases_absent_sig rem + +let scrape_for_type_of env mty = + let rec loop env path mty = + match mty, path with + | Mty_alias(_, path), _ -> begin + try + let md = Env.find_module path env in + loop env (Some path) md.md_type + with Not_found -> mty + end + | mty, Some path -> + strengthen ~aliasable:false env mty path + | _ -> mty + in + make_aliases_absent (loop env None mty) + (* In nondep_supertype, env is only used for the type it assigns to id. Hence there is no need to keep env up-to-date by adding the bindings traversed. *) @@ -175,17 +212,36 @@ let nondep_supertype env mid mty = in nondep_mty env Co mty -let enrich_typedecl env p decl = +let enrich_typedecl env p id decl = match decl.type_manifest with Some _ -> decl | None -> try let orig_decl = Env.find_type p env in - if orig_decl.type_arity <> decl.type_arity - then decl - else {decl with type_manifest = - Some(Btype.newgenty(Tconstr(p, decl.type_params, ref Mnil)))} - with Not_found -> + if decl.type_arity <> orig_decl.type_arity then + decl + else + let orig_ty = + Ctype.reify_univars + (Btype.newgenty(Tconstr(p, orig_decl.type_params, ref Mnil))) + in + let new_ty = + Ctype.reify_univars + (Btype.newgenty(Tconstr(Pident id, decl.type_params, ref Mnil))) + in + let env = Env.add_type ~check:false id decl env in + Ctype.mcomp env orig_ty new_ty; + let orig_ty = + Btype.newgenty(Tconstr(p, decl.type_params, ref Mnil)) + in + {decl with type_manifest = Some orig_ty} + with Not_found | Ctype.Unify _ -> + (* - Not_found: type which was not present in the signature, so we don't + have anything to do. + - Unify: the current declaration is not compatible with the one we + got from the signature. We should just fail now, but then, we could + also have failed if the arities of the two decls were different, + which we didn't. *) decl let rec enrich_modtype env p mty = @@ -198,7 +254,7 @@ let rec enrich_modtype env p mty = and enrich_item env p = function Sig_type(id, decl, rs) -> Sig_type(id, - enrich_typedecl env (Pdot(p, Ident.name id, nopos)) decl, rs) + enrich_typedecl env (Pdot(p, Ident.name id, nopos)) id decl, rs) | Sig_module(id, md, rs) -> Sig_module(id, {md with @@ -305,7 +361,6 @@ let contains_type env mty = module PathSet = Set.Make (Path) module PathMap = Map.Make (Path) -module IdentSet = Set.Make (Ident) let rec get_prefixes = function Pident _ -> PathSet.empty @@ -334,10 +389,10 @@ let rec collect_ids subst bindings p = Pident id -> let ids = try collect_ids subst bindings (Ident.find_same id bindings) - with Not_found -> IdentSet.empty + with Not_found -> Ident.Set.empty in - IdentSet.add id ids - | _ -> IdentSet.empty + Ident.Set.add id ids + | _ -> Ident.Set.empty end let collect_arg_paths mty = @@ -365,17 +420,17 @@ let collect_arg_paths mty = let it = {type_iterators with it_path; it_signature_item} in it.it_module_type it mty; it.it_module_type unmark_iterators mty; - PathSet.fold (fun p -> IdentSet.union (collect_ids !subst !bindings p)) - !paths IdentSet.empty + PathSet.fold (fun p -> Ident.Set.union (collect_ids !subst !bindings p)) + !paths Ident.Set.empty -let rec remove_aliases env excl mty = +let rec remove_aliases_mty env excl mty = match mty with Mty_signature sg -> Mty_signature (remove_aliases_sig env excl sg) | Mty_alias _ -> let mty' = Env.scrape_alias env mty in if mty' = mty then mty else - remove_aliases env excl mty' + remove_aliases_mty env excl mty' | mty -> mty @@ -385,10 +440,10 @@ and remove_aliases_sig env excl sg = | Sig_module(id, md, rs) :: rem -> let mty = match md.md_type with - Mty_alias _ when IdentSet.mem id excl -> + Mty_alias _ when Ident.Set.mem id excl -> md.md_type | mty -> - remove_aliases env excl mty + remove_aliases_mty env excl mty in Sig_module(id, {md with md_type = mty} , rs) :: remove_aliases_sig (Env.add_module id mty env) excl rem @@ -398,12 +453,14 @@ and remove_aliases_sig env excl sg = | it :: rem -> it :: remove_aliases_sig env excl rem -let remove_aliases env sg = - let excl = collect_arg_paths sg in - (* PathSet.iter (fun p -> Format.eprintf "%a@ " Printtyp.path p) excl; - Format.eprintf "@."; *) - remove_aliases env excl sg +let scrape_for_type_of ~remove_aliases env mty = + if remove_aliases then begin + let excl = collect_arg_paths mty in + remove_aliases_mty env excl mty + end else begin + scrape_for_type_of env mty + end (* Lower non-generalizable type variables *) diff --git a/typing/mtype.mli b/typing/mtype.mli index 84e870ac..a2cfadfd 100644 --- a/typing/mtype.mli +++ b/typing/mtype.mli @@ -21,6 +21,9 @@ val scrape: Env.t -> module_type -> module_type (* Expand toplevel module type abbreviations till hitting a "hard" module type (signature, functor, or abstract module type ident. *) +val scrape_for_type_of: + remove_aliases:bool -> Env.t -> module_type -> module_type + (* Expand module aliases *) val freshen: module_type -> module_type (* Return an alpha-equivalent copy of the given module type where bound identifiers are fresh. *) @@ -38,8 +41,8 @@ val no_code_needed_sig: Env.t -> signature -> bool (* Determine whether a module needs no implementation code, i.e. consists only of type definitions. *) val enrich_modtype: Env.t -> Path.t -> module_type -> module_type -val enrich_typedecl: Env.t -> Path.t -> type_declaration -> type_declaration +val enrich_typedecl: Env.t -> Path.t -> Ident.t -> type_declaration -> + type_declaration val type_paths: Env.t -> Path.t -> module_type -> Path.t list val contains_type: Env.t -> module_type -> bool -val remove_aliases: Env.t -> module_type -> module_type val lower_nongen: int -> module_type -> unit diff --git a/typing/oprint.ml b/typing/oprint.ml index e825513b..f65ad7ea 100644 --- a/typing/oprint.ml +++ b/typing/oprint.ml @@ -151,7 +151,7 @@ let print_out_value ppf tree = | Oval_int32 i -> parenthesize_if_neg ppf "%lil" i (i < 0l) | Oval_int64 i -> parenthesize_if_neg ppf "%LiL" i (i < 0L) | Oval_nativeint i -> parenthesize_if_neg ppf "%nin" i (i < 0n) - | Oval_float f -> parenthesize_if_neg ppf "%s" (float_repres f) (f < 0.0) + | Oval_float f -> parenthesize_if_neg ppf "%s" (float_repres f) (f < 0.0 || 1. /. f = neg_infinity) | Oval_string (_,_, Ostr_bytes) as tree -> pp_print_char ppf '('; print_simple_tree ppf tree; @@ -592,9 +592,12 @@ and print_out_type_decl kwd ppf td = print_private td.otype_private print_record_decl lbls | Otyp_sum constrs -> + let variants fmt constrs = + if constrs = [] then fprintf fmt "|" else + fprintf fmt "%a" (print_list print_out_constr + (fun ppf -> fprintf ppf "@ | ")) constrs in fprintf ppf " =%a@;<1 2>%a" - print_private td.otype_private - (print_list print_out_constr (fun ppf -> fprintf ppf "@ | ")) constrs + print_private td.otype_private variants constrs | Otyp_open -> fprintf ppf " =%a .." print_private td.otype_private diff --git a/typing/parmatch.ml b/typing/parmatch.ml index cb5e07b0..adc75862 100644 --- a/typing/parmatch.ml +++ b/typing/parmatch.ml @@ -115,23 +115,7 @@ let zero = make_pat (Tpat_constant (Const_int 0)) Ctype.none Env.empty when an "incoherence" is not detected by this check. *) - -let simplify_head_pat p k = - let rec simplify_head_pat p k = - match p.pat_desc with - | Tpat_alias (p,_,_) -> simplify_head_pat p k - | Tpat_var (_,_) -> omega :: k - | Tpat_or (p1,p2,_) -> simplify_head_pat p1 (simplify_head_pat p2 k) - | _ -> p :: k - in simplify_head_pat p k - -let rec simplified_first_col = function - | [] -> [] - | [] :: _ -> assert false (* the rows are non-empty! *) - | (p::_) :: rows -> - simplify_head_pat p (simplified_first_col rows) - -(* Given the simplified first column of a matrix, this function first looks for +(* Given the first column of a simplified matrix, this function first looks for a "discriminating" pattern on that column (i.e. a non-omega one) and then check that every other head pattern in the column is coherent with that one. *) @@ -166,8 +150,7 @@ let all_coherent column = Array.length lbl1.lbl_all = Array.length lbl2.lbl_all | Tpat_any, _ | _, Tpat_any - | Tpat_record ([], _), Tpat_record (_, _) - | Tpat_record (_, _), Tpat_record ([], _) + | Tpat_record ([], _), Tpat_record ([], _) | Tpat_variant _, Tpat_variant _ | Tpat_array _, Tpat_array _ | Tpat_lazy _, Tpat_lazy _ -> true @@ -266,7 +249,14 @@ let const_compare x y = Pervasives.compare (float_of_string f1) (float_of_string f2) | Const_string (s1, _), Const_string (s2, _) -> String.compare s1 s2 - | _, _ -> Pervasives.compare x y + | (Const_int _ + |Const_char _ + |Const_string (_, _) + |Const_float _ + |Const_int32 _ + |Const_int64 _ + |Const_nativeint _ + ), _ -> Pervasives.compare x y let records_args l1 l2 = (* Invariant: fields are already sorted by Typecore.type_label_a_list *) @@ -357,157 +347,11 @@ let clean_copy ty = if ty.level = Btype.generic_level then ty else Subst.type_expr Subst.identity ty -let get_type_path ty tenv = +let get_constructor_type_path ty tenv = let ty = Ctype.repr (Ctype.expand_head tenv (clean_copy ty)) in match ty.desc with | Tconstr (path,_,_) -> path - | _ -> fatal_error "Parmatch.get_type_path" - -(*************************************) -(* Values as patterns pretty printer *) -(*************************************) - -open Format -;; - -let is_cons = function -| {cstr_name = "::"} -> true -| _ -> false - -let pretty_const c = match c with -| Const_int i -> Printf.sprintf "%d" i -| Const_char c -> Printf.sprintf "%C" c -| Const_string (s, _) -> Printf.sprintf "%S" s -| Const_float f -> Printf.sprintf "%s" f -| Const_int32 i -> Printf.sprintf "%ldl" i -| Const_int64 i -> Printf.sprintf "%LdL" i -| Const_nativeint i -> Printf.sprintf "%ndn" i - -let rec pretty_val ppf v = - match v.pat_extra with - (cstr, _loc, _attrs) :: rem -> - begin match cstr with - | Tpat_unpack -> - fprintf ppf "@[(module %a)@]" pretty_val { v with pat_extra = rem } - | Tpat_constraint _ -> - fprintf ppf "@[(%a : _)@]" pretty_val { v with pat_extra = rem } - | Tpat_type _ -> - fprintf ppf "@[(# %a)@]" pretty_val { v with pat_extra = rem } - | Tpat_open _ -> - fprintf ppf "@[(# %a)@]" pretty_val { v with pat_extra = rem } - end - | [] -> - match v.pat_desc with - | Tpat_any -> fprintf ppf "_" - | Tpat_var (x,_) -> fprintf ppf "%s" (Ident.name x) - | Tpat_constant c -> fprintf ppf "%s" (pretty_const c) - | Tpat_tuple vs -> - fprintf ppf "@[(%a)@]" (pretty_vals ",") vs - | Tpat_construct (_, cstr, []) -> - fprintf ppf "%s" cstr.cstr_name - | Tpat_construct (_, cstr, [w]) -> - fprintf ppf "@[<2>%s@ %a@]" cstr.cstr_name pretty_arg w - | Tpat_construct (_, cstr, vs) -> - let name = cstr.cstr_name in - begin match (name, vs) with - ("::", [v1;v2]) -> - fprintf ppf "@[%a::@,%a@]" pretty_car v1 pretty_cdr v2 - | _ -> - fprintf ppf "@[<2>%s@ @[(%a)@]@]" name (pretty_vals ",") vs - end - | Tpat_variant (l, None, _) -> - fprintf ppf "`%s" l - | Tpat_variant (l, Some w, _) -> - fprintf ppf "@[<2>`%s@ %a@]" l pretty_arg w - | Tpat_record (lvs,_) -> - let filtered_lvs = List.filter - (function - | (_,_,{pat_desc=Tpat_any}) -> false (* do not show lbl=_ *) - | _ -> true) lvs in - begin match filtered_lvs with - | [] -> fprintf ppf "_" - | (_, lbl, _) :: q -> - let elision_mark ppf = - (* we assume that there is no label repetitions here *) - if Array.length lbl.lbl_all > 1 + List.length q then - fprintf ppf ";@ _@ " - else () in - fprintf ppf "@[{%a%t}@]" - pretty_lvals filtered_lvs elision_mark - end - | Tpat_array vs -> - fprintf ppf "@[[| %a |]@]" (pretty_vals " ;") vs - | Tpat_lazy v -> - fprintf ppf "@[<2>lazy@ %a@]" pretty_arg v - | Tpat_alias (v, x,_) -> - fprintf ppf "@[(%a@ as %a)@]" pretty_val v Ident.print x - | Tpat_or (v,w,_) -> - fprintf ppf "@[(%a|@,%a)@]" pretty_or v pretty_or w - -and pretty_car ppf v = match v.pat_desc with -| Tpat_construct (_,cstr, [_ ; _]) - when is_cons cstr -> - fprintf ppf "(%a)" pretty_val v -| _ -> pretty_val ppf v - -and pretty_cdr ppf v = match v.pat_desc with -| Tpat_construct (_,cstr, [v1 ; v2]) - when is_cons cstr -> - fprintf ppf "%a::@,%a" pretty_car v1 pretty_cdr v2 -| _ -> pretty_val ppf v - -and pretty_arg ppf v = match v.pat_desc with -| Tpat_construct (_,_,_::_) -| Tpat_variant (_, Some _, _) -> fprintf ppf "(%a)" pretty_val v -| _ -> pretty_val ppf v - -and pretty_or ppf v = match v.pat_desc with -| Tpat_or (v,w,_) -> - fprintf ppf "%a|@,%a" pretty_or v pretty_or w -| _ -> pretty_val ppf v - -and pretty_vals sep ppf = function - | [] -> () - | [v] -> pretty_val ppf v - | v::vs -> - fprintf ppf "%a%s@ %a" pretty_val v sep (pretty_vals sep) vs - -and pretty_lvals ppf = function - | [] -> () - | [_,lbl,v] -> - fprintf ppf "%s=%a" lbl.lbl_name pretty_val v - | (_, lbl,v)::rest -> - fprintf ppf "%s=%a;@ %a" - lbl.lbl_name pretty_val v pretty_lvals rest - -let top_pretty ppf v = - fprintf ppf "@[%a@]@?" pretty_val v - - -let pretty_pat p = - top_pretty Format.str_formatter p ; - prerr_string (Format.flush_str_formatter ()) - -type matrix = pattern list list - -let pretty_line ps = - List.iter - (fun p -> - top_pretty Format.str_formatter p ; - prerr_string " <" ; - prerr_string (Format.flush_str_formatter ()) ; - prerr_string ">") - ps - -let pretty_matrix (pss : matrix) = - prerr_endline "begin matrix" ; - List.iter - (fun ps -> - pretty_line ps ; - prerr_endline "") - pss ; - prerr_endline "end matrix" - + | _ -> assert false (****************************) (* Utilities for matching *) @@ -551,19 +395,6 @@ let extract_fields omegas arg = with Not_found -> omega) omegas -let all_record_args lbls = match lbls with -| (_,{lbl_all=lbl_all},_)::_ -> - let t = - Array.map - (fun lbl -> mknoloc (Longident.Lident "?temp?"), lbl,omega) - lbl_all in - List.iter - (fun ((_, lbl,_) as x) -> t.(lbl.lbl_pos) <- x) - lbls ; - Array.to_list t -| _ -> fatal_error "Parmatch.all_record_args" - - (* Build argument list when p2 >= p1, where p1 is a simple pattern *) let rec simple_match_args p1 p2 = match p2.pat_desc with | Tpat_alias (p2,_,_) -> simple_match_args p1 p2 @@ -614,41 +445,71 @@ let rec normalize_pat q = match q.pat_desc with make_pat (Tpat_lazy omega) q.pat_type q.pat_env | Tpat_or _ -> fatal_error "Parmatch.normalize_pat" -(* - Build normalized (cf. supra) discriminating pattern, - in the non-data type case -*) +(* Consider a pattern matrix whose first column has been simplified to contain + only _ or a head constructor + | p1, r1... + | p2, r2... + | p3, r3... + | ... -let discr_pat q pss = + We build a normalized /discriminating/ pattern from a pattern [q] by folding + over the first column of the matrix, "refining" [q] as we go: - let rec acc_pat acc pss = match pss with - ({pat_desc = Tpat_alias (p,_,_)}::ps)::pss -> - acc_pat acc ((p::ps)::pss) - | ({pat_desc = Tpat_or (p1,p2,_)}::ps)::pss -> - acc_pat acc ((p1::ps)::(p2::ps)::pss) - | ({pat_desc = (Tpat_any | Tpat_var _)}::_)::pss -> - acc_pat acc pss - | (({pat_desc = Tpat_tuple _} as p)::_)::_ -> normalize_pat p - | (({pat_desc = Tpat_lazy _} as p)::_)::_ -> normalize_pat p - | (({pat_desc = Tpat_record (largs,closed)} as p)::_)::pss -> - let new_omegas = - List.fold_right - (fun (lid, lbl,_) r -> - try - let _ = get_field lbl.lbl_pos r in - r - with Not_found -> - (lid, lbl,omega)::r) - largs (record_arg acc) - in - acc_pat - (make_pat (Tpat_record (new_omegas, closed)) p.pat_type p.pat_env) - pss - | _ -> acc in + - when we encounter a row starting with [Tpat_tuple] or [Tpat_lazy] then we + can stop and return that pattern, as we cannot refine any further. Indeed, + these constructors are alone in their signature, so they will subsume + whatever other pattern we might find, as well as the pattern we're threading + along. + + - when we find a [Tpat_record] then it is a bit more involved: it is also + alone in its signature, however it might only be matching a subset of the + record fields. We use these fields to refine our accumulator and keep going + as another row might match on different fields. + + - rows starting with a wildcard do not bring any information, so we ignore + them and keep going - match normalize_pat q with - | {pat_desc= (Tpat_any | Tpat_record _)} as q -> acc_pat q pss - | q -> q + - if we encounter anything else (i.e. any other constructor), then we just + stop and return our accumulator. +*) +let discr_pat q pss = + let rec refine_pat acc = function + | [] -> acc + | (head, _) :: rows -> + match head.pat_desc with + | Tpat_or _ | Tpat_var _ | Tpat_alias _ -> assert false + | Tpat_any -> refine_pat acc rows + | Tpat_tuple _ | Tpat_lazy _ -> normalize_pat head + | Tpat_record (largs, closed) -> + (* N.B. we could make this case "simpler" by refining the record case + using [all_record_args]. + In which case we wouldn't need to fold over the first column for + records. + However it makes the witness we generate for the exhaustivity warning + less pretty. *) + let new_omegas = + List.fold_right + (fun (lid, lbl,_) r -> + try + let _ = get_field lbl.lbl_pos r in + r + with Not_found -> + (lid, lbl,omega)::r) + largs (record_arg acc) + in + let new_acc = + make_pat (Tpat_record (new_omegas, closed)) head.pat_type head.pat_env + in + refine_pat new_acc rows + | _ -> acc + in + let q = normalize_pat q in + (* short-circuiting: clearly if we have anything other than [Tpat_record] or + [Tpat_any] to start with, we're not going to be able refine at all. So + there's no point going over the matrix. *) + match q.pat_desc with + | Tpat_any | Tpat_record _ -> refine_pat q pss + | _ -> q (* In case a matching value is found, set actual arguments @@ -717,111 +578,177 @@ let do_set_args erase_mutable q r = match q with let set_args q r = do_set_args false q r and set_args_erase_mutable q r = do_set_args true q r -(* filter pss according to pattern q *) -let filter_one q pss = +(* Given a matrix of non-empty rows + p1 :: r1... + p2 :: r2... + p3 :: r3... + + Simplify the first column [p1 p2 p3] by splitting all or-patterns. + The result is a list of couples + (simple pattern, rest of row) + where a "simple pattern" starts with either the catch-all pattern omega (_) + or a head constructor. + + For example, + x :: r1 + (Some _) as y :: r2 + (None as x) as y :: r3 + (Some x | (None as x)) :: r4 + becomes + (_, r1) + (Some _, r2) + (None, r3) + (Some x, r4) + (None, r4) + *) +let simplify_head_pat ~add_column p ps k = + let rec simplify_head_pat p ps k = + match p.pat_desc with + | Tpat_alias (p,_,_) -> simplify_head_pat p ps k + | Tpat_var (_,_) -> add_column omega ps k + | Tpat_or (p1,p2,_) -> simplify_head_pat p1 ps (simplify_head_pat p2 ps k) + | _ -> add_column p ps k + in simplify_head_pat p ps k + +let rec simplify_first_col = function + | [] -> [] + | [] :: _ -> assert false (* the rows are non-empty! *) + | (p::ps) :: rows -> + let add_column p ps k = (p, ps) :: k in + simplify_head_pat ~add_column p ps (simplify_first_col rows) + + +(* Builds the specialized matrix of [pss] according to pattern [q]. + See section 3.1 of http://moscova.inria.fr/~maranget/papers/warn/warn.pdf + + NOTES: + - expects [pss] to be a "simplified matrix", cf. [simplify_first_col] + - [q] was produced by [discr_pat] + - we are polymorphic on the type of matrices we work on, in particular a row + might not simply be a [pattern list]. That's why we have the [extend_row] + parameter. +*) +let build_specialized_submatrix ~extend_row q pss = let rec filter_rec = function - ({pat_desc = Tpat_alias(p,_,_)}::ps)::pss -> - filter_rec ((p::ps)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps)::pss -> - filter_rec ((p1::ps)::(p2::ps)::pss) - | (p::ps)::pss -> + | ({pat_desc = (Tpat_alias _ | Tpat_or _ | Tpat_var _) }, _) :: _ -> + assert false + | (p, ps) :: pss -> if simple_match q p - then (simple_match_args q p @ ps) :: filter_rec pss + then extend_row (simple_match_args q p) ps :: filter_rec pss else filter_rec pss | _ -> [] in filter_rec pss -(* - Filter pss in the ``extra case''. This applies : - - According to an extra constructor (datatype case, non-complete signature). - - According to anything (all-variables case). +(* The "default" and "specialized" matrices of a given matrix. + See section 3.1 of http://moscova.inria.fr/~maranget/papers/warn/warn.pdf . *) -let filter_extra pss = - let rec filter_rec = function - ({pat_desc = Tpat_alias(p,_,_)}::ps)::pss -> - filter_rec ((p::ps)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps)::pss -> - filter_rec ((p1::ps)::(p2::ps)::pss) - | ({pat_desc = (Tpat_any | Tpat_var(_))} :: qs) :: pss -> - qs :: filter_rec pss - | _::pss -> filter_rec pss - | [] -> [] in - filter_rec pss +type 'matrix specialized_matrices = { + default : 'matrix; + constrs : (pattern * 'matrix) list; +} + +(* Consider a pattern matrix whose first column has been simplified + to contain only _ or a head constructor + | p1, r1... + | p2, r2... + | p3, r3... + | ... -(* - Pattern p0 is the discriminating pattern, - returns [(q0,pss0) ; ... ; (qn,pssn)] - where the qi's are simple patterns and the pssi's are - matched matrices. - - NOTES - * (qi,[]) is impossible. - * In the case when matching is useless (all-variable case), - returns [] + We split this matrix into a list of /specialized/ sub-matrices, one for + each head constructor appearing in the first column. For each row whose + first column starts with a head constructor, remove this head + column, prepend one column for each argument of the constructor, + and add the resulting row in the sub-matrix corresponding to this + head constructor. + + Rows whose left column is omega (the Any pattern _) may match any + head constructor, so they are added to all sub-matrices. + + In the case where all the rows in the matrix have an omega on their first + column, then there is only one /specialized/ sub-matrix, formed of all these + omega rows. + This matrix is also called the /default/ matrix. + + See the documentation of [build_specialized_submatrix] for an explanation of + the [extend_row] parameter. *) +let build_specialized_submatrices ~extend_row q rows = + let extend_group discr p r rs = + let r = extend_row (simple_match_args discr p) r in + (discr, r :: rs) + in -let filter_all pat0 pss = + (* insert a row of head [p] and rest [r] into the right group *) + let rec insert_constr p r = function + | [] -> + (* if no group matched this row, it has a head constructor that + was never seen before; add a new sub-matrix for this head *) + [extend_group (normalize_pat p) p r []] + | (q0,rs) as bd::env -> + if simple_match q0 p + then extend_group q0 p r rs :: env + else bd :: insert_constr p r env + in - let rec insert q qs env = - match env with - [] -> - let q0 = normalize_pat q in - [q0, [simple_match_args q0 q @ qs]] - | ((q0,pss) as c)::env -> - if simple_match q0 q - then (q0, ((simple_match_args q0 q @ qs) :: pss)) :: env - else c :: insert q qs env in - - let rec filter_rec env = function - ({pat_desc = Tpat_alias(p,_,_)}::ps)::pss -> - filter_rec env ((p::ps)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps)::pss -> - filter_rec env ((p1::ps)::(p2::ps)::pss) - | ({pat_desc = (Tpat_any | Tpat_var(_))}::_)::pss -> - filter_rec env pss - | (p::ps)::pss -> - filter_rec (insert p ps env) pss - | _ -> env - - and filter_omega env = function - ({pat_desc = Tpat_alias(p,_,_)}::ps)::pss -> - filter_omega env ((p::ps)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps)::pss -> - filter_omega env ((p1::ps)::(p2::ps)::pss) - | ({pat_desc = (Tpat_any | Tpat_var(_))}::ps)::pss -> - filter_omega - (List.map (fun (q,qss) -> (q,(simple_match_args q omega @ ps) :: qss)) - env) - pss - | _::pss -> filter_omega env pss - | [] -> env in - - filter_omega - (filter_rec - (match pat0.pat_desc with - (Tpat_record(_) | Tpat_tuple(_) | Tpat_lazy(_)) -> [pat0,[]] - | _ -> []) - pss) - pss + (* insert a row of head omega into all groups *) + let insert_omega r env = + List.map (fun (q0,rs) -> extend_group q0 omega r rs) env + in + + let rec form_groups constr_groups omega_tails = function + | [] -> (constr_groups, omega_tails) + | ({pat_desc=(Tpat_var _|Tpat_alias _|Tpat_or _)},_)::_ -> assert false + | ({pat_desc=Tpat_any}, tail) :: rest -> + (* note that calling insert_omega here would be wrong + as some groups may not have been formed yet, if the + first row with this head pattern comes after in the list *) + form_groups constr_groups (tail :: omega_tails) rest + | (p,r) :: rest -> + form_groups (insert_constr p r constr_groups) omega_tails rest + in + + let constr_groups, omega_tails = + let initial_constr_group = + match q.pat_desc with + | Tpat_record(_) | Tpat_tuple(_) | Tpat_lazy(_) -> + (* [q] comes from [discr_pat], and in this case subsumes any of the + patterns we could find on the first column of [rows]. So it is better + to use it for our initial environment than any of the normalized + pattern we might obtain from the first column. *) + [q,[]] + | _ -> [] + in + form_groups initial_constr_group [] rows + in + { + default = omega_tails; + constrs = + (* insert omega rows in all groups *) + List.fold_right insert_omega omega_tails constr_groups; + } (* Variant related functions *) -let rec set_last a = function - [] -> [] - | [_] -> [a] - | x::l -> x :: set_last a l - -(* mark constructor lines for failure when they are incomplete *) -let rec mark_partial = function - ({pat_desc = Tpat_alias(p,_,_)}::ps)::pss -> - mark_partial ((p::ps)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps)::pss -> - mark_partial ((p1::ps)::(p2::ps)::pss) - | ({pat_desc = (Tpat_any | Tpat_var(_))} :: _ as ps) :: pss -> - ps :: mark_partial pss - | ps::pss -> - (set_last zero ps) :: mark_partial pss - | [] -> [] +let set_last a = + let rec loop = function + | [] -> assert false + | [_] -> [a] + | x::l -> x :: loop l + in + function + | (_, []) -> (a, []) + | (first, row) -> (first, loop row) + +(* mark constructor lines for failure when they are incomplete + + Precondition: the input matrix has been simplified so that its + first column only contains _ or head constructors. *) +let mark_partial = + List.map (function + | ({pat_desc=(Tpat_var _|Tpat_alias _|Tpat_or _)},_) -> assert false + | ({pat_desc = Tpat_any }, _) as ps -> ps + | ps -> set_last zero ps + ) let close_variant env row = let row = Btype.row_repr row in @@ -850,10 +777,14 @@ let row_of_pat pat = (* Check whether the first column of env makes up a complete signature or - not. + not. We work on the discriminating patterns of each sub-matrix: they + are simplified, and are not omega/Tpat_any. *) - let full_match closing env = match env with +| ({pat_desc = (Tpat_any | Tpat_var _ | Tpat_alias _ | Tpat_or _)},_) :: _ -> + (* discriminating patterns are simplified *) + assert false +| [] -> false | ({pat_desc = Tpat_construct(_,c,_)},_) :: _ -> if c.cstr_consts < 0 then false (* extensions *) else List.length env = c.cstr_consts + c.cstr_nonconsts @@ -888,10 +819,6 @@ let full_match closing env = match env with | ({pat_desc = Tpat_record(_)},_) :: _ -> true | ({pat_desc = Tpat_array(_)},_) :: _ -> false | ({pat_desc = Tpat_lazy(_)},_) :: _ -> true -| ({pat_desc = (Tpat_any|Tpat_var _|Tpat_alias _|Tpat_or _)},_) :: _ -| [] - -> - assert false (* Written as a non-fragile matching, PR#7451 originated from a fragile matching below. *) let should_extend ext env = match ext with @@ -902,7 +829,7 @@ let should_extend ext env = match ext with begin match p.pat_desc with | Tpat_construct (_, {cstr_tag=(Cstr_constant _|Cstr_block _|Cstr_unboxed)},_) -> - let path = get_type_path p.pat_type p.pat_env in + let path = get_constructor_type_path p.pat_type p.pat_env in Path.same path ext | Tpat_construct (_, {cstr_tag=(Cstr_extension _)},_) -> false @@ -943,7 +870,7 @@ let complete_tags nconsts nconstrs tags = done ; r -(* build a pattern from a constructor list *) +(* build a pattern from a constructor description *) let pat_of_constr ex_pat cstr = {ex_pat with pat_desc = Tpat_construct (mknoloc (Longident.Lident "?pat_of_constr?"), @@ -956,6 +883,7 @@ let rec orify_many = function | [x] -> x | x :: xs -> orify x (orify_many xs) +(* build an or-pattern from a constructor list *) let pat_of_constrs ex_pat cstrs = if cstrs = [] then raise Empty else orify_many (List.map (pat_of_constr ex_pat) cstrs) @@ -1035,10 +963,10 @@ let build_other_constant proj make first next p env = (* Builds a pattern that is incompatible with all patterns in - in the first column of env + the first column of env *) -let some_other_tag = "" +let some_private_tag = "" let build_other ext env = match env with | ({pat_desc = Tpat_construct (lid, {cstr_tag=Cstr_extension _},_)},_) :: _ -> @@ -1047,8 +975,11 @@ let build_other ext env = match env with {lid with txt="*extension*"})) Ctype.none Env.empty | ({pat_desc = Tpat_construct _} as p,_) :: _ -> begin match ext with - | Some ext when Path.same ext (get_type_path p.pat_type p.pat_env) -> - extra_pat + | Some ext -> + if Path.same ext (get_constructor_type_path p.pat_type p.pat_env) then + extra_pat + else + build_other_constrs env p | _ -> build_other_constrs env p end @@ -1075,7 +1006,12 @@ let build_other ext env = match env with [] row.row_fields with [] -> - make_other_pat some_other_tag true + let tag = + if Btype.row_fixed row then some_private_tag else + let rec mktag tag = + if List.mem tag tags then mktag (tag ^ "'") else tag in + mktag "AnyOtherTag" + in make_other_pat tag true | pat::other_pats -> List.fold_left (fun p_res pat -> @@ -1160,15 +1096,6 @@ let build_other ext env = match env with | [] -> omega | _ -> omega -(* - Core function : - Is the last row of pattern matrix pss + qs satisfiable ? - That is : - Does there exists at least one value vector, es such that : - 1- for all ps in pss ps # es (ps and es are not compatible) - 2- qs <= es (es matches qs) -*) - let rec has_instance p = match p.pat_desc with | Tpat_variant (l,_,r) when is_absent l r -> false | Tpat_any | Tpat_var _ | Tpat_constant _ | Tpat_variant (_,None,_) -> true @@ -1186,6 +1113,15 @@ and has_instances = function | q::rem -> has_instance q && has_instances rem (* + Core function : + Is the last row of pattern matrix pss + qs satisfiable ? + That is : + Does there exists at least one value vector, es such that : + 1- for all ps in pss ps # es (ps and es are not compatible) + 2- qs <= es (es matches qs) + + --- + In two places in the following function, we check the coherence of the first column of (pss + qs). If it is incoherent, then we exit early saying that (pss + qs) is not @@ -1209,177 +1145,156 @@ let rec satisfiable pss qs = match pss with | {pat_desc = Tpat_alias(q,_,_)}::qs -> satisfiable pss (q::qs) | {pat_desc = (Tpat_any | Tpat_var(_))}::qs -> - if not (all_coherent (simplified_first_col pss)) then + let pss = simplify_first_col pss in + if not (all_coherent (first_column pss)) then false else begin - let q0 = discr_pat omega pss in - match filter_all q0 pss with - (* first column of pss is made of variables only *) - | [] -> satisfiable (filter_extra pss) qs - | constrs -> - if full_match false constrs then - List.exists - (fun (p,pss) -> - not (is_absent_pat p) && - satisfiable pss (simple_match_args p omega @ qs)) - constrs - else - satisfiable (filter_extra pss) qs + let { default; constrs } = + let q0 = discr_pat omega pss in + build_specialized_submatrices ~extend_row:(@) q0 pss in + if not (full_match false constrs) then + satisfiable default qs + else + List.exists + (fun (p,pss) -> + not (is_absent_pat p) && + satisfiable pss (simple_match_args p omega @ qs)) + constrs end | {pat_desc=Tpat_variant (l,_,r)}::_ when is_absent l r -> false | q::qs -> - if not (all_coherent (q :: simplified_first_col pss)) then + let pss = simplify_first_col pss in + if not (all_coherent (q :: first_column pss)) then false else begin let q0 = discr_pat q pss in - satisfiable (filter_one q0 pss) (simple_match_args q0 q @ qs) + satisfiable (build_specialized_submatrix ~extend_row:(@) q0 pss) + (simple_match_args q0 q @ qs) end -(* Also return the remaining cases, to enable GADT handling +(* While [satisfiable] only checks whether the last row of [pss + qs] is + satisfiable, this function returns the (possibly empty) list of vectors [es] + which verify: + 1- for all ps in pss, ps # es (ps and es are not compatible) + 2- qs <= es (es matches qs) + + This is done to enable GADT handling For considerations regarding the coherence check, see the comment on [satisfiable] above. *) -let rec satisfiables pss qs = match pss with -| [] -> if has_instances qs then [qs] else [] -| _ -> - match qs with - | [] -> [] - | {pat_desc = Tpat_or(q1,q2,_)}::qs -> - satisfiables pss (q1::qs) @ satisfiables pss (q2::qs) - | {pat_desc = Tpat_alias(q,_,_)}::qs -> - satisfiables pss (q::qs) - | {pat_desc = (Tpat_any | Tpat_var(_))}::qs -> - if not (all_coherent (simplified_first_col pss)) then - [] - else begin - let q0 = discr_pat omega pss in - let wild p = - List.map (fun qs -> p::qs) (satisfiables (filter_extra pss) qs) in - match filter_all q0 pss with - (* first column of pss is made of variables only *) - | [] -> - wild omega - | (p,_)::_ as constrs -> - let for_constrs () = - List.flatten ( - List.map - (fun (p,pss) -> - if is_absent_pat p then [] else - List.map (set_args p) - (satisfiables pss (simple_match_args p omega @ qs))) - constrs ) - in - if full_match false constrs then for_constrs () else - match p.pat_desc with - Tpat_construct _ -> - (* activate this code for checking non-gadt constructors *) - wild (build_other_constrs constrs p) @ for_constrs () - | _ -> - wild omega - end - | {pat_desc=Tpat_variant (l,_,r)}::_ when is_absent l r -> [] - | q::qs -> - if not (all_coherent (q :: simplified_first_col pss)) then - [] - else begin - let q0 = discr_pat q pss in - List.map (set_args q0) - (satisfiables (filter_one q0 pss) (simple_match_args q0 q @ qs)) - end +let rec list_satisfying_vectors pss qs = + match pss with + | [] -> if has_instances qs then [qs] else [] + | _ -> + match qs with + | [] -> [] + | {pat_desc = Tpat_or(q1,q2,_)}::qs -> + list_satisfying_vectors pss (q1::qs) @ + list_satisfying_vectors pss (q2::qs) + | {pat_desc = Tpat_alias(q,_,_)}::qs -> + list_satisfying_vectors pss (q::qs) + | {pat_desc = (Tpat_any | Tpat_var(_))}::qs -> + let pss = simplify_first_col pss in + if not (all_coherent (first_column pss)) then + [] + else begin + let q0 = discr_pat omega pss in + let wild default_matrix p = + List.map (fun qs -> p::qs) + (list_satisfying_vectors default_matrix qs) + in + match build_specialized_submatrices ~extend_row:(@) q0 pss with + | { default; constrs = [] } -> + (* first column of pss is made of variables only *) + wild default omega + | { default; constrs = ((p,_)::_ as constrs) } -> + let for_constrs () = + List.flatten ( + List.map (fun (p,pss) -> + if is_absent_pat p then + [] + else + let witnesses = + list_satisfying_vectors pss + (simple_match_args p omega @ qs) + in + List.map (set_args p) witnesses + ) constrs + ) + in + if full_match false constrs then for_constrs () else + begin match p.pat_desc with + | Tpat_construct _ -> + (* activate this code for checking non-gadt constructors *) + wild default (build_other_constrs constrs p) + @ for_constrs () + | _ -> + wild default omega + end + end + | {pat_desc=Tpat_variant (l,_,r)}::_ when is_absent l r -> [] + | q::qs -> + let pss = simplify_first_col pss in + if not (all_coherent (q :: first_column pss)) then + [] + else begin + let q0 = discr_pat q pss in + List.map (set_args q0) + (list_satisfying_vectors + (build_specialized_submatrix ~extend_row:(@) q0 pss) + (simple_match_args q0 q @ qs)) + end -(* - Now another satisfiable function that additionally - supplies an example of a matching value. +(******************************************) +(* Look for a row that matches some value *) +(******************************************) - This function should be called for exhaustiveness check only. +(* + Useful for seeing if the example of + non-matched value can indeed be matched + (by a guarded clause) *) -type 'a result = - | Rnone (* No matching value *) - | Rsome of 'a (* This matching value *) +let rec do_match pss qs = match qs with +| [] -> + begin match pss with + | []::_ -> true + | _ -> false + end +| q::qs -> match q with + | {pat_desc = Tpat_or (q1,q2,_)} -> + do_match pss (q1::qs) || do_match pss (q2::qs) + | {pat_desc = Tpat_any} -> + let rec remove_first_column = function + | (_::ps)::rem -> ps::remove_first_column rem + | _ -> [] + in + do_match (remove_first_column pss) qs + | _ -> + let q0 = normalize_pat q in + let pss = simplify_first_col pss in + (* [pss] will (or won't) match [q0 :: qs] regardless of the coherence of + its first column. *) + do_match + (build_specialized_submatrix ~extend_row:(@) q0 pss) + (simple_match_args q0 q @ qs) -(* -let rec try_many f = function - | [] -> Rnone - | (p,pss)::rest -> - match f (p,pss) with - | Rnone -> try_many f rest - | r -> r -*) + +type 'a exhaust_result = + | No_matching_value + | Witnesses of 'a list let rappend r1 r2 = match r1, r2 with - | Rnone, _ -> r2 - | _, Rnone -> r1 - | Rsome l1, Rsome l2 -> Rsome (l1 @ l2) + | No_matching_value, _ -> r2 + | _, No_matching_value -> r1 + | Witnesses l1, Witnesses l2 -> Witnesses (l1 @ l2) -let rec try_many_gadt f = function - | [] -> Rnone +let rec try_many f = function + | [] -> No_matching_value | (p,pss)::rest -> - rappend (f (p, pss)) (try_many_gadt f rest) + rappend (f (p, pss)) (try_many f rest) -(* -let rec exhaust ext pss n = match pss with -| [] -> Rsome (omegas n) -| []::_ -> Rnone -| pss -> - let q0 = discr_pat omega pss in - begin match filter_all q0 pss with - (* first column of pss is made of variables only *) - | [] -> - begin match exhaust ext (filter_extra pss) (n-1) with - | Rsome r -> Rsome (q0::r) - | r -> r - end - | constrs -> - let try_non_omega (p,pss) = - if is_absent_pat p then - Rnone - else - match - exhaust - ext pss (List.length (simple_match_args p omega) + n - 1) - with - | Rsome r -> Rsome (set_args p r) - | r -> r in - if - full_match true false constrs && not (should_extend ext constrs) - then - try_many try_non_omega constrs - else - (* - D = filter_extra pss is the default matrix - as it is included in pss, one can avoid - recursive calls on specialized matrices, - Essentially : - * D exhaustive => pss exhaustive - * D non-exhaustive => we have a non-filtered value - *) - let r = exhaust ext (filter_extra pss) (n-1) in - match r with - | Rnone -> Rnone - | Rsome r -> - try - Rsome (build_other ext constrs::r) - with - (* cannot occur, since constructors don't make a full signature *) - | Empty -> fatal_error "Parmatch.exhaust" - end - -let combinations f lst lst' = - let rec iter2 x = - function - [] -> [] - | y :: ys -> - f x y :: iter2 x ys - in - let rec iter = - function - [] -> [] - | x :: xs -> iter2 x lst' @ iter xs - in - iter lst -*) (* let print_pat pat = let rec string_of_pat pat = @@ -1403,16 +1318,21 @@ let print_pat pat = Printf.fprintf stderr "PAT[%s]\n%!" (string_of_pat pat) *) -(* strictly more powerful than exhaust; however, exhaust - was kept for backwards compatibility *) -let rec exhaust_gadt (ext:Path.t option) pss n = match pss with -| [] -> Rsome [omegas n] -| []::_ -> Rnone +(* + Now another satisfiable function that additionally + supplies an example of a matching value. + + This function should be called for exhaustiveness check only. +*) +let rec exhaust (ext:Path.t option) pss n = match pss with +| [] -> Witnesses [omegas n] +| []::_ -> No_matching_value | pss -> - if not (all_coherent (simplified_first_col pss)) then + let pss = simplify_first_col pss in + if not (all_coherent (first_column pss)) then (* We're considering an ill-typed branch, we won't actually be able to produce a well typed value taking that branch. *) - Rnone + No_matching_value else begin (* Assuming the first column is ill-typed but considered coherent, we might end up producing an ill-typed witness of non-exhaustivity @@ -1425,60 +1345,50 @@ let rec exhaust_gadt (ext:Path.t option) pss n = match pss with we might fail to warn the user that the matching is fragile. See for example testsuite/tests/warnings/w04_failure.ml. *) let q0 = discr_pat omega pss in - match filter_all q0 pss with - (* first column of pss is made of variables only *) - | [] -> - begin match exhaust_gadt ext (filter_extra pss) (n-1) with - | Rsome r -> Rsome (List.map (fun row -> q0::row) r) + match build_specialized_submatrices ~extend_row:(@) q0 pss with + | { default; constrs = [] } -> + (* first column of pss is made of variables only *) + begin match exhaust ext default (n-1) with + | Witnesses r -> Witnesses (List.map (fun row -> q0::row) r) | r -> r end - | constrs -> + | { default; constrs } -> let try_non_omega (p,pss) = if is_absent_pat p then - Rnone + No_matching_value else match - exhaust_gadt + exhaust ext pss (List.length (simple_match_args p omega) + n - 1) with - | Rsome r -> Rsome (List.map (fun row -> (set_args p row)) r) + | Witnesses r -> Witnesses (List.map (fun row -> (set_args p row)) r) | r -> r in - let before = try_many_gadt try_non_omega constrs in + let before = try_many try_non_omega constrs in if full_match false constrs && not (should_extend ext constrs) then before else - (* - D = filter_extra pss is the default matrix - as it is included in pss, one can avoid - recursive calls on specialized matrices, - Essentially : - * D exhaustive => pss exhaustive - * D non-exhaustive => we have a non-filtered value - *) - let r = exhaust_gadt ext (filter_extra pss) (n-1) in + let r = exhaust ext default (n-1) in match r with - | Rnone -> before - | Rsome r -> + | No_matching_value -> before + | Witnesses r -> try let p = build_other ext constrs in let dug = List.map (fun tail -> p :: tail) r in match before with - | Rnone -> Rsome dug - | Rsome x -> Rsome (x @ dug) + | No_matching_value -> Witnesses dug + | Witnesses x -> Witnesses (x @ dug) with (* cannot occur, since constructors don't make a full signature *) | Empty -> fatal_error "Parmatch.exhaust" - end + end -let exhaust_gadt ext pss n = - let ret = exhaust_gadt ext pss n in +let exhaust ext pss n = + let ret = exhaust ext pss n in match ret with - Rnone -> Rnone - | Rsome lst -> - (* The following line is needed to compile stdlib/printf.ml *) - if lst = [] then Rsome (omegas n) else + No_matching_value -> No_matching_value + | Witnesses lst -> let singletons = List.map (function @@ -1486,7 +1396,7 @@ let exhaust_gadt ext pss n = | _ -> assert false) lst in - Rsome [orify_many singletons] + Witnesses [orify_many singletons] (* Another exhaustiveness check, enforcing variant typing. @@ -1504,34 +1414,46 @@ let rec pressure_variants tdefs = function | [] -> false | []::_ -> true | pss -> - if not (all_coherent (simplified_first_col pss)) then + let pss = simplify_first_col pss in + if not (all_coherent (first_column pss)) then true else begin let q0 = discr_pat omega pss in - match filter_all q0 pss with - [] -> pressure_variants tdefs (filter_extra pss) - | constrs -> + match build_specialized_submatrices ~extend_row:(@) q0 pss with + | { default; constrs = [] } -> pressure_variants tdefs default + | { default; constrs } -> let rec try_non_omega = function - (_p,pss) :: rem -> + | (_p,pss) :: rem -> let ok = pressure_variants tdefs pss in + (* The order below matters : we want [pressure_variants] to be + called on all the specialized submatrices because we might + close some variant in any of them regardless of whether [ok] + is true for [pss] or not *) try_non_omega rem && ok | [] -> true in if full_match (tdefs=None) constrs then try_non_omega constrs else if tdefs = None then - pressure_variants None (filter_extra pss) + pressure_variants None default else let full = full_match true constrs in let ok = - if full then try_non_omega constrs - else try_non_omega (filter_all q0 (mark_partial pss)) + if full then + try_non_omega constrs + else begin + let { constrs = partial_constrs; _ } = + build_specialized_submatrices ~extend_row:(@) q0 + (mark_partial pss) + in + try_non_omega partial_constrs + end in begin match constrs, tdefs with ({pat_desc=Tpat_variant _} as p,_):: _, Some env -> let row = row_of_pat p in if Btype.row_fixed row - || pressure_variants None (filter_extra pss) then () + || pressure_variants None default then () else close_variant env row | _ -> () end; @@ -1558,8 +1480,8 @@ type answer = - left -> elements not to be processed, - right -> elements to be processed *) -type 'a row = {no_ors : 'a list ; ors : 'a list ; active : 'a list} - +type usefulness_row = + {no_ors : pattern list ; ors : pattern list ; active : pattern list} (* let pretty_row {ors=ors ; no_ors=no_ors; active=active} = @@ -1625,33 +1547,16 @@ let push_or r = match r.active with let push_or_column rs = List.map push_or rs and push_no_or_column rs = List.map push_no_or rs -(* Those are adaptations of the previous homonymous functions that - work on the current column, instead of the first column -*) - -let discr_pat q rs = - discr_pat q (List.map (fun r -> r.active) rs) - -let filter_one q rs = - let rec filter_rec rs = match rs with +let rec simplify_first_usefulness_col = function | [] -> [] - | r::rem -> - match r.active with - | [] -> assert false - | {pat_desc = Tpat_alias(p,_,_)}::ps -> - filter_rec ({r with active = p::ps}::rem) - | {pat_desc = Tpat_or(p1,p2,_)}::ps -> - filter_rec - ({r with active = p1::ps}:: - {r with active = p2::ps}:: - rem) - | p::ps -> - if simple_match q p then - {r with active=simple_match_args q p @ ps} :: filter_rec rem - else - filter_rec rem in - filter_rec rs - + | row :: rows -> + match row.active with + | [] -> assert false (* the rows are non-empty! *) + | p :: ps -> + let add_column p ps k = + (p, { row with active = ps }) :: k in + simplify_head_pat ~add_column p ps + (simplify_first_usefulness_col rows) (* Back to normal matrices *) let make_vector r = List.rev r.no_ors @@ -1697,12 +1602,6 @@ let extract_columns pss qs = match pss with The idea is to first look for or patterns (recursive case), then check or-patterns argument usefulness (terminal case) *) -let rec simplified_first_usefulness_col = function - | [] -> [] - | row :: rows -> - match row.active with - | [] -> assert false (* the rows are non-empty! *) - | p :: _ -> simplify_head_pat p (simplified_first_usefulness_col rows) let rec every_satisfiables pss qs = match qs.active with | [] -> @@ -1751,14 +1650,16 @@ let rec every_satisfiables pss qs = match qs.active with Unused | _ -> (* standard case, filter matrix *) - (* The handling of incoherent matrices is kept in line with + let pss = simplify_first_usefulness_col pss in + (* The handling of incoherent matrices is kept in line with [satisfiable] *) - if not (all_coherent (uq :: simplified_first_usefulness_col pss)) then + if not (all_coherent (uq :: first_column pss)) then Unused else begin let q0 = discr_pat q pss in every_satisfiables - (filter_one q0 pss) + (build_specialized_submatrix q0 pss + ~extend_row:(fun ps r -> { r with active = ps @ r.active })) {qs with active=simple_match_args q0 q @ rem} end end @@ -1929,75 +1830,18 @@ let rec initial_matrix = function | {c_guard=Some _} :: rem -> initial_matrix rem | {c_guard=None; c_lhs=p} :: rem -> [p] :: initial_matrix rem -(******************************************) -(* Look for a row that matches some value *) -(******************************************) - (* - Useful for seeing if the example of - non-matched value can indeed be matched - (by a guarded clause) + Build up a working pattern matrix by keeping + only the patterns which are guarded *) +let rec initial_only_guarded = function + | [] -> [] + | { c_guard = None; _} :: rem -> + initial_only_guarded rem + | { c_lhs = pat; _ } :: rem -> + [pat] :: initial_only_guarded rem - -exception NoGuard - -let rec initial_all no_guard = function - | [] -> - if no_guard then - raise NoGuard - else - [] - | {c_lhs=pat; c_guard; _} :: rem -> - ([pat], pat.pat_loc) :: initial_all (no_guard && c_guard = None) rem - - -let rec do_filter_var = function - | (_::ps,loc)::rem -> (ps,loc)::do_filter_var rem - | _ -> [] - -let do_filter_one q pss = - let rec filter_rec = function - | ({pat_desc = Tpat_alias(p,_,_)}::ps,loc)::pss -> - filter_rec ((p::ps,loc)::pss) - | ({pat_desc = Tpat_or(p1,p2,_)}::ps,loc)::pss -> - filter_rec ((p1::ps,loc)::(p2::ps,loc)::pss) - | (p::ps,loc)::pss -> - if simple_match q p - then (simple_match_args q p @ ps, loc) :: filter_rec pss - else filter_rec pss - | _ -> [] in - filter_rec pss - -let rec do_match pss qs = match qs with -| [] -> - begin match pss with - | ([],loc)::_ -> Some loc - | _ -> None - end -| q::qs -> match q with - | {pat_desc = Tpat_or (q1,q2,_)} -> - begin match do_match pss (q1::qs) with - | None -> do_match pss (q2::qs) - | r -> r - end - | {pat_desc = Tpat_any} -> - do_match (do_filter_var pss) qs - | _ -> - let q0 = normalize_pat q in - (* [pss] will (or won't) match [q0 :: qs] regardless of the coherence of - its first column. *) - do_match (do_filter_one q0 pss) (simple_match_args q0 q @ qs) - - -let check_partial_all v casel = - try - let pss = initial_all true casel in - do_match pss [v] - with - | NoGuard -> None - (************************) (* Exhaustiveness check *) (************************) @@ -2076,12 +1920,13 @@ let contains_extension pat = (* Build an untyped or-pattern from its expected type *) let ppat_of_type env ty = match pats_of_type env ty with - [{pat_desc = Tpat_any}] -> + | [] -> raise Empty + | [{pat_desc = Tpat_any}] -> (Conv.mkpat Parsetree.Ppat_any, Hashtbl.create 0, Hashtbl.create 0) | pats -> Conv.conv (orify_many pats) -let do_check_partial ?pred exhaust loc casel pss = match pss with +let do_check_partial ~pred loc casel pss = match pss with | [] -> (* This can occur @@ -2100,20 +1945,17 @@ let do_check_partial ?pred exhaust loc casel pss = match pss with Partial | ps::_ -> begin match exhaust None pss (List.length ps) with - | Rnone -> Total - | Rsome [u] -> + | No_matching_value -> Total + | Witnesses [u] -> let v = - match pred with - | Some pred -> - let (pattern,constrs,labels) = Conv.conv u in - let u' = pred constrs labels pattern in - (* pretty_pat u; - begin match u' with - None -> prerr_endline ": impossible" - | Some _ -> prerr_endline ": possible" - end; *) - u' - | None -> Some u + let (pattern,constrs,labels) = Conv.conv u in + let u' = pred constrs labels pattern in + (* pretty_pat u; + begin match u' with + None -> prerr_endline ": impossible" + | Some _ -> prerr_endline ": possible" + end; *) + u' in begin match v with None -> Total @@ -2122,18 +1964,11 @@ let do_check_partial ?pred exhaust loc casel pss = match pss with let errmsg = try let buf = Buffer.create 16 in - let fmt = formatter_of_buffer buf in - top_pretty fmt v; - begin match check_partial_all v casel with - | None -> () - | Some _ -> - (* This is 'Some loc', where loc is the location of - a possibly matching clause. - Forget about loc, because printing two locations - is a pain in the top-level *) - Buffer.add_string buf - "\n(However, some guarded clause may match this value.)" - end; + let fmt = Format.formatter_of_buffer buf in + Printpat.top_pretty fmt v; + if do_match (initial_only_guarded casel) [v] then + Buffer.add_string buf + "\n(However, some guarded clause may match this value.)"; if contains_extension v then Buffer.add_string buf "\nMatching over values of extensible variant types \ @@ -2152,16 +1987,6 @@ let do_check_partial ?pred exhaust loc casel pss = match pss with fatal_error "Parmatch.check_partial" end -(* -let do_check_partial_normal loc casel pss = - do_check_partial exhaust loc casel pss - *) - -let do_check_partial_gadt pred loc casel pss = - do_check_partial ~pred exhaust_gadt loc casel pss - - - (*****************) (* Fragile check *) (*****************) @@ -2184,7 +2009,7 @@ let extendable_path path = let rec collect_paths_from_pat r p = match p.pat_desc with | Tpat_construct(_, {cstr_tag=(Cstr_constant _|Cstr_block _|Cstr_unboxed)},ps) -> - let path = get_type_path p.pat_type p.pat_env in + let path = get_constructor_type_path p.pat_type p.pat_env in List.fold_left collect_paths_from_pat (if extendable_path path then add_path path r else r) @@ -2212,7 +2037,7 @@ let rec collect_paths_from_pat r p = match p.pat_desc with the type is extended. *) -let do_check_fragile_param exhaust loc casel pss = +let do_check_fragile loc casel pss = let exts = List.fold_left (fun r c -> collect_paths_from_pat r c.c_lhs) @@ -2225,16 +2050,13 @@ let do_check_fragile_param exhaust loc casel pss = List.iter (fun ext -> match exhaust (Some ext) pss (List.length ps) with - | Rnone -> + | No_matching_value -> Location.prerr_warning loc (Warnings.Fragile_match (Path.name ext)) - | Rsome _ -> ()) + | Witnesses _ -> ()) exts -(*let do_check_fragile_normal = do_check_fragile_param exhaust*) -let do_check_fragile_gadt = do_check_fragile_param exhaust_gadt - (********************************) (* Exported unused clause check *) (********************************) @@ -2255,13 +2077,22 @@ let check_unused pred casel = (* Do not warn for unused [pat -> .] *) if r = Unused && refute then () else let r = - (* Do not refine if there are no other lines *) + (* Do not refine if either: + - we already know the clause is unused + - the clause under consideration is not a refutation clause + and either: + + there are no other lines + + we do not care whether the types prevent this clause to be + reached. + If the clause under consideration *is* a refutation clause + then we do need to check more carefully whether it can be + refuted or not. *) let skip = r = Unused || (not refute && pref = []) || not(refute || Warnings.is_active Warnings.Unreachable_case) in if skip then r else (* Then look for empty patterns *) - let sfs = satisfiables pss qs in + let sfs = list_satisfying_vectors pss qs in if sfs = [] then Unused else let sfs = List.map (function [u] -> u | _ -> assert false) sfs in @@ -2286,7 +2117,7 @@ let check_unused pred casel = p.pat_loc Warnings.Unused_pat) ps | Used -> () - with Empty | Not_found | NoGuard -> assert false + with Empty | Not_found -> assert false end ; if c_guard <> None then @@ -2347,26 +2178,16 @@ let inactive ~partial pat = on exhaustive matches only. *) -let check_partial_param do_check_partial do_check_fragile loc casel = - let pss = initial_matrix casel in - let pss = get_mins le_pats pss in - let total = do_check_partial loc casel pss in - if - total = Total && Warnings.is_active (Warnings.Fragile_match "") - then begin - do_check_fragile loc casel pss - end ; - total - -(*let check_partial = - check_partial_param - do_check_partial_normal - do_check_fragile_normal*) - -let check_partial_gadt pred loc casel = - check_partial_param (do_check_partial_gadt pred) - do_check_fragile_gadt loc casel - +let check_partial pred loc casel = + let pss = initial_matrix casel in + let pss = get_mins le_pats pss in + let total = do_check_partial ~pred loc casel pss in + if + total = Total && Warnings.is_active (Warnings.Fragile_match "") + then begin + do_check_fragile loc casel pss + end ; + total (*************************************) (* Ambiguous variable in or-patterns *) @@ -2414,157 +2235,170 @@ let check_partial_gadt pred loc casel = to a specific guard. *) -module IdSet = Set.Make(Ident) - -let pattern_vars p = IdSet.of_list (Typedtree.pat_bound_idents p) +let pattern_vars p = Ident.Set.of_list (Typedtree.pat_bound_idents p) (* Row for ambiguous variable search, - unseen is the traditional pattern row, - seen is a list of position bindings *) - -type amb_row = { unseen : pattern list ; seen : IdSet.t list; } - - -(* Push binding variables now *) - -let rec do_push r p ps seen k = match p.pat_desc with -| Tpat_alias (p,x,_) -> do_push (IdSet.add x r) p ps seen k -| Tpat_var (x,_) -> - (omega,{ unseen = ps; seen=IdSet.add x r::seen; })::k -| Tpat_or (p1,p2,_) -> - do_push r p1 ps seen (do_push r p2 ps seen k) -| _ -> - (p,{ unseen = ps; seen = r::seen; })::k - -let rec push_vars = function - | [] -> [] - | { unseen = [] }::_ -> assert false - | { unseen = p::ps; seen; }::rem -> - do_push IdSet.empty p ps seen (push_vars rem) - -let collect_stable = function - | [] -> assert false - | { seen=xss; _}::rem -> - let rec c_rec xss = function - | [] -> xss - | {seen=yss; _}::rem -> - let xss = List.map2 IdSet.inter xss yss in - c_rec xss rem in - let inters = c_rec xss rem in - List.fold_left IdSet.union IdSet.empty inters - - -(*********************************************) -(* Filtering utilities for our specific rows *) -(*********************************************) - -(* Take a pattern matrix as a list (rows) of lists (columns) of patterns - | p1, p2, .., pn - | q1, q2, .., qn - | r1, r2, .., rn - | ... - - We split this matrix into a list of sub-matrices, one for each head - constructor appearing in the leftmost column. For each row whose - left column starts with a head constructor, remove this head - column, prepend one column for each argument of the constructor, - and add the resulting row in the sub-matrix corresponding to this - head constructor. - - Rows whose left column is omega (the Any pattern _) may match any - head constructor, so they are added to all groups. - - The list of sub-matrices is represented as a list of pair - (head constructor, submatrix) + row is the traditional pattern row, + varsets contain a list of head variable sets (varsets) + + A given varset contains all the variables that appeared at the head + of a pattern in the row at some point during traversal: they would + all be bound to the same value at matching time. On the contrary, + two variables of different varsets appeared at different places in + the pattern and may be bound to distinct sub-parts of the matched + value. + + All rows of a (sub)matrix have rows of the same length, + but also varsets of the same length. + + Varsets are populated when simplifying the first column + -- the variables of the head pattern are collected in a new varset. + For example, + { row = x :: r1; varsets = s1 } + { row = (Some _) as y :: r2; varsets = s2 } + { row = (None as x) as y :: r3; varsets = s3 } + { row = (Some x | (None as x)) :: r4 with varsets = s4 } + becomes + (_, { row = r1; varsets = {x} :: s1 }) + (Some _, { row = r2; varsets = {y} :: s2 }) + (None, { row = r3; varsets = {x, y} :: s3 }) + (Some x, { row = r4; varsets = {} :: s4 }) + (None, { row = r4; varsets = {x} :: s4 }) *) +type amb_row = { row : pattern list ; varsets : Ident.Set.t list; } -let filter_all = - (* the head constructor (as a pattern with omega arguments) of - a pattern *) - let discr_head pat = - match pat.pat_desc with - | Tpat_record (lbls, closed) -> - (* a partial record pattern { f1 = p1; f2 = p2; _ } - needs to be expanded, otherwise matching against this head - would drop the pattern arguments for non-mentioned fields *) - let lbls = all_record_args lbls in - normalize_pat { pat with pat_desc = Tpat_record (lbls, closed) } - | _ -> normalize_pat pat - in - - (* insert a row of head [p] and rest [r] into the right group *) - let rec insert p r env = match env with - | [] -> - (* if no group matched this row, it has a head constructor that - was never seen before; add a new sub-matrix for this head *) - let p0 = discr_head p in - [p0,[{ r with unseen = simple_match_args p0 p @ r.unseen }]] - | (q0,rs) as bd::env -> - if simple_match q0 p then begin - let r = { r with unseen = simple_match_args q0 p@r.unseen; } in - (q0,r::rs)::env - end - else bd::insert p r env in - - (* insert a row of head omega into all groups *) - let insert_omega r env = - List.map - (fun (q0,rs) -> - let r = - { r with unseen = simple_match_args q0 omega @ r.unseen; } in - (q0,r::rs)) - env - in - - let rec filter_rec env = function - | [] -> env - | ({pat_desc=(Tpat_var _|Tpat_alias _|Tpat_or _)},_)::_ -> assert false - | ({pat_desc=Tpat_any}, _)::rs -> filter_rec env rs - | (p,r)::rs -> filter_rec (insert p r env) rs in +let simplify_head_amb_pat head_bound_variables varsets ~add_column p ps k = + let rec simpl head_bound_variables varsets p ps k = + match p.pat_desc with + | Tpat_alias (p,x,_) -> + simpl (Ident.Set.add x head_bound_variables) varsets p ps k + | Tpat_var (x,_) -> + let rest_of_the_row = + { row = ps; varsets = Ident.Set.add x head_bound_variables :: varsets; } + in + add_column omega rest_of_the_row k + | Tpat_or (p1,p2,_) -> + simpl head_bound_variables varsets p1 ps + (simpl head_bound_variables varsets p2 ps k) + | _ -> + add_column p { row = ps; varsets = head_bound_variables :: varsets; } k + in simpl head_bound_variables varsets p ps k - let rec filter_omega env = function - | [] -> env - | ({pat_desc=(Tpat_var _|Tpat_alias _|Tpat_or _)},_)::_ -> assert false - | ({pat_desc=Tpat_any},r)::rs -> filter_omega (insert_omega r env) rs - | _::rs -> filter_omega env rs in +(* + To accurately report ambiguous variables, one must consider + that previous clauses have already matched some values. + Consider for example: + + | (Foo x, Foo y) -> ... + | ((Foo x, _) | (_, Foo x)) when bar x -> ... + + The second line taken in isolation uses an unstable variable, + but the discriminating values, of the shape [(Foo v1, Foo v2)], + would all be filtered by the line above. + + To track this information, the matrices we analyze contain both + *positive* rows, that describe the rows currently being analyzed + (of type Varsets.row, so that their varsets are tracked) and + *negative rows*, that describe the cases already matched against. + + The values matched by a signed matrix are the values matched by + some of the positive rows but none of the negative rows. In + particular, a variable is stable if, for any value not matched by + any of the negative rows, the environment captured by any of the + matching positive rows is identical. +*) +type ('a, 'b) signed = Positive of 'a | Negative of 'b - fun rs -> - (* first insert the rows with head constructors, - to get the definitive list of groups *) - let env = filter_rec [] rs in - (* then add the omega rows to all groups *) - filter_omega env rs +let rec simplify_first_amb_col = function + | [] -> [] + | (Negative [] | Positive { row = []; _ }) :: _ -> assert false + | Negative (n :: ns) :: rem -> + let add_column n ns k = (n, Negative ns) :: k in + simplify_head_pat + ~add_column n ns (simplify_first_amb_col rem) + | Positive { row = p::ps; varsets; }::rem -> + let add_column p ps k = (p, Positive ps) :: k in + simplify_head_amb_pat + Ident.Set.empty varsets + ~add_column p ps (simplify_first_amb_col rem) (* Compute stable bindings *) -let rec do_stable rs = match rs with -| [] -> assert false (* No empty matrix *) -| { unseen=[]; _ }::_ -> - collect_stable rs -| _ -> - let rs = push_vars rs in - if not (all_coherent (first_column rs)) then begin - (* If the first column is incoherent, then all the variables of this - matrix are stable. *) - List.fold_left (fun acc (_, { seen; _ }) -> - List.fold_left IdSet.union acc seen - ) IdSet.empty rs - end else begin - (* If the column is ill-typed but deemed coherent, we might spuriously - warn about some variables being unstable. - As sad as that might be, the warning can be silenced by splitting the - or-pattern... *) - match filter_all rs with - | [] -> - do_stable (List.map snd rs) - | (_,rs)::env -> - List.fold_left - (fun xs (_,rs) -> IdSet.inter xs (do_stable rs)) - (do_stable rs) env - end - -let stable p = do_stable [{unseen=[p]; seen=[];}] +type stable_vars = + | All + | Vars of Ident.Set.t + +let stable_inter sv1 sv2 = match sv1, sv2 with + | All, sv | sv, All -> sv + | Vars s1, Vars s2 -> Vars (Ident.Set.inter s1 s2) + +let reduce f = function +| [] -> invalid_arg "reduce" +| x::xs -> List.fold_left f x xs + +let rec matrix_stable_vars m = match m with + | [] -> All + | ((Positive {row = []; _} | Negative []) :: _) as empty_rows -> + let exception Negative_empty_row in + (* if at least one empty row is negative, the matrix matches no value *) + let get_varsets = function + | Negative n -> + (* All rows have the same number of columns; + if the first row is empty, they all are. *) + assert (n = []); + raise Negative_empty_row + | Positive p -> + assert (p.row = []); + p.varsets in + begin match List.map get_varsets empty_rows with + | exception Negative_empty_row -> All + | rows_varsets -> + let stables_in_varsets = + reduce (List.map2 Ident.Set.inter) rows_varsets in + (* The stable variables are those stable at any position *) + Vars + (List.fold_left Ident.Set.union Ident.Set.empty stables_in_varsets) + end + | m -> + let is_negative = function + | Negative _ -> true + | Positive _ -> false in + if List.for_all is_negative m then + (* optimization: quit early if there are no positive rows. + This may happen often when the initial matrix has many + negative cases and few positive cases (a small guarded + clause after a long list of clauses) *) + All + else begin + let m = simplify_first_amb_col m in + if not (all_coherent (first_column m)) then + All + else begin + (* If the column is ill-typed but deemed coherent, we might + spuriously warn about some variables being unstable. + As sad as that might be, the warning can be silenced by + splitting the or-pattern... *) + let submatrices = + let extend_row columns = function + | Negative r -> Negative (columns @ r) + | Positive r -> Positive { r with row = columns @ r.row } in + let q0 = discr_pat omega m in + let { default; constrs } = + build_specialized_submatrices ~extend_row q0 m in + let non_default = List.map snd constrs in + if full_match false constrs + then non_default + else default :: non_default in + (* A stable variable must be stable in each submatrix. *) + let submat_stable = List.map matrix_stable_vars submatrices in + List.fold_left stable_inter All submat_stable + end + end +let pattern_stable_vars ns p = + matrix_stable_vars + (List.fold_left (fun m n -> Negative n :: m) + [Positive {varsets = []; row = [p]}] ns) (* All identifier paths that appear in an expression that occurs as a clause right hand side or guard. @@ -2585,13 +2419,13 @@ let stable p = do_stable [{unseen=[p]; seen=[];}] *) let all_rhs_idents exp = - let ids = ref IdSet.empty in + let ids = ref Ident.Set.empty in let module Iterator = TypedtreeIter.MakeIterator(struct include TypedtreeIter.DefaultIteratorArgument let enter_expression exp = match exp.exp_desc with | Texp_ident (path, _lid, _descr) -> List.iter - (fun id -> ids := IdSet.add id !ids) + (fun id -> ids := Ident.Set.add id !ids) (Path.heads path) | _ -> () @@ -2608,9 +2442,9 @@ let all_rhs_idents exp = {mod_desc= Tmod_unpack ({exp_desc=Texp_ident (Path.Pident id_exp,_,_)},_)}, _) -> - assert (IdSet.mem id_exp !ids) ; - if not (IdSet.mem id_mod !ids) then begin - ids := IdSet.remove id_exp !ids + assert (Ident.Set.mem id_exp !ids) ; + if not (Ident.Set.mem id_mod !ids) then begin + ids := Ident.Set.remove id_exp !ids end | _ -> assert false end @@ -2623,19 +2457,23 @@ let check_ambiguous_bindings = let warn0 = Ambiguous_pattern [] in fun cases -> if is_active warn0 then - List.iter - (fun case -> match case with - | { c_guard=None ; _} -> () + let check_case ns case = match case with + | { c_lhs = p; c_guard=None ; _} -> [p]::ns | { c_lhs=p; c_guard=Some g; _} -> let all = - IdSet.inter (pattern_vars p) (all_rhs_idents g) in - if not (IdSet.is_empty all) then begin - let st = stable p in - let ambiguous = IdSet.diff all st in - if not (IdSet.is_empty ambiguous) then begin - let pps = IdSet.elements ambiguous |> List.map Ident.name in - let warn = Ambiguous_pattern pps in - Location.prerr_warning p.pat_loc warn - end - end) - cases + Ident.Set.inter (pattern_vars p) (all_rhs_idents g) in + if not (Ident.Set.is_empty all) then begin + match pattern_stable_vars ns p with + | All -> () + | Vars stable -> + let ambiguous = Ident.Set.diff all stable in + if not (Ident.Set.is_empty ambiguous) then begin + let pps = + Ident.Set.elements ambiguous |> List.map Ident.name in + let warn = Ambiguous_pattern pps in + Location.prerr_warning p.pat_loc warn + end + end; + ns + in + ignore (List.fold_left check_case [] cases) diff --git a/typing/parmatch.mli b/typing/parmatch.mli index feecb0c5..4426795c 100644 --- a/typing/parmatch.mli +++ b/typing/parmatch.mli @@ -13,30 +13,39 @@ (* *) (**************************************************************************) -(* Detection of partial matches and unused match cases. *) +(** Detection of partial matches and unused match cases. *) + open Asttypes open Typedtree open Types -val pretty_const : constant -> string -val top_pretty : Format.formatter -> pattern -> unit -val pretty_pat : pattern -> unit -val pretty_line : pattern list -> unit -val pretty_matrix : pattern list list -> unit - val omega : pattern +(** aka. "Tpat_any" or "_" *) + val omegas : int -> pattern list +(** [List.init (fun _ -> omega)] *) + val omega_list : 'a list -> pattern list +(** [List.map (fun _ -> omega)] *) + val normalize_pat : pattern -> pattern -val all_record_args : - (Longident.t loc * label_description * pattern) list -> - (Longident.t loc * label_description * pattern) list +(** Keep only the "head" of a pattern: all arguments are replaced by [omega], so + are variables. *) + val const_compare : constant -> constant -> int +(** [const_compare c1 c2] compares the actual values represented by [c1] and + [c2], while simply using [Pervasives.compare] would compare the + representations. + + cf. MPR#5758 *) val le_pat : pattern -> pattern -> bool +(** [le_pat p q] means: forall V, V matches q implies V matches p *) + val le_pats : pattern list -> pattern list -> bool +(** [le_pats (p1 .. pm) (q1 .. qn)] means: forall i <= m, [le_pat pi qi] *) -(* Exported compatibility functor, abstracted over constructor equality *) +(** Exported compatibility functor, abstracted over constructor equality *) module Compat : functor (Constr: sig @@ -50,15 +59,21 @@ module Compat : end exception Empty + val lub : pattern -> pattern -> pattern +(** [lub p q] is a pattern that matches all values matched by [p] and [q]. + May raise [Empty], when [p] and [q] are not compatible. *) + val lubs : pattern list -> pattern list -> pattern list +(** [lubs [p1; ...; pn] [q1; ...; qk]], where [n < k], is + [[lub p1 q1; ...; lub pk qk]]. *) val get_mins : ('a -> 'a -> bool) -> 'a list -> 'a list -(* Those two functions recombine one pattern and its arguments: - For instance: - (_,_)::p1::p2::rem -> (p1, p2)::rem - The second one will replace mutable arguments by '_' +(** Those two functions recombine one pattern and its arguments: + For instance: + (_,_)::p1::p2::rem -> (p1, p2)::rem + The second one will replace mutable arguments by '_' *) val set_args : pattern -> pattern list -> pattern list val set_args_erase_mutable : pattern -> pattern list -> pattern list @@ -66,6 +81,9 @@ val set_args_erase_mutable : pattern -> pattern list -> pattern list val pat_of_constr : pattern -> constructor_description -> pattern val complete_constrs : pattern -> constructor_tag list -> constructor_description list + +(** [ppat_of_type] builds an untyped or-pattern from its expected type. + May raise [Empty] when [type_expr] is an empty variant *) val ppat_of_type : Env.t -> type_expr -> Parsetree.pattern * @@ -73,7 +91,7 @@ val ppat_of_type : (string, label_description) Hashtbl.t val pressure_variants: Env.t -> pattern list -> unit -val check_partial_gadt: +val check_partial: ((string, constructor_description) Hashtbl.t -> (string, label_description) Hashtbl.t -> Parsetree.pattern -> pattern option) -> @@ -96,5 +114,5 @@ val inactive : partial:partial -> pattern -> bool (* Ambiguous bindings *) val check_ambiguous_bindings : case list -> unit -(* The tag used for open polymorphic variant types *) -val some_other_tag : label +(* The tag used for open polymorphic variant types with an abstract row *) +val some_private_tag : label diff --git a/typing/predef.ml b/typing/predef.ml index e00df7fe..2989d426 100644 --- a/typing/predef.ml +++ b/typing/predef.ml @@ -125,7 +125,8 @@ let decl_abstr = type_private = Asttypes.Public; type_manifest = None; type_variance = []; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_attributes = []; type_immediate = false; type_unboxed = unboxed_false_default_false; @@ -243,12 +244,7 @@ let build_initial_env add_type add_exception empty_env = (safe_string, unsafe_string) let builtin_values = - List.map (fun id -> Ident.make_global id; (Ident.name id, id)) - [ident_match_failure; ident_out_of_memory; ident_stack_overflow; - ident_invalid_argument; - ident_failure; ident_not_found; ident_sys_error; ident_end_of_file; - ident_division_by_zero; ident_sys_blocked_io; - ident_assert_failure; ident_undefined_recursive_module ] + List.map (fun id -> (Ident.name id, id)) all_predef_exns (* Start non-predef identifiers at 1000. This way, more predefs can be defined in this file (above!) without breaking .cmi diff --git a/typing/printpat.ml b/typing/printpat.ml new file mode 100644 index 00000000..e19b55ba --- /dev/null +++ b/typing/printpat.ml @@ -0,0 +1,156 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +(* Values as patterns pretty printer *) + +open Asttypes +open Typedtree +open Types +open Format + +let is_cons = function +| {cstr_name = "::"} -> true +| _ -> false + +let pretty_const c = match c with +| Const_int i -> Printf.sprintf "%d" i +| Const_char c -> Printf.sprintf "%C" c +| Const_string (s, _) -> Printf.sprintf "%S" s +| Const_float f -> Printf.sprintf "%s" f +| Const_int32 i -> Printf.sprintf "%ldl" i +| Const_int64 i -> Printf.sprintf "%LdL" i +| Const_nativeint i -> Printf.sprintf "%ndn" i + +let rec pretty_val ppf v = + match v.pat_extra with + (cstr, _loc, _attrs) :: rem -> + begin match cstr with + | Tpat_unpack -> + fprintf ppf "@[(module %a)@]" pretty_val { v with pat_extra = rem } + | Tpat_constraint _ -> + fprintf ppf "@[(%a : _)@]" pretty_val { v with pat_extra = rem } + | Tpat_type _ -> + fprintf ppf "@[(# %a)@]" pretty_val { v with pat_extra = rem } + | Tpat_open _ -> + fprintf ppf "@[(# %a)@]" pretty_val { v with pat_extra = rem } + end + | [] -> + match v.pat_desc with + | Tpat_any -> fprintf ppf "_" + | Tpat_var (x,_) -> fprintf ppf "%s" (Ident.name x) + | Tpat_constant c -> fprintf ppf "%s" (pretty_const c) + | Tpat_tuple vs -> + fprintf ppf "@[(%a)@]" (pretty_vals ",") vs + | Tpat_construct (_, cstr, []) -> + fprintf ppf "%s" cstr.cstr_name + | Tpat_construct (_, cstr, [w]) -> + fprintf ppf "@[<2>%s@ %a@]" cstr.cstr_name pretty_arg w + | Tpat_construct (_, cstr, vs) -> + let name = cstr.cstr_name in + begin match (name, vs) with + ("::", [v1;v2]) -> + fprintf ppf "@[%a::@,%a@]" pretty_car v1 pretty_cdr v2 + | _ -> + fprintf ppf "@[<2>%s@ @[(%a)@]@]" name (pretty_vals ",") vs + end + | Tpat_variant (l, None, _) -> + fprintf ppf "`%s" l + | Tpat_variant (l, Some w, _) -> + fprintf ppf "@[<2>`%s@ %a@]" l pretty_arg w + | Tpat_record (lvs,_) -> + let filtered_lvs = List.filter + (function + | (_,_,{pat_desc=Tpat_any}) -> false (* do not show lbl=_ *) + | _ -> true) lvs in + begin match filtered_lvs with + | [] -> fprintf ppf "_" + | (_, lbl, _) :: q -> + let elision_mark ppf = + (* we assume that there is no label repetitions here *) + if Array.length lbl.lbl_all > 1 + List.length q then + fprintf ppf ";@ _@ " + else () in + fprintf ppf "@[{%a%t}@]" + pretty_lvals filtered_lvs elision_mark + end + | Tpat_array vs -> + fprintf ppf "@[[| %a |]@]" (pretty_vals " ;") vs + | Tpat_lazy v -> + fprintf ppf "@[<2>lazy@ %a@]" pretty_arg v + | Tpat_alias (v, x,_) -> + fprintf ppf "@[(%a@ as %a)@]" pretty_val v Ident.print x + | Tpat_or (v,w,_) -> + fprintf ppf "@[(%a|@,%a)@]" pretty_or v pretty_or w + +and pretty_car ppf v = match v.pat_desc with +| Tpat_construct (_,cstr, [_ ; _]) + when is_cons cstr -> + fprintf ppf "(%a)" pretty_val v +| _ -> pretty_val ppf v + +and pretty_cdr ppf v = match v.pat_desc with +| Tpat_construct (_,cstr, [v1 ; v2]) + when is_cons cstr -> + fprintf ppf "%a::@,%a" pretty_car v1 pretty_cdr v2 +| _ -> pretty_val ppf v + +and pretty_arg ppf v = match v.pat_desc with +| Tpat_construct (_,_,_::_) +| Tpat_variant (_, Some _, _) -> fprintf ppf "(%a)" pretty_val v +| _ -> pretty_val ppf v + +and pretty_or ppf v = match v.pat_desc with +| Tpat_or (v,w,_) -> + fprintf ppf "%a|@,%a" pretty_or v pretty_or w +| _ -> pretty_val ppf v + +and pretty_vals sep ppf = function + | [] -> () + | [v] -> pretty_val ppf v + | v::vs -> + fprintf ppf "%a%s@ %a" pretty_val v sep (pretty_vals sep) vs + +and pretty_lvals ppf = function + | [] -> () + | [_,lbl,v] -> + fprintf ppf "%s=%a" lbl.lbl_name pretty_val v + | (_, lbl,v)::rest -> + fprintf ppf "%s=%a;@ %a" + lbl.lbl_name pretty_val v pretty_lvals rest + +let top_pretty ppf v = + fprintf ppf "@[%a@]@?" pretty_val v + + +let pretty_pat p = + top_pretty Format.str_formatter p ; + prerr_string (Format.flush_str_formatter ()) + +type matrix = pattern list list + +let pretty_line fmt = + List.iter (fun p -> + Format.fprintf fmt " <"; + top_pretty fmt p; + Format.fprintf fmt ">"; + ) + +let pretty_matrix fmt (pss : matrix) = + Format.fprintf fmt "begin matrix\n" ; + List.iter (fun ps -> + pretty_line fmt ps ; + Format.fprintf fmt "\n" + ) pss; + Format.fprintf fmt "end matrix\n%!" diff --git a/typing/printpat.mli b/typing/printpat.mli new file mode 100644 index 00000000..48292bf8 --- /dev/null +++ b/typing/printpat.mli @@ -0,0 +1,22 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* *) +(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* en Automatique. *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + + + +val pretty_const : Asttypes.constant -> string +val top_pretty : Format.formatter -> Typedtree.pattern -> unit +val pretty_pat : Typedtree.pattern -> unit +val pretty_line : Format.formatter -> Typedtree.pattern list -> unit +val pretty_matrix : Format.formatter -> Typedtree.pattern list list -> unit diff --git a/typing/printtyp.ml b/typing/printtyp.ml index cadf6117..f2e6f196 100644 --- a/typing/printtyp.ml +++ b/typing/printtyp.ml @@ -48,29 +48,101 @@ let ident ppf id = pp_print_string ppf (ident_name id) (* Print a path *) -let ident_pervasives = Ident.create_persistent "Pervasives" +let ident_stdlib = Ident.create_persistent "Stdlib" let printing_env = ref Env.empty let non_shadowed_pervasive = function - | Pdot(Pident id, s, _pos) as path -> - Ident.same id ident_pervasives && + | Pdot(Pident id, s, _) as path -> + Ident.same id ident_stdlib && (try Path.same path (Env.lookup_type (Lident s) !printing_env) with Not_found -> true) + | Pdot(Pdot (Pident id, "Pervasives", _), s, _) as path -> + Ident.same id ident_stdlib && + (* Make sure Stdlib. is the same as Stdlib.Pervasives. *) + (try + let td = + Env.find_type (Env.lookup_type (Lident s) !printing_env) + !printing_env + in + match td.type_private, td.type_manifest with + | Private, _ | _, None -> false + | Public, Some te -> + match (Btype.repr te).desc with + | Tconstr (path', _, _) -> Path.same path path' + | _ -> false + with Not_found -> true) | _ -> false +let find_double_underscore s = + let len = String.length s in + let rec loop i = + if i + 1 >= len then + None + else if s.[i] = '_' && s.[i + 1] = '_' then + Some i + else + loop (i + 1) + in + loop 0 + +let rec module_path_is_an_alias_of env path ~alias_of = + match Env.find_module path env with + | { md_type = Mty_alias (_, path'); _ } -> + Path.same path' alias_of || + module_path_is_an_alias_of env path' ~alias_of + | _ -> false + | exception Not_found -> false + +(* Simple heuristic to print Foo__bar.* as Foo.Bar.* when Foo.Bar is an alias + for Foo__bar. This pattern is used by the stdlib. *) +let rec rewrite_double_underscore_paths env p = + match p with + | Pdot (p, s, n) -> + Pdot (rewrite_double_underscore_paths env p, s, n) + | Papply (a, b) -> + Papply (rewrite_double_underscore_paths env a, + rewrite_double_underscore_paths env b) + | Pident id -> + let name = Ident.name id in + match find_double_underscore name with + | None -> p + | Some i -> + let better_lid = + Ldot + (Lident (String.sub name 0 i), + String.capitalize_ascii + (String.sub name (i + 2) (String.length name - i - 2))) + in + match Env.lookup_module ~load:true better_lid env with + | exception Not_found -> p + | p' -> + if module_path_is_an_alias_of env p' ~alias_of:p then + p' + else + p + +let rewrite_double_underscore_paths env p = + if env == Env.empty then + p + else + rewrite_double_underscore_paths env p + let rec tree_of_path = function | Pident id -> Oide_ident (ident_name id) - | Pdot(_, s, _pos) as path when non_shadowed_pervasive path -> + | Pdot(_, s, _pos) as path + when non_shadowed_pervasive path -> Oide_ident s | Pdot(p, s, _pos) -> Oide_dot (tree_of_path p, s) | Papply(p1, p2) -> - Oide_apply (tree_of_path p1, tree_of_path p2) + Oide_apply (tree_of_path p1, + tree_of_path p2) let rec path ppf = function | Pident id -> ident ppf id - | Pdot(_, s, _pos) as path when non_shadowed_pervasive path -> + | Pdot(_, s, _pos) as path + when non_shadowed_pervasive path -> pp_print_string ppf s | Pdot(p, s, _pos) -> path ppf p; @@ -79,6 +151,11 @@ let rec path ppf = function | Papply(p1, p2) -> fprintf ppf "%a(%a)" path p1 path p2 +let tree_of_path p = + tree_of_path (rewrite_double_underscore_paths !printing_env p) +let path ppf p = + path ppf (rewrite_double_underscore_paths !printing_env p) + let rec string_of_out_ident = function | Oide_ident s -> s | Oide_dot (id, s) -> String.concat "." [string_of_out_ident id; s] @@ -292,13 +369,9 @@ let penalty s = if s <> "" && s.[0] = '_' then 10 else - try - for i = 0 to String.length s - 2 do - if s.[i] = '_' && s.[i + 1] = '_' then - raise Exit - done; - 1 - with Exit -> 10 + match find_double_underscore s with + | None -> 1 + | Some _ -> 10 let rec path_size = function Pident id -> @@ -315,9 +388,11 @@ let same_printing_env env = let set_printing_env env = printing_env := env; - if !Clflags.real_paths - || !printing_env == Env.empty || same_printing_env env then () else - begin + if !Clflags.real_paths || + !printing_env == Env.empty || + same_printing_env env then + () + else begin (* printf "Reset printing_map@."; *) printing_old := env; printing_pers := Env.used_persistent (); @@ -345,8 +420,9 @@ let wrap_printing_env env f = set_printing_env env; try_finally f (fun () -> set_printing_env Env.empty) -let wrap_printing_env env f = - Env.without_cmis (wrap_printing_env env) f +let wrap_printing_env ~error env f = + if error then Env.without_cmis (wrap_printing_env env) f + else wrap_printing_env env f let is_unambiguous path env = let l = Env.find_shadowed_types path env in @@ -380,7 +456,9 @@ let rec get_best_path r = get_best_path r let best_type_path p = - if !Clflags.real_paths || !printing_env == Env.empty + if !printing_env == Env.empty + then (p, Id) + else if !Clflags.real_paths then (p, Id) else let (p', s) = normalize_type_path !printing_env p in @@ -758,6 +836,15 @@ and type_sch ppf ty = typexp true ppf ty and type_scheme ppf ty = reset_and_mark_loops ty; typexp true ppf ty +let type_expansion ppf ty1 ty2 = + let tree1 = tree_of_typexp false ty1 in + let tree2 = tree_of_typexp false ty2 in + let pp = !Oprint.out_type in + if tree1 = tree2 then + pp ppf tree1 + else + fprintf ppf "@[<2>%a@ =@ %a@]" pp tree1 pp tree2 + (* Maxence *) let type_scheme_max ?(b_reset_names=true) ppf ty = if b_reset_names then reset_names () ; @@ -1197,7 +1284,8 @@ let filter_rem_sig item rem = let dummy = { type_params = []; type_arity = 0; type_kind = Type_abstract; type_private = Public; type_manifest = None; type_variance = []; - type_newtype_level = None; type_loc = Location.none; + type_is_newtype = false; type_expansion_scope = None; + type_loc = Location.none; type_attributes = []; type_immediate = false; type_unboxed = unboxed_false_default_false; @@ -1352,7 +1440,7 @@ let type_expansion t ppf t' = then begin add_delayed (proxy t); type_expr ppf t end else let t' = if proxy t == proxy t' then unalias t' else t' in - fprintf ppf "@[<2>%a@ =@ %a@]" type_expr t type_expr t' + type_expansion ppf t t' let type_path_expansion tp ppf tp' = if Path.same tp tp' then path ppf tp else @@ -1413,89 +1501,120 @@ let print_tags ppf fields = fprintf ppf "`%s" t; List.iter (fun (t, _) -> fprintf ppf ",@ `%s" t) fields -let has_explanation t3 t4 = - match t3.desc, t4.desc with - Tfield _, (Tnil|Tconstr _) | (Tnil|Tconstr _), Tfield _ - | Tnil, Tconstr _ | Tconstr _, Tnil - | _, Tvar _ | Tvar _, _ - | Tvariant _, Tvariant _ -> true - | Tfield (l,_,_,{desc=Tnil}), Tfield (l',_,_,{desc=Tnil}) -> l = l' +let is_unit env ty = + match (Ctype.expand_head env ty).desc with + | Tconstr (p, _, _) -> Path.same p Predef.path_unit | _ -> false -let rec mismatch = function - (_, t) :: (_, t') :: rem -> - begin match mismatch rem with - Some _ as m -> m - | None -> - if has_explanation t t' then Some(t,t') else None - end - | [] -> None - | _ -> assert false +let unifiable env ty1 ty2 = + let snap = Btype.snapshot () in + let res = + try Ctype.unify env ty1 ty2; true + with Unify _ -> false + in + Btype.backtrack snap; + res -let explanation unif t3 t4 ppf = +let explanation env unif t3 t4 : (Format.formatter -> unit) option = match t3.desc, t4.desc with + | Tarrow (_, ty1, ty2, _), _ + when is_unit env ty1 && unifiable env ty2 t4 -> + Some (fun ppf -> + fprintf ppf + "@,@[Hint: Did you forget to provide `()' as argument?@]") + | _, Tarrow (_, ty1, ty2, _) + when is_unit env ty1 && unifiable env t3 ty2 -> + Some (fun ppf -> + fprintf ppf + "@,@[Hint: Did you forget to wrap the expression using `fun () ->'?@]") | Ttuple [], Tvar _ | Tvar _, Ttuple [] -> - fprintf ppf "@,Self type cannot escape its class" + Some (fun ppf -> + fprintf ppf "@,Self type cannot escape its class") | Tconstr (p, _, _), Tvar _ when unif && t4.level < Path.binding_time p -> - fprintf ppf - "@,@[The type constructor@;<1 2>%a@ would escape its scope@]" - path p + Some (fun ppf -> + fprintf ppf + "@,@[The type constructor@;<1 2>%a@ would escape its scope@]" + path p) | Tvar _, Tconstr (p, _, _) when unif && t3.level < Path.binding_time p -> - fprintf ppf - "@,@[The type constructor@;<1 2>%a@ would escape its scope@]" - path p + Some (fun ppf -> + fprintf ppf + "@,@[The type constructor@;<1 2>%a@ would escape its scope@]" + path p) | Tvar _, Tunivar _ | Tunivar _, Tvar _ -> - fprintf ppf "@,The universal variable %a would escape its scope" - type_expr (if is_Tunivar t3 then t3 else t4) + Some (fun ppf -> + fprintf ppf "@,The universal variable %a would escape its scope" + type_expr (if is_Tunivar t3 then t3 else t4)) | Tvar _, _ | _, Tvar _ -> - let t, t' = if is_Tvar t3 then (t3, t4) else (t4, t3) in - if occur_in Env.empty t t' then - fprintf ppf "@,@[The type variable %a occurs inside@ %a@]" - type_expr t type_expr t' - else - fprintf ppf "@,@[This instance of %a is ambiguous:@ %s@]" - type_expr t' - "it would escape the scope of its equation" + Some (fun ppf -> + let t, t' = if is_Tvar t3 then (t3, t4) else (t4, t3) in + if occur_in Env.empty t t' then + fprintf ppf "@,@[The type variable %a occurs inside@ %a@]" + type_expr t type_expr t' + else + fprintf ppf "@,@[This instance of %a is ambiguous:@ %s@]" + type_expr t' + "it would escape the scope of its equation") | Tfield (lab, _, _, _), _ when lab = dummy_method -> - fprintf ppf - "@,Self type cannot be unified with a closed object type" + Some (fun ppf -> + fprintf ppf + "@,Self type cannot be unified with a closed object type") | _, Tfield (lab, _, _, _) when lab = dummy_method -> - fprintf ppf - "@,Self type cannot be unified with a closed object type" + Some (fun ppf -> + fprintf ppf + "@,Self type cannot be unified with a closed object type") | Tfield (l,_,_,{desc=Tnil}), Tfield (l',_,_,{desc=Tnil}) when l = l' -> - fprintf ppf "@,Types for method %s are incompatible" l + Some (fun ppf -> + fprintf ppf "@,Types for method %s are incompatible" l) | (Tnil|Tconstr _), Tfield (l, _, _, _) -> - fprintf ppf - "@,@[The first object type has no method %s@]" l + Some (fun ppf -> + fprintf ppf + "@,@[The first object type has no method %s@]" l) | Tfield (l, _, _, _), (Tnil|Tconstr _) -> - fprintf ppf - "@,@[The second object type has no method %s@]" l + Some (fun ppf -> + fprintf ppf + "@,@[The second object type has no method %s@]" l) | Tnil, Tconstr _ | Tconstr _, Tnil -> - fprintf ppf - "@,@[The %s object type has an abstract row, it cannot be closed@]" - (if t4.desc = Tnil then "first" else "second") + Some (fun ppf -> + fprintf ppf + "@,@[The %s object type has an abstract row, it cannot be closed@]" + (if t4.desc = Tnil then "first" else "second")) | Tvariant row1, Tvariant row2 -> - let row1 = row_repr row1 and row2 = row_repr row2 in - begin match - row1.row_fields, row1.row_closed, row2.row_fields, row2.row_closed with - | [], true, [], true -> - fprintf ppf "@,These two variant types have no intersection" - | [], true, (_::_ as fields), _ -> - fprintf ppf - "@,@[The first variant type does not allow tag(s)@ @[%a@]@]" - print_tags fields - | (_::_ as fields), _, [], true -> - fprintf ppf - "@,@[The second variant type does not allow tag(s)@ @[%a@]@]" - print_tags fields - | [l1,_], true, [l2,_], true when l1 = l2 -> - fprintf ppf "@,Types for tag `%s are incompatible" l1 - | _ -> () + Some (fun ppf -> + let row1 = row_repr row1 and row2 = row_repr row2 in + begin match + row1.row_fields, row1.row_closed, row2.row_fields, row2.row_closed with + | [], true, [], true -> + fprintf ppf "@,These two variant types have no intersection" + | [], true, (_::_ as fields), _ -> + fprintf ppf + "@,@[The first variant type does not allow tag(s)@ @[%a@]@]" + print_tags fields + | (_::_ as fields), _, [], true -> + fprintf ppf + "@,@[The second variant type does not allow tag(s)@ @[%a@]@]" + print_tags fields + | [l1,_], true, [l2,_], true when l1 = l2 -> + fprintf ppf "@,Types for tag `%s are incompatible" l1 + | _ -> () + end) + | _ -> + None + +let rec mismatch env unif = function + (_, t) :: (_, t') :: rem -> + begin match mismatch env unif rem with + Some _ as m -> m + | None -> explanation env unif t t' end - | _ -> () + | [] -> None + | _ -> assert false +let explain mis ppf = + match mis with + | None -> () + | Some explain -> explain ppf let warn_on_missing_def env ppf t = match t.desc with @@ -1510,11 +1629,6 @@ let warn_on_missing_def env ppf t = end | _ -> () -let explanation unif mis ppf = - match mis with - None -> () - | Some (t3, t4) -> explanation unif t3 t4 ppf - let ident_same_name id1 id2 = if Ident.equal id1 id2 && not (Ident.same id1 id2) then begin add_unique id1; add_unique id2 @@ -1539,11 +1653,11 @@ let rec trace_same_names = function type_same_name t1 t2; type_same_name t1' t2'; trace_same_names rem | _ -> () -let unification_error env unif tr txt1 ppf txt2 = +let unification_error env unif tr txt1 ppf txt2 ty_expect_explanation = reset (); trace_same_names tr; let tr = List.map (fun (t, t') -> (t, hide_variant_name t')) tr in - let mis = mismatch tr in + let mis = mismatch env unif tr in match tr with | [] | _ :: [] -> assert false | t1 :: t2 :: tr -> @@ -1557,12 +1671,14 @@ let unification_error env unif tr txt1 ppf txt2 = "@[\ @[%t@;<1 2>%a@ \ %t@;<1 2>%a\ + %t\ @]%a%t\ @]" txt1 (type_expansion t1) t1' txt2 (type_expansion t2) t2' + ty_expect_explanation (trace false "is not compatible with type") tr - (explanation unif mis); + (explain mis); if env <> Env.empty then begin warn_on_missing_def env ppf t1; @@ -1573,9 +1689,12 @@ let unification_error env unif tr txt1 ppf txt2 = print_labels := true; raise exn -let report_unification_error ppf env ?(unif=true) - tr txt1 txt2 = - wrap_printing_env env (fun () -> unification_error env unif tr txt1 ppf txt2) +let report_unification_error ppf env ?(unif=true) tr + ?(type_expected_explanation = fun _ -> ()) + txt1 txt2 = + wrap_printing_env env (fun () -> unification_error env unif tr txt1 ppf txt2 + type_expected_explanation) + ~error:true ;; let trace fst keep_last txt ppf tr = @@ -1592,19 +1711,19 @@ let trace fst keep_last txt ppf tr = raise exn let report_subtyping_error ppf env tr1 txt1 tr2 = - wrap_printing_env env (fun () -> + wrap_printing_env ~error:true env (fun () -> reset (); let tr1 = List.map prepare_expansion tr1 and tr2 = List.map prepare_expansion tr2 in fprintf ppf "@[%a" (trace true (tr2 = []) txt1) tr1; if tr2 = [] then fprintf ppf "@]" else - let mis = mismatch tr2 in + let mis = mismatch env true tr2 in fprintf ppf "%a%t@]" (trace false (mis = None) "is not compatible with type") tr2 - (explanation true mis)) + (explain mis)) let report_ambiguous_type_error ppf env (tp0, tp0') tpl txt1 txt2 txt3 = - wrap_printing_env env (fun () -> + wrap_printing_env ~error:true env (fun () -> reset (); List.iter (fun (tp, tp') -> path_same_name tp0 tp; path_same_name tp0' tp') diff --git a/typing/printtyp.mli b/typing/printtyp.mli index 8fd027ec..b824d164 100644 --- a/typing/printtyp.mli +++ b/typing/printtyp.mli @@ -27,9 +27,10 @@ val string_of_path: Path.t -> string val raw_type_expr: formatter -> type_expr -> unit val string_of_label: Asttypes.arg_label -> string -val wrap_printing_env: Env.t -> (unit -> 'a) -> 'a +val wrap_printing_env: error:bool -> Env.t -> (unit -> 'a) -> 'a (* Call the function using the environment for type path shortening *) (* This affects all the printing functions below *) + (* Also, if [~error:true], then disable the loading of cmis *) val reset: unit -> unit val mark_loops: type_expr -> unit @@ -75,7 +76,9 @@ val prepare_expansion: type_expr * type_expr -> type_expr * type_expr val trace: bool -> bool-> string -> formatter -> (type_expr * type_expr) list -> unit val report_unification_error: - formatter -> Env.t -> ?unif:bool -> (type_expr * type_expr) list -> + formatter -> Env.t -> ?unif:bool -> + (type_expr * type_expr) list -> + ?type_expected_explanation:(formatter -> unit) -> (formatter -> unit) -> (formatter -> unit) -> unit val report_subtyping_error: @@ -88,3 +91,8 @@ val report_ambiguous_type_error: (* for toploop *) val print_items: (Env.t -> signature_item -> 'a option) -> Env.t -> signature_item list -> (out_sig_item * 'a option) list + +(* Simple heuristic to rewrite Foo__bar.* as Foo.Bar.* when Foo.Bar is an alias for + Foo__bar. This pattern is used by the stdlib. *) +val rewrite_double_underscore_paths: Env.t -> Path.t -> Path.t + diff --git a/typing/stypes.ml b/typing/stypes.ml index 8435669e..5615037a 100644 --- a/typing/stypes.ml +++ b/typing/stypes.ml @@ -159,7 +159,7 @@ let print_info pp prev_loc ti = printtyp_reset_maybe loc; Printtyp.mark_loops typ; Format.pp_print_string Format.str_formatter " "; - Printtyp.wrap_printing_env env + Printtyp.wrap_printing_env ~error:false env (fun () -> Printtyp.type_sch Format.str_formatter typ); Format.pp_print_newline Format.str_formatter (); let s = Format.flush_str_formatter () in diff --git a/typing/subst.ml b/typing/subst.ml index fb5f9019..ad9d8d68 100644 --- a/typing/subst.ml +++ b/typing/subst.ml @@ -131,7 +131,7 @@ let reset_for_saving () = new_id := -1 let newpersty desc = decr new_id; - { desc = desc; level = generic_level; id = !new_id } + { desc = desc; level = generic_level; scope = None; id = !new_id } (* ensure that all occurrences of 'Tvar None' are physically shared *) let tvar_none = Tvar None @@ -299,7 +299,8 @@ let type_declaration s decl = end; type_private = decl.type_private; type_variance = decl.type_variance; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = loc s decl.type_loc; type_attributes = attrs s decl.type_attributes; type_immediate = decl.type_immediate; diff --git a/typing/typeclass.ml b/typing/typeclass.ml index 371d2ad7..53542c5c 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -75,6 +75,7 @@ type error = | Mutability_mismatch of string * mutable_flag | No_overriding of string * string | Duplicate of string * string + | Closing_self_type of type_expr exception Error of Location.t * Env.t * error exception Error_forward of Location.error @@ -250,13 +251,12 @@ let enter_met_env ?check loc lab kind ty val_env met_env par_env = (* Enter an instance variable in the environment *) let enter_val cl_num vars inh lab mut virt ty val_env met_env par_env loc = - let instance = Ctype.instance val_env in let (id, virt) = try let (id, mut', virt', ty') = Vars.find lab !vars in if mut' <> mut then raise (Error(loc, val_env, Mutability_mismatch(lab, mut))); - Ctype.unify val_env (instance ty) (instance ty'); + Ctype.unify val_env (Ctype.instance ty) (Ctype.instance ty'); (if not inh then Some id else None), (if virt' = Concrete then virt' else virt) with @@ -735,8 +735,9 @@ and class_field_aux self_loc cl_num self_type meths vars (fun () -> (* Read the generalized type *) let (_, ty) = Meths.find lab.txt !meths in - let meth_type = - Btype.newgenty (Tarrow(Nolabel, self_type, ty, Cok)) in + let meth_type = mk_expected ( + Btype.newgenty (Tarrow(Nolabel, self_type, ty, Cok)) + ) in Ctype.raise_nongen_level (); vars := vars_local; let texp = type_expect met_env meth_expr meth_type in @@ -760,10 +761,11 @@ and class_field_aux self_loc cl_num self_type meths vars let field = lazy begin Ctype.raise_nongen_level (); - let meth_type = + let meth_type = mk_expected ( Ctype.newty (Tarrow (Nolabel, self_type, - Ctype.instance_def Predef.type_unit, Cok)) in + Ctype.instance_def Predef.type_unit, Cok)) + ) in vars := vars_local; let texp = type_expect met_env expr meth_type in Ctype.end_def (); @@ -779,6 +781,15 @@ and class_field_aux self_loc cl_num self_type meths vars | Pcf_extension ext -> raise (Error_forward (Builtin_attributes.error_of_extension ext)) +(* N.B. the self type of a final object type doesn't contain a dummy method in + the beginning. + We only explicitely add a dummy method to class definitions (and class (type) + declarations)), which are later removed (made absent) by [final_decl]. + + If we ever find a dummy method in a final object self type, it means that + somehow we've unified the self type of the object with the self type of a not + yet finished class. + When this happens, we cannot close the object type and must error. *) and class_structure cl_num final val_env met_env loc { pcstr_self = spat; pcstr_fields = str } = (* Environment for substructures *) @@ -787,11 +798,15 @@ and class_structure cl_num final val_env met_env loc (* Location of self. Used for locations of self arguments *) let self_loc = {spat.ppat_loc with Location.loc_ghost = true} in - (* Self type, with a dummy method preventing it from being closed/escaped. *) - let self_type = Ctype.newvar () in - Ctype.unify val_env - (Ctype.filter_method val_env dummy_method Private self_type) - (Ctype.newty (Ttuple [])); + let self_type = Ctype.newobj (Ctype.newvar ()) in + + (* Adding a dummy method to the self type prevents it from being closed / + escaping. + That isn't needed for objects though. *) + if not final then + Ctype.unify val_env + (Ctype.filter_method val_env dummy_method Private self_type) + (Ctype.newty (Ttuple [])); (* Private self is used for private method calls *) let private_self = if final then Ctype.newvar () else self_type in @@ -848,7 +863,10 @@ and class_structure cl_num final val_env met_env loc if final then begin (* Unify private_self and a copy of self_type. self_type will not be modified after this point *) - Ctype.close_object self_type; + begin try Ctype.close_object self_type + with Ctype.Unify [] -> + raise(Error(loc, val_env, Closing_self_type self_type)) + end; let mets = virtual_methods {sign with csig_self = self_type} in let vals = Vars.fold @@ -859,13 +877,7 @@ and class_structure cl_num final val_env met_env loc let self_methods = List.fold_right (fun (lab,kind,ty) rem -> - if lab = dummy_method then - (* allow public self and private self to be unified *) - match Btype.field_kind_repr kind with - Fvar r -> Btype.set_kind r Fabsent; rem - | _ -> rem - else - Ctype.newty(Tfield(lab, Btype.copy_kind kind, ty, rem))) + Ctype.newty(Tfield(lab, Btype.copy_kind kind, ty, rem))) methods (Ctype.newty Tnil) in begin try Ctype.unify val_env private_self @@ -881,7 +893,7 @@ and class_structure cl_num final val_env met_env loc (* Generalize the spine of methods accessed through self *) Meths.iter (fun _ (_,ty) -> Ctype.generalize_spine ty) ms; meths := - Meths.map (fun (id,ty) -> (id, Ctype.generic_instance val_env ty)) ms; + Meths.map (fun (id,ty) -> (id, Ctype.generic_instance ty)) ms; (* But keep levels correct on the type of self *) Meths.iter (fun _ (_,ty) -> Ctype.unify val_env ty (Ctype.newvar ())) ms end; @@ -1006,7 +1018,7 @@ and class_expr_aux cl_num val_env met_env scl = {exp_desc = Texp_ident(path, mknoloc (Longident.Lident (Ident.name id)), vd); exp_loc = Location.none; exp_extra = []; - exp_type = Ctype.instance val_env' vd.val_type; + exp_type = Ctype.instance vd.val_type; exp_attributes = []; (* check *) exp_env = val_env'}) end @@ -1161,7 +1173,7 @@ and class_expr_aux cl_num val_env met_env scl = {exp_desc = Texp_ident(path, mknoloc(Longident.Lident (Ident.name id)),vd); exp_loc = Location.none; exp_extra = []; - exp_type = Ctype.instance val_env vd.val_type; + exp_type = Ctype.instance vd.val_type; exp_attributes = []; exp_env = val_env; } @@ -1279,7 +1291,8 @@ let temp_abbrev loc env id arity = type_private = Public; type_manifest = Some ty; type_variance = Misc.replicate_list Variance.full arity; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = loc; type_attributes = []; (* or keep attrs from the class decl? *) type_immediate = false; @@ -1398,7 +1411,9 @@ let class_infos define_class kind begin let ty = Ctype.self_type obj_type in Ctype.hide_private_methods ty; - Ctype.close_object ty; + begin try Ctype.close_object ty + with Ctype.Unify [] -> raise(Error(cl.pci_loc, env, Closing_self_type ty)) + end; begin try List.iter2 (Ctype.unify env) obj_params obj_params' with Ctype.Unify _ -> @@ -1443,7 +1458,7 @@ let class_infos define_class kind begin try Ctype.unify env (constructor_type constr obj_type) - (Ctype.instance env constr_type) + (Ctype.instance constr_type) with Ctype.Unify trace -> raise(Error(cl.pci_loc, env, Constructor_type_mismatch (cl.pci_name.txt, trace))) @@ -1514,7 +1529,7 @@ let class_infos define_class kind cty_new = begin match cl.pci_virt with | Virtual -> None - | Concrete -> Some (Ctype.instance env constr_type) + | Concrete -> Some (Ctype.instance constr_type) end; cty_loc = cl.pci_loc; cty_attributes = cl.pci_attributes; @@ -1527,7 +1542,8 @@ let class_infos define_class kind type_private = Public; type_manifest = Some obj_ty; type_variance = List.map (fun _ -> Variance.full) obj_params; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = cl.pci_loc; type_attributes = []; (* or keep attrs from cl? *) type_immediate = false; @@ -1546,7 +1562,8 @@ let class_infos define_class kind type_private = Public; type_manifest = Some cl_ty; type_variance = List.map (fun _ -> Variance.full) cl_params; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = cl.pci_loc; type_attributes = []; (* or keep attrs from cl? *) type_immediate = false; @@ -1566,6 +1583,21 @@ let final_decl env define_class raise(Error(cl.pci_loc, env, Non_collapsable_conjunction (id, clty, trace))) end; + (* make the dummy method disappear *) + begin + let self_type = Ctype.self_type clty.cty_type in + let methods, _ = + Ctype.flatten_fields + (Ctype.object_fields (Ctype.expand_head env self_type)) + in + List.iter (fun (lab,kind,_) -> + if lab = dummy_method then + match Btype.field_kind_repr kind with + Fvar r -> Btype.set_kind r Fabsent + | _ -> () + ) methods + end; + List.iter Ctype.generalize clty.cty_params; generalize_class_type true clty.cty_type; Misc.may Ctype.generalize clty.cty_new; @@ -1764,7 +1796,7 @@ let rec unify_parents env ty cl = begin try let decl = Env.find_class p env in let _, body = Ctype.find_cltype_for_path env decl.cty_path in - Ctype.unify env ty (Ctype.instance env body) + Ctype.unify env ty (Ctype.instance body) with Not_found -> () | _exn -> assert false @@ -1972,9 +2004,16 @@ let report_error env ppf = function | Duplicate (kind, name) -> fprintf ppf "@[The %s `%s'@ has multiple definitions in this object@]" kind name + | Closing_self_type self -> + fprintf ppf + "@[Cannot close type of object literal:@ %a@,\ + it has been unified with the self type of a class that is not yet@ \ + completely defined.@]" + Printtyp.type_scheme self let report_error env ppf err = - Printtyp.wrap_printing_env env (fun () -> report_error env ppf err) + Printtyp.wrap_printing_env ~error:true + env (fun () -> report_error env ppf err) let () = Location.register_error_of_exn diff --git a/typing/typeclass.mli b/typing/typeclass.mli index 1735bf9e..b9a0d210 100644 --- a/typing/typeclass.mli +++ b/typing/typeclass.mli @@ -117,6 +117,7 @@ type error = | Mutability_mismatch of string * mutable_flag | No_overriding of string * string | Duplicate of string * string + | Closing_self_type of type_expr exception Error of Location.t * Env.t * error exception Error_forward of Location.error diff --git a/typing/typecore.ml b/typing/typecore.ml index bf86107c..c6a40713 100644 --- a/typing/typecore.ml +++ b/typing/typecore.ml @@ -23,6 +23,22 @@ open Typedtree open Btype open Ctype +type type_forcing_context = + | If_conditional + | If_no_else_branch + | While_loop_conditional + | While_loop_body + | For_loop_start_index + | For_loop_stop_index + | For_loop_body + | Assert_condition + | Sequence_left_hand_side + +type type_expected = { + ty: type_expr; + explanation: type_forcing_context option; +} + type error = Polymorphic_label of Longident.t | Constructor_arity_mismatch of Longident.t * int * int @@ -31,13 +47,13 @@ type error = | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string | Orpat_vars of Ident.t * Ident.t list - | Expr_type_clash of (type_expr * type_expr) list + | Expr_type_clash of (type_expr * type_expr) list * type_forcing_context option | Apply_non_function of type_expr | Apply_wrong_label of arg_label * type_expr | Label_multiply_defined of string | Label_missing of Ident.t list | Label_not_mutable of Longident.t - | Wrong_name of string * type_expr * string * Path.t * string * string list + | Wrong_name of string * type_expected * string * Path.t * string * string list | Name_type_mismatch of string * Longident.t * (Path.t * Path.t) * (Path.t * Path.t) list | Invalid_format of string @@ -53,8 +69,8 @@ type error = | Value_multiply_overridden of string | Coercion_failure of type_expr * type_expr * (type_expr * type_expr) list * bool - | Too_many_arguments of bool * type_expr - | Abstract_wrong_label of arg_label * type_expr + | Too_many_arguments of bool * type_expr * type_forcing_context option + | Abstract_wrong_label of arg_label * type_expr * type_forcing_context option | Scoping_let_module of string * type_expr | Masked_instance_variable of Longident.t | Not_a_variant_type of Longident.t @@ -65,7 +81,6 @@ type error = | Not_a_packed_module of type_expr | Recursive_local_constraint of (type_expr * type_expr) list | Unexpected_existential - | Unqualified_gadt_pattern of Path.t * string | Invalid_interval | Invalid_for_loop_index | No_value_clauses @@ -80,6 +95,7 @@ type error = | Illegal_letrec_pat | Illegal_letrec_expr | Illegal_class_expr + | Empty_pattern exception Error of Location.t * Env.t * error exception Error_forward of Location.error @@ -133,6 +149,8 @@ type recarg = | Rejected +let mk_expected ?explanation ty = { ty; explanation; } + let case lhs rhs = {c_lhs = lhs; c_guard = None; c_rhs = rhs} @@ -367,27 +385,21 @@ let unify_exp_types loc env ty expected_ty = unify env ty expected_ty with Unify trace -> - raise(Error(loc, env, Expr_type_clash(trace))) + raise(Error(loc, env, Expr_type_clash(trace, None))) | Tags(l1,l2) -> raise(Typetexp.Error(loc, env, Typetexp.Variant_tags (l1, l2))) (* level at which to create the local type declarations *) -let newtype_level = ref None -let get_newtype_level () = - match !newtype_level with +let gadt_equations_level = ref None +let get_gadt_equations_level () = + match !gadt_equations_level with Some y -> y | None -> assert false let unify_pat_types_gadt loc env ty ty' = - let newtype_level = - match !newtype_level with - | None -> assert false - | Some x -> x - in - try - unify_gadt ~newtype_level env ty ty' + try unify_gadt ~equations_level:(get_gadt_equations_level ()) env ty ty' with - Unify trace -> + | Unify trace -> raise(Error(loc, !env, Pattern_type_clash(trace))) | Tags(l1,l2) -> raise(Typetexp.Error(loc, !env, Typetexp.Variant_tags (l1, l2))) @@ -625,8 +637,7 @@ let rec expand_path env p = Some {type_manifest = Some ty} -> begin match repr ty with {desc=Tconstr(p,_,_)} -> expand_path env p - | _ -> p - (* PR#6394: recursive module may introduce incoherent manifest *) + | _ -> assert false end | _ -> let p' = Env.normalize_path None env p in @@ -657,7 +668,7 @@ end) = struct let lookup_from_type env tpath lid = let descrs = get_descrs (Env.find_type_descrs tpath env) in - Env.mark_type_used env (Path.last tpath) (Env.find_type tpath env); + Env.mark_type_used (Path.last tpath) (Env.find_type tpath env); match lid.txt with Longident.Lident s -> begin try @@ -665,7 +676,8 @@ end) = struct with Not_found -> let names = List.map get_name descrs in raise (Error (lid.loc, env, - Wrong_name ("", newvar (), type_kind, tpath, s, names))) + Wrong_name ("", mk_expected (newvar ()), + type_kind, tpath, s, names))) end | _ -> raise Not_found @@ -691,8 +703,7 @@ end) = struct in List.find check_type lbls - let disambiguate ?(warn=Location.prerr_warning) ?(check_lk=fun _ _ -> ()) - ?scope lid env opath lbls = + let disambiguate ?(warn=Location.prerr_warning) ?scope lid env opath lbls = let scope = match scope with None -> lbls | Some l -> l in let lbl = match opath with None -> @@ -734,7 +745,6 @@ end) = struct lbl with Not_found -> try let lbl = lookup_from_type env tpath lid in - check_lk tpath lbl; if in_env lbl then begin let s = Printtyp.string_of_path tpath in @@ -1009,7 +1019,11 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env pat_env = !env } in if explode > 0 then - let (sp, constrs, labels) = Parmatch.ppat_of_type !env expected_ty in + let (sp, constrs, labels) = + try + Parmatch.ppat_of_type !env expected_ty + with Parmatch.Empty -> raise (Error (loc, !env, Empty_pattern)) + in if sp.ppat_desc = Parsetree.Ppat_any then k' Tpat_any else if mode = Inside_or then raise Need_backtrack else let explode = @@ -1130,14 +1144,10 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env [Hashtbl.find constrs s, (fun () -> ())] | _ -> Typetexp.find_all_constructors !env lid.loc lid.txt in - let check_lk tpath constr = - if constr.cstr_generalized then - raise (Error (lid.loc, !env, - Unqualified_gadt_pattern (tpath, constr.cstr_name))) - in let constr = - wrap_disambiguate "This variant pattern is expected to have" expected_ty - (Constructor.disambiguate lid !env opath ~check_lk) candidates + wrap_disambiguate "This variant pattern is expected to have" + (mk_expected expected_ty) + (Constructor.disambiguate lid !env opath) candidates in if constr.cstr_generalized && constrs <> None && mode = Inside_or then raise Need_backtrack; @@ -1175,7 +1185,8 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env raise(Error(loc, !env, Constructor_arity_mismatch(lid.txt, constr.cstr_arity, List.length sargs))); let (ty_args, ty_res) = - instance_constructor ~in_pattern:(env, get_newtype_level ()) constr + instance_constructor ~in_pattern:(env, get_gadt_equations_level ()) + constr in (* PR#7214: do not use gadt unification for toplevel lets *) if not constr.cstr_generalized || mode = Inside_or || no_existentials @@ -1213,9 +1224,9 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env row_more = newvar (); row_fixed = false; row_name = None } in - (* PR#7404: allow some_other_tag blindly, as it would not unify with + (* PR#7404: allow some_private_tag blindly, as it would not unify with the abstract row variable *) - if l = Parmatch.some_other_tag then assert (constrs <> None) + if l = Parmatch.some_private_tag then assert (constrs <> None) else unify_pat_types loc !env (newty (Tvariant row)) expected_ty; let k arg = rp k { @@ -1274,7 +1285,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env in if constrs = None then k (wrap_disambiguate "This record pattern is expected to have" - expected_ty + (mk_expected expected_ty) (type_label_a_list ?labels loc false !env type_label_pat opath lid_sp_list) (k' (fun x -> x))) @@ -1285,8 +1296,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env let ty_elt = newvar() in unify_pat_types loc !env (instance_def (Predef.type_array ty_elt)) expected_ty; - let spl_ann = List.map (fun p -> (p,newvar())) spl in - map_fold_cont (fun (p,_) -> type_pat p ty_elt) spl_ann (fun pl -> + map_fold_cont (fun p -> type_pat p ty_elt) spl (fun pl -> rp k { pat_desc = Tpat_array pl; pat_loc = loc; pat_extra=[]; @@ -1356,7 +1366,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env if separate then begin end_def(); generalize_structure ty; - instance !env ty, instance !env ty + instance ty, instance ty end else ty, ty in unify_pat_types loc !env ty expected_ty; @@ -1399,16 +1409,16 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env let type_pat ?(allow_existentials=false) ?constrs ?labels ?(mode=Normal) ?(explode=0) ?(lev=get_current_level()) env sp expected_ty = - newtype_level := Some lev; + gadt_equations_level := Some lev; try let r = type_pat ~no_existentials:(not allow_existentials) ~constrs ~labels ~mode ~explode ~env sp expected_ty (fun x -> x) in iter_pattern (fun p -> p.pat_env <- !env) r; - newtype_level := None; + gadt_equations_level := None; r with e -> - newtype_level := None; + gadt_equations_level := None; raise e @@ -1434,7 +1444,7 @@ let partial_pred ~lev ?mode ?explode env expected_ty constrs labels p = let check_partial ?(lev=get_current_level ()) env expected_ty loc cases = let explode = match cases with [_] -> 5 | _ -> 0 in - Parmatch.check_partial_gadt + Parmatch.check_partial (partial_pred ~lev ~explode env expected_ty) loc cases let check_unused ?(lev=get_current_level ()) env expected_ty cases = @@ -1647,7 +1657,8 @@ let rec is_nonexpansive exp = is_nonexpansive exp | Texp_apply ( { exp_desc = Texp_ident (_, _, {val_kind = - Val_prim {Primitive.prim_name = "%raise"}}) }, + Val_prim {Primitive.prim_name = + ("%raise" | "%reraise" | "%raise_notrace")}}) }, [Nolabel, Some e]) -> is_nonexpansive e | _ -> false @@ -1750,7 +1761,7 @@ struct val empty : t (** No variables are accessed in an expression; it might be a constant or a global identifier *) - + val unguarded : t -> Ident.t list (** The list of identifiers that are used in an unguarded context *) @@ -1785,14 +1796,14 @@ struct x y let single id access = M.add id access M.empty - + let empty = M.empty let list_matching p t = let r = ref [] in M.iter (fun id v -> if p v then r := id :: !r) t; !r - + let unguarded = list_matching (function Unguarded | Dereferenced -> true | _ -> false) @@ -1808,7 +1819,7 @@ struct let empty = Ident.empty let join x y = - let r = + let r = Ident.fold_all (fun id v tbl -> let v' = try Ident.find_same id tbl with Not_found -> Use.empty in @@ -1868,7 +1879,7 @@ struct if Path.same p Predef.path_int || Path.same p Predef.path_char then `Pintarray else if Path.same p Predef.path_float then - `Pfloatarray + if Config.flat_float_array then `Pfloatarray else `Paddrarray else if Path.same p Predef.path_string || Path.same p Predef.path_array || Path.same p Predef.path_nativeint @@ -1909,24 +1920,76 @@ struct let has_concrete_element_type : Typedtree.expression -> bool = fun e -> array_kind e <> `Pgenarray + (* See the note on abstracted arguments in the documentation for + Typedtree.Texp_apply *) + let is_abstracted_arg : arg_label * expression option -> bool = function + | (_, None) -> true + | (_, Some _) -> false + type sd = Static | Dynamic - let rec classify_expression : Typedtree.expression -> sd = - fun exp -> match exp.exp_desc with - | Texp_let (_, _, e) + let classify_expression : Typedtree.expression -> sd = + (* We need to keep track of the size of expressions + bound by local declarations, to be able to predict + the size of variables. Compare: + + let rec r = + let y = fun () -> r () + in y + + and + + let rec r = + let y = if Random.bool () then ignore else fun () -> r () + in y + + In both cases the final adress of `r` must be known before `y` is compiled, + and this is only possible if `r` has a statically-known size. + + The first definition can be allowed (`y` has a statically-known + size) but the second one is unsound (`y` has no statically-known size). + *) + let rec classify_expression env e = match e.exp_desc with + (* binding and variable cases *) + | Texp_let (rec_flag, vb, e) -> + let env = classify_value_bindings rec_flag env vb in + classify_expression env e + | Texp_ident (path, _, _) -> + classify_path env path + + (* non-binding cases *) | Texp_letmodule (_, _, _, e) | Texp_sequence (_, e) - | Texp_letexception (_, e) -> classify_expression e - | Texp_ident _ + | Texp_letexception (_, e) -> + classify_expression env e + + | Texp_construct (_, {cstr_tag = Cstr_unboxed}, [e]) -> + classify_expression env e + | Texp_construct _ -> + Static + + | Texp_record { representation = Record_unboxed _; + fields = [| _, Overridden (_,e) |] } -> + classify_expression env e + | Texp_record _ -> + Static + + | Texp_apply ({exp_desc = Texp_ident (_, _, vd)}, _) + when is_ref vd -> + Static + | Texp_apply (_,args) + when List.exists is_abstracted_arg args -> + Static + | Texp_apply _ -> + Dynamic + | Texp_for _ | Texp_constant _ | Texp_new _ | Texp_instvar _ | Texp_tuple _ | Texp_array _ - | Texp_construct _ | Texp_variant _ - | Texp_record _ | Texp_setfield _ | Texp_while _ | Texp_setinstvar _ @@ -1935,17 +1998,68 @@ struct | Texp_function _ | Texp_lazy _ | Texp_unreachable - | Texp_extension_constructor _ -> Static - | Texp_apply ({exp_desc = Texp_ident (_, _, vd)}, _) - when is_ref vd -> Static - | Texp_apply _ + | Texp_extension_constructor _ -> + Static + | Texp_match _ | Texp_ifthenelse _ | Texp_send _ | Texp_field _ | Texp_assert _ | Texp_try _ - | Texp_override _ -> Dynamic + | Texp_override _ -> + Dynamic + and classify_value_bindings rec_flag env bindings = + (* We use a non-recursive classification, classifying each + binding with respect to the old environment + (before all definitions), even if the bindings are recursive. + + Note: computing a fixpoint in some way would be more + precise, as the following could be allowed: + + let rec topdef = + let rec x = y and y = fun () -> topdef () + in x + *) + ignore rec_flag; + let old_env = env in + let add_value_binding env vb = + match vb.vb_pat.pat_desc with + | Tpat_var (id, _loc) -> + let size = classify_expression old_env vb.vb_expr in + Ident.add id size env + | _ -> + (* Note: we don't try to compute any size for complex patterns *) + env + in + List.fold_left add_value_binding env bindings + and classify_path env = function + | Path.Pident x -> + begin + try Ident.find_same x env + with Not_found -> + (* an identifier will be missing from the map if either: + - it is a non-local identifier + (bound outside the letrec-binding we are analyzing) + - or it is bound by a complex (let p = e in ...) local binding + - or it is bound within a module (let module M = ... in ...) + that we are not traversing for size computation + + For non-local identifiers it might be reasonable (although + not completely clear) to consider them Static (they have + already been evaluated), but for the others we must + under-approximate with Dynamic. + + This could be fixed by a more complete implementation. + *) + Dynamic + end + | Path.Pdot _ | Path.Papply _ -> + (* local modules could have such paths to local definitions; + classify_expression could be extend to compute module + shapes more precisely *) + Dynamic + in classify_expression Ident.empty let rec expression : Env.env -> Typedtree.expression -> Use.t = fun env exp -> match exp.exp_desc with @@ -1971,7 +2085,7 @@ struct (join (inspect (expression env e1)) (inspect (expression env e2))) - (* The body is evaluated, but not used, and not available + (* The body is evaluated, but not used, and not available for inclusion in another value *) (discard (expression env e3))) @@ -1984,11 +2098,14 @@ struct | Texp_apply ({exp_desc = Texp_ident (_, _, vd)}, [_, Some arg]) when is_ref vd -> Use.guard (expression env arg) - | Texp_apply (e, args) -> - let arg env (_, eo) = option expression env eo in - Use.(join - (inspect (expression env e)) - (inspect (list arg env args))) + | Texp_apply (e, args) -> + let arg env (_, eo) = option expression env eo in + let ty = Use.join (list arg env args) (expression env e) in + if List.exists is_abstracted_arg args + then (* evaluate expressions, abstract over the results + let g = f and x = e in fun z -> g ~x z *) + Use.discard ty + else Use.inspect ty | Texp_tuple exprs -> Use.guard (list expression env exprs) | Texp_array exprs when array_kind exp = `Pfloatarray -> @@ -2070,7 +2187,7 @@ struct begin match Typeopt.classify_lazy_argument e with | `Constant_or_function | `Identifier _ - | `Float -> + | `Float_that_cannot_be_shortcut -> expression env e | `Other -> Use.delay (expression env e) @@ -2213,7 +2330,7 @@ struct else Use.discard ty (* as in 'let' *) in let vars = pattern_variables c_lhs in - let env = + let env = List.fold_left (fun env id -> Ident.add id ty env) env @@ -2226,7 +2343,7 @@ struct fun rec_flag env bindings -> match rec_flag with | Recursive -> - (* Approximation: + (* Approximation: let rec y = let rec x1 = e1 and x2 = e2 @@ -2285,7 +2402,7 @@ struct let ty = expression (build_unguarded_env idlist) expr in match Use.unguarded ty, Use.dependent ty, classify_expression expr with | _ :: _, _, _ (* The expression inspects rec-bound variables *) - | _, _ :: _, Dynamic -> (* The expression depends on rec-bound variables + | _, _ :: _, Dynamic -> (* The expression depends on rec-bound variables and its size is unknown *) raise(Error(expr.exp_loc, env, Illegal_letrec_expr)) | [], _, Static (* The expression has known size *) @@ -2365,7 +2482,7 @@ let rec type_approx env sexp = let ty = type_approx env e in let ty1 = approx_type env sty in begin try unify env ty ty1 with Unify trace -> - raise(Error(sexp.pexp_loc, env, Expr_type_clash trace)) + raise(Error(sexp.pexp_loc, env, Expr_type_clash (trace, None))) end; ty1 | Pexp_coerce (e, sty1, sty2) -> @@ -2377,7 +2494,7 @@ let rec type_approx env sexp = and ty1 = approx_ty_opt sty1 and ty2 = approx_type env sty2 in begin try unify env ty ty1 with Unify trace -> - raise(Error(sexp.pexp_loc, env, Expr_type_clash trace)) + raise(Error(sexp.pexp_loc, env, Expr_type_clash (trace, None))) end; ty2 | _ -> newvar () @@ -2514,22 +2631,27 @@ let contains_polymorphic_variant p = in try loop p; false with Exit -> true -let contains_gadt env p = - let rec loop env p = +let contains_gadt p = + let check p = + match p.pat_desc with + | Tpat_construct (_, cd, _) when cd.cstr_generalized -> + raise Exit + | _ -> () + in + try iter_pattern check p; false with Exit -> true + +(* There are various things that we need to do in presence of GADT constructors + that aren't required if there are none. + However, because of disambiguation, we can't know for sure whether the + patterns contain some GADT constructors. So we conservatively assume that + any constructor might be a GADT constructor. *) +let may_contain_gadts p = + let rec loop p = match p.ppat_desc with - | Ppat_construct (lid, _) -> - begin try - let cstrs = Env.lookup_all_constructors lid.txt env in - List.iter (fun (cstr,_) -> if cstr.cstr_generalized then raise Exit) - cstrs - with Not_found -> () - end; iter_ppat (loop env) p - | Ppat_open (lid,sub_p) -> - let _, new_env = !type_open Asttypes.Override env p.ppat_loc lid in - loop new_env sub_p - | _ -> iter_ppat (loop env) p + | Ppat_construct (_, _) -> raise Exit + | _ -> iter_ppat loop p in - try loop env p; false with Exit -> true + try loop p; false with Exit -> true let check_absent_variant env = iter_pattern @@ -2554,7 +2676,7 @@ let check_absent_variant env = let duplicate_ident_types caselist env = let caselist = - List.filter (fun {pc_lhs} -> contains_gadt env pc_lhs) caselist in + List.filter (fun {pc_lhs} -> may_contain_gadts pc_lhs) caselist in Env.copy_types (all_idents_cases caselist) env (* Getting proper location of already typed expressions. @@ -2596,7 +2718,7 @@ let unify_exp env exp expected_ty = let rec type_exp ?recarg env sexp = (* We now delegate everything to type_expect *) - type_expect ?recarg env sexp (newvar ()) + type_expect ?recarg env sexp (mk_expected (newvar ())) (* Typing of an expression with an expected type. This provide better error messages, and allows controlled @@ -2604,23 +2726,37 @@ let rec type_exp ?recarg env sexp = In the principal case, [type_expected'] may be at generic_level. *) -and type_expect ?in_function ?recarg env sexp ty_expected = +and type_expect ?in_function ?recarg env sexp ty_expected_explained = let previous_saved_types = Cmt_format.get_saved_types () in let exp = Builtin_attributes.warning_scope sexp.pexp_attributes (fun () -> - type_expect_ ?in_function ?recarg env sexp ty_expected + type_expect_ ?in_function ?recarg env sexp ty_expected_explained ) in Cmt_format.set_saved_types (Cmt_format.Partial_expression exp :: previous_saved_types); exp -and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = +and with_explanation explanation f = + match explanation with + | None -> f () + | Some explanation -> + try f () + with Error (loc', env', Expr_type_clash(trace', None)) + when not loc'.Location.loc_ghost -> + raise (Error (loc', env', Expr_type_clash(trace', Some explanation))) + +and type_expect_ + ?in_function ?(recarg=Rejected) + env sexp ty_expected_explained = + let { ty = ty_expected; explanation } = ty_expected_explained in let loc = sexp.pexp_loc in (* Record the expression type before unifying it with the expected type *) + let with_explanation = with_explanation explanation in let rue exp = - unify_exp env (re exp) (instance env ty_expected); + with_explanation (fun () -> + unify_exp env (re exp) (instance ty_expected)); exp in match sexp.pexp_desc with @@ -2679,7 +2815,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = Texp_ident(path, lid, desc) end; exp_loc = loc; exp_extra = []; - exp_type = instance env desc.val_type; + exp_type = instance desc.val_type; exp_attributes = sexp.pexp_attributes; exp_env = env } end @@ -2701,7 +2837,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = if is_format then let format_parsetree = { (type_format loc str env) with pexp_loc = sexp.pexp_loc } in - type_expect ?in_function env format_parsetree ty_expected + type_expect ?in_function env format_parsetree ty_expected_explained else rue { exp_desc = Texp_constant cst; @@ -2720,12 +2856,12 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_env = env } | Pexp_let(Nonrecursive, [{pvb_pat=spat; pvb_expr=sval; pvb_attributes=[]}], sbody) - when contains_gadt env spat -> + when may_contain_gadts spat -> (* TODO: allow non-empty attributes? *) type_expect ?in_function env {sexp with pexp_desc = Pexp_match (sval, [Ast_helper.Exp.case spat sbody])} - ty_expected + ty_expected_explained | Pexp_let(rec_flag, spat_sexp_list, sbody) -> let scp = match sexp.pexp_attributes, rec_flag with @@ -2736,7 +2872,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let (pat_exp_list, new_env, unpacks) = type_let env rec_flag spat_sexp_list scp true in let body = - type_expect new_env (wrap_unpacks sbody unpacks) ty_expected in + type_expect new_env (wrap_unpacks sbody unpacks) + ty_expected_explained in let () = if rec_flag = Recursive then check_recursive_bindings env pat_exp_list @@ -2780,14 +2917,14 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = Exp.let_ ~loc Nonrecursive ~attrs:[mknoloc "#default",PStr []] [Vb.mk spat smatch] sbody in - type_function ?in_function loc sexp.pexp_attributes env ty_expected + type_function ?in_function loc sexp.pexp_attributes env ty_expected_explained l [Exp.case pat body] | Pexp_fun (l, None, spat, sbody) -> - type_function ?in_function loc sexp.pexp_attributes env ty_expected + type_function ?in_function loc sexp.pexp_attributes env ty_expected_explained l [Ast_helper.Exp.case spat sbody] | Pexp_function caselist -> type_function ?in_function - loc sexp.pexp_attributes env ty_expected Nolabel caselist + loc sexp.pexp_attributes env ty_expected_explained Nolabel caselist | Pexp_apply(sfunct, sargs) -> assert (sargs <> []); begin_def (); (* one more level for non-returning functions *) @@ -2806,7 +2943,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = lower_args (ty::seen) ty_fun | _ -> () in - let ty = instance env funct.exp_type in + let ty = instance funct.exp_type in end_def (); wrap_trace_gadt_instances env (lower_args []) ty; begin_def (); @@ -2845,11 +2982,11 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = re { exp_desc = Texp_match(arg, val_cases, exn_cases, partial); exp_loc = loc; exp_extra = []; - exp_type = instance env ty_expected; + exp_type = instance ty_expected; exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_try(sbody, caselist) -> - let body = type_expect env sbody ty_expected in + let body = type_expect env sbody ty_expected_explained in let cases, _ = type_cases env Predef.type_exn ty_expected false loc caselist in re { @@ -2862,9 +2999,11 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = assert (List.length sexpl >= 2); let subtypes = List.map (fun _ -> newgenvar ()) sexpl in let to_unify = newgenty (Ttuple subtypes) in - unify_exp_types loc env to_unify ty_expected; + with_explanation (fun () -> + unify_exp_types loc env to_unify ty_expected); let expl = - List.map2 (fun body ty -> type_expect env body ty) sexpl subtypes + List.map2 (fun body ty -> type_expect env body (mk_expected ty)) + sexpl subtypes in re { exp_desc = Texp_tuple expl; @@ -2874,10 +3013,10 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_construct(lid, sarg) -> - type_construct env loc lid sarg ty_expected sexp.pexp_attributes + type_construct env loc lid sarg ty_expected_explained sexp.pexp_attributes | Pexp_variant(l, sarg) -> (* Keep sharing *) - let ty_expected0 = instance env ty_expected in + let ty_expected0 = instance ty_expected in begin try match sarg, expand_head env ty_expected, expand_head env ty_expected0 with | Some sarg, {desc = Tvariant row}, {desc = Tvariant row0} -> @@ -2942,7 +3081,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let decl = Env.find_type p' env in begin_def (); let ty = - newconstr p' (instance_list env decl.type_params) in + newconstr p' (instance_list decl.type_params) in end_def (); generalize_structure ty; ty, op @@ -2951,13 +3090,15 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = in let closed = (opt_sexp = None) in let lbl_exp_list = - wrap_disambiguate "This record expression is expected to have" ty_record + wrap_disambiguate "This record expression is expected to have" + (mk_expected ty_record) (type_label_a_list loc closed env (fun e k -> k (type_label_exp true env loc ty_record e)) opath lid_sexp_list) (fun x -> x) in - unify_exp_types loc env ty_record (instance env ty_expected); + with_explanation (fun () -> + unify_exp_types loc env ty_record (instance ty_expected)); (* type_label_a_list returns a list of labels sorted by lbl_pos *) (* note: check_duplicates would better be implemented in @@ -3002,7 +3143,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = in None, label_definitions | Some exp -> - let ty_exp = instance env exp.exp_type in + let ty_exp = instance exp.exp_type in let unify_kept lbl = let _, ty_arg1, ty_res1 = instance_label false lbl in unify_exp_types exp.exp_loc env ty_exp ty_res1; @@ -3012,8 +3153,9 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = Overridden (lid, lbl_exp) | exception Not_found -> begin let _, ty_arg2, ty_res2 = instance_label false lbl in - unify env ty_arg1 ty_arg2; - unify env (instance env ty_expected) ty_res2; + unify_exp_types loc env ty_arg1 ty_arg2; + with_explanation (fun () -> + unify_exp_types loc env (instance ty_expected) ty_res2); Kept ty_arg1 end in @@ -3042,7 +3184,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = extended_expression = opt_exp }; exp_loc = loc; exp_extra = []; - exp_type = instance env ty_expected; + exp_type = instance ty_expected; exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_field(srecord, lid) -> @@ -3074,19 +3216,23 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = | Pexp_array(sargl) -> let ty = newgenvar() in let to_unify = Predef.type_array ty in - unify_exp_types loc env to_unify ty_expected; - let argl = List.map (fun sarg -> type_expect env sarg ty) sargl in + with_explanation (fun () -> + unify_exp_types loc env to_unify ty_expected); + let argl = + List.map (fun sarg -> type_expect env sarg (mk_expected ty)) sargl in re { exp_desc = Texp_array argl; exp_loc = loc; exp_extra = []; - exp_type = instance env ty_expected; + exp_type = instance ty_expected; exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_ifthenelse(scond, sifso, sifnot) -> - let cond = type_expect env scond Predef.type_bool in + let cond = type_expect env scond + (mk_expected ~explanation:If_conditional Predef.type_bool) in begin match sifnot with None -> - let ifso = type_expect env sifso Predef.type_unit in + let ifso = type_expect env sifso + (mk_expected ~explanation:If_no_else_branch Predef.type_unit) in rue { exp_desc = Texp_ifthenelse(cond, ifso, None); exp_loc = loc; exp_extra = []; @@ -3094,8 +3240,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_attributes = sexp.pexp_attributes; exp_env = env } | Some sifnot -> - let ifso = type_expect env sifso ty_expected in - let ifnot = type_expect env sifnot ty_expected in + let ifso = type_expect env sifso ty_expected_explained in + let ifnot = type_expect env sifnot ty_expected_explained in (* Keep sharing *) unify_exp env ifnot ifso.exp_type; re { @@ -3106,8 +3252,9 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_env = env } end | Pexp_sequence(sexp1, sexp2) -> - let exp1 = type_statement env sexp1 in - let exp2 = type_expect env sexp2 ty_expected in + let exp1 = type_statement ~explanation:Sequence_left_hand_side + env sexp1 in + let exp2 = type_expect env sexp2 ty_expected_explained in re { exp_desc = Texp_sequence(exp1, exp2); exp_loc = loc; exp_extra = []; @@ -3115,8 +3262,9 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_while(scond, sbody) -> - let cond = type_expect env scond Predef.type_bool in - let body = type_statement env sbody in + let cond = type_expect env scond + (mk_expected ~explanation:While_loop_conditional Predef.type_bool) in + let body = type_statement ~explanation:While_loop_body env sbody in rue { exp_desc = Texp_while(cond, body); exp_loc = loc; exp_extra = []; @@ -3124,8 +3272,10 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_attributes = sexp.pexp_attributes; exp_env = env } | Pexp_for(param, slow, shigh, dir, sbody) -> - let low = type_expect env slow Predef.type_int in - let high = type_expect env shigh Predef.type_int in + let low = type_expect env slow + (mk_expected ~explanation:For_loop_start_index Predef.type_int) in + let high = type_expect env shigh + (mk_expected ~explanation:For_loop_stop_index Predef.type_int) in let id, new_env = match param.ppat_desc with | Ppat_any -> Ident.create "_for", env @@ -3137,7 +3287,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = | _ -> raise (Error (param.ppat_loc, env, Invalid_for_loop_index)) in - let body = type_statement new_env sbody in + let body = type_statement ~explanation:For_loop_body new_env sbody in rue { exp_desc = Texp_for(id, param, low, high, dir, body); exp_loc = loc; exp_extra = []; @@ -3153,7 +3303,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = if separate then begin end_def (); generalize_structure ty; - (type_argument env sarg ty (instance env ty), instance env ty) + (type_argument env sarg ty (instance ty), instance ty) end else (type_argument env sarg ty ty, ty) in @@ -3185,7 +3335,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let tv = newvar () in let gen = generalizable tv.level arg.exp_type in (try unify_var env tv arg.exp_type with Unify trace -> - raise(Error(arg.exp_loc, env, Expr_type_clash trace))); + raise(Error(arg.exp_loc, env, Expr_type_clash (trace, None)))); gen end else true in @@ -3243,8 +3393,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = end_def (); generalize_structure ty; generalize_structure ty'; - (type_argument env sarg ty (instance env ty), - instance env ty', Some cty, cty') + (type_argument env sarg ty (instance ty), + instance ty', Some cty, cty') end else (type_argument env sarg ty ty, ty', Some cty, cty') in @@ -3294,7 +3444,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let method_type = newvar () in let (obj_ty, res_ty) = filter_arrow env method_type Nolabel in unify env obj_ty desc.val_type; - unify env res_ty (instance env typ); + unify env res_ty (instance typ); let exp = Texp_apply({exp_desc = Texp_ident(Path.Pident method_id, lid, @@ -3333,7 +3483,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let typ = match repr typ with {desc = Tpoly (ty, [])} -> - instance env ty + instance ty | {desc = Tpoly (ty, tl); level = l} -> if !Clflags.principal && l <> generic_level then Location.prerr_warning loc @@ -3390,7 +3540,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = match desc.val_kind with Val_ivar (Mutable, cl_num) -> let newval = - type_expect env snewval (instance env desc.val_type) in + type_expect env snewval (mk_expected (instance desc.val_type)) + in let (path_self, _) = Env.lookup_value (Longident.Lident ("self-" ^ cl_num)) env in @@ -3436,7 +3587,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = let type_override (lab, snewval) = begin try let (id, _, _, ty) = Vars.find lab.txt !vars in - (Path.Pident id, lab, type_expect env snewval (instance env ty)) + (Path.Pident id, lab, + type_expect env snewval (mk_expected (instance ty))) with Not_found -> let vars = Vars.fold (fun var _ li -> var::li) !vars [] in @@ -3461,10 +3613,11 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = Ident.set_current_time ty.level; let context = Typetexp.narrow () in let modl = !type_module env smodl in + Mtype.lower_nongen ty.level modl.mod_type; let (id, new_env) = Env.enter_module name.txt modl.mod_type env in Ctype.init_def(Ident.current_time()); Typetexp.widen context; - let body = type_expect new_env sbody ty_expected in + let body = type_expect new_env sbody ty_expected_explained in (* go back to original level *) end_def (); (* Unification of body.exp_type with the fresh variable ty @@ -3488,7 +3641,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_env = env } | Pexp_letexception(cd, sbody) -> let (cd, newenv) = Typedecl.transl_exception env cd in - let body = type_expect newenv sbody ty_expected in + let body = type_expect newenv sbody ty_expected_explained in re { exp_desc = Texp_letexception(cd, body); exp_loc = loc; exp_extra = []; @@ -3497,11 +3650,12 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_env = env } | Pexp_assert (e) -> - let cond = type_expect env e Predef.type_bool in + let cond = type_expect env e + (mk_expected ~explanation:Assert_condition Predef.type_bool) in let exp_type = match cond.exp_desc with | Texp_construct(_, {cstr_name="false"}, _) -> - instance env ty_expected + instance ty_expected | _ -> instance_def Predef.type_unit in @@ -3515,12 +3669,13 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = | Pexp_lazy e -> let ty = newgenvar () in let to_unify = Predef.type_lazy_t ty in - unify_exp_types loc env to_unify ty_expected; - let arg = type_expect env e ty in + with_explanation (fun () -> + unify_exp_types loc env to_unify ty_expected); + let arg = type_expect env e (mk_expected ty) in re { exp_desc = Texp_lazy arg; exp_loc = loc; exp_extra = []; - exp_type = instance env ty_expected; + exp_type = instance ty_expected; exp_attributes = sexp.pexp_attributes; exp_env = env; } @@ -3547,12 +3702,13 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = generalize_structure ty end; if sty <> None then - unify_exp_types loc env (instance env ty) (instance env ty_expected); + with_explanation (fun () -> + unify_exp_types loc env (instance ty) (instance ty_expected)); let exp = match (expand_head env ty).desc with Tpoly (ty', []) -> - let exp = type_expect env sbody ty' in - { exp with exp_type = instance env ty } + let exp = type_expect env sbody (mk_expected ty') in + { exp with exp_type = instance ty } | Tpoly (ty', tl) -> (* One more level to generalize locally *) begin_def (); @@ -3562,10 +3718,10 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = end_def (); generalize_structure ty'' end; - let exp = type_expect env sbody ty'' in + let exp = type_expect env sbody (mk_expected ty'') in end_def (); check_univars env false "method" exp ty_expected vars; - { exp with exp_type = instance env ty } + { exp with exp_type = instance ty } | Tvar _ -> let exp = type_exp env sbody in let exp = {exp with exp_type = newty (Tpoly (exp.exp_type, []))} in @@ -3580,7 +3736,6 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = (* remember original level *) begin_def (); (* Create a fake abstract type declaration for name. *) - let level = get_current_level () in let decl = { type_params = []; type_arity = 0; @@ -3588,7 +3743,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = type_private = Public; type_manifest = None; type_variance = []; - type_newtype_level = Some (level, level); + type_is_newtype = true; + type_expansion_scope = None; type_loc = loc; type_attributes = []; type_immediate = false; @@ -3626,7 +3782,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = (Texp_newtype name, loc, sexp.pexp_attributes) :: body.exp_extra } | Pexp_pack m -> let (p, nl) = - match Ctype.expand_head env (instance env ty_expected) with + match Ctype.expand_head env (instance ty_expected) with {desc = Tpackage (p, nl, _tl)} -> if !Clflags.principal && (Ctype.expand_head env ty_expected).level < Btype.generic_level @@ -3648,7 +3804,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = exp_env = env } | Pexp_open (ovf, lid, e) -> let (path, newenv) = !type_open ovf env sexp.pexp_loc lid in - let exp = type_expect newenv e ty_expected in + let exp = type_expect newenv e ty_expected_explained in { exp with exp_extra = (Texp_open (ovf, path, lid, newenv), loc, sexp.pexp_attributes) :: @@ -3682,26 +3838,29 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected = | Pexp_unreachable -> re { exp_desc = Texp_unreachable; exp_loc = loc; exp_extra = []; - exp_type = instance env ty_expected; + exp_type = instance ty_expected; exp_attributes = sexp.pexp_attributes; exp_env = env } -and type_function ?in_function loc attrs env ty_expected l caselist = +and type_function ?in_function loc attrs env ty_expected_explained l caselist = + let { ty = ty_expected; explanation } = ty_expected_explained in let (loc_fun, ty_fun) = match in_function with Some p -> p - | None -> (loc, instance env ty_expected) + | None -> (loc, instance ty_expected) in let separate = !Clflags.principal || Env.has_local_constraints env in if separate then begin_def (); let (ty_arg, ty_res) = - try filter_arrow env (instance env ty_expected) l + try filter_arrow env (instance ty_expected) l with Unify _ -> match expand_head env ty_expected with {desc = Tarrow _} as ty -> - raise(Error(loc, env, Abstract_wrong_label(l, ty))) + raise(Error(loc, env, Abstract_wrong_label(l, ty, explanation))) | _ -> raise(Error(loc_fun, env, - Too_many_arguments (in_function <> None, ty_fun))) + Too_many_arguments (in_function <> None, + ty_fun, + explanation))) in let ty_arg = if is_optional l then @@ -3732,7 +3891,7 @@ and type_function ?in_function loc attrs env ty_expected l caselist = re { exp_desc = Texp_function { arg_label = l; param; cases; partial; }; exp_loc = loc; exp_extra = []; - exp_type = instance env (newgenty (Tarrow(l, ty_arg, ty_res, Cok))); + exp_type = instance (newgenty (Tarrow(l, ty_arg, ty_res, Cok))); exp_attributes = attrs; exp_env = env } @@ -3748,12 +3907,12 @@ and type_label_access env srecord lid = let opath = try let (p0, p,_) = extract_concrete_record env ty_exp in - Some(p0, p, ty_exp.level = generic_level || not !Clflags.principal) + Some(p0, p, (repr ty_exp).level = generic_level || not !Clflags.principal) with Not_found -> None in let labels = Typetexp.find_all_labels env lid.loc lid.txt in let label = - wrap_disambiguate "This expression has" ty_exp + wrap_disambiguate "This expression has" (mk_expected ty_exp) (Label.disambiguate lid env opath) labels in (record, label, opath) @@ -4022,7 +4181,7 @@ and type_label_exp create env loc ty_expected generalize_structure ty_res end; begin try - unify env (instance_def ty_res) (instance env ty_expected) + unify env (instance_def ty_res) (instance ty_expected) with Unify trace -> raise (Error(lid.loc, env, Label_mismatch(lid.txt, trace))) end; @@ -4040,7 +4199,7 @@ and type_label_exp create env loc ty_expected raise (Error(lid.loc, env, Private_label(lid.txt, ty_expected))); let arg = let snap = if vars = [] then None else Some (Btype.snapshot ()) in - let arg = type_argument env sarg ty_arg (instance env ty_arg) in + let arg = type_argument env sarg ty_arg (instance ty_arg) in end_def (); try check_univars env (vars <> []) "field value" arg label.lbl_arg vars; @@ -4058,7 +4217,7 @@ and type_label_exp create env loc ty_expected with Error (_, _, Less_general _) as e -> raise e | _ -> raise exn (* In case of failure return the first error *) in - (lid, label, {arg with exp_type = instance env arg.exp_type}) + (lid, label, {arg with exp_type = instance arg.exp_type}) and type_argument ?recarg env sarg ty_expected' ty_expected = (* ty_expected' may be generic *) @@ -4088,7 +4247,7 @@ and type_argument ?recarg env sarg ty_expected' ty_expected = let rec make_args args ty_fun = match (expand_head env ty_fun).desc with | Tarrow (l,ty_arg,ty_fun,_) when is_optional l -> - let ty = option_none (instance env ty_arg) sarg.pexp_loc in + let ty = option_none (instance ty_arg) sarg.pexp_loc in make_args ((l, Some ty) :: args) ty_fun | Tarrow (l,_,ty_res',_) when l = Nolabel || !Clflags.classic -> List.rev args, ty_fun, no_labels ty_res' @@ -4098,8 +4257,8 @@ and type_argument ?recarg env sarg ty_expected' ty_expected = let args, ty_fun', simple_res = make_args [] texp.exp_type in let warn = !Clflags.principal && (lv <> generic_level || (repr ty_fun').level <> generic_level) - and texp = {texp with exp_type = instance env texp.exp_type} - and ty_fun = instance env ty_fun' in + and texp = {texp with exp_type = instance texp.exp_type} + and ty_fun = instance ty_fun' in if not (simple_res || no_labels ty_res) then begin unify_exp env texp ty_expected; texp @@ -4149,7 +4308,7 @@ and type_argument ?recarg env sarg ty_expected' ty_expected = func let_var) } end | _ -> - let texp = type_expect ?recarg env sarg ty_expected' in + let texp = type_expect ?recarg env sarg (mk_expected ty_expected') in unify_exp env texp ty_expected; texp @@ -4174,7 +4333,7 @@ and type_application env funct sargs = (function l, None -> l, None | l, Some f -> l, Some (f ())) (List.rev args), - instance env (result_type omitted ty_fun)) + instance (result_type omitted ty_fun)) | (l1, sarg1) :: sargl -> let (ty1, ty2) = let ty_fun = expand_head env ty_fun in @@ -4211,7 +4370,7 @@ and type_application env funct sargs = in let optional = is_optional l1 in let arg1 () = - let arg1 = type_expect env sarg1 ty1 in + let arg1 = type_expect env sarg1 (mk_expected ty1) in if optional then unify_exp env arg1 (type_option(newvar())); arg1 @@ -4304,7 +4463,7 @@ and type_application env funct sargs = may_warn funct.exp_loc (Warnings.Without_principality "eliminated optional argument"); ignored := (l,ty,lv) :: !ignored; - Some (fun () -> option_none (instance env ty) Location.none) + Some (fun () -> option_none (instance ty) Location.none) end else begin may_warn funct.exp_loc (Warnings.Without_principality "commuted an argument"); @@ -4328,7 +4487,7 @@ and type_application env funct sargs = let is_ignore funct = match funct.exp_desc with Texp_ident (_, _, {val_kind=Val_prim{Primitive.prim_name="%ignore"}}) -> - (try ignore (filter_arrow env (instance env funct.exp_type) Nolabel); + (try ignore (filter_arrow env (instance funct.exp_type) Nolabel); true with Unify _ -> false) | _ -> false @@ -4337,9 +4496,9 @@ and type_application env funct sargs = (* Special case for ignore: avoid discarding warning *) [Nolabel, sarg] when is_ignore funct -> let ty_arg, ty_res = - filter_arrow env (instance env funct.exp_type) Nolabel + filter_arrow env (instance funct.exp_type) Nolabel in - let exp = type_expect env sarg ty_arg in + let exp = type_expect env sarg (mk_expected ty_arg) in begin match (expand_head env exp.exp_type).desc with | Tarrow _ -> Location.prerr_warning exp.exp_loc Warnings.Partial_application @@ -4351,11 +4510,12 @@ and type_application env funct sargs = | _ -> let ty = funct.exp_type in if ignore_labels then - type_args [] [] ty (instance env ty) ty [] sargs + type_args [] [] ty (instance ty) ty [] sargs else - type_args [] [] ty (instance env ty) ty sargs [] + type_args [] [] ty (instance ty) ty sargs [] -and type_construct env loc lid sarg ty_expected attrs = +and type_construct env loc lid sarg ty_expected_explained attrs = + let { ty = ty_expected; explanation } = ty_expected_explained in let opath = try let (p0, p,_) = extract_concrete_variant env ty_expected in @@ -4364,7 +4524,8 @@ and type_construct env loc lid sarg ty_expected attrs = in let constrs = Typetexp.find_all_constructors env lid.loc lid.txt in let constr = - wrap_disambiguate "This variant expression is expected to have" ty_expected + wrap_disambiguate "This variant expression is expected to have" + ty_expected_explained (Constructor.disambiguate lid env opath) constrs in Env.mark_constructor Env.Positive env (Longident.last lid.txt) constr; Builtin_attributes.check_deprecated loc constr.cstr_attributes @@ -4392,19 +4553,20 @@ and type_construct env loc lid sarg ty_expected attrs = if separate then begin end_def (); generalize_structure ty_res; - unify_exp env {texp with exp_type = instance_def ty_res} - (instance env ty_expected); + with_explanation explanation (fun () -> + unify_exp env {texp with exp_type = instance_def ty_res} + (instance ty_expected)); end_def (); List.iter generalize_structure ty_args; generalize_structure ty_res; end; let ty_args0, ty_res = - match instance_list env (ty_res :: ty_args) with + match instance_list (ty_res :: ty_args) with t :: tl -> tl, t | _ -> assert false in let texp = {texp with exp_type = ty_res} in - if not separate then unify_exp env texp (instance env ty_expected); + if not separate then unify_exp env texp (instance ty_expected); let recarg = match constr.cstr_inlined with | None -> Rejected @@ -4429,7 +4591,7 @@ and type_construct env loc lid sarg ty_expected attrs = (* Typing of statements (expressions whose values are discarded) *) -and type_statement env sexp = +and type_statement ?explanation env sexp = let loc = (final_subexpression sexp).pexp_loc in begin_def(); let exp = type_exp env sexp in @@ -4439,7 +4601,8 @@ and type_statement env sexp = Location.prerr_warning loc Warnings.Nonreturning_statement; if !Clflags.strict_sequence then let expected_ty = instance_def Predef.type_unit in - unify_exp env exp expected_ty; + with_explanation explanation (fun () -> + unify_exp env exp expected_ty); exp else begin begin match ty.desc with @@ -4456,19 +4619,22 @@ and type_statement env sexp = end (* Typing of match cases *) +and check_scope_escape loc env level ty = + try Ctype.check_scope_escape level ty + with Unify trace -> + raise(Error(loc, env, Pattern_type_clash(trace))) and type_cases ?in_function env ty_arg ty_res partial_flag loc caselist = (* ty_arg is _fully_ generalized *) let patterns = List.map (fun {pc_lhs=p} -> p) caselist in let contains_polyvars = List.exists contains_polymorphic_variant patterns in - let erase_either = contains_polyvars && contains_variant_either ty_arg - and has_gadts = List.exists (contains_gadt env) patterns in -(* prerr_endline ( if has_gadts then "contains gadt" else "no gadt"); *) + let erase_either = contains_polyvars && contains_variant_either ty_arg in + let may_contain_gadts = List.exists may_contain_gadts patterns in let ty_arg = - if (has_gadts || erase_either) && not !Clflags.principal + if (may_contain_gadts || erase_either) && not !Clflags.principal then correct_levels ty_arg else ty_arg and ty_res, env = - if has_gadts && not !Clflags.principal then + if may_contain_gadts && not !Clflags.principal then correct_levels ty_res, duplicate_ident_types caselist env else ty_res, env in @@ -4483,25 +4649,28 @@ and type_cases ?in_function env ty_arg ty_res partial_flag loc caselist = | [{pc_lhs}] when is_var pc_lhs -> false | _ -> true in + let outer_level = get_current_level () in let init_env () = (* raise level for existentials *) begin_def (); Ident.set_current_time (get_current_level ()); let lev = Ident.current_time () in - Ctype.init_def (lev+1000); (* up to 1000 existentials *) - (lev, Env.add_gadt_instance_level lev env) + Ctype.init_def (lev+100000); (* up to 1000 existentials *) + lev in - let lev, env = - if has_gadts then init_env () else (get_current_level (), env) + let lev = + if may_contain_gadts then init_env () else get_current_level () in -(* if has_gadts then - Format.printf "lev = %d@.%a@." lev Printtyp.raw_type_expr ty_res; *) (* Do we need to propagate polymorphism *) let propagate = - !Clflags.principal || has_gadts || (repr ty_arg).level = generic_level || + !Clflags.principal || may_contain_gadts || (repr ty_arg).level = generic_level || match caselist with [{pc_lhs}] when is_var pc_lhs -> false | _ -> true in + let take_partial_instance = + if !Clflags.principal || erase_either + then Some false else None + in if propagate then begin_def (); (* propagation of the argument *) let pattern_force = ref [] in (* Format.printf "@[%i %i@ %a@]@." lev (get_current_level()) @@ -4517,31 +4686,36 @@ and type_cases ?in_function env ty_arg ty_res partial_flag loc caselist = in if !Clflags.principal then begin_def (); (* propagation of pattern *) let scope = Some (Annot.Idef loc) in + begin_def (); + let ty_arg = instance ?partial:take_partial_instance ty_arg in + end_def (); + generalize_structure ty_arg; + let expected_ty_arg = instance ty_arg in let (pat, ext_env, force, unpacks) = - let partial = - if !Clflags.principal || erase_either - then Some false else None in - let ty_arg = instance ?partial env ty_arg in - type_pattern ~lev env pc_lhs scope ty_arg + type_pattern ~lev env pc_lhs scope expected_ty_arg in pattern_force := force @ !pattern_force; let pat = if !Clflags.principal then begin end_def (); iter_pattern (fun {pat_type=t} -> generalize_structure t) pat; - { pat with pat_type = instance ext_env pat.pat_type } + { pat with pat_type = instance pat.pat_type } end else pat in - (pat, (ext_env, unpacks))) + (* Ensure that no ambivalent pattern type escapes its branch *) + check_scope_escape pat.pat_loc env outer_level ty_arg; + (pat, ty_arg, (ext_env, unpacks))) caselist in (* Unify all cases (delayed to keep it order-free) *) let ty_arg' = newvar () in let unify_pats ty = - List.iter (fun (pat, (ext_env, _)) -> unify_pat ext_env pat ty) - pat_env_list in + List.iter (fun (pat, pat_ty, _) -> + unify_pat_types pat.pat_loc env pat_ty ty + ) pat_env_list + in unify_pats ty_arg'; (* Check for polymorphic variants to close *) - let patl = List.map fst pat_env_list in + let patl = List.map (fun (pat, _, _) -> pat) pat_env_list in if List.exists has_variants patl then begin Parmatch.pressure_variants env patl; List.iter (iter_pattern finalize_variant) patl @@ -4549,27 +4723,28 @@ and type_cases ?in_function env ty_arg ty_res partial_flag loc caselist = (* `Contaminating' unifications start here *) List.iter (fun f -> f()) !pattern_force; (* Post-processing and generalization *) - if propagate || erase_either then unify_pats (instance env ty_arg); + if take_partial_instance <> None then unify_pats (instance ty_arg); if propagate then begin List.iter (iter_pattern (fun {pat_type=t} -> unify_var env t (newvar()))) patl; end_def (); + generalize ty_arg'; List.iter (iter_pattern (fun {pat_type=t} -> generalize t)) patl; end; (* type bodies *) let in_function = if List.length caselist = 1 then in_function else None in let cases = List.map2 - (fun (pat, (ext_env, unpacks)) {pc_lhs; pc_guard; pc_rhs} -> + (fun (pat, _, (ext_env, unpacks)) {pc_lhs = _; pc_guard; pc_rhs} -> let sexp = wrap_unpacks pc_rhs unpacks in let ty_res' = if !Clflags.principal then begin begin_def (); - let ty = instance ~partial:true env ty_res in + let ty = instance ~partial:true ty_res in end_def (); generalize_structure ty; ty end - else if contains_gadt env pc_lhs then correct_levels ty_res + else if contains_gadt pat then correct_levels ty_res else ty_res in (* Format.printf "@[%i %i, ty_res' =@ %a@]@." lev (get_current_level()) Printtyp.raw_type_expr ty_res'; *) @@ -4579,51 +4754,58 @@ and type_cases ?in_function env ty_arg ty_res partial_flag loc caselist = | Some scond -> Some (type_expect ext_env (wrap_unpacks scond unpacks) - Predef.type_bool) + (mk_expected Predef.type_bool)) in - let exp = type_expect ?in_function ext_env sexp ty_res' in + let exp = + type_expect ?in_function ext_env sexp (mk_expected ty_res') in { c_lhs = pat; c_guard = guard; - c_rhs = {exp with exp_type = instance env ty_res'} + c_rhs = {exp with exp_type = instance ty_res'} } ) pat_env_list caselist in - if !Clflags.principal || has_gadts then begin - let ty_res' = instance env ty_res in + if !Clflags.principal || may_contain_gadts then begin + let ty_res' = instance ty_res in List.iter (fun c -> unify_exp env c.c_rhs ty_res') cases end; - let do_init = has_gadts || needs_exhaust_check in - let lev, env = - if do_init && not has_gadts then init_env () else lev, env in + (* We could check whether there actually is a GADT here instead of reusing + [has_constructor], but I'm not sure it's worth it. *) + let do_init = may_contain_gadts || needs_exhaust_check in + let lev = + if do_init && not may_contain_gadts then init_env () else lev in let ty_arg_check = if do_init then (* Hack: use for_saving to copy variables too *) - Subst.type_expr (Subst.for_saving Subst.identity) ty_arg - else ty_arg + Subst.type_expr (Subst.for_saving Subst.identity) ty_arg' + else ty_arg' in let partial = if partial_flag then - check_partial ~lev env ty_arg_check loc cases + check_partial ~lev env (instance ty_arg_check) loc cases else Partial in - let unused_check () = - List.iter (fun (pat, (env, _)) -> check_absent_variant env pat) + let unused_check do_init = + let lev = + if do_init then init_env () else get_current_level () + in + List.iter (fun (pat, _, (env, _)) -> check_absent_variant env pat) pat_env_list; - check_unused ~lev env (instance env ty_arg_check) cases ; + check_unused ~lev env (instance ty_arg_check) cases ; + if do_init then end_def (); Parmatch.check_ambiguous_bindings cases in if contains_polyvars || do_init then - add_delayed_check unused_check + add_delayed_check (fun () -> unused_check do_init) else - unused_check (); + unused_check false; (* Check for unused cases, do not delay because of gadts *) if do_init then begin end_def (); (* Ensure that existential types do not escape *) - unify_exp_types loc env (instance env ty_res) (newvar ()) ; + unify_exp_types loc env (instance ty_res) (newvar ()) ; end; cases, partial @@ -4694,7 +4876,7 @@ and type_let ?(check = fun s -> Warnings.Unused_var s) List.map (fun pat -> iter_pattern (fun pat -> generalize_structure pat.pat_type) pat; - {pat with pat_type = instance env pat.pat_type}) + {pat with pat_type = instance pat.pat_type}) pat_list end else pat_list in (* Only bind pattern variables after generalizing *) @@ -4758,7 +4940,7 @@ and type_let ?(check = fun s -> Warnings.Unused_var s) slot := (name, vd) :: !slot; rec_needed := true | None -> List.iter - (fun (name, vd) -> Env.mark_value_used env name vd) + (fun (name, vd) -> Env.mark_value_used name vd) (get_ref slot); used := true; some_used := true @@ -4787,14 +4969,14 @@ and type_let ?(check = fun s -> Warnings.Unused_var s) end; let exp = Builtin_attributes.warning_scope pvb_attributes - (fun () -> type_expect exp_env sexp ty') + (fun () -> type_expect exp_env sexp (mk_expected ty')) in end_def (); check_univars env true "definition" exp pat.pat_type vars; - {exp with exp_type = instance env exp.exp_type} + {exp with exp_type = instance exp.exp_type} | _ -> Builtin_attributes.warning_scope pvb_attributes (fun () -> - type_expect exp_env sexp pat.pat_type)) + type_expect exp_env sexp (mk_expected pat.pat_type))) spat_sexp_list pat_slot_list in current_slot := None; if is_recursive && not !rec_needed @@ -4835,7 +5017,7 @@ and type_let ?(check = fun s -> Warnings.Unused_var s) l spat_sexp_list in if is_recursive then - List.iter + List.iter (fun {vb_pat=pat} -> match pat.pat_desc with Tpat_var _ -> () | Tpat_alias ({pat_desc=Tpat_any}, _, _) -> () @@ -4889,6 +5071,34 @@ let spellcheck_idents ppf unbound valid_idents = open Format open Printtyp +let report_type_expected_explanation expl ppf = + match expl with + | If_conditional -> + fprintf ppf "the condition of an if-statement" + | If_no_else_branch -> + fprintf ppf "the result of a conditional with no else branch" + | While_loop_conditional -> + fprintf ppf "the condition of a while-loop" + | While_loop_body -> + fprintf ppf "the body of a while-loop" + | For_loop_start_index -> + fprintf ppf "a for-loop start index" + | For_loop_stop_index -> + fprintf ppf "a for-loop stop index" + | For_loop_body -> + fprintf ppf "the body of a for-loop" + | Assert_condition -> + fprintf ppf "the condition of an assertion" + | Sequence_left_hand_side -> + fprintf ppf "the left-hand side of a sequence" + +let report_type_expected_explanation_opt expl ppf = + match expl with + | None -> () + | Some expl -> + fprintf ppf "@ because it is in %t" + (report_type_expected_explanation expl) + let report_error env ppf = function | Polymorphic_label lid -> fprintf ppf "@[The record field %a is polymorphic.@ %s@]" @@ -4924,8 +5134,10 @@ let report_error env ppf = function fprintf ppf "Variable %s must occur on both sides of this | pattern" (Ident.name id); spellcheck_idents ppf id valid_idents - | Expr_type_clash trace -> + | Expr_type_clash (trace, explanation) -> report_unification_error ppf env trace + ~type_expected_explanation: + (report_type_expected_explanation_opt explanation) (function ppf -> fprintf ppf "This expression has type") (function ppf -> @@ -4963,7 +5175,8 @@ let report_error env ppf = function print_labels labels | Label_not_mutable lid -> fprintf ppf "The record field %a is not mutable" longident lid - | Wrong_name (eorp, ty, kind, p, name, valid_names) -> + | Wrong_name (eorp, ty_expected, kind, p, name, valid_names) -> + let { ty; explanation } = ty_expected in reset_and_mark_loops ty; if Path.is_constructor_typath p then begin fprintf ppf "@[The field %s is not part of the record \ @@ -4971,8 +5184,9 @@ let report_error env ppf = function name path p; end else begin - fprintf ppf "@[@[<2>%s type@ %a@]@ " - eorp type_expr ty; + fprintf ppf "@[@[<2>%s type@ %a%t@]@ " + eorp type_expr ty + (report_type_expected_explanation_opt explanation); fprintf ppf "The %s %s does not belong to type %a@]" (label_of_kind kind) name (*kind*) path p; @@ -5031,28 +5245,33 @@ let report_error env ppf = function (function ppf -> fprintf ppf "but is here used with type"); if b then - fprintf ppf ".@.@[%s@ %s@]" + fprintf ppf ".@.@[%s@ %s@ %s@]" "This simple coercion was not fully general." - "Consider using a double coercion." - | Too_many_arguments (in_function, ty) -> + "Hint: Consider using a fully explicit coercion" + "of the form: `(foo : ty1 :> ty2)'." + | Too_many_arguments (in_function, ty, explanation) -> reset_and_mark_loops ty; if in_function then begin fprintf ppf "This function expects too many arguments,@ "; - fprintf ppf "it should have type@ %a" + fprintf ppf "it should have type@ %a%t" type_expr ty + (report_type_expected_explanation_opt explanation) end else begin fprintf ppf "This expression should not be a function,@ "; - fprintf ppf "the expected type is@ %a" + fprintf ppf "the expected type is@ %a%t" type_expr ty + (report_type_expected_explanation_opt explanation) end - | Abstract_wrong_label (l, ty) -> + | Abstract_wrong_label (l, ty, explanation) -> let label_mark = function | Nolabel -> "but its first argument is not labelled" | l -> sprintf "but its first argument is labelled %s" (prefixed_label_name l) in reset_and_mark_loops ty; - fprintf ppf "@[@[<2>This function should have type@ %a@]@,%s@]" - type_expr ty (label_mark l) + fprintf ppf "@[@[<2>This function should have type@ %a%t@]@,%s@]" + type_expr ty + (report_type_expected_explanation_opt explanation) + (label_mark l) | Scoping_let_module(id, ty) -> reset_and_mark_loops ty; fprintf ppf @@ -5097,10 +5316,6 @@ let report_error env ppf = function | Unexpected_existential -> fprintf ppf "Unexpected existential" - | Unqualified_gadt_pattern (tpath, name) -> - fprintf ppf "@[The GADT constructor %s of type %a@ %s.@]" - name path tpath - "must be qualified in this pattern" | Invalid_interval -> fprintf ppf "@[Only character intervals are supported in patterns.@]" | Invalid_for_loop_index -> @@ -5124,7 +5339,7 @@ let report_error env ppf = function "@[%s@ %s@ %a@]" "This match case could not be refuted." "Here is an example of a value that would reach it:" - Parmatch.top_pretty pat + Printpat.top_pretty pat | Invalid_extension_constructor_payload -> fprintf ppf "Invalid [%%extension_constructor] payload, a constructor is expected." @@ -5144,9 +5359,10 @@ let report_error env ppf = function "This kind of expression is not allowed as right-hand side of `let rec'" | Illegal_class_expr -> fprintf ppf "This kind of recursive class expression is not allowed" + | Empty_pattern -> assert false let report_error env ppf err = - wrap_printing_env env (fun () -> report_error env ppf err) + wrap_printing_env ~error:true env (fun () -> report_error env ppf err) let () = Location.register_error_of_exn diff --git a/typing/typecore.mli b/typing/typecore.mli index 42f125c1..30a0854a 100644 --- a/typing/typecore.mli +++ b/typing/typecore.mli @@ -19,6 +19,40 @@ open Asttypes open Types open Format +(* This variant is used to print improved error messages, and does not affect + the behavior of the typechecker itself. + + It describes possible explanation for types enforced by a keyword of the + language; e.g. "if" requires the condition to be of type bool, and the + then-branch to be of type unit if there is no else branch; "for" requires + indices to be of type int, and the body to be of type unit. +*) +type type_forcing_context = + | If_conditional + | If_no_else_branch + | While_loop_conditional + | While_loop_body + | For_loop_start_index + | For_loop_stop_index + | For_loop_body + | Assert_condition + | Sequence_left_hand_side + +(* The combination of a type and a "type forcing context". The intent is that it + describes a type that is "expected" (required) by the context. If unifying + with such a type fails, then the "explanation" field explains why it was + required, in order to display a more enlightening error message. +*) +type type_expected = private { + ty: type_expr; + explanation: type_forcing_context option; +} + +val mk_expected: + ?explanation:type_forcing_context -> + type_expr -> + type_expected + val is_nonexpansive: Typedtree.expression -> bool val type_binding: @@ -49,7 +83,7 @@ val check_partial: Location.t -> Typedtree.case list -> Typedtree.partial val type_expect: ?in_function:(Location.t * type_expr) -> - Env.t -> Parsetree.expression -> type_expr -> Typedtree.expression + Env.t -> Parsetree.expression -> type_expected -> Typedtree.expression val type_exp: Env.t -> Parsetree.expression -> Typedtree.expression val type_approx: @@ -78,13 +112,13 @@ type error = | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string | Orpat_vars of Ident.t * Ident.t list - | Expr_type_clash of (type_expr * type_expr) list + | Expr_type_clash of (type_expr * type_expr) list * type_forcing_context option | Apply_non_function of type_expr | Apply_wrong_label of arg_label * type_expr | Label_multiply_defined of string | Label_missing of Ident.t list | Label_not_mutable of Longident.t - | Wrong_name of string * type_expr * string * Path.t * string * string list + | Wrong_name of string * type_expected * string * Path.t * string * string list | Name_type_mismatch of string * Longident.t * (Path.t * Path.t) * (Path.t * Path.t) list | Invalid_format of string @@ -100,8 +134,8 @@ type error = | Value_multiply_overridden of string | Coercion_failure of type_expr * type_expr * (type_expr * type_expr) list * bool - | Too_many_arguments of bool * type_expr - | Abstract_wrong_label of arg_label * type_expr + | Too_many_arguments of bool * type_expr * type_forcing_context option + | Abstract_wrong_label of arg_label * type_expr * type_forcing_context option | Scoping_let_module of string * type_expr | Masked_instance_variable of Longident.t | Not_a_variant_type of Longident.t @@ -112,7 +146,6 @@ type error = | Not_a_packed_module of type_expr | Recursive_local_constraint of (type_expr * type_expr) list | Unexpected_existential - | Unqualified_gadt_pattern of Path.t * string | Invalid_interval | Invalid_for_loop_index | No_value_clauses @@ -127,6 +160,7 @@ type error = | Illegal_letrec_pat | Illegal_letrec_expr | Illegal_class_expr + | Empty_pattern exception Error of Location.t * Env.t * error exception Error_forward of Location.error diff --git a/typing/typedecl.ml b/typing/typedecl.ml index 2369b84c..5e4b9d5a 100644 --- a/typing/typedecl.ml +++ b/typing/typedecl.ml @@ -104,7 +104,8 @@ let enter_type rec_flag env sdecl id = begin match sdecl.ptype_manifest with None -> None | Some _ -> Some(Ctype.newvar ()) end; type_variance = List.map (fun _ -> Variance.full) sdecl.ptype_params; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; @@ -132,14 +133,17 @@ let rec get_unboxed_type_representation env ty fuel = | Tconstr (p, args, _) -> begin match Env.find_type p env with | exception Not_found -> Some ty + | {type_immediate = true; _} -> Some Predef.type_int | {type_unboxed = {unboxed = false}} -> Some ty | {type_params; type_kind = Type_record ([{ld_type = ty2; _}], _) | Type_variant [{cd_args = Cstr_tuple [ty2]; _}] | Type_variant [{cd_args = Cstr_record [{ld_type = ty2; _}]; _}]} - -> get_unboxed_type_representation env - (Ctype.apply env type_params ty2 args) (fuel - 1) + -> + let ty2 = match ty2.desc with Tpoly (t, _) -> t | _ -> ty2 in + get_unboxed_type_representation env + (Ctype.apply env type_params ty2 args) (fuel - 1) | {type_kind=Type_abstract} -> None (* This case can occur when checking a recursive unboxed type declaration. *) @@ -425,7 +429,6 @@ let transl_declaration env sdecl id = match sdecl.ptype_kind with | Ptype_abstract -> Ttype_abstract, Type_abstract | Ptype_variant scstrs -> - assert (scstrs <> []); if List.exists (fun cstr -> cstr.pcd_res <> None) scstrs then begin match cstrs with [] -> () @@ -515,7 +518,8 @@ let transl_declaration env sdecl id = type_private = sdecl.ptype_private; type_manifest = man; type_variance = List.map (fun _ -> Variance.full) params; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; @@ -683,6 +687,7 @@ let check_coherence env loc id decl = then [Includecore.Constraint] else Includecore.type_declarations ~loc ~equality:true env + ~mark:true (Path.last path) decl' id @@ -1306,7 +1311,7 @@ let transl_type_decl env rec_flag sdecl_list = match !current_slot with | Some slot -> slot := (name, td) :: !slot | None -> - List.iter (fun (name, d) -> Env.mark_type_used env name d) + List.iter (fun (name, d) -> Env.mark_type_used name d) (get_ref slot); old_callback () ); @@ -1424,7 +1429,7 @@ let transl_extension_constructor env type_path type_params let (args, cstr_res) = Ctype.instance_constructor cdescr in let res, ret_type = if cdescr.cstr_generalized then - let params = Ctype.instance_list env type_params in + let params = Ctype.instance_list type_params in let res = Ctype.newconstr type_path params in let ret_type = Some (Ctype.newconstr type_path params) in res, ret_type @@ -1573,7 +1578,7 @@ let transl_type_extension extend env loc styext = let ttype_params = make_params env styext.ptyext_params in let type_params = List.map (fun (cty, _) -> cty.ctyp_type) ttype_params in List.iter2 (Ctype.unify_var env) - (Ctype.instance_list env type_decl.type_params) + (Ctype.instance_list type_decl.type_params) type_params; let constructors = List.map (transl_extension_constructor env type_path @@ -1795,7 +1800,7 @@ let transl_value_decl env loc valdecl = (* Translate a "with" constraint -- much simplified version of transl_type_decl. *) let transl_with_constraint env id row_path orig_decl sdecl = - Env.mark_type_used env (Ident.name id) orig_decl; + Env.mark_type_used (Ident.name id) orig_decl; reset_type_variables(); Ctype.begin_def(); let tparams = make_params env sdecl.ptype_params in @@ -1845,7 +1850,8 @@ let transl_with_constraint env id row_path orig_decl sdecl = type_private = priv; type_manifest = man; type_variance = []; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = sdecl.ptype_loc; type_attributes = sdecl.ptype_attributes; type_immediate = false; @@ -1893,7 +1899,8 @@ let abstract_type_decl arity = type_private = Public; type_manifest = None; type_variance = replicate_list Variance.full arity; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_loc = Location.none; type_attributes = []; type_immediate = false; diff --git a/typing/typemod.ml b/typing/typemod.ml index 84fc6490..1812e089 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -94,6 +94,38 @@ let type_open_ ?used_slot ?toplevel ovf env loc lid = ignore (extract_sig_open env lid.loc md.md_type); assert false +let type_initially_opened_module env module_name = + let loc = Location.in_file "compiler internals" in + let lid = { Asttypes.loc; txt = Longident.Lident module_name } in + let path = Typetexp.lookup_module ~load:true env lid.loc lid.txt in + match Env.open_signature_of_initially_opened_module path env with + | Some env -> path, env + | None -> + let md = Env.find_module path env in + ignore (extract_sig_open env lid.loc md.md_type); + assert false + +let initial_env ~loc ~safe_string ~initially_opened_module + ~open_implicit_modules = + let env = + if safe_string then + Env.initial_safe_string + else + Env.initial_unsafe_string + in + let env = + match initially_opened_module with + | None -> env + | Some name -> + snd (type_initially_opened_module env name) + in + let open_implicit_module env m = + let open Asttypes in + let lid = {loc; txt = Longident.parse m } in + snd (type_open_ Override env lid.loc lid) + in + List.fold_left open_implicit_module env open_implicit_modules + let type_open ?toplevel env sod = let (path, newenv) = Builtin_attributes.warning_scope sod.popen_attributes @@ -214,9 +246,7 @@ let retype_applicative_functor_type ~loc env funct arg = | Mty_functor (_, Some mty_param, _) -> mty_param | _ -> assert false (* could trigger due to MPR#7611 *) in - let aliasable = not (Env.is_functor_arg arg env) in - ignore(Includemod.modtypes ~loc env - (Mtype.strengthen ~aliasable env mty_arg arg) mty_param) + Includemod.check_modtype_inclusion ~loc env mty_arg arg mty_param (* When doing a deep destructive substitution with type M.N.t := .., we change M and M.N and so we have to check that uses of the modules other than just @@ -290,7 +320,7 @@ let params_are_constrained = loop ;; -let merge_constraint initial_env loc sg constr = +let merge_constraint initial_env remove_aliases loc sg constr = let lid = match constr with | Pwith_type (lid, _) | Pwith_module (lid, _) @@ -329,7 +359,8 @@ let merge_constraint initial_env loc sg constr = ) sdecl.ptype_params; type_loc = sdecl.ptype_loc; - type_newtype_level = None; + type_is_newtype = false; + type_expansion_scope = None; type_attributes = []; type_immediate = false; type_unboxed = unboxed_false_default_false; @@ -369,7 +400,9 @@ let merge_constraint initial_env loc sg constr = | (Sig_module(id, md, rs) :: rem, [s], Pwith_module (_, lid')) when Ident.name id = s -> let path, md' = Typetexp.find_module initial_env loc lid'.txt in - let md'' = {md' with md_type = Mtype.remove_aliases env md'.md_type} in + let mty = md'.md_type in + let mty = Mtype.scrape_for_type_of ~remove_aliases env mty in + let md'' = { md' with md_type = mty } in let newmd = Mtype.strengthen_decl ~aliasable:false env md'' path in ignore(Includemod.modtypes ~loc env newmd.md_type md.md_type); (Pident id, lid, Twith_module (path, lid')), @@ -377,7 +410,8 @@ let merge_constraint initial_env loc sg constr = | (Sig_module(id, md, rs) :: rem, [s], Pwith_modsubst (_, lid')) when Ident.name id = s -> let path, md' = Typetexp.find_module initial_env loc lid'.txt in - let newmd = Mtype.strengthen_decl ~aliasable:false env md' path in + let aliasable = not (Env.is_functor_arg path env) in + let newmd = Mtype.strengthen_decl ~aliasable env md' path in ignore(Includemod.modtypes ~loc env newmd.md_type md.md_type); real_ids := [Pident id]; (Pident id, lid, Twith_modsubst (path, lid')), @@ -673,6 +707,15 @@ let simplify_signature sg = let (sg, _) = aux sg in sg +let has_remove_aliases_attribute attr = + let remove_aliases = + Attr_helper.get_no_payload_attribute + ["remove_aliases"; "ocaml.remove_aliases"] attr + in + match remove_aliases with + | None -> false + | Some _ -> true + (* Check and translate a module type expression *) let transl_modtype_longident loc env lid = @@ -732,10 +775,12 @@ and transl_modtype_aux env smty = | Pmty_with(sbody, constraints) -> let body = transl_modtype env sbody in let init_sg = extract_sig env sbody.pmty_loc body.mty_type in + let remove_aliases = has_remove_aliases_attribute smty.pmty_attributes in let (rev_tcstrs, final_sg) = List.fold_left (fun (rev_tcstrs,sg) sdecl -> - let (tcstr, sg) = merge_constraint env smty.pmty_loc sg sdecl + let (tcstr, sg) = + merge_constraint env remove_aliases smty.pmty_loc sg sdecl in (tcstr :: rev_tcstrs, sg) ) @@ -1082,7 +1127,7 @@ let enrich_type_decls anchor decls oldenv newenv = let id = info.typ_id in let info' = Mtype.enrich_typedecl oldenv (Pdot(p, Ident.name id, nopos)) - info.typ_type + id info.typ_type in Env.add_type ~check:true id info' e) oldenv decls @@ -1233,10 +1278,11 @@ let package_subtype env p1 nl1 tl1 p2 nl2 tl2 = let () = Ctype.package_subtype := package_subtype -let wrap_constraint env arg mty explicit = +let wrap_constraint env mark arg mty explicit = + let mark = if mark then Includemod.Mark_both else Includemod.Mark_neither in let coercion = try - Includemod.modtypes ~loc:arg.mod_loc env arg.mod_type mty + Includemod.modtypes ~loc:arg.mod_loc env ~mark arg.mod_type mty with Includemod.Error msg -> raise(Error(arg.mod_loc, env, Not_included msg)) in { mod_desc = Tmod_constraint(arg, mty, explicit, coercion); @@ -1294,7 +1340,7 @@ and type_module_aux ~alias sttn funct_body anchor env smod = in let sg' = simplify_signature sg in if List.length sg' = List.length sg then md else - wrap_constraint (Env.implicit_coercion env) md (Mty_signature sg') + wrap_constraint env false md (Mty_signature sg') Tmodtype_implicit | Pmod_functor(name, smty, sbody) -> let mty = may_map (transl_modtype env) smty in @@ -1357,7 +1403,10 @@ and type_module_aux ~alias sttn funct_body anchor env smod = | Pmod_constraint(sarg, smty) -> let arg = type_module ~alias true funct_body anchor env sarg in let mty = transl_modtype env smty in - rm {(wrap_constraint env arg mty.mty_type (Tmodtype_explicit mty)) with + let md = + wrap_constraint env true arg mty.mty_type (Tmodtype_explicit mty) + in + rm { md with mod_loc = smod.pmod_loc; mod_attributes = smod.pmod_attributes; } @@ -1702,19 +1751,20 @@ and normalize_signature_item env = function (* Extract the module type of a module expression *) let type_module_type_of env smod = + let remove_aliases = has_remove_aliases_attribute smod.pmod_attributes in let tmty = match smod.pmod_desc with | Pmod_ident lid -> (* turn off strengthening in this case *) let path, md = Typetexp.find_module env smod.pmod_loc lid.txt in - rm { mod_desc = Tmod_ident (path, lid); - mod_type = md.md_type; - mod_env = env; - mod_attributes = smod.pmod_attributes; - mod_loc = smod.pmod_loc } - | _ -> type_module env smod in + rm { mod_desc = Tmod_ident (path, lid); + mod_type = md.md_type; + mod_env = env; + mod_attributes = smod.pmod_attributes; + mod_loc = smod.pmod_loc } + | _ -> type_module env smod + in let mty = tmty.mod_type in - (* PR#6307: expand aliases at root and submodules *) - let mty = Mtype.remove_aliases env mty in + let mty = Mtype.scrape_for_type_of ~remove_aliases env mty in (* PR#5036: must not contain non-generalized type variables *) if not (closed_modtype env mty) then raise(Error(smod.pmod_loc, env, Non_generalizable_module mty)); @@ -1755,7 +1805,7 @@ let type_package env m p nl = (* go back to original level *) Ctype.end_def (); if nl = [] then - (wrap_constraint env modl (Mty_ident p) Tmodtype_implicit, []) + (wrap_constraint env true modl (Mty_ident p) Tmodtype_implicit, []) else let mty = modtype_of_package env modl.mod_loc p nl tl' in List.iter2 (fun n ty -> @@ -1763,7 +1813,7 @@ let type_package env m p nl = with Ctype.Unify _ -> raise (Error(m.pmod_loc, env, Scoping_pack (n,ty)))) nl tl'; - (wrap_constraint env modl mty Tmodtype_implicit, tl') + (wrap_constraint env true modl mty Tmodtype_implicit, tl') (* Fill in the forward declarations *) let () = @@ -1789,7 +1839,7 @@ let type_implementation sourcefile outputprefix modulename initial_env ast = let simple_sg = simplify_signature sg in if !Clflags.print_types then begin Typecore.force_delayed_checks (); - Printtyp.wrap_printing_env initial_env + Printtyp.wrap_printing_env ~error:false initial_env (fun () -> fprintf std_formatter "%a@." Printtyp.signature simple_sg); (str, Tcoerce_none) (* result is ignored by Compile.implementation *) end else begin @@ -1804,7 +1854,9 @@ let type_implementation sourcefile outputprefix modulename initial_env ast = Interface_not_compiled sourceintf)) in let dclsig = Env.read_signature modulename intf_file in let coercion = - Includemod.compunit initial_env sourcefile sg intf_file dclsig in + Includemod.compunit initial_env ~mark:Includemod.Mark_positive + sourcefile sg intf_file dclsig + in Typecore.force_delayed_checks (); (* It is important to run these checks after the inclusion test above, so that value declarations which are not used internally but exported @@ -1814,8 +1866,9 @@ let type_implementation sourcefile outputprefix modulename initial_env ast = (str, coercion) end else begin let coercion = - Includemod.compunit initial_env sourcefile sg - "(inferred signature)" simple_sg in + Includemod.compunit initial_env ~mark:Includemod.Mark_positive + sourcefile sg "(inferred signature)" simple_sg + in check_nongen_schemes finalenv simple_sg; normalize_signature finalenv simple_sg; Typecore.force_delayed_checks (); @@ -2022,7 +2075,7 @@ let report_error ppf = function path p let report_error env ppf err = - Printtyp.wrap_printing_env env (fun () -> report_error ppf err) + Printtyp.wrap_printing_env ~error:true env (fun () -> report_error ppf err) let () = Location.register_error_of_exn diff --git a/typing/typemod.mli b/typing/typemod.mli index fb767db2..68d2103e 100644 --- a/typing/typemod.mli +++ b/typing/typemod.mli @@ -36,7 +36,8 @@ val transl_signature: val check_nongen_schemes: Env.t -> Types.signature -> unit val type_open_: - ?used_slot:bool ref -> ?toplevel:bool -> Asttypes.override_flag -> + ?used_slot:bool ref -> ?toplevel:bool -> + Asttypes.override_flag -> Env.t -> Location.t -> Longident.t Asttypes.loc -> Path.t * Env.t val modtype_of_package: Env.t -> Location.t -> @@ -52,6 +53,12 @@ val save_signature: val package_units: Env.t -> string list -> string -> string -> Typedtree.module_coercion +(* Should be in Envaux, but it breaks the build of the debugger *) +val initial_env: + loc:Location.t -> safe_string:bool -> + initially_opened_module:string option -> + open_implicit_modules:string list -> Env.t + type error = Cannot_apply of module_type | Not_included of Includemod.error list diff --git a/typing/typeopt.ml b/typing/typeopt.ml index 1d3101e3..4851b6c9 100644 --- a/typing/typeopt.ml +++ b/typing/typeopt.ml @@ -50,6 +50,7 @@ let is_base_type env ty base_ty_path = | _ -> false let maybe_pointer_type env ty = + let ty = scrape_ty env ty in if Ctype.maybe_pointer_type env ty then Pointer else @@ -121,7 +122,7 @@ let array_pattern_kind pat = array_type_kind pat.pat_env pat.pat_type let bigarray_decode_type env ty tbl dfl = match scrape env ty with | Tconstr(Pdot(Pident mod_id, type_name, _), [], _) - when Ident.name mod_id = "CamlinternalBigarray" -> + when Ident.name mod_id = "Stdlib__bigarray" -> begin try List.assoc type_name tbl with Not_found -> dfl end | _ -> dfl @@ -184,7 +185,7 @@ let lazy_val_requires_forward env ty = taken into account when determining whether a recursive binding is safe. *) let classify_lazy_argument : Typedtree.expression -> [`Constant_or_function - |`Float + |`Float_that_cannot_be_shortcut |`Identifier of [`Forward_value|`Other] |`Other] = fun e -> match e.exp_desc with @@ -195,7 +196,9 @@ let classify_lazy_argument : Typedtree.expression -> | Texp_construct (_, {cstr_arity = 0}, _) -> `Constant_or_function | Texp_constant(Const_float _) -> - `Float + if Config.flat_float_array + then `Float_that_cannot_be_shortcut + else `Constant_or_function | Texp_ident _ when lazy_val_requires_forward e.exp_env e.exp_type -> `Identifier `Forward_value | Texp_ident _ -> diff --git a/typing/typeopt.mli b/typing/typeopt.mli index 299e8222..24ea55f4 100644 --- a/typing/typeopt.mli +++ b/typing/typeopt.mli @@ -32,6 +32,6 @@ val value_kind : Env.t -> Types.type_expr -> Lambda.value_kind val classify_lazy_argument : Typedtree.expression -> [ `Constant_or_function - | `Float + | `Float_that_cannot_be_shortcut | `Identifier of [`Forward_value | `Other] | `Other] diff --git a/typing/types.ml b/typing/types.ml index 7ef6eaff..3003fc98 100644 --- a/typing/types.ml +++ b/typing/types.ml @@ -22,6 +22,7 @@ open Asttypes type type_expr = { mutable desc: type_desc; mutable level: int; + mutable scope: int option; id: int } and type_desc = @@ -145,7 +146,8 @@ type type_declaration = type_private: private_flag; type_manifest: type_expr option; type_variance: Variance.t list; - type_newtype_level: (int * int) option; + type_is_newtype: bool; + type_expansion_scope: int option; type_loc: Location.t; type_attributes: Parsetree.attributes; type_immediate: bool; diff --git a/typing/types.mli b/typing/types.mli index 28317b52..b88c87ee 100644 --- a/typing/types.mli +++ b/typing/types.mli @@ -58,6 +58,7 @@ open Asttypes type type_expr = { mutable desc: type_desc; mutable level: int; + mutable scope: int option; id: int } and type_desc = @@ -134,7 +135,7 @@ and type_desc = [< `X | `Y > `X ] (row_closed = true) type t = [> `X ] as 'a (row_more = Tvar a) - type t = private [> `X ] (row_more = Tconstr (t#row, [], ref Mnil) + type t = private [> `X ] (row_more = Tconstr (t#row, [], ref Mnil)) And for: @@ -290,8 +291,8 @@ type type_declaration = type_manifest: type_expr option; type_variance: Variance.t list; (* covariant, contravariant, weakly contravariant, injective *) - type_newtype_level: (int * int) option; - (* definition level * expansion level *) + type_is_newtype: bool; + type_expansion_scope: int option; type_loc: Location.t; type_attributes: Parsetree.attributes; type_immediate: bool; (* true iff type should not be a pointer *) diff --git a/typing/typetexp.ml b/typing/typetexp.ml index 5347c42d..d392fc58 100644 --- a/typing/typetexp.ml +++ b/typing/typetexp.ml @@ -52,10 +52,15 @@ type error = | Unbound_class of Longident.t | Unbound_modtype of Longident.t | Unbound_cltype of Longident.t - | Ill_typed_functor_application of Longident.t + | Ill_typed_functor_application + of Longident.t * Longident.t * Includemod.error list option | Illegal_reference_to_recursive_module - | Access_functor_as_structure of Longident.t - | Apply_structure_as_functor of Longident.t + | Wrong_use_of_module of Longident.t * [ `Structure_used_as_functor + | `Abstract_used_as_functor + | `Functor_used_as_structure + | `Abstract_used_as_structure + | `Generative_used_as_applicative + ] | Cannot_scrape_alias of Longident.t * Path.t | Opened_object of Path.t option | Not_an_object of type_expr @@ -66,10 +71,6 @@ exception Error_forward of Location.error type variable_context = int * (string, type_expr) Tbl.t -(* Local definitions *) - -let instance_list = Ctype.instance_list Env.empty - (* Narrowing unbound identifier errors. *) let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = @@ -81,6 +82,7 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = | Env.Recmodule -> raise (Error (loc, env, Illegal_reference_to_recursive_module)) in + let error e = raise (Error (loc, env, e)) in begin match lid with | Longident.Lident _ -> () | Longident.Ldot (mlid, _) -> @@ -88,33 +90,44 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = let md = Env.find_module (Env.lookup_module ~load:true mlid env) env in begin match Env.scrape_alias env md.md_type with | Mty_functor _ -> - raise (Error (loc, env, Access_functor_as_structure mlid)) - | Mty_alias(_, p) -> - raise (Error (loc, env, Cannot_scrape_alias(mlid, p))) - | _ -> () + error (Wrong_use_of_module (mlid, `Functor_used_as_structure)) + | Mty_ident _ -> + error (Wrong_use_of_module (mlid, `Abstract_used_as_structure)) + | Mty_alias(_, p) -> error (Cannot_scrape_alias(mlid, p)) + | Mty_signature _ -> () end | Longident.Lapply (flid, mlid) -> check_module flid; let fmd = Env.find_module (Env.lookup_module ~load:true flid env) env in - begin match Env.scrape_alias env fmd.md_type with - | Mty_signature _ -> - raise (Error (loc, env, Apply_structure_as_functor flid)) - | Mty_alias(_, p) -> - raise (Error (loc, env, Cannot_scrape_alias(flid, p))) - | _ -> () - end; + let mty_param = + match Env.scrape_alias env fmd.md_type with + | Mty_signature _ -> + error (Wrong_use_of_module (flid, `Structure_used_as_functor)) + | Mty_ident _ -> + error (Wrong_use_of_module (flid, `Abstract_used_as_functor)) + | Mty_alias(_, p) -> error (Cannot_scrape_alias(flid, p)) + | Mty_functor (_, None, _) -> + error (Wrong_use_of_module (flid, `Generative_used_as_applicative)) + | Mty_functor (_, Some mty_param, _) -> mty_param + in check_module mlid; - let mmd = Env.find_module (Env.lookup_module ~load:true mlid env) env in + let mpath = Env.lookup_module ~load:true mlid env in + let mmd = Env.find_module mpath env in begin match Env.scrape_alias env mmd.md_type with - | Mty_alias(_, p) -> - raise (Error (loc, env, Cannot_scrape_alias(mlid, p))) - | _ -> - raise (Error (loc, env, Ill_typed_functor_application lid)) + | Mty_alias(_, p) -> error (Cannot_scrape_alias(mlid, p)) + | mty_arg -> + let details = + try Includemod.check_modtype_inclusion + ~loc env mty_arg mpath mty_param; + None (* should be impossible *) + with Includemod.Error e -> Some e + in + error (Ill_typed_functor_application (flid, mlid, details)) end end; - raise (Error (loc, env, make_error lid)) + error (make_error lid) -let find_component (lookup : ?loc:_ -> _) make_error env loc lid = +let find_component (lookup : ?loc:_ -> ?mark:_ -> _) make_error env loc lid = try match lid with | Longident.Ldot (Longident.Lident "*predef*", s) -> @@ -161,7 +174,7 @@ let find_value env loc lid = r let lookup_module ?(load=false) env loc lid = - find_component (fun ?loc lid env -> (Env.lookup_module ~load ?loc lid env)) + find_component (fun ?loc ?mark lid env -> (Env.lookup_module ~load ?loc ?mark lid env)) (fun lid -> Unbound_module lid) env loc lid let find_module env loc lid = @@ -325,9 +338,9 @@ and transl_type_aux env policy styp = if name <> "" && name.[0] = '_' then raise (Error (styp.ptyp_loc, env, Invalid_variable_name ("'" ^ name))); begin try - instance env (List.assoc name !univars) + instance (List.assoc name !univars) with Not_found -> try - instance env (fst(Tbl.find name !used_variables)) + instance (fst(Tbl.find name !used_variables)) with Not_found -> let v = if policy = Univars then new_pre_univar ~name () else newvar ~name () @@ -474,7 +487,7 @@ and transl_type_aux env policy styp = let t = try List.assoc alias !univars with Not_found -> - instance env (fst(Tbl.find alias !used_variables)) + instance (fst(Tbl.find alias !used_variables)) in let ty = transl_type env policy st in begin try unify_var env t ty.ctyp_type with Unify trace -> @@ -495,7 +508,7 @@ and transl_type_aux env policy styp = end_def (); generalize_structure t; end; - let t = instance env t in + let t = instance t in let px = Btype.proxy t in begin match px.desc with | Tvar None -> Btype.log_type px; px.desc <- Tvar (Some alias) @@ -807,7 +820,7 @@ let transl_simple_type_univars env styp = in make_fixed_univars typ.ctyp_type; { typ with ctyp_type = - instance env (Btype.newgenty (Tpoly (typ.ctyp_type, univs))) } + instance (Btype.newgenty (Tpoly (typ.ctyp_type, univs))) } let transl_simple_type_delayed env styp = univars := []; used_variables := Tbl.empty; @@ -894,7 +907,7 @@ let report_error env ppf = function | Present_has_no_type l -> fprintf ppf "The present constructor %s has no type" l | Constructor_mismatch (ty, ty') -> - wrap_printing_env env (fun () -> + wrap_printing_env ~error:true env (fun () -> Printtyp.reset_and_mark_loops_list [ty; ty']; fprintf ppf "@[%s %a@ %s@ %a@]" "This variant type contains a constructor" @@ -928,7 +941,7 @@ let report_error env ppf = function | Multiple_constraints_on_type s -> fprintf ppf "Multiple constraints for type %a" longident s | Method_mismatch (l, ty, ty') -> - wrap_printing_env env (fun () -> + wrap_printing_env ~error:true env (fun () -> Printtyp.reset_and_mark_loops_list [ty; ty']; fprintf ppf "@[Method '%s' has type %a,@ which should be %a@]" l Printtyp.type_expr ty Printtyp.type_expr ty') @@ -953,14 +966,33 @@ let report_error env ppf = function | Unbound_cltype lid -> fprintf ppf "Unbound class type %a" longident lid; spellcheck ppf fold_cltypes env lid; - | Ill_typed_functor_application lid -> - fprintf ppf "Ill-typed functor application %a" longident lid + | Ill_typed_functor_application (flid, mlid, details) -> + (match details with + | None -> + fprintf ppf "@[Ill-typed functor application %a(%a)@]" + longident flid longident mlid + | Some inclusion_error -> + fprintf ppf "@[The type of %a does not match %a's parameter@\n%a@]" + longident mlid longident flid Includemod.report_error inclusion_error) | Illegal_reference_to_recursive_module -> - fprintf ppf "Illegal recursive module reference" - | Access_functor_as_structure lid -> - fprintf ppf "The module %a is a functor, not a structure" longident lid - | Apply_structure_as_functor lid -> - fprintf ppf "The module %a is a structure, not a functor" longident lid + fprintf ppf "Illegal recursive module reference" + | Wrong_use_of_module (lid, details) -> + (match details with + | `Structure_used_as_functor -> + fprintf ppf "@[The module %a is a structure, it cannot be applied@]" + longident lid + | `Abstract_used_as_functor -> + fprintf ppf "@[The module %a is abstract, it cannot be applied@]" + longident lid + | `Functor_used_as_structure -> + fprintf ppf "@[The module %a is a functor, \ + it cannot have any components@]" longident lid + | `Abstract_used_as_structure -> + fprintf ppf "@[The module %a is abstract, \ + it cannot have any components@]" longident lid + | `Generative_used_as_applicative -> + fprintf ppf "@[The functor %a is generative,@ it@ cannot@ be@ \ + applied@ in@ type@ expressions@]" longident lid) | Cannot_scrape_alias(lid, p) -> fprintf ppf "The module %a is an alias for module %a, which is missing" diff --git a/typing/typetexp.mli b/typing/typetexp.mli index c6bc5e43..87e95505 100644 --- a/typing/typetexp.mli +++ b/typing/typetexp.mli @@ -64,10 +64,15 @@ type error = | Unbound_class of Longident.t | Unbound_modtype of Longident.t | Unbound_cltype of Longident.t - | Ill_typed_functor_application of Longident.t + | Ill_typed_functor_application + of Longident.t * Longident.t * Includemod.error list option | Illegal_reference_to_recursive_module - | Access_functor_as_structure of Longident.t - | Apply_structure_as_functor of Longident.t + | Wrong_use_of_module of Longident.t * [ `Structure_used_as_functor + | `Abstract_used_as_functor + | `Functor_used_as_structure + | `Abstract_used_as_structure + | `Generative_used_as_applicative + ] | Cannot_scrape_alias of Longident.t * Path.t | Opened_object of Path.t option | Not_an_object of type_expr diff --git a/typing/untypeast.ml b/typing/untypeast.ml index e4ec51ce..625c70ef 100644 --- a/typing/untypeast.ml +++ b/typing/untypeast.ml @@ -708,7 +708,7 @@ let core_type sub ct = let class_structure sub cs = let rec remove_self = function | { pat_desc = Tpat_alias (p, id, _s) } - when string_is_prefix "selfpat-" id.Ident.name -> + when string_is_prefix "selfpat-" (Ident.name id) -> remove_self p | p -> p in diff --git a/utils/build_path_prefix_map.ml b/utils/build_path_prefix_map.ml new file mode 100644 index 00000000..40e3e8e3 --- /dev/null +++ b/utils/build_path_prefix_map.ml @@ -0,0 +1,104 @@ +type path = string +type path_prefix = string +type error_message = string + +let errorf fmt = Printf.kprintf (fun err -> Error err) fmt + +let encode_prefix str = + let buf = Buffer.create (String.length str) in + let push_char = function + | '%' -> Buffer.add_string buf "%#" + | '=' -> Buffer.add_string buf "%+" + | ':' -> Buffer.add_string buf "%." + | c -> Buffer.add_char buf c + in + String.iter push_char str; + Buffer.contents buf + +let decode_prefix str = + let buf = Buffer.create (String.length str) in + let rec loop i = + if i >= String.length str + then Ok (Buffer.contents buf) + else match str.[i] with + | ('=' | ':') as c -> + errorf "invalid character '%c' in key or value" c + | '%' -> + let push c = Buffer.add_char buf c; loop (i + 2) in + if i + 1 = String.length str then + errorf "invalid encoded string %S (trailing '%%')" str + else begin match str.[i + 1] with + | '#' -> push '%' + | '+' -> push '=' + | '.' -> push ':' + | c -> errorf "invalid %%-escaped character '%c'" c + end + | c -> + Buffer.add_char buf c; + loop (i + 1) + in loop 0 + +type pair = { target: path_prefix; source : path_prefix } + +let encode_pair { target; source } = + String.concat "=" [encode_prefix target; encode_prefix source] + +let decode_pair str = + match String.index str '=' with + | exception Not_found -> + errorf "invalid key/value pair %S, no '=' separator" str + | equal_pos -> + let encoded_target = String.sub str 0 equal_pos in + let encoded_source = + String.sub str (equal_pos + 1) (String.length str - equal_pos - 1) in + match decode_prefix encoded_target, decode_prefix encoded_source with + | Ok target, Ok source -> Ok { target; source } + | ((Error _ as err), _) | (_, (Error _ as err)) -> err + +type map = pair option list + +let encode_map map = + let encode_elem = function + | None -> "" + | Some pair -> encode_pair pair + in + List.map encode_elem map + |> String.concat ":" + +let decode_map str = + let exception Shortcut of error_message in + let decode_or_empty = function + | "" -> None + | pair -> + begin match decode_pair pair with + | Ok str -> Some str + | Error err -> raise (Shortcut err) + end + in + let pairs = String.split_on_char ':' str in + match List.map decode_or_empty pairs with + | exception (Shortcut err) -> Error err + | map -> Ok map + +let rewrite_opt prefix_map path = + let is_prefix = function + | None -> false + | Some { target = _; source } -> + String.length source <= String.length path + && String.equal source (String.sub path 0 (String.length source)) + in + match + List.find is_prefix + (* read key/value pairs from right to left, as the spec demands *) + (List.rev prefix_map) + with + | exception Not_found -> None + | None -> None + | Some { source; target } -> + Some (target ^ (String.sub path (String.length source) + (String.length path - String.length source))) + +let rewrite prefix_map path = + match rewrite_opt prefix_map path with + | None -> path + | Some path -> path diff --git a/utils/build_path_prefix_map.mli b/utils/build_path_prefix_map.mli new file mode 100644 index 00000000..c21f4583 --- /dev/null +++ b/utils/build_path_prefix_map.mli @@ -0,0 +1,24 @@ +type path = string +type path_prefix = string +type error_message = string + +val encode_prefix : path_prefix -> string +val decode_prefix : string -> (path_prefix, error_message) result + +type pair = { target: path_prefix; source : path_prefix } + +val encode_pair : pair -> string +val decode_pair : string -> (pair, error_message) result + +type map = pair option list + +val encode_map : map -> string +val decode_map : string -> (map, error_message) result + +val rewrite_opt : map -> path -> path option +(** [rewrite_opt map path] tries to find a source in [map] + that is a prefix of the input [path]. If it succeeds, + it replaces this prefix with the corresponding target. + If it fails, it just returns [None]. *) + +val rewrite : map -> path -> path diff --git a/utils/clflags.ml b/utils/clflags.ml index c502c41c..4e2916b7 100644 --- a/utils/clflags.ml +++ b/utils/clflags.ml @@ -92,6 +92,7 @@ and for_package = ref (None: string option) (* -for-pack *) and error_size = ref 500 (* -error-size *) and float_const_prop = ref true (* -no-float-const-prop *) and transparent_modules = ref false (* -trans-mod *) +let unique_ids = ref true let dump_source = ref false (* -dsource *) let dump_parsetree = ref false (* -dparsetree *) and dump_typedtree = ref false (* -dtypedtree *) @@ -134,7 +135,8 @@ let native_code = ref false (* set to true under ocamlopt *) let force_slash = ref false (* for ocamldep *) let clambda_checks = ref false (* -clambda-checks *) -let flambda_invariant_checks = ref true (* -flambda-invariants *) +let flambda_invariant_checks = + ref Config.with_flambda_invariants (* -flambda-(no-)invariants *) let dont_write_files = ref false (* set to true under ocamldoc *) diff --git a/utils/clflags.mli b/utils/clflags.mli index 9a15649f..04c41c64 100644 --- a/utils/clflags.mli +++ b/utils/clflags.mli @@ -119,6 +119,7 @@ val for_package : string option ref val error_size : int ref val float_const_prop : bool ref val transparent_modules : bool ref +val unique_ids : bool ref val dump_source : bool ref val dump_parsetree : bool ref val dump_typedtree : bool ref diff --git a/utils/config.mli b/utils/config.mli index 2e0bd869..e7dd460d 100644 --- a/utils/config.mli +++ b/utils/config.mli @@ -150,6 +150,8 @@ val profiling : bool val flambda : bool (* Whether the compiler was configured for flambda *) +val with_flambda_invariants : bool + (* Whether the invariants checks for flambda are enabled *) val spacetime : bool (* Whether the compiler was configured for Spacetime profiling *) diff --git a/utils/config.mlp b/utils/config.mlp index 434283b5..22750c4e 100644 --- a/utils/config.mlp +++ b/utils/config.mlp @@ -73,6 +73,7 @@ let mkdll, mkexe, mkmaindll = let profiling = %%PROFILING%% let flambda = %%FLAMBDA%% +let with_flambda_invariants = %%WITH_FLAMBDA_INVARIANTS%% let safe_string = %%FORCE_SAFE_STRING%% let default_safe_string = %%DEFAULT_SAFE_STRING%% let windows_unicode = %%WINDOWS_UNICODE%% != 0 @@ -81,25 +82,26 @@ let flat_float_array = %%FLAT_FLOAT_ARRAY%% let afl_instrument = %%AFL_INSTRUMENT%% -let exec_magic_number = "Caml1999X011" -and cmi_magic_number = "Caml1999I022" -and cmo_magic_number = "Caml1999O022" -and cma_magic_number = "Caml1999A022" +let exec_magic_number = "Caml1999X023" + (* exec_magic_number is duplicated in byterun/caml/exec.h *) +and cmi_magic_number = "Caml1999I023" +and cmo_magic_number = "Caml1999O023" +and cma_magic_number = "Caml1999A023" and cmx_magic_number = if flambda then - "Caml1999y022" + "Caml1999y023" else - "Caml1999Y022" + "Caml1999Y023" and cmxa_magic_number = if flambda then - "Caml1999z022" + "Caml1999z023" else - "Caml1999Z022" -and ast_impl_magic_number = "Caml1999M022" -and ast_intf_magic_number = "Caml1999N022" -and cmxs_magic_number = "Caml1999D022" + "Caml1999Z023" +and ast_impl_magic_number = "Caml1999M023" +and ast_intf_magic_number = "Caml1999N023" +and cmxs_magic_number = "Caml1999D023" (* cmxs_magic_number is duplicated in otherlibs/dynlink/natdynlink.ml *) -and cmt_magic_number = "Caml1999T022" +and cmt_magic_number = "Caml1999T023" let load_path = ref ([] : string list) diff --git a/utils/misc.ml b/utils/misc.ml index 052eea2a..7878f467 100644 --- a/utils/misc.ml +++ b/utils/misc.ml @@ -308,7 +308,9 @@ let no_overflow_add a b = (a lxor b) lor (a lxor (lnot (a+b))) < 0 let no_overflow_sub a b = (a lxor (lnot b)) lor (b lxor (a-b)) < 0 -let no_overflow_mul a b = b <> 0 && (a * b) / b = a +(* Taken from Hacker's Delight, chapter "Overflow Detection" *) +let no_overflow_mul a b = + not ((a = min_int && b < 0) || (b <> 0 && (a * b) / b <> a)) let no_overflow_lsl a k = 0 <= k && k < Sys.word_size && min_int asr k <= a && a <= max_int asr k diff --git a/utils/terminfo.ml b/utils/terminfo.ml index 5ed4bb5b..03e882f4 100644 --- a/utils/terminfo.ml +++ b/utils/terminfo.ml @@ -2,9 +2,9 @@ (* *) (* OCaml *) (* *) -(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) +(* Xavier Leroy, projet Gallium, INRIA Paris *) (* *) -(* Copyright 1996 Institut National de Recherche en Informatique et *) +(* Copyright 2017 Institut National de Recherche en Informatique et *) (* en Automatique. *) (* *) (* All rights reserved. This file is distributed under the terms of *) @@ -13,14 +13,33 @@ (* *) (**************************************************************************) -(* Basic interface to the terminfo database *) +open Printf + +external isatty : out_channel -> bool = "caml_sys_isatty" +external terminfo_rows: out_channel -> int = "caml_terminfo_rows" type status = | Uninitialised | Bad_term - | Good_term of int -;; -external setup : out_channel -> status = "caml_terminfo_setup";; -external backup : int -> unit = "caml_terminfo_backup";; -external standout : bool -> unit = "caml_terminfo_standout";; -external resume : int -> unit = "caml_terminfo_resume";; + | Good_term + +let setup oc = + let term = try Sys.getenv "TERM" with Not_found -> "" in + (* Same heuristics as in Misc.Color.should_enable_color *) + if term <> "" && term <> "dumb" && isatty oc + then Good_term + else Bad_term + +let num_lines oc = + let rows = terminfo_rows oc in + if rows > 0 then rows else 24 + (* 24 is a reasonable default for an ANSI-style terminal *) + +let backup oc n = + if n >= 1 then fprintf oc "\027[%dA%!" n + +let resume oc n = + if n >= 1 then fprintf oc "\027[%dB%!" n + +let standout oc b = + output_string oc (if b then "\027[4m" else "\027[0m"); flush oc diff --git a/utils/terminfo.mli b/utils/terminfo.mli index 92af80f9..f70f224d 100644 --- a/utils/terminfo.mli +++ b/utils/terminfo.mli @@ -18,9 +18,10 @@ type status = | Uninitialised | Bad_term - | Good_term of int (* number of lines of the terminal *) -;; -external setup : out_channel -> status = "caml_terminfo_setup";; -external backup : int -> unit = "caml_terminfo_backup";; -external standout : bool -> unit = "caml_terminfo_standout";; -external resume : int -> unit = "caml_terminfo_resume";; + | Good_term + +val setup : out_channel -> status +val num_lines : out_channel -> int +val backup : out_channel -> int -> unit +val standout : out_channel -> bool -> unit +val resume : out_channel -> int -> unit diff --git a/utils/warnings.ml b/utils/warnings.ml index 23f3f1d5..46142677 100644 --- a/utils/warnings.ml +++ b/utils/warnings.ml @@ -303,8 +303,16 @@ let defaults_warn_error = "-a+31";; let () = parse_options false defaults_w;; let () = parse_options true defaults_warn_error;; +let ref_manual_explanation () = + (* manual references are checked a posteriori by the manual + cross-reference consistency check in manual/tests*) + let[@manual.ref "s:comp-warnings"] chapter, section = 9, 5 in + Printf.sprintf "(See manual section %d.%d)" chapter section + let message = function - | Comment_start -> "this is the start of a comment." + | Comment_start -> + "this `(*' is the start of a comment.\n\ + Hint: Did you forget spaces when writing the infix operator `( * )'?" | Comment_not_end -> "this is not the end of a comment." | Deprecated (s, _, _) -> (* Reduce \r\n to \n: @@ -472,7 +480,7 @@ let message = function Printf.sprintf "Code should not depend on the actual values of\n\ this constructor's arguments. They are only for information\n\ - and may change in future versions. (See manual section 8.5)" + and may change in future versions. %t" ref_manual_explanation | Unreachable_case -> "this match case is unreachable.\n\ Consider replacing it with a refutation case ' -> .'" @@ -494,8 +502,8 @@ let message = function "variables " ^ String.concat "," vars in Printf.sprintf "Ambiguous or-pattern variables under guard;\n\ - %s may match different arguments. (See manual section 8.5)" - msg + %s may match different arguments. %t" + msg ref_manual_explanation | No_cmx_file name -> Printf.sprintf "no cmx file was found in path for module %s, \ -- 2.30.2