summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.depend24
-rw-r--r--Changes13
-rw-r--r--VERSION2
-rw-r--r--dune3
-rw-r--r--man/ocamlc.m2
-rw-r--r--ocamltest/dune2
-rw-r--r--runtime/.depend52
-rw-r--r--testsuite/tests/typing-implicit_unpack/implicit_unpack.ml9
-rw-r--r--testsuite/tests/typing-short-paths/pr7543.compilers.reference7
-rw-r--r--typing/parmatch.mli8
-rw-r--r--typing/typecore.ml353
-rw-r--r--typing/typemod.ml110
-rw-r--r--utils/warnings.ml2
13 files changed, 403 insertions, 184 deletions
diff --git a/.depend b/.depend
index 8e50d87497..fb99b9bf19 100644
--- a/.depend
+++ b/.depend
@@ -5613,30 +5613,6 @@ asmcomp/debug/reg_with_debug_info.cmx : \
asmcomp/debug/reg_with_debug_info.cmi : \
asmcomp/reg.cmi \
middle_end/backend_var.cmi
-driver/compdynlink.cmi :
-driver/compdynlink_common.cmo : \
- driver/compdynlink_types.cmi \
- driver/compdynlink_platform_intf.cmi \
- driver/compdynlink_common.cmi
-driver/compdynlink_common.cmx : \
- driver/compdynlink_types.cmx \
- driver/compdynlink_platform_intf.cmx \
- driver/compdynlink_common.cmi
-driver/compdynlink_common.cmi : \
- driver/compdynlink_platform_intf.cmi
-driver/compdynlink_platform_intf.cmo : \
- driver/compdynlink_types.cmi \
- driver/compdynlink_platform_intf.cmi
-driver/compdynlink_platform_intf.cmx : \
- driver/compdynlink_types.cmx \
- driver/compdynlink_platform_intf.cmi
-driver/compdynlink_platform_intf.cmi : \
- driver/compdynlink_types.cmi
-driver/compdynlink_types.cmo : \
- driver/compdynlink_types.cmi
-driver/compdynlink_types.cmx : \
- driver/compdynlink_types.cmi
-driver/compdynlink_types.cmi :
driver/compenv.cmo : \
utils/warnings.cmi \
utils/profile.cmi \
diff --git a/Changes b/Changes
index 8341b917ef..fee7a03608 100644
--- a/Changes
+++ b/Changes
@@ -99,6 +99,10 @@ Working version
(Gabriel Scherer and Florian Angeletti,
review by Thomas Refis and Gabriel Scherer)
+- #9030: clarify and document the parameter space of type_pat
+ (Gabriel Scherer and Florian Angeletti and Jacques Garrigue,
+ review by Florian Angeletti and Thomas Refis)
+
- #8975: "ocamltests" files are no longer required or used by
"ocamltest". Instead, any text file in the testsuite directory containing a
valid "TEST" block will be automatically included in the testsuite.
@@ -299,6 +303,15 @@ Working version
- #8891: Warn about unused functor parameters
(Thomas Refis, review by Gabriel Radanne)
+- #8903: Improve errors for first-class modules
+ (Leo White, review by Jacques Garrigue)
+
+- #9046: disable warning 30 by default
+ This outdated warning complained on label/constructor name conflicts
+ within a mutually-recursive type declarations; there is now no need
+ to complain thanks to type-based disambiguation.
+ (Gabriel Scherer)
+
### Build system:
- #8840: use ocaml{c,opt}.opt when available to build internal tools
diff --git a/VERSION b/VERSION
index bf083856e7..a94273810b 100644
--- a/VERSION
+++ b/VERSION
@@ -1,4 +1,4 @@
-4.10.0+multicore+dev0
+4.10.0+multicore+dev1
# The version string is the first line of this file.
# It must be in the format described in stdlib/sys.mli
diff --git a/dune b/dune
index bde1e21700..653708c246 100644
--- a/dune
+++ b/dune
@@ -147,7 +147,8 @@
(modules
;; asmcomp/
afl_instrument arch asmgen asmlibrarian asmlink asmpackager branch_relaxation
- branch_relaxation_intf cmm cmmgen cmmgen_state coloring comballoc CSE CSEgen
+ branch_relaxation_intf cmm_helpers cmm cmmgen cmmgen_state coloring comballoc
+ CSE CSEgen
deadcode domainstate emit emitaux interf interval linear linearize linscan
liveness mach printcmm printlinear printmach proc reg reload reloadgen
schedgen scheduling selectgen selection spacetime_profiling spill split
diff --git a/man/ocamlc.m b/man/ocamlc.m
index 3fdaf6f1cb..6b8530095a 100644
--- a/man/ocamlc.m
+++ b/man/ocamlc.m
@@ -1018,7 +1018,7 @@ mentioned here corresponds to the empty set.
.IP
The default setting is
-.BR \-w\ +a\-4\-6\-7\-9\-27\-29\-32..42\-44\-45\-48\-50\-60\-66 .
+.BR \-w\ +a\-4\-6\-7\-9\-27\-29\-30\-32..42\-44\-45\-48\-50\-60\-66 .
Note that warnings
.BR 5 \ and \ 10
are not always triggered, depending on the internals of the type checker.
diff --git a/ocamltest/dune b/ocamltest/dune
index 9d3361a298..ff6cb83085 100644
--- a/ocamltest/dune
+++ b/ocamltest/dune
@@ -22,7 +22,7 @@
(rule
(targets ocamltest_config.ml)
- (deps ../Makefile.config ../Makefile.common Makefile
+ (deps ../Makefile.config ../Makefile.common ../Makefile.best_binaries Makefile
./ocamltest_config.ml.in ./getocamloptdefaultflags)
(action (run make %{targets})))
diff --git a/runtime/.depend b/runtime/.depend
index c38fa9b0a0..1143113f8b 100644
--- a/runtime/.depend
+++ b/runtime/.depend
@@ -104,9 +104,9 @@ extern_b.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/domain.h caml/md5.h caml/reverse.h
fail_byt_b.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/byte_domain_state.tbl caml/fail.h caml/io.h \
- caml/platform.h caml/memory.h caml/gc.h caml/major_gc.h \
- caml/minor_gc.h caml/addrmap.h caml/domain.h caml/printexc.h \
+ caml/domain_state.tbl caml/byte_domain_state.tbl caml/callback.h \
+ caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
+ caml/domain.h caml/fail.h caml/io.h caml/platform.h caml/printexc.h \
caml/signals.h caml/fiber.h caml/roots.h
fail_nat_b.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
@@ -472,9 +472,9 @@ extern_bd.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/domain.h caml/md5.h caml/reverse.h
fail_byt_bd.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/byte_domain_state.tbl caml/fail.h caml/io.h \
- caml/platform.h caml/memory.h caml/gc.h caml/major_gc.h \
- caml/minor_gc.h caml/addrmap.h caml/domain.h caml/printexc.h \
+ caml/domain_state.tbl caml/byte_domain_state.tbl caml/callback.h \
+ caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
+ caml/domain.h caml/fail.h caml/io.h caml/platform.h caml/printexc.h \
caml/signals.h caml/fiber.h caml/roots.h
fail_nat_bd.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
@@ -846,9 +846,9 @@ extern_bi.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/domain.h caml/md5.h caml/reverse.h
fail_byt_bi.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/byte_domain_state.tbl caml/fail.h caml/io.h \
- caml/platform.h caml/memory.h caml/gc.h caml/major_gc.h \
- caml/minor_gc.h caml/addrmap.h caml/domain.h caml/printexc.h \
+ caml/domain_state.tbl caml/byte_domain_state.tbl caml/callback.h \
+ caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
+ caml/domain.h caml/fail.h caml/io.h caml/platform.h caml/printexc.h \
caml/signals.h caml/fiber.h caml/roots.h
fail_nat_bi.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
@@ -1214,9 +1214,9 @@ extern_bpic.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/domain.h caml/md5.h caml/reverse.h
fail_byt_bpic.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/byte_domain_state.tbl caml/fail.h caml/io.h \
- caml/platform.h caml/memory.h caml/gc.h caml/major_gc.h \
- caml/minor_gc.h caml/addrmap.h caml/domain.h caml/printexc.h \
+ caml/domain_state.tbl caml/byte_domain_state.tbl caml/callback.h \
+ caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
+ caml/domain.h caml/fail.h caml/io.h caml/platform.h caml/printexc.h \
caml/signals.h caml/fiber.h caml/roots.h
fail_nat_bpic.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
@@ -1575,9 +1575,10 @@ extern_n.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/minor_gc.h caml/addrmap.h caml/domain.h caml/md5.h caml/reverse.h
fail_byt_n.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
- caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
- caml/domain.h caml/printexc.h caml/signals.h caml/fiber.h caml/roots.h
+ caml/domain_state.tbl caml/callback.h caml/memory.h caml/gc.h \
+ caml/major_gc.h caml/minor_gc.h caml/addrmap.h caml/domain.h \
+ caml/fail.h caml/io.h caml/platform.h caml/printexc.h caml/signals.h \
+ caml/fiber.h caml/roots.h
fail_nat_n.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
@@ -1923,9 +1924,10 @@ extern_nd.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/minor_gc.h caml/addrmap.h caml/domain.h caml/md5.h caml/reverse.h
fail_byt_nd.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
- caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
- caml/domain.h caml/printexc.h caml/signals.h caml/fiber.h caml/roots.h
+ caml/domain_state.tbl caml/callback.h caml/memory.h caml/gc.h \
+ caml/major_gc.h caml/minor_gc.h caml/addrmap.h caml/domain.h \
+ caml/fail.h caml/io.h caml/platform.h caml/printexc.h caml/signals.h \
+ caml/fiber.h caml/roots.h
fail_nat_nd.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
@@ -2277,9 +2279,10 @@ extern_ni.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/minor_gc.h caml/addrmap.h caml/domain.h caml/md5.h caml/reverse.h
fail_byt_ni.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
- caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
- caml/domain.h caml/printexc.h caml/signals.h caml/fiber.h caml/roots.h
+ caml/domain_state.tbl caml/callback.h caml/memory.h caml/gc.h \
+ caml/major_gc.h caml/minor_gc.h caml/addrmap.h caml/domain.h \
+ caml/fail.h caml/io.h caml/platform.h caml/printexc.h caml/signals.h \
+ caml/fiber.h caml/roots.h
fail_nat_ni.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
@@ -2625,9 +2628,10 @@ extern_npic.$(O): extern.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/minor_gc.h caml/addrmap.h caml/domain.h caml/md5.h caml/reverse.h
fail_byt_npic.$(O): fail_byt.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
- caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
- caml/memory.h caml/gc.h caml/major_gc.h caml/minor_gc.h caml/addrmap.h \
- caml/domain.h caml/printexc.h caml/signals.h caml/fiber.h caml/roots.h
+ caml/domain_state.tbl caml/callback.h caml/memory.h caml/gc.h \
+ caml/major_gc.h caml/minor_gc.h caml/addrmap.h caml/domain.h \
+ caml/fail.h caml/io.h caml/platform.h caml/printexc.h caml/signals.h \
+ caml/fiber.h caml/roots.h
fail_nat_npic.$(O): fail_nat.c caml/alloc.h caml/misc.h caml/config.h caml/m.h \
caml/s.h caml/camlatomic.h caml/mlvalues.h caml/domain_state.h \
caml/domain_state.tbl caml/fail.h caml/io.h caml/platform.h \
diff --git a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml
index 8dbdadbe2e..bd256f2c0b 100644
--- a/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml
+++ b/testsuite/tests/typing-implicit_unpack/implicit_unpack.ml
@@ -468,7 +468,7 @@ Line 4, characters 10-51:
4 | (module struct type elt = A type t = elt list end : S with type t = _ list)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: The type t in this module cannot be exported.
- Its type contains local dependencies: %M.elt list
+ Its type contains local dependencies: elt list
|}];;
type 'a s = (module S with type t = 'a);;
@@ -487,7 +487,7 @@ Line 1, characters 23-44:
1 | let x : 'a s = (module struct type t = A end);;
^^^^^^^^^^^^^^^^^^^^^
Error: The type t in this module cannot be exported.
- Its type contains local dependencies: %M.t
+ Its type contains local dependencies: t
|}];;
let x : 'a s = (module struct end);;
@@ -495,6 +495,7 @@ let x : 'a s = (module struct end);;
Line 1, characters 23-33:
1 | let x : 'a s = (module struct end);;
^^^^^^^^^^
-Error: The type t in this module cannot be exported.
- Its type contains local dependencies: %M.t
+Error: Signature mismatch:
+ Modules do not match: sig end is not included in S
+ The type `t' is required but not provided
|}];;
diff --git a/testsuite/tests/typing-short-paths/pr7543.compilers.reference b/testsuite/tests/typing-short-paths/pr7543.compilers.reference
index ee55eef11f..67c42e5c82 100644
--- a/testsuite/tests/typing-short-paths/pr7543.compilers.reference
+++ b/testsuite/tests/typing-short-paths/pr7543.compilers.reference
@@ -5,13 +5,10 @@ Line 1, characters 19-20:
1 | 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
+ Modules do not match: sig type 'a t = 'a end is not included in S
Type declarations do not match:
type 'a t = 'a
is not included in
- type t = N.t
+ type t
They have different arities.
diff --git a/typing/parmatch.mli b/typing/parmatch.mli
index 72d2ffe3eb..e7778fdfb8 100644
--- a/typing/parmatch.mli
+++ b/typing/parmatch.mli
@@ -91,6 +91,14 @@ val ppat_of_type :
(string, label_description) Hashtbl.t
val pressure_variants: Env.t -> pattern list -> unit
+
+(** [check_partial pred loc caselist] and [check_unused refute pred caselist]
+ are called with a function [pred] which will be given counter-example
+ candidates: they may be partially ill-typed, and have to be type-checked
+ to extract a valid counter-example.
+ [pred] returns a valid counter-example or [None].
+ [refute] indicates that [check_unused] was called on a refutation clause.
+ *)
val check_partial:
((string, constructor_description) Hashtbl.t ->
(string, label_description) Hashtbl.t ->
diff --git a/typing/typecore.ml b/typing/typecore.ml
index df9a0a66e1..6ff90a7ed2 100644
--- a/typing/typecore.ml
+++ b/typing/typecore.ml
@@ -946,28 +946,6 @@ let type_continuation_pat env expected_ty sp =
raise (Error_forward (Builtin_attributes.error_of_extension ext))
| _ -> raise (Error (loc, env, Invalid_continuation_pattern))
-(* Remember current state for backtracking.
- No variable information, as we only backtrack on
- patterns without variables (cf. assert statements). *)
-type state =
- { snapshot: Btype.snapshot;
- levels: Ctype.levels;
- env: Env.t; }
-let save_state env =
- { snapshot = Btype.snapshot ();
- levels = Ctype.save_levels ();
- env = !env; }
-let set_state s env =
- Btype.backtrack s.snapshot;
- Ctype.set_levels s.levels;
- env := s.env
-
-(* type_pat does not generate local constraints inside or patterns *)
-type type_pat_mode =
- | Normal
- | Inside_or (* inside a non-split or-pattern *)
- | Split_or (* always split or-patterns *)
-
(* "half typed" cases are produced in [type_cases] when we've just typechecked
the pattern but haven't type-checked the body yet.
At this point we might have added some type equalities to the environment,
@@ -1010,13 +988,151 @@ let rec has_literal_pattern p = match p.ppat_desc with
| Ppat_or (p, q) ->
has_literal_pattern p || has_literal_pattern q
-exception Need_backtrack
-
let check_scope_escape loc env level ty =
try Ctype.check_scope_escape env level ty
with Unify trace ->
raise(Error(loc, env, Pattern_type_clash(trace, None)))
+type pattern_checking_mode =
+ | Normal
+ (** We are checking user code. *)
+ | Counter_example of counter_example_checking_info
+ (** In [Counter_example] mode, we are checking a counter-example
+ candidate produced by Parmatch. This is a syntactic pattern that
+ represents a set of values by using or-patterns (p_1 | ... | p_n)
+ to enumerate all alternatives in the counter-example
+ search. These or-patterns occur at every choice point, possibly
+ deep inside the pattern.
+
+ Parmatch does not use type information, so this pattern may
+ exhibit two issues:
+ - some parts of the pattern may be ill-typed due to GADTs, and
+ - some wildcard patterns may not match any values: their type is
+ empty.
+
+ The aim of [type_pat] in the [Counter_example] mode is to refine
+ this syntactic pattern into a well-typed pattern, and ensure
+ that it matches at least one concrete value.
+ - It filters ill-typed branches of or-patterns.
+ (see {!splitting_mode} below)
+ - It tries to check that wildcard patterns are non-empty.
+ (see {!explosion_fuel})
+ *)
+
+and counter_example_checking_info = {
+ explosion_fuel: int;
+ splitting_mode: splitting_mode;
+ constrs: (string, Types.constructor_description) Hashtbl.t;
+ labels: (string, Types.label_description) Hashtbl.t;
+ }
+(**
+ [explosion_fuel] controls the checking of wildcard patterns. We
+ eliminate potentially-empty wildcard patterns by exploding them
+ into concrete sub-patterns, for example (K1 _ | K2 _) or
+ { l1: _; l2: _ }. [explosion_fuel] is the depth limit on wildcard
+ explosion. Such depth limit is required to avoid non-termination
+ and compilation-time blowups.
+
+ [splitting_mode] controls the handling of or-patterns. In
+ [Counter_example] mode, we only need to select one branch that
+ leads to a well-typed pattern. Checking all branches is expensive,
+ we use different search strategies (see {!splitting_mode}) to
+ reduce the number of explored alternatives.
+
+ [constrs] and [labels] contain metadata produced by [Parmatch] to
+ type-check the given syntactic pattern. [Parmatch] produces
+ counter-examples by turning typed patterns into
+ [Parsetree.pattern]. In this process, constructor and label paths
+ are lost, and are replaced by generated strings. [constrs] and
+ [labels] map those synthetic names back to the typed descriptions
+ of the original names.
+ *)
+
+(** Due to GADT constraints, an or-pattern produced within
+ a counter-example may have ill-typed branches. Consider for example
+
+ type _ tag = Int : int tag | Bool : bool tag
+
+ then [Parmatch] will propose the or-pattern [Int | Bool] whenever
+ a pattern of type [tag] is required to form a counter-example. For
+ example, a function expects a (int tag option) and only [None] is
+ handled by the user-written pattern. [Some (Int | Bool)] is not
+ well-typed in this context, only the sub-pattern [Some Int] is.
+ In this example, the expected type coming from the context
+ suffices to know which or-pattern branch must be chosen.
+
+ In the general case, choosing a branch can have non-local effects
+ on the typability of the term. For example, consider a tuple type
+ ['a tag * ...'a...], where the first component is a GADT. All
+ constructor choices for this GADT lead to a well-typed branch in
+ isolation (['a] is unconstrained), but choosing one of them adds
+ a constraint on ['a] that may make the other tuple elements
+ ill-typed.
+
+ In general, after choosing each possible branch of the or-pattern,
+ [type_pat] has to check the rest of the pattern to tell if this
+ choice leads to a well-typed term. This may lead to an explosion
+ of typing/search work -- the rest of the term may in turn contain
+ alternatives.
+
+ We use careful strategies to try to limit counterexample-checking
+ time; [splitting_mode] represents those strategies.
+*)
+and splitting_mode =
+ | Backtrack_or
+ (** Always backtrack in or-patterns.
+
+ [Backtrack_or] selects a single alternative from an or-pattern
+ by using backtracking, trying to choose each branch in turn, and
+ to complete it into a valid sub-pattern. We call this
+ "splitting" the or-pattern.
+
+ We use this mode when looking for unused patterns or sub-patterns,
+ in particular to check a refutation clause (p -> .).
+ *)
+ | Refine_or of { inside_nonsplit_or: bool; }
+ (** Only backtrack when needed.
+
+ [Refine_or] tries another approach for refining or-pattern.
+
+ Instead of always splitting each or-pattern, It first attempts to
+ find branches that do not introduce new constraints (because they
+ do not contain GADT constructors). Those branches are such that,
+ if they fail, all other branches will fail.
+
+ If we find one such branch, we attempt to complete the subpattern
+ (checking what's outside the or-pattern), ignoring other
+ branches -- we never consider another branch choice again. If all
+ branches are constrained, it falls back to splitting the
+ or-pattern.
+
+ We use this mode when checking exhaustivity of pattern matching.
+ *)
+
+(** This exception is only used internally within [type_pat_aux], to jump
+ back to the parent or-pattern in the [Refine_or] strategy.
+
+ Such a parent exists precisely when [inside_nonsplit_or = true];
+ it's an invariant that we always setup an exception handler for
+ [Need_backtrack] when we set this flag. *)
+ exception Need_backtrack
+
+(** Remember current typing state for backtracking.
+ No variable information, as we only backtrack on
+ patterns without variables (cf. assert statements). *)
+type state =
+ { snapshot: Btype.snapshot;
+ levels: Ctype.levels;
+ env: Env.t; }
+let save_state env =
+ { snapshot = Btype.snapshot ();
+ levels = Ctype.save_levels ();
+ env = !env; }
+let set_state s env =
+ Btype.backtrack s.snapshot;
+ Ctype.set_levels s.levels;
+ env := s.env
+
(** Find the first alternative in the tree of or-patterns for which
[f] does not raise an error. If all fail, the last error is
propagated *)
@@ -1027,35 +1143,52 @@ let rec find_valid_alternative f pat =
with Error _ -> find_valid_alternative f p2)
| _ -> f pat
-(* type_pat propagates the expected type as well as maps for
- constructors and labels.
- Unification may update the typing environment. *)
-(* constrs <> None => called from parmatch: backtrack on or-patterns
- explode > 0 => explode Ppat_any for gadts *)
-(* Need_backtrack exceptions are raised in the [Inside_or] mode to backtrack
- to the outermost or-pattern *)
-let rec type_pat ?(exception_allowed=false) ~constrs ~labels ~no_existentials
- ~mode ~explode ~env sp expected_ty k =
+let no_explosion = function
+ | Normal -> Normal
+ | Counter_example info ->
+ Counter_example { info with explosion_fuel = 0 }
+
+let get_splitting_mode = function
+ | Normal -> None
+ | Counter_example {splitting_mode} -> Some splitting_mode
+
+let enter_nonsplit_or mode = match mode with
+ | Normal -> Normal
+ | Counter_example info ->
+ let splitting_mode = match info.splitting_mode with
+ | Backtrack_or ->
+ (* in Backtrack_or mode, or-patterns are always split *)
+ assert false
+ | Refine_or _ ->
+ Refine_or {inside_nonsplit_or = true}
+ in Counter_example { info with splitting_mode }
+
+let rec type_pat ?(exception_allowed=false) ~no_existentials ~mode
+ ~env sp expected_ty k =
Builtin_attributes.warning_scope sp.ppat_attributes
(fun () ->
- type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
- ~explode ~env sp expected_ty k
+ type_pat_aux ~exception_allowed ~no_existentials ~mode
+ ~env sp expected_ty k
)
-and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
- ~explode ~env sp expected_ty k =
- let type_pat ?(exception_allowed=false) ?(constrs=constrs) ?(labels=labels)
- ?(mode=mode) ?(explode=explode) ?(env=env) =
- type_pat ~exception_allowed ~constrs ~labels ~no_existentials ~mode ~explode
- ~env
+and type_pat_aux ~exception_allowed ~no_existentials ~mode
+ ~env sp expected_ty k =
+ let type_pat ?(exception_allowed=false) ?(mode=mode) ?(env=env) =
+ type_pat ~exception_allowed ~no_existentials ~mode ~env
in
let loc = sp.ppat_loc in
let rup k x =
- if constrs = None then (ignore (rp x));
+ if mode = Normal then (ignore (rp x));
unify_pat !env x (instance expected_ty);
k x
in
- let rp k x : pattern = if constrs = None then k (rp x) else k x in
+ let rp k x : pattern = if mode = Normal then k (rp x) else k x in
+ let construction_not_used_in_counterexamples = (mode = Normal) in
+ let must_backtrack_on_gadt = match get_splitting_mode mode with
+ | None -> false
+ | Some Backtrack_or -> false
+ | Some (Refine_or {inside_nonsplit_or}) -> inside_nonsplit_or
+ in
match sp.ppat_desc with
Ppat_any ->
let k' d = rp k {
@@ -1065,22 +1198,27 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
pat_attributes = sp.ppat_attributes;
pat_env = !env }
in
- if explode > 0 then
- 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 =
- match sp.ppat_desc with
- Parsetree.Ppat_or _ -> explode - 5
- | _ -> explode - 1
- in
- type_pat ~constrs:(Some constrs) ~labels:(Some labels)
- ~explode sp expected_ty k
- else k' Tpat_any
+ begin match mode with
+ | Normal -> k' Tpat_any
+ | Counter_example {explosion_fuel; _} when explosion_fuel <= 0 ->
+ k' Tpat_any
+ | Counter_example ({explosion_fuel; _} as info) ->
+ begin match Parmatch.ppat_of_type !env expected_ty with
+ | exception Parmatch.Empty -> raise (Error (loc, !env, Empty_pattern))
+ | (sp, constrs, labels) ->
+ if sp.ppat_desc = Parsetree.Ppat_any then k' Tpat_any else
+ if must_backtrack_on_gadt then raise Need_backtrack else
+ let explosion_fuel =
+ match sp.ppat_desc with
+ Parsetree.Ppat_or _ -> explosion_fuel - 5
+ | _ -> explosion_fuel - 1
+ in
+ let mode =
+ Counter_example { info with explosion_fuel; constrs; labels }
+ in
+ type_pat ~mode sp expected_ty k
+ end
+ end
| Ppat_var name ->
let ty = instance expected_ty in
let id = (* PR#7330 *)
@@ -1096,7 +1234,7 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
pat_attributes = sp.ppat_attributes;
pat_env = !env }
| Ppat_unpack name ->
- assert (constrs = None);
+ assert construction_not_used_in_counterexamples;
let t = instance expected_ty in
begin match name.txt with
| None ->
@@ -1122,7 +1260,7 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
{ppat_desc=Ppat_var name; ppat_loc=lloc; ppat_attributes = attrs},
({ptyp_desc=Ptyp_poly _} as sty)) ->
(* explicitly polymorphic type *)
- assert (constrs = None);
+ assert construction_not_used_in_counterexamples;
let cty, force = Typetexp.transl_simple_type_delayed !env sty in
let ty = cty.ctyp_type in
unify_pat_types lloc !env ty (instance expected_ty);
@@ -1145,7 +1283,7 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
| _ -> assert false
end
| Ppat_alias(sq, name) ->
- assert (constrs = None);
+ assert construction_not_used_in_counterexamples;
type_pat sq expected_ty (fun q ->
begin_def ();
let ty_var = build_as_type !env q in
@@ -1180,7 +1318,7 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
in
let p = if c1 <= c2 then loop c1 c2 else loop c2 c1 in
let p = {p with ppat_loc=loc} in
- type_pat ~explode:0 p expected_ty k
+ type_pat ~mode:(no_explosion mode) p expected_ty k
(* TODO: record 'extra' to remember about interval *)
| Ppat_interval _ ->
raise (Error (loc, !env, Invalid_interval))
@@ -1208,9 +1346,11 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
with Not_found -> None
in
let constr =
- match lid.txt, constrs with
- Longident.Lident s, Some constrs ->
- assert (Hashtbl.mem constrs s); Hashtbl.find constrs s
+ match lid.txt, mode with
+ | Longident.Lident s, Counter_example {constrs; _} ->
+ (* assert: cf. {!counter_example_checking_info} documentation *)
+ assert (Hashtbl.mem constrs s);
+ Hashtbl.find constrs s
| _ ->
let candidates =
Env.lookup_all_constructors Env.Pattern ~loc:lid.loc lid.txt !env in
@@ -1218,8 +1358,8 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
(mk_expected expected_ty)
(Constructor.disambiguate Env.Pattern lid !env opath) candidates
in
- if constr.cstr_generalized && constrs <> None && mode = Inside_or
- then raise Need_backtrack;
+ if constr.cstr_generalized && must_backtrack_on_gadt then
+ raise Need_backtrack;
begin match no_existentials, constr.cstr_existentials with
| None, _ | _, [] -> ()
| Some r, (_ :: _ as exs) ->
@@ -1305,7 +1445,8 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
generalize_structure expected_ty;
(* PR#7404: allow some_private_tag blindly, as it would not unify with
the abstract row variable *)
- if l = Parmatch.some_private_tag then assert (constrs <> None)
+ if l = Parmatch.some_private_tag
+ then assert (match mode with Normal -> false | Counter_example _ -> true)
else unify_pat_types loc !env (newgenty (Tvariant row)) expected_ty;
let k arg =
rp k {
@@ -1356,15 +1497,17 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
pat_attributes = sp.ppat_attributes;
pat_env = !env }
in
- if constrs = None then
- k (wrap_disambiguate "This record pattern is expected to have"
- (mk_expected expected_ty)
- (type_label_a_list ?labels loc false !env type_label_pat opath
- lid_sp_list)
- (k' (fun x -> x)))
- else
- type_label_a_list ?labels loc false !env type_label_pat opath
- lid_sp_list (k' k)
+ begin match mode with
+ | Normal ->
+ k (wrap_disambiguate "This record pattern is expected to have"
+ (mk_expected expected_ty)
+ (type_label_a_list loc false !env type_label_pat opath
+ lid_sp_list)
+ (k' (fun x -> x)))
+ | Counter_example {labels; _} ->
+ type_label_a_list ~labels loc false !env type_label_pat opath
+ lid_sp_list (k' k)
+ end
| Ppat_array spl ->
let ty_elt = newgenvar() in
begin_def ();
@@ -1381,12 +1524,17 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
pat_attributes = sp.ppat_attributes;
pat_env = !env })
| Ppat_or(sp1, sp2) ->
+ let may_split, must_split =
+ match get_splitting_mode mode with
+ | None -> false, false
+ | Some Backtrack_or -> true, true
+ | Some (Refine_or _) -> true, false in
let state = save_state env in
let split_or sp =
- assert (constrs <> None);
+ assert may_split;
let typ pat = type_pat ~exception_allowed pat expected_ty k in
find_valid_alternative (fun pat -> set_state state env; typ pat) sp in
- if mode = Split_or then split_or sp else begin
+ if must_split then split_or sp else begin
let initial_pattern_variables = !pattern_variables in
let initial_module_variables = !module_variables in
let equation_level = !gadt_equations_level in
@@ -1396,9 +1544,10 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
let lev = get_current_level () in
gadt_equations_level := Some lev;
let env1 = ref !env in
+ let inside_or = enter_nonsplit_or mode in
let p1 =
- try Some (type_pat ~exception_allowed ~mode:Inside_or sp1 expected_ty
- ~env:env1 (fun x -> x))
+ try Some (type_pat ~exception_allowed ~mode:inside_or
+ sp1 expected_ty ~env:env1 (fun x -> x))
with Need_backtrack -> None in
let p1_variables = !pattern_variables in
let p1_module_variables = !module_variables in
@@ -1406,8 +1555,8 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
module_variables := initial_module_variables;
let env2 = ref !env in
let p2 =
- try Some (type_pat ~exception_allowed ~mode:Inside_or sp2 expected_ty
- ~env:env2 (fun x -> x))
+ try Some (type_pat ~exception_allowed ~mode:inside_or
+ sp2 expected_ty ~env:env2 (fun x -> x))
with Need_backtrack -> None in
end_def ();
gadt_equations_level := equation_level;
@@ -1422,7 +1571,13 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
) p2_variables;
begin match p1, p2 with
| None, None ->
- if mode = Inside_or then raise Need_backtrack else split_or sp
+ let inside_nonsplit_or =
+ match get_splitting_mode mode with
+ | None | Some Backtrack_or -> false
+ | Some (Refine_or {inside_nonsplit_or}) -> inside_nonsplit_or in
+ if inside_nonsplit_or
+ then raise Need_backtrack
+ else split_or sp
| Some p, None | None, Some p -> rp k p (* no variables in this case *)
| Some p1, Some p2 ->
let alpha_env =
@@ -1441,7 +1596,7 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
let nv = newgenvar () in
unify_pat_types loc !env (Predef.type_lazy_t nv) expected_ty;
(* do not explode under lazy: PR#7421 *)
- type_pat ~explode:0 sp1 nv (fun p1 ->
+ type_pat ~mode:(no_explosion mode) sp1 nv (fun p1 ->
rp k {
pat_desc = Tpat_lazy p1;
pat_loc = loc; pat_extra=[];
@@ -1507,12 +1662,12 @@ and type_pat_aux ~exception_allowed ~constrs ~labels ~no_existentials ~mode
| Ppat_extension ext ->
raise (Error_forward (Builtin_attributes.error_of_extension ext))
-let type_pat ?exception_allowed ?no_existentials ?constrs ?labels ?(mode=Normal)
- ?(explode=0) ?(lev=get_current_level()) env sp expected_ty =
+let type_pat ?exception_allowed ?no_existentials ?(mode=Normal)
+ ?(lev=get_current_level()) env sp expected_ty =
Misc.protect_refs [Misc.R (gadt_equations_level, Some lev)] (fun () ->
let r =
- type_pat ?exception_allowed ~no_existentials ~constrs ~labels ~mode
- ~explode ~env sp expected_ty (fun x -> x)
+ type_pat ?exception_allowed ~no_existentials ~mode
+ ~env sp expected_ty (fun x -> x)
in
iter_pattern (fun p -> p.pat_env <- !env) r;
r
@@ -1520,15 +1675,20 @@ let type_pat ?exception_allowed ?no_existentials ?constrs ?labels ?(mode=Normal)
(* this function is passed to Partial.parmatch
to type check gadt nonexhaustiveness *)
-let partial_pred ~lev ?mode ?explode env expected_ty constrs labels p =
+let partial_pred ~lev ~splitting_mode ?(explode=0)
+ env expected_ty constrs labels p =
let env = ref env in
let state = save_state env in
+ let mode =
+ Counter_example {
+ splitting_mode;
+ explosion_fuel = explode;
+ constrs; labels;
+ } in
try
reset_pattern None true;
let typed_p =
- Ctype.with_passive_variants
- (type_pat ~lev ~constrs ~labels ?mode ?explode env p)
- expected_ty
+ Ctype.with_passive_variants (type_pat ~lev ~mode env p) expected_ty
in
set_state state env;
(* types are invalidated but we don't need them here *)
@@ -1539,14 +1699,15 @@ 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
+ let splitting_mode = Refine_or {inside_nonsplit_or = false} in
Parmatch.check_partial
- (partial_pred ~lev ~explode env expected_ty) loc cases
+ (partial_pred ~lev ~splitting_mode ~explode env expected_ty) loc cases
let check_unused ?(lev=get_current_level ()) env expected_ty cases =
Parmatch.check_unused
(fun refute constrs labels spat ->
match
- partial_pred ~lev ~mode:Split_or ~explode:5
+ partial_pred ~lev ~splitting_mode:Backtrack_or ~explode:5
env expected_ty constrs labels spat
with
Some pat when refute ->
diff --git a/typing/typemod.ml b/typing/typemod.ml
index 64bcf5fc1d..b1800f1f30 100644
--- a/typing/typemod.ml
+++ b/typing/typemod.ml
@@ -2485,6 +2485,42 @@ let type_module_type_of env smod =
(* For Typecore *)
+(* Graft a longident onto a path *)
+let rec extend_path path =
+ fun lid ->
+ match lid with
+ | Lident name -> Pdot(path, name)
+ | Ldot(m, name) -> Pdot(extend_path path m, name)
+ | Lapply _ -> assert false
+
+(* Lookup a type's longident within a signature *)
+let lookup_type_in_sig sg =
+ let types, modules =
+ List.fold_left
+ (fun acc item ->
+ match item with
+ | Sig_type(id, _, _, _) ->
+ let types, modules = acc in
+ let types = String.Map.add (Ident.name id) id types in
+ types, modules
+ | Sig_module(id, _, _, _, _) ->
+ let types, modules = acc in
+ let modules = String.Map.add (Ident.name id) id modules in
+ types, modules
+ | _ -> acc)
+ (String.Map.empty, String.Map.empty) sg
+ in
+ let rec module_path = function
+ | Lident name -> Pident (String.Map.find name modules)
+ | Ldot(m, name) -> Pdot(module_path m, name)
+ | Lapply _ -> assert false
+ in
+ fun lid ->
+ match lid with
+ | Lident name -> Pident (String.Map.find name types)
+ | Ldot(m, name) -> Pdot(module_path m, name)
+ | Lapply _ -> assert false
+
let type_package env m p nl =
(* Same as Pexp_letmodule *)
(* remember original level *)
@@ -2493,40 +2529,62 @@ let type_package env m p nl =
let modl = type_module env m in
let scope = Ctype.create_scope () in
Typetexp.widen context;
- let (mp, env) =
- match modl.mod_desc with
- | Tmod_ident (mp,_) -> (mp, env)
- | Tmod_constraint ({mod_desc=Tmod_ident (mp,_)}, _, Tmodtype_implicit, _)
- -> (mp, env) (* PR#6982 *)
- | _ ->
- let (id, new_env) =
- Env.enter_module ~scope "%M" Mp_present modl.mod_type env
+ let nl', tl', env =
+ match nl with
+ | [] -> [], [], env
+ | nl ->
+ let type_path, env =
+ match modl.mod_desc with
+ | Tmod_ident (mp,_)
+ | Tmod_constraint
+ ({mod_desc=Tmod_ident (mp,_)}, _, Tmodtype_implicit, _) ->
+ (* We special case these because interactions between
+ strengthening of module types and packages can cause
+ spurious escape errors. See examples from PR#6982 in the
+ testsuite. This can be removed when such issues are
+ fixed. *)
+ extend_path mp, env
+ | _ ->
+ let sg = extract_sig_open env modl.mod_loc modl.mod_type in
+ let sg, env = Env.enter_signature ~scope sg env in
+ lookup_type_in_sig sg, env
in
- (Pident id, new_env)
- in
- let rec mkpath mp = function
- | Lident name -> Pdot(mp, name)
- | Ldot (m, name) -> Pdot(mkpath mp m, name)
- | _ -> assert false
+ let nl', tl' =
+ List.fold_right
+ (fun lid (nl, tl) ->
+ match type_path lid with
+ | exception Not_found -> (nl, tl)
+ | path -> begin
+ match Env.find_type path env with
+ | exception Not_found -> (nl, tl)
+ | decl ->
+ if decl.type_arity > 0 then begin
+ (nl, tl)
+ end else begin
+ let t = Btype.newgenty (Tconstr (path,[],ref Mnil)) in
+ (lid :: nl, t :: tl)
+ end
+ end)
+ nl ([], [])
+ in
+ nl', tl', env
in
- let tl' =
- List.map
- (fun name -> Btype.newgenty (Tconstr (mkpath mp name,[],ref Mnil)))
- (* beware of interactions with Printtyp and short-path:
- mp.name may have an arity > 0, cf. PR#7534 *)
- nl in
(* go back to original level *)
Ctype.end_def ();
- if nl = [] then
- (wrap_constraint env true modl (Mty_ident p) Tmodtype_implicit, [])
- else let mty = modtype_of_package env modl.mod_loc p nl tl' in
+ let mty =
+ if nl = [] then (Mty_ident p)
+ else modtype_of_package env modl.mod_loc p nl' tl'
+ in
List.iter2
(fun n ty ->
try Ctype.unify env ty (Ctype.newvar ())
with Ctype.Unify _ ->
- raise (Error(m.pmod_loc, env, Scoping_pack (n,ty))))
- nl tl';
- (wrap_constraint env true modl mty Tmodtype_implicit, tl')
+ raise (Error(modl.mod_loc, env, Scoping_pack (n,ty))))
+ nl' tl';
+ let modl = wrap_constraint env true modl mty Tmodtype_implicit in
+ (* Dropped exports should have produced an error above *)
+ assert (List.length nl = List.length tl');
+ modl, tl'
(* Fill in the forward declarations *)
diff --git a/utils/warnings.ml b/utils/warnings.ml
index 2b335d3c60..9c83485453 100644
--- a/utils/warnings.ml
+++ b/utils/warnings.ml
@@ -393,7 +393,7 @@ let parse_options errflag s =
current := {(!current) with error; active}
(* If you change these, don't forget to change them in man/ocamlc.m *)
-let defaults_w = "+a-4-6-7-9-27-29-32..42-44-45-48-50-60-66-67";;
+let defaults_w = "+a-4-6-7-9-27-29-30-32..42-44-45-48-50-60-66-67";;
let defaults_warn_error = "-a+31";;
let () = parse_options false defaults_w;;