diff --git a/Changes b/Changes index aa8880ad07e..a91fe1ecdbe 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,22 @@ -OCaml 4.14 maintenance branch +OCaml 4.14.1 (20 December 2022) +------------------------------ + +### Bug fixes: + +- #11803, #11808: on x86, the destination of an integer comparison must be + a register, it cannot be a stack slot. + (Vincent Laviron, review by Xavier Leroy, report by + Emilio Jesús Gallego Arias) + + +OCaml 4.14.1 ----------------------------- +### Compiler user-interface and warnings: + +- #11184, #11670: Stop calling ranlib on created / installed libraries + (Sébastien Hinderer and Xavier Leroy, review by the same) + ### Build system: - #11370, #11373: Don't pass CFLAGS to flexlink during configure. @@ -12,6 +28,10 @@ OCaml 4.14 maintenance branch ### Bug fixes: +- #10768, #11340: Fix typechecking regression when combining first class + modules and GADTs. + (Jacques Garrigue, report by François Thiré, review by Matthew Ryan) + - #11204: Fix regression introduced in 4.14.0 that would trigger Warning 17 when calling virtual methods introduced by constraining the self type from within the class definition. @@ -50,6 +70,34 @@ OCaml 4.14 maintenance branch - #11516, #11524: Fix the `deprecated_mutable` attribute. (Chris Casinghino, review by Nicolás Ojeda Bär and Florian Angeletti) +- #11194, #11609: Fix inconsistent type variable names in "unbound type var" + messages + (Ulysse Gérard and Florian Angeletti, review Florian Angeletti and + Gabriel Scherer) + +- #11622: Prevent stack overflow when printing a constructor or record + mismatch error involving recursive types. + (Florian Angeletti, review by Gabriel Scherer) + +- #11732: Ensure that types from packed modules are always generalised + (Stephen Dolan and Leo White, review by Jacques Garrigue) + +- #11737: Fix segfault condition in Unix.stat under Windows in the presence of + multiple threads. + (Marc Lasson, Nicolás Ojeda Bär, review by Gabriel Scherer and David Allsopp) + +- #11776: Extend environment with functor parameters in `strengthen_lazy`. + (Chris Casinghino and Luke Maurer, review by Gabriel Scherer) + +- #11533, #11534: follow synonyms again in #show_module_type + (this had stopped working in 4.14.0) + (Gabriel Scherer, review by Jacques Garrigue, report by Yaron Minsky) + +- #11768, #11788: Fix crash at start-up of bytecode programs in + no-naked-pointers mode caused by wrong initialization of caml_global_data + (Xavier Leroy, report by Etienne Millon, review by Gabriel Scherer) + + OCaml 4.14.0 (28 March 2022) ---------------------------- diff --git a/README.win32.adoc b/README.win32.adoc index ecf6b1ef45e..410a8eef306 100644 --- a/README.win32.adoc +++ b/README.win32.adoc @@ -63,9 +63,7 @@ Only the `make` Cygwin package is required. `diffutils` is required if you wish to be able to run the test suite. Unless you are also compiling the Cygwin port of OCaml, you do not need the -`gcc-core` or `flexdll` packages. If you do install them, care may be required -to ensure that a particular build is using the correct installation of -`flexlink`. +`gcc-core` or `flexdll` packages. [[bmflex]] In addition to Cygwin, FlexDLL must also be installed, which is available from @@ -197,7 +195,7 @@ quickly as it will be unable to link `ocamlrun`. Now run: - ./configure --build=i686-pc-cygwin --host=i686-pc-windows + ./configure --build=x86_64-pc-cygwin --host=i686-pc-windows for 32-bit, or: @@ -262,7 +260,7 @@ the WinZip Options Window.) Now run: - ./configure --build=i686-pc-cygwin --host=i686-w64-mingw32 + ./configure --build=x86_64-pc-cygwin --host=i686-w64-mingw32 for 32-bit, or: diff --git a/VERSION b/VERSION index af8345c4cc5..71631ae527f 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -4.14.0+jst +4.14.1+jst # Starting with OCaml 4.14, although the version string that appears above is # still correct and this file can thus still be used to figure it out, diff --git a/asmcomp/amd64/reload.ml b/asmcomp/amd64/reload.ml index 1f4cadc391b..9e3cadbe440 100644 --- a/asmcomp/amd64/reload.ml +++ b/asmcomp/amd64/reload.ml @@ -33,7 +33,7 @@ open Mach Iload R R R Istore R R Iintop(Icomp) R R S - or S S R + or R S R Iintop(Imul|Idiv|Imod) R R S Iintop(Imulh) R R S Iintop(shift) S S R @@ -41,6 +41,7 @@ open Mach or S S R Iintop_imm(Iadd, n)/lea R R Iintop_imm(Imul, n) R R + Iintop_imm(Icomp, n) R S Iintop_imm(others) S S Inegf...Idivf R R S Ifloatofint R S @@ -66,7 +67,14 @@ inherit Reloadgen.reload_generic as super method! reload_operation op arg res = match op with - | Iintop(Iadd|Isub|Iand|Ior|Ixor|Icomp _|Icheckbound) -> + | Iintop(Iadd|Isub|Iand|Ior|Ixor|Icheckbound) -> + (* One of the two arguments can reside in the stack, but not both *) + if stackp arg.(0) && stackp arg.(1) + then ([|arg.(0); self#makereg arg.(1)|], res) + else (arg, res) + | Iintop(Icomp _) -> + (* The result must be a register (PR#11803) *) + let res = self#makeregs res in (* One of the two arguments can reside in the stack, but not both *) if stackp arg.(0) && stackp arg.(1) then ([|arg.(0); self#makereg arg.(1)|], res) @@ -80,6 +88,9 @@ method! reload_operation op arg res = if stackp arg.(0) then (let r = self#makereg arg.(0) in ([|r|], [|r|])) else (arg, res) + | Iintop_imm(Icomp _, _) -> + (* The result must be in a register (PR#11803) *) + (arg, self#makeregs res) | Iintop(Imulh | Idiv | Imod | Ilsl | Ilsr | Iasr) | Iintop_imm(_, _) -> (* The argument(s) and results can be either in register or on stack *) diff --git a/asmcomp/i386/reload.ml b/asmcomp/i386/reload.ml index 09497e05075..6a20e887bac 100644 --- a/asmcomp/i386/reload.ml +++ b/asmcomp/i386/reload.ml @@ -40,7 +40,14 @@ method! makereg r = method! reload_operation op arg res = match op with - Iintop(Iadd|Isub|Iand|Ior|Ixor|Icomp _|Icheckbound) -> + Iintop(Iadd|Isub|Iand|Ior|Ixor|Icheckbound) -> + (* One of the two arguments can reside in the stack *) + if stackp arg.(0) && stackp arg.(1) + then ([|arg.(0); self#makereg arg.(1)|], res) + else (arg, res) + | Iintop(Icomp _) -> + (* The result must be a register (PR#11803) *) + let res = self#makeregs res in (* One of the two arguments can reside in the stack *) if stackp arg.(0) && stackp arg.(1) then ([|arg.(0); self#makereg arg.(1)|], res) @@ -60,6 +67,9 @@ method! reload_operation op arg res = if stackp arg.(0) then let r = self#makereg arg.(0) in ([|r|], [|r|]) else (arg, res) + | Iintop_imm(Icomp _, _) -> + (* The result must be in a register (PR#11803) *) + (arg, self#makeregs res) | Iintop(Imulh | Ilsl | Ilsr | Iasr) | Iintop_imm(_, _) | Ifloatofint | Iintoffloat | Ispecific(Ipush) -> (* The argument(s) can be either in register or on stack *) diff --git a/asmcomp/reloadgen.ml b/asmcomp/reloadgen.ml index 704283eb52a..f23b884ff24 100644 --- a/asmcomp/reloadgen.ml +++ b/asmcomp/reloadgen.ml @@ -46,7 +46,7 @@ method makereg r = newr.spill_cost <- 100000; newr -method private makeregs rv = +method makeregs rv = let n = Array.length rv in let newv = Array.make n Reg.dummy in for i = 0 to n-1 do newv.(i) <- self#makereg rv.(i) done; diff --git a/asmcomp/reloadgen.mli b/asmcomp/reloadgen.mli index 638082f0a71..0cf264c4341 100644 --- a/asmcomp/reloadgen.mli +++ b/asmcomp/reloadgen.mli @@ -20,6 +20,7 @@ class reload_generic : object (* Can be overridden to reflect instructions that can operate directly on stack locations *) method makereg : Reg.t -> Reg.t + method makeregs : Reg.t array -> Reg.t array (* Can be overridden to avoid creating new registers of some class (i.e. if all "registers" of that class are actually on stack) *) method fundecl : Mach.fundecl -> int array -> Mach.fundecl * bool diff --git a/boot/ocamlc b/boot/ocamlc index bc807050053..7258f66b342 100755 Binary files a/boot/ocamlc and b/boot/ocamlc differ diff --git a/boot/ocamllex b/boot/ocamllex index 2c580b5b169..8aade94241a 100755 Binary files a/boot/ocamllex and b/boot/ocamllex differ diff --git a/build-aux/ocaml_version.m4 b/build-aux/ocaml_version.m4 index 72194bc467a..c90f88c6be4 100644 --- a/build-aux/ocaml_version.m4 +++ b/build-aux/ocaml_version.m4 @@ -25,7 +25,7 @@ # The following macro, OCAML__DEVELOPMENT_VERSION, should be either # [true] of [false]. -m4_define([OCAML__DEVELOPMENT_VERSION], [true]) +m4_define([OCAML__DEVELOPMENT_VERSION], [false]) # The three following components (major, minor and patch level) MUST be # integers. They MUST NOT be left-padded with zeros and all of them, diff --git a/configure b/configure index c4873903310..cdf0729707b 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for OCaml 4.14.0+jst. +# Generated by GNU Autoconf 2.71 for OCaml 4.14.0. # # Report bugs to . # @@ -621,8 +621,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='OCaml' PACKAGE_TARNAME='ocaml' -PACKAGE_VERSION='4.14.0+jst' -PACKAGE_STRING='OCaml 4.14.0+jst' +PACKAGE_VERSION='4.14.0' +PACKAGE_STRING='OCaml 4.14.0' PACKAGE_BUGREPORT='caml-list@inria.fr' PACKAGE_URL='http://www.ocaml.org' @@ -1477,7 +1477,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures OCaml 4.14.0+jst to adapt to many kinds of systems. +\`configure' configures OCaml 4.14.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1544,7 +1544,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of OCaml 4.14.0+jst:";; + short | recursive ) echo "Configuration of OCaml 4.14.0:";; esac cat <<\_ACEOF @@ -1717,7 +1717,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -OCaml configure 4.14.0+jst +OCaml configure 4.14.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2374,7 +2374,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by OCaml $as_me 4.14.0+jst, which was +It was created by OCaml $as_me 4.14.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3130,8 +3130,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuring OCaml version 4.14.0+jst" >&5 -printf "%s\n" "$as_me: Configuring OCaml version 4.14.0+jst" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuring OCaml version 4.14.0" >&5 +printf "%s\n" "$as_me: Configuring OCaml version 4.14.0" >&6;} # Configuration variables @@ -3179,11 +3179,11 @@ bootstrapping_flexdll=false -VERSION=4.14.0+jst +VERSION=4.14.0 -OCAML_DEVELOPMENT_VERSION=true +OCAML_DEVELOPMENT_VERSION=false -OCAML_RELEASE_EXTRA='Some (Plus, "jst")' +OCAML_RELEASE_EXTRA=None OCAML_VERSION_MAJOR=4 @@ -3191,7 +3191,7 @@ OCAML_VERSION_MINOR=14 OCAML_VERSION_PATCHLEVEL=0 -OCAML_VERSION_EXTRA=jst +OCAML_VERSION_EXTRA= OCAML_VERSION_SHORT=4.14 @@ -3320,13 +3320,13 @@ printf "%s\n" "#define OCAML_VERSION_MINOR 14" >>confdefs.h printf "%s\n" "#define OCAML_VERSION_PATCHLEVEL 0" >>confdefs.h -printf "%s\n" "#define OCAML_VERSION_ADDITIONAL \"jst\"" >>confdefs.h +printf "%s\n" "#define OCAML_VERSION_ADDITIONAL \"\"" >>confdefs.h - printf "%s\n" "#define OCAML_VERSION_EXTRA \"jst\"" >>confdefs.h + printf "%s\n" "#define OCAML_VERSION_EXTRA \"\"" >>confdefs.h printf "%s\n" "#define OCAML_VERSION 41400" >>confdefs.h -printf "%s\n" "#define OCAML_VERSION_STRING \"4.14.0+jst\"" >>confdefs.h +printf "%s\n" "#define OCAML_VERSION_STRING \"4.14.0\"" >>confdefs.h # Checks for system types @@ -13564,7 +13564,7 @@ case $ocaml_cv_cc_vendor in #( cc_warnings='-Wall -Wdeclaration-after-statement' ;; esac -case $enable_warn_error,true in #( +case $enable_warn_error,false in #( yes,*|,true) : cc_warnings="$cc_warnings $warn_error_flag" ;; #( *) : @@ -18888,7 +18888,7 @@ fi -case $enable_ocamltest,true in #( +case $enable_ocamltest,false in #( yes,*|,true) : ocamltest='ocamltest' ;; #( *) : @@ -19676,7 +19676,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by OCaml $as_me 4.14.0+jst, which was +This file was extended by OCaml $as_me 4.14.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19745,7 +19745,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -OCaml config.status 4.14.0+jst +OCaml config.status 4.14.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/driver/main_args.ml b/driver/main_args.ml index b7c652855c1..75d55e56275 100644 --- a/driver/main_args.ml +++ b/driver/main_args.ml @@ -591,10 +591,6 @@ let mk_no_unboxed_types f = " unannotated unboxable types will not be unboxed (default)" ;; -let mk_force_tmc f = - "-force-tmc", Arg.Unit f, " Rewrite all possible TMC calls" -;; - let mk_unsafe f = "-unsafe", Arg.Unit f, " Do not compile bounds checking on array and string access" @@ -978,7 +974,6 @@ module type Common_options = sig val _no_strict_sequence : unit -> unit val _strict_formats : unit -> unit val _no_strict_formats : unit -> unit - val _force_tmc : unit -> unit val _unboxed_types : unit -> unit val _no_unboxed_types : unit -> unit val _unsafe_string : unit -> unit @@ -1281,7 +1276,6 @@ struct mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; mk_thread F._thread; - mk_force_tmc F._force_tmc; mk_unboxed_types F._unboxed_types; mk_no_unboxed_types F._no_unboxed_types; mk_unsafe F._unsafe; @@ -1491,7 +1485,6 @@ struct mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; mk_thread F._thread; - mk_force_tmc F._force_tmc; mk_unbox_closures F._unbox_closures; mk_unbox_closures_factor F._unbox_closures_factor; mk_inline_max_unroll F._inline_max_unroll; @@ -1698,7 +1691,6 @@ struct mk_strict_formats F._strict_formats; mk_no_strict_formats F._no_strict_formats; mk_thread F._thread; - mk_force_tmc F._force_tmc; mk_unboxed_types F._unboxed_types; mk_no_unboxed_types F._no_unboxed_types; mk_unsafe_string F._unsafe_string; @@ -1998,7 +1990,6 @@ module Default = struct let _noprompt = set noprompt let _nopromptcont = set nopromptcont let _stdin () = (* placeholder: file_argument ""*) () - let _force_tmc = set force_tmc let _version () = print_version () let _vnum () = print_version_num () let _eval (_:string) = () @@ -2035,7 +2026,6 @@ module Default = struct "Profiling with \"gprof\" (option `-p') is only supported up to \ OCaml 4.08.0" let _shared () = shared := true; dlcode := true - let _force_tmc = set force_tmc let _v () = Compenv.print_version_and_library "native-code compiler" let _no_probes = clear probes let _probes = set probes @@ -2059,7 +2049,6 @@ module Default = struct let _pp s = Clflags.preprocessor := (Some s) let _ppx s = Clflags.all_ppx := (s :: (!Clflags.all_ppx)) let _thread = set Clflags.use_threads - let _force_tmc = set force_tmc let _v () = Compenv.print_version_and_library "documentation generator" let _verbose = set Clflags.verbose let _version = Compenv.print_version_string @@ -2093,7 +2082,6 @@ third-party libraries such as Lwt, but with a different API." let _output_complete_exe () = _output_complete_obj (); output_complete_executable := true let _output_obj () = output_c_object := true; custom_runtime := true - let _force_tmc = set force_tmc let _use_prims s = use_prims := s let _use_runtime s = use_runtime := s let _v () = Compenv.print_version_and_library "compiler" diff --git a/driver/main_args.mli b/driver/main_args.mli index c3f3cf0d12f..4a86131731c 100644 --- a/driver/main_args.mli +++ b/driver/main_args.mli @@ -42,7 +42,6 @@ module type Common_options = sig val _no_strict_sequence : unit -> unit val _strict_formats : unit -> unit val _no_strict_formats : unit -> unit - val _force_tmc : unit -> unit val _unboxed_types : unit -> unit val _no_unboxed_types : unit -> unit val _unsafe_string : unit -> unit diff --git a/otherlibs/win32unix/stat.c b/otherlibs/win32unix/stat.c index ab90993d220..056fac98f09 100644 --- a/otherlibs/win32unix/stat.c +++ b/otherlibs/win32unix/stat.c @@ -347,6 +347,7 @@ static int do_stat(int do_lstat, int use_64, const char* opath, HANDLE fstat, __ CAMLprim value unix_stat(value path) { + CAMLparam1(path); struct _stat64 buf; __int64 st_ino; @@ -354,11 +355,12 @@ CAMLprim value unix_stat(value path) if (!do_stat(0, 0, String_val(path), NULL, &st_ino, &buf)) { uerror("stat", path); } - return stat_aux(0, st_ino, &buf); + CAMLreturn (stat_aux(0, st_ino, &buf)); } CAMLprim value unix_stat_64(value path) { + CAMLparam1(path); struct _stat64 buf; __int64 st_ino; @@ -366,11 +368,12 @@ CAMLprim value unix_stat_64(value path) if (!do_stat(0, 1, String_val(path), NULL, &st_ino, &buf)) { uerror("stat", path); } - return stat_aux(1, st_ino, &buf); + CAMLreturn (stat_aux(1, st_ino, &buf)); } CAMLprim value unix_lstat(value path) { + CAMLparam1(path); struct _stat64 buf; __int64 st_ino; @@ -378,11 +381,12 @@ CAMLprim value unix_lstat(value path) if (!do_stat(1, 0, String_val(path), NULL, &st_ino, &buf)) { uerror("lstat", path); } - return stat_aux(0, st_ino, &buf); + CAMLreturn (stat_aux(0, st_ino, &buf)); } CAMLprim value unix_lstat_64(value path) { + CAMLparam1(path); struct _stat64 buf; __int64 st_ino; @@ -390,7 +394,7 @@ CAMLprim value unix_lstat_64(value path) if (!do_stat(1, 1, String_val(path), NULL, &st_ino, &buf)) { uerror("lstat", path); } - return stat_aux(1, st_ino, &buf); + CAMLreturn (stat_aux(1, st_ino, &buf)); } static value do_fstat(value handle, int use_64) diff --git a/runtime/stacks.c b/runtime/stacks.c index a1409b2abd7..611b05018ed 100644 --- a/runtime/stacks.c +++ b/runtime/stacks.c @@ -24,7 +24,7 @@ #include "caml/mlvalues.h" #include "caml/stacks.h" -value caml_global_data = 0; +value caml_global_data = Val_unit; /* must be a valid value (#11768) */ uintnat caml_max_stack_size; /* also used in gc_ctrl.c */ diff --git a/stdlib/string.mli b/stdlib/string.mli index 26b9029d21c..e19ed67531d 100644 --- a/stdlib/string.mli +++ b/stdlib/string.mli @@ -142,8 +142,8 @@ val concat : string -> string list -> string val cat : string -> string -> string (** [cat s1 s2] concatenates s1 and s2 ([s1 ^ s2]). - @raise Invalid_argument if the result is longer then - than {!Sys.max_string_length} bytes. + @raise Invalid_argument if the result is longer than + {!Sys.max_string_length} bytes. @since 4.13.0 *) diff --git a/stdlib/stringLabels.mli b/stdlib/stringLabels.mli index 210e7fe5859..ae225457531 100644 --- a/stdlib/stringLabels.mli +++ b/stdlib/stringLabels.mli @@ -144,8 +144,8 @@ val concat : sep:string -> string list -> string val cat : string -> string -> string (** [cat s1 s2] concatenates s1 and s2 ([s1 ^ s2]). - @raise Invalid_argument if the result is longer then - than {!Sys.max_string_length} bytes. + @raise Invalid_argument if the result is longer than + {!Sys.max_string_length} bytes. @since 4.13.0 *) diff --git a/testsuite/tests/tool-toplevel/show.ml b/testsuite/tests/tool-toplevel/show.ml index 425c6c7e4e1..28b59d9fdb1 100644 --- a/testsuite/tests/tool-toplevel/show.ml +++ b/testsuite/tests/tool-toplevel/show.ml @@ -124,3 +124,52 @@ type _ t += A : int t [%%expect{| type 'a t += A : int t |}];; + + + + +(* regression tests for #11533 *) +#show Set.OrderedType;; +[%%expect {| +module type OrderedType = sig type t val compare : t -> t -> int end +|}];; + +(* extra tests after #11533 + + The regression in #11533 would only show up when showing values defined + outside the current module. Those new tests below test modules and module + types from the standard library. To minimize test churn / promotion, + we are looking for some that will change as little as possible + in the future. + + - For module type it's easy: OrderedType is fixed in stone as + changing it would break all code using Set.Make. + + - For modules we use Stdlib.Unit, one of the stdlib modules + that is less likely to change very often (there are only + so many features you can add to 'unit'). +*) +module U = Stdlib.Unit;; +module type OT = Set.OrderedType;; +[%%expect {| +module U = Unit +module type OT = Set.OrderedType +|}];; + +#show U;; +[%%expect {| +module U = Unit +module U : + sig + type t = unit = () + val equal : t -> t -> bool + val compare : t -> t -> int + val to_string : t -> string + end +|}];; + +#show OT;; +[%%expect {| +module type OT = Set.OrderedType +module type OT = sig type t val compare : t -> t -> int end +|}];; diff --git a/testsuite/tests/typing-modules/inclusion_errors.ml b/testsuite/tests/typing-modules/inclusion_errors.ml index 4e7ff09b77c..e4333a08a1d 100644 --- a/testsuite/tests/typing-modules/inclusion_errors.ml +++ b/testsuite/tests/typing-modules/inclusion_errors.ml @@ -1715,3 +1715,96 @@ Error: Signature mismatch: type t = < m : int > A private row type would be revealed. |}];; + + +(** Unexpected recursive types *) +module M: sig + type _ t = A : ( as 'a) -> ( as 'b) t +end = struct + type _ t = A : ( as 'a) -> ( as 'b) t +end +[%%expect {| +Lines 3-5, characters 6-3: +3 | ......struct +4 | type _ t = A : ( as 'a) -> ( as 'b) t +5 | end +Error: Signature mismatch: + Modules do not match: + sig + type _ t = A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) t + end + is not included in + sig type _ t = A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) t end + Type declarations do not match: + type _ t = A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) t + is not included in + type _ t = A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) t + Constructors do not match: + A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) t + is not the same as: + A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) t + The type < x : 'a * 'a > as 'a is not equal to the type + < x : 'b > as 'b + Types for method x are incompatible +|}] +module R: sig + type t = { a: ( as 'a) } +end = struct + type t = { a: ( as 'a) } +end +[%%expect {| +Lines 3-5, characters 6-3: +3 | ......struct +4 | type t = { a: ( as 'a) } +5 | end +Error: Signature mismatch: + Modules do not match: + sig type t = { a : < x : 'a * 'a > as 'a; } end + is not included in + sig type t = { a : < x : 'a > as 'a; } end + Type declarations do not match: + type t = { a : < x : 'a * 'a > as 'a; } + is not included in + type t = { a : < x : 'a > as 'a; } + Fields do not match: + a : < x : 'a * 'a > as 'a; + is not the same as: + a : < x : 'a > as 'a; + The type < x : 'a * 'a > as 'a is not equal to the type + < x : 'b > as 'b + Types for method x are incompatible +|}] +type _ ext = .. +module Ext: sig + type _ ext += A : ( as 'a) -> ( as 'b) ext +end = struct + type _ ext += A : ( as 'a) -> ( as 'b) ext +end +[%%expect {| +type _ ext = .. +Lines 4-6, characters 6-3: +4 | ......struct +5 | type _ ext += A : ( as 'a) -> ( as 'b) ext +6 | end +Error: Signature mismatch: + Modules do not match: + sig + type _ ext += + A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) ext + end + is not included in + sig + type _ ext += A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) ext + end + Extension declarations do not match: + type _ ext += A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) ext + is not included in + type _ ext += A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) ext + Constructors do not match: + A : (< x : 'b * 'b > as 'b) -> (< y : 'a > as 'a) ext + is not the same as: + A : (< x : 'b > as 'b) -> (< y : 'a > as 'a) ext + The type < x : 'a * 'a > as 'a is not equal to the type + < x : 'b > as 'b + Types for method x are incompatible +|}] diff --git a/testsuite/tests/typing-objects/Tests.ml b/testsuite/tests/typing-objects/Tests.ml index 2961f74e2ba..7456f125089 100644 --- a/testsuite/tests/typing-objects/Tests.ml +++ b/testsuite/tests/typing-objects/Tests.ml @@ -1405,3 +1405,16 @@ class virtual c = cv [%%expect {| class virtual c : cv |}];; + +(** Test classes abbreviations with a recursive type *) +class ['a] c = object method m: ( as 'b) -> unit = fun _ -> () end +class d = ['a] c +[%%expect {| +class ['a] c : object method m : (< f : 'b; x : 'a > as 'b) -> unit end +Line 2, characters 0-16: +2 | class d = ['a] c + ^^^^^^^^^^^^^^^^ +Error: Some type variables are unbound in this type: class d : ['a] c + The method m has type (< f : 'b; x : 'a > as 'b) -> unit where 'a + is unbound +|}] diff --git a/testsuite/tests/typing-objects/unbound-type-var.ml b/testsuite/tests/typing-objects/unbound-type-var.ml new file mode 100644 index 00000000000..9e00cea2021 --- /dev/null +++ b/testsuite/tests/typing-objects/unbound-type-var.ml @@ -0,0 +1,19 @@ +(* TEST + * expect +*) + +class test a c = +object + method b = c +end + +[%%expect{| +Lines 1-4, characters 0-3: +1 | class test a c = +2 | object +3 | method b = c +4 | end +Error: Some type variables are unbound in this type: + class test : 'a -> 'b -> object method b : 'b end + The method b has type 'b where 'b is unbound +|}] diff --git a/tools/ocamlmklib.ml b/tools/ocamlmklib.ml index 48f636bc10b..1cf8ef919f4 100644 --- a/tools/ocamlmklib.ml +++ b/tools/ocamlmklib.ml @@ -26,7 +26,7 @@ let mklib out files opts = else "" in Printf.sprintf "link -lib -nologo %s-out:%s %s %s" machine out opts files - else Printf.sprintf "%s rc %s %s %s" Config.ar out opts files + else Printf.sprintf "%s rcs %s %s %s" Config.ar out opts files (* PR#4783: under Windows, don't use absolute paths because we do not know where the binary distribution will be installed. *) diff --git a/toplevel/topdirs.ml b/toplevel/topdirs.ml index a9f8c554a5c..02c72b427fc 100644 --- a/toplevel/topdirs.ml +++ b/toplevel/topdirs.ml @@ -545,6 +545,9 @@ let is_rec_module id md = Btype.unmark_iterators.it_module_declaration Btype.unmark_iterators md; rs +let secretly_the_same_path env path1 path2 = + let norm path = Printtyp.rewrite_double_underscore_paths env path in + Path.same (norm path1) (norm path2) let () = reg_show_prim "show_module" @@ -554,27 +557,46 @@ let () = | Pident id -> id | _ -> id in - let rec accum_aliases md acc = - let acc rs = + let rec accum_aliases path md acc = + let def rs = Sig_module (id, Mp_present, {md with md_type = trim_signature md.md_type}, - rs, Exported) :: acc in + rs, Exported) in match md.md_type with - | Mty_alias path -> - let md = Env.find_module path env in - accum_aliases md (acc Trec_not) + | Mty_alias new_path -> + let md = Env.find_module new_path env in + accum_aliases new_path md + (if secretly_the_same_path env path new_path + then acc + else def Trec_not :: acc) | Mty_ident _ | Mty_signature _ | Mty_functor _ -> - List.rev (acc (is_rec_module id md)) + List.rev (def (is_rec_module id md) :: acc) in - accum_aliases md [] + accum_aliases path md [] ) "Print the signature of the corresponding module." let () = reg_show_prim "show_module_type" (fun env loc id lid -> - let _path, desc = Env.lookup_modtype ~loc lid env in - [ Sig_modtype (id, desc, Exported) ] + let path, mtd = Env.lookup_modtype ~loc lid env in + let id = match path with + | Pident id -> id + | _ -> id + in + let rec accum_defs path mtd acc = + let def = Sig_modtype (id, mtd, Exported) in + match mtd.mtd_type with + | Some (Mty_ident new_path) -> + let mtd = Env.find_modtype new_path env in + accum_defs new_path mtd + (if secretly_the_same_path env path new_path + then acc + else def :: acc) + | None | Some (Mty_alias _ | Mty_signature _ | Mty_functor _) -> + List.rev (def :: acc) + in + accum_defs path mtd [] ) "Print the signature of the corresponding module type." diff --git a/typing/printtyp.ml b/typing/printtyp.ml index 004a5648cad..75beaa1f2fc 100644 --- a/typing/printtyp.ml +++ b/typing/printtyp.ml @@ -1084,7 +1084,10 @@ let reset () = reset_except_context () let prepare_for_printing tyl = - reset_except_context (); List.iter prepare_type tyl + reset_except_context (); + List.iter prepare_type tyl + +let add_type_to_preparation = prepare_type (* Disabled in classic mode when printing an unification error *) let print_labels = ref true @@ -1518,10 +1521,13 @@ and tree_of_label l = let constructor ppf c = reset_except_context (); + prepare_type_constructor_arguments c.cd_args; + Option.iter prepare_type c.cd_res; !Oprint.out_constr ppf (tree_of_constructor c) let label ppf l = reset_except_context (); + prepare_type l.ld_type; !Oprint.out_label ppf (tree_of_label l) let tree_of_type_declaration id decl rs = @@ -1589,6 +1595,8 @@ let extension_constructor id ppf ext = let extension_only_constructor id ppf ext = reset_except_context (); + prepare_type_constructor_arguments ext.ext_args; + Option.iter prepare_type ext.ext_ret_type; let name = Ident.name id in let args, ret = extension_constructor_args_and_ret_type_subtree diff --git a/typing/printtyp.mli b/typing/printtyp.mli index 719be215906..ac59f837e6f 100644 --- a/typing/printtyp.mli +++ b/typing/printtyp.mli @@ -108,6 +108,12 @@ val type_expr: formatter -> type_expr -> unit Any type variables that are shared between multiple types in the input list will be given the same name when printed with [prepared_type_expr]. *) val prepare_for_printing: type_expr list -> unit + +(** [add_type_to_preparation ty] extend a previous type expression preparation + to the type expression [ty] +*) +val add_type_to_preparation: type_expr -> unit + val prepared_type_expr: formatter -> type_expr -> unit (** The function [prepared_type_expr] is a less-safe but more-flexible version of [type_expr] that should only be called on [type_expr]s that have been diff --git a/typing/typeclass.ml b/typing/typeclass.ml index 10505840e6d..864df442311 100644 --- a/typing/typeclass.ml +++ b/typing/typeclass.ml @@ -2009,7 +2009,6 @@ let report_error env ppf = function (function ppf -> fprintf ppf "but is expected to have type") | Unexpected_field (ty, lab) -> - Printtyp.prepare_for_printing [ty]; fprintf ppf "@[@[<2>This object is expected to have type :@ %a@]\ @ This type does not have a method %s." @@ -2098,7 +2097,8 @@ let report_error env ppf = function let print_reason ppf (ty0, real, lab, ty) = let ty1 = if real then ty0 else Btype.newgenty(Tobject(ty0, ref None)) in - Printtyp.prepare_for_printing [ty; ty1]; + Printtyp.add_type_to_preparation ty; + Printtyp.add_type_to_preparation ty1; fprintf ppf "The method %s@ has type@;<1 2>%a@ where@ %a@ is unbound" lab diff --git a/typing/typemod.ml b/typing/typemod.ml index 6fa3f3cded0..bb27a94da6d 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -2139,8 +2139,11 @@ and package_constraints env loc mty constrs = let modtype_of_package env loc p fl = (* We call Ctype.correct_levels to ensure that the types being added to the module type are at generic_level. *) - package_constraints env loc (Mty_ident p) - (List.map (fun (n, t) -> Longident.flatten n, Ctype.correct_levels t) fl) + let mty = + package_constraints env loc (Mty_ident p) + (List.map (fun (n, t) -> Longident.flatten n, Ctype.correct_levels t) fl) + in + Subst.modtype Keep Subst.identity mty let package_subtype env p1 fl1 p2 fl2 = let mkmty p fl = @@ -2160,9 +2163,11 @@ let () = Ctype.package_subtype := package_subtype let wrap_constraint env mark arg mty explicit = let mark = if mark then Includemod.Mark_both else Includemod.Mark_neither in + let mty1 = Subst.modtype Keep Subst.identity arg.mod_type in + let mty2 = Subst.modtype Keep Subst.identity mty in let coercion = try - Includemod.modtypes ~loc:arg.mod_loc env ~mark arg.mod_type mty + Includemod.modtypes ~loc:arg.mod_loc env ~mark mty1 mty2 with Includemod.Error msg -> raise(Error(arg.mod_loc, env, Not_included msg)) in { mod_desc = Tmod_constraint(arg, mty, explicit, coercion); diff --git a/utils/clflags.ml b/utils/clflags.ml index b0c0e4c8d73..35c733da5d8 100644 --- a/utils/clflags.ml +++ b/utils/clflags.ml @@ -137,7 +137,6 @@ let profile_columns : Profile.column list ref = ref [] (* -dprofile/-dtimings *) let native_code = ref false (* set to true under ocamlopt *) -let force_tmc = ref false (* -force-tmc *) let force_slash = ref false (* for ocamldep *) let clambda_checks = ref false (* -clambda-checks *) let cmm_invariants = diff --git a/utils/clflags.mli b/utils/clflags.mli index fa28152d7ce..dd7ab286833 100644 --- a/utils/clflags.mli +++ b/utils/clflags.mli @@ -172,7 +172,6 @@ val dlcode : bool ref val pic_code : bool ref val runtime_variant : string ref val with_runtime : bool ref -val force_tmc : bool ref val force_slash : bool ref val keep_docs : bool ref val keep_locs : bool ref