aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.common2
-rw-r--r--checker/checkInductive.ml3
-rw-r--r--checker/checker.ml4
-rw-r--r--clib/cArray.ml8
-rw-r--r--clib/cArray.mli3
-rw-r--r--configure.ml3
-rwxr-xr-xdev/build/windows/makecoq_mingw.sh9
-rwxr-xr-xdev/ci/ci-perennial.sh5
-rw-r--r--dev/ci/user-overlays/12653-SkySkimmer-cumul-syntax.sh15
-rw-r--r--dev/ci/user-overlays/13312-ejgallego-attributes+bool_single.sh6
-rw-r--r--dev/ci/user-overlays/13386-master+fix9971-primproj-canonical-structure-on-evar-type.sh9
-rw-r--r--doc/changelog/02-specification-language/12653-cumul-syntax.rst5
-rw-r--r--doc/changelog/02-specification-language/13312-attributes+bool_single.rst17
-rw-r--r--doc/changelog/02-specification-language/13386-master+fix9971-primproj-canonical-structure-on-evar-type.rst6
-rw-r--r--doc/changelog/03-notations/12765-master+partial-app-in-recursive-notation.rst4
-rw-r--r--doc/changelog/03-notations/12984-master+import-notation-make-active-again.rst12
-rw-r--r--doc/changelog/03-notations/12986-master+ordering-notation-by-precision.rst5
-rw-r--r--doc/changelog/04-tactics/13381-bfs_eauto.rst4
-rw-r--r--doc/sphinx/addendum/program.rst8
-rw-r--r--doc/sphinx/addendum/type-classes.rst7
-rw-r--r--doc/sphinx/addendum/universe-polymorphism.rst110
-rw-r--r--doc/sphinx/changes.rst8
-rwxr-xr-xdoc/sphinx/conf.py3
-rw-r--r--doc/sphinx/language/core/basic.rst26
-rw-r--r--doc/sphinx/language/core/coinductive.rst6
-rw-r--r--doc/sphinx/language/core/definitions.rst2
-rw-r--r--doc/sphinx/language/core/inductive.rst32
-rw-r--r--doc/sphinx/language/core/records.rst6
-rw-r--r--doc/sphinx/language/core/variants.rst6
-rw-r--r--doc/sphinx/language/extensions/canonical.rst34
-rw-r--r--doc/sphinx/practical-tools/utilities.rst88
-rw-r--r--doc/sphinx/user-extensions/syntax-extensions.rst49
-rw-r--r--doc/tools/docgram/fullGrammar1
-rw-r--r--doc/tools/docgram/orderedGrammar11
-rw-r--r--interp/constrexpr.ml3
-rw-r--r--interp/constrintern.ml30
-rw-r--r--interp/constrintern.mli5
-rw-r--r--interp/notation.ml51
-rw-r--r--interp/notation_ops.ml271
-rw-r--r--interp/notation_ops.mli5
-rw-r--r--kernel/byterun/coq_fix_code.c11
-rw-r--r--kernel/byterun/coq_float64.c (renamed from kernel/byterun/coq_float64.h)52
-rw-r--r--kernel/byterun/coq_interp.c139
-rw-r--r--kernel/byterun/coq_memory.c3
-rw-r--r--kernel/byterun/coq_values.h3
-rw-r--r--kernel/byterun/dune2
-rw-r--r--kernel/context.ml9
-rw-r--r--kernel/context.mli3
-rw-r--r--kernel/entries.ml9
-rw-r--r--kernel/genOpcodeFiles.ml18
-rw-r--r--kernel/indTyping.ml11
-rw-r--r--kernel/inferCumulativity.ml109
-rw-r--r--kernel/inferCumulativity.mli4
-rw-r--r--kernel/type_errors.ml5
-rw-r--r--kernel/type_errors.mli3
-rw-r--r--kernel/vmbytecodes.ml13
-rw-r--r--kernel/vmbytecodes.mli5
-rw-r--r--kernel/vmbytegen.ml37
-rw-r--r--kernel/vmemitcodes.ml45
-rw-r--r--kernel/vmlambda.ml55
-rw-r--r--kernel/vmlambda.mli4
-rw-r--r--kernel/vmvalues.ml21
-rw-r--r--plugins/ltac/rewrite.ml19
-rw-r--r--plugins/micromega/persistent_cache.ml29
-rw-r--r--plugins/ssrmatching/ssrmatching.ml2
-rw-r--r--pretyping/evarconv.ml15
-rw-r--r--pretyping/recordops.ml22
-rw-r--r--pretyping/recordops.mli3
-rw-r--r--pretyping/retyping.ml12
-rw-r--r--test-suite/bugs/closed/bug_13246.v69
-rw-r--r--test-suite/bugs/closed/bug_13366.v5
-rw-r--r--test-suite/bugs/closed/bug_9809.v30
-rw-r--r--test-suite/bugs/closed/bug_9971.v27
-rw-r--r--test-suite/output/Notations3.out10
-rw-r--r--test-suite/output/Notations3.v24
-rw-r--r--test-suite/output/Notations4.out18
-rw-r--r--test-suite/output/Notations4.v73
-rw-r--r--test-suite/output/UnboundRef.out3
-rw-r--r--test-suite/output/UnboundRef.v2
-rw-r--r--test-suite/output/attributes.out11
-rw-r--r--test-suite/output/attributes.v9
-rw-r--r--test-suite/output/bug_10824.out4
-rw-r--r--test-suite/output/bug_10824.v12
-rw-r--r--test-suite/output/bug_7443.out13
-rw-r--r--test-suite/output/bug_7443.v37
-rw-r--r--test-suite/primitive/float/next_up_down.v43
-rw-r--r--test-suite/success/CumulInd.v20
-rw-r--r--test-suite/success/Template.v2
-rw-r--r--test-suite/success/attribute_syntax.v18
-rw-r--r--vernac/attributes.ml148
-rw-r--r--vernac/attributes.mli25
-rw-r--r--vernac/comInductive.ml31
-rw-r--r--vernac/comInductive.mli13
-rw-r--r--vernac/g_vernac.mlg45
-rw-r--r--vernac/himsg.ml6
-rw-r--r--vernac/ppvernac.ml33
-rw-r--r--vernac/record.ml42
-rw-r--r--vernac/record.mli2
-rw-r--r--vernac/vernacentries.ml12
-rw-r--r--vernac/vernacexpr.ml5
100 files changed, 1644 insertions, 693 deletions
diff --git a/Makefile.common b/Makefile.common
index caf1821ce5..1f59bff183 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -122,7 +122,7 @@ LIBCOQRUN:=kernel/byterun/lib$(COQRUN).a
DLLCOQRUN:=$(dir $(LIBCOQRUN))dll$(COQRUN)$(DLLEXT)
BYTERUN:=$(addprefix kernel/byterun/, \
- coq_fix_code.o coq_memory.o coq_values.o coq_interp.o )
+ coq_fix_code.o coq_float64.o coq_memory.o coq_values.o coq_interp.o )
# LINK ORDER:
# respecting this order is useful for developers that want to load or link
diff --git a/checker/checkInductive.ml b/checker/checkInductive.ml
index 7bb714aa17..7513564cf0 100644
--- a/checker/checkInductive.ml
+++ b/checker/checkInductive.ml
@@ -69,6 +69,7 @@ let to_entry (mb:mutual_inductive_body) : Entries.mutual_inductive_entry =
in
let mind_entry_template = Array.exists check_template mb.mind_packets in
let () = if mind_entry_template then assert (Array.for_all check_template mb.mind_packets) in
+ let mind_entry_variance = Option.map (Array.map (fun v -> Some v)) mb.mind_variance in
{
mind_entry_record;
mind_entry_finite = mb.mind_finite;
@@ -76,7 +77,7 @@ let to_entry (mb:mutual_inductive_body) : Entries.mutual_inductive_entry =
mind_entry_inds;
mind_entry_universes;
mind_entry_template;
- mind_entry_cumulative= Option.has_some mb.mind_variance;
+ mind_entry_variance;
mind_entry_private = mb.mind_private;
}
diff --git a/checker/checker.ml b/checker/checker.ml
index e2c90e2b93..08d92bb7b3 100644
--- a/checker/checker.ml
+++ b/checker/checker.ml
@@ -298,7 +298,9 @@ let explain_exn = function
| DisallowedSProp -> str"DisallowedSProp"
| BadRelevance -> str"BadRelevance"
| BadInvert -> str"BadInvert"
- | UndeclaredUniverse _ -> str"UndeclaredUniverse"))
+ | UndeclaredUniverse _ -> str"UndeclaredUniverse"
+ | BadVariance _ -> str "BadVariance"
+ ))
| InductiveError e ->
hov 0 (str "Error related to inductive types")
diff --git a/clib/cArray.ml b/clib/cArray.ml
index 7249bcada0..95ae48a7ba 100644
--- a/clib/cArray.ml
+++ b/clib/cArray.ml
@@ -56,6 +56,7 @@ sig
(int -> 'a -> 'b -> 'c -> 'd) -> 'a array -> 'b array -> 'c array -> 'd array
val map_left : ('a -> 'b) -> 'a array -> 'b array
val iter2_i : (int -> 'a -> 'b -> unit) -> 'a array -> 'b array -> unit
+ val iter3 : ('a -> 'b -> 'c -> unit) -> 'a array -> 'b array -> 'c array -> unit
val fold_left_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b array -> 'a * 'c array
val fold_right_map : ('a -> 'c -> 'b * 'c) -> 'a array -> 'c -> 'b array * 'c
val fold_left2_map : ('a -> 'b -> 'c -> 'a * 'd) -> 'a -> 'b array -> 'c array -> 'a * 'd array
@@ -392,6 +393,13 @@ let iter2_i f v1 v2 =
let () = if not (Int.equal len2 len1) then invalid_arg "Array.iter2" in
for i = 0 to len1 - 1 do f i (uget v1 i) (uget v2 i) done
+let iter3 f v1 v2 v3 =
+ let len1 = Array.length v1 in
+ let len2 = Array.length v2 in
+ let len3 = Array.length v3 in
+ let () = if not (Int.equal len2 len1) || not (Int.equal len1 len3) then invalid_arg "Array.iter3" in
+ for i = 0 to len1 - 1 do f (uget v1 i) (uget v2 i) (uget v3 i) done
+
let map_right f a =
let l = length a in
if l = 0 then [||] else begin
diff --git a/clib/cArray.mli b/clib/cArray.mli
index f40ceb56db..664bad4c0a 100644
--- a/clib/cArray.mli
+++ b/clib/cArray.mli
@@ -92,6 +92,9 @@ sig
val iter2_i : (int -> 'a -> 'b -> unit) -> 'a array -> 'b array -> unit
(** Iter on two arrays. Raise [Invalid_argument "Array.iter2_i"] if sizes differ. *)
+ val iter3 : ('a -> 'b -> 'c -> unit) -> 'a array -> 'b array -> 'c array -> unit
+ (** Iter on three arrays. Raise [Invalid_argument "Array.iter3"] if sizes differ. *)
+
val fold_left_map : ('a -> 'b -> 'a * 'c) -> 'a -> 'b array -> 'a * 'c array
(** [fold_left_map f e_0 [|l_1...l_n|] = e_n,[|k_1...k_n|]]
where [(e_i,k_i)=f e_{i-1} l_i]; see also [Smart.fold_left_map] *)
diff --git a/configure.ml b/configure.ml
index 7fd1acb53e..6a4b1f9a75 100644
--- a/configure.ml
+++ b/configure.ml
@@ -692,10 +692,13 @@ let operating_system =
let check_for_zarith () =
let zarith,_ = tryrun camlexec.find ["query";"zarith"] in
+ let zarith_cmai base = Sys.file_exists (base / "z.cmi") && Sys.file_exists (base / "zarith.cma") in
let zarith_version, _ = run camlexec.find ["query"; "zarith"; "-format"; "%v"] in
match zarith with
| "" ->
die "Zarith library not installed, required"
+ | _ when not (zarith_cmai zarith) ->
+ die "Zarith library installed but no development files found (try installing the -dev package)"
| _ ->
let zarith_version_int = List.map int_of_string (numeric_prefix_list zarith_version) in
if zarith_version_int >= [1;10;0] then
diff --git a/dev/build/windows/makecoq_mingw.sh b/dev/build/windows/makecoq_mingw.sh
index fc8921e63d..6f6b3cd6d2 100755
--- a/dev/build/windows/makecoq_mingw.sh
+++ b/dev/build/windows/makecoq_mingw.sh
@@ -404,8 +404,7 @@ function build_prep {
# ------------------------------------------------------------------------------
# Like build_prep, but gets the data from an entry in ci-basic-overlay.sh
-# This assumes the following definitions exist in ci-basic-overlay.sh,
-# or in a file in the user-overlays folder:
+# This assumes the following definitions exist in ci-basic-overlay.sh
# $1_CI_REF
# $1_CI_ARCHIVEURL
# $1_CI_GITURL
@@ -432,7 +431,7 @@ function build_prep_overlay {
}
# ------------------------------------------------------------------------------
-# Load overlay version variables from ci-basic-overlay.sh and user-overlays/*.sh
+# Load overlay version variables from ci-basic-overlay.sh
# ------------------------------------------------------------------------------
function load_overlay_data {
@@ -448,9 +447,6 @@ function load_overlay_data {
export CI_PULL_REQUEST=""
fi
- for overlay in /build/user-overlays/*.sh; do
- . "$overlay"
- done
. /build/ci-basic-overlay.sh
}
@@ -1441,7 +1437,6 @@ function make_coq {
# Copy these files somewhere the plugin builds can find them
logn copy-basic-overlays cp dev/ci/ci-basic-overlay.sh /build/
- logn copy-user-overlays cp -r dev/ci/user-overlays /build/
build_post
fi
diff --git a/dev/ci/ci-perennial.sh b/dev/ci/ci-perennial.sh
index f3be66e814..306cbdf63c 100755
--- a/dev/ci/ci-perennial.sh
+++ b/dev/ci/ci-perennial.sh
@@ -6,7 +6,4 @@ ci_dir="$(dirname "$0")"
FORCE_GIT=1
git_download perennial
-# required by Perennial's coqc.py build wrapper
-export LC_ALL=C.UTF-8
-
-( cd "${CI_BUILD_DIR}/perennial" && git submodule update --init --recursive && make TIMED=false )
+( cd "${CI_BUILD_DIR}/perennial" && git submodule update --init --recursive && make TIMED=false lite )
diff --git a/dev/ci/user-overlays/12653-SkySkimmer-cumul-syntax.sh b/dev/ci/user-overlays/12653-SkySkimmer-cumul-syntax.sh
new file mode 100644
index 0000000000..1473f6df8b
--- /dev/null
+++ b/dev/ci/user-overlays/12653-SkySkimmer-cumul-syntax.sh
@@ -0,0 +1,15 @@
+if [ "$CI_PULL_REQUEST" = "12653" ] || [ "$CI_BRANCH" = "cumul-syntax" ]; then
+
+ overlay elpi https://github.com/SkySkimmer/coq-elpi cumul-syntax
+
+ overlay equations https://github.com/SkySkimmer/Coq-Equations cumul-syntax
+
+ overlay mtac2 https://github.com/SkySkimmer/Mtac2 cumul-syntax
+
+ overlay paramcoq https://github.com/SkySkimmer/paramcoq cumul-syntax
+
+ overlay rewriter https://github.com/SkySkimmer/rewriter cumul-syntax
+
+ overlay metacoq https://github.com/SkySkimmer/metacoq cumul-syntax
+
+fi
diff --git a/dev/ci/user-overlays/13312-ejgallego-attributes+bool_single.sh b/dev/ci/user-overlays/13312-ejgallego-attributes+bool_single.sh
new file mode 100644
index 0000000000..3bdbcf7d6e
--- /dev/null
+++ b/dev/ci/user-overlays/13312-ejgallego-attributes+bool_single.sh
@@ -0,0 +1,6 @@
+if [ "$CI_PULL_REQUEST" = "13312" ] || [ "$CI_BRANCH" = "attributes+bool_single" ]; then
+
+ overlay unicoq https://github.com/ejgallego/unicoq attributes+bool_single
+ overlay elpi https://github.com/ejgallego/coq-elpi attributes+bool_single
+
+fi
diff --git a/dev/ci/user-overlays/13386-master+fix9971-primproj-canonical-structure-on-evar-type.sh b/dev/ci/user-overlays/13386-master+fix9971-primproj-canonical-structure-on-evar-type.sh
new file mode 100644
index 0000000000..95f0de2bd3
--- /dev/null
+++ b/dev/ci/user-overlays/13386-master+fix9971-primproj-canonical-structure-on-evar-type.sh
@@ -0,0 +1,9 @@
+if [ "$CI_PULL_REQUEST" = "13386" ] || [ "$CI_BRANCH" = "master+fix9971-primproj-canonical-structure-on-evar-type" ]; then
+
+ unicoq_CI_REF=master+adapting-coq-pr13386
+ unicoq_CI_GITURL=https://github.com/herbelin/unicoq
+
+ elpi_CI_REF=coq-master+adapting-coq-pr13386
+ elpi_CI_GITURL=https://github.com/herbelin/coq-elpi
+
+fi
diff --git a/doc/changelog/02-specification-language/12653-cumul-syntax.rst b/doc/changelog/02-specification-language/12653-cumul-syntax.rst
new file mode 100644
index 0000000000..ba97f7c796
--- /dev/null
+++ b/doc/changelog/02-specification-language/12653-cumul-syntax.rst
@@ -0,0 +1,5 @@
+- **Added:** Commands :cmd:`Inductive`, :cmd:`Record` and synonyms now
+ support syntax `Inductive foo@{=i +j *k l}` to specify variance
+ information for their universes (in :ref:`Cumulative <cumulative>`
+ mode) (`#12653 <https://github.com/coq/coq/pull/12653>`_, by Gaëtan
+ Gilbert).
diff --git a/doc/changelog/02-specification-language/13312-attributes+bool_single.rst b/doc/changelog/02-specification-language/13312-attributes+bool_single.rst
new file mode 100644
index 0000000000..f069bc616b
--- /dev/null
+++ b/doc/changelog/02-specification-language/13312-attributes+bool_single.rst
@@ -0,0 +1,17 @@
+- **Changed:**
+ :term:`Boolean attributes <boolean attribute>` are now specified using
+ key/value pairs, that is to say :n:`@ident__attr{? = {| yes | no } }`.
+ If the value is missing, the default is :n:`yes`. The old syntax is still
+ supported, but produces the ``deprecated-attribute-syntax`` warning.
+
+ Deprecated attributes are :attr:`universes(monomorphic)`,
+ :attr:`universes(notemplate)` and :attr:`universes(noncumulative)`, which are
+ respectively replaced by :attr:`universes(polymorphic=no) <universes(polymorphic)>`,
+ :attr:`universes(template=no) <universes(template)>`
+ and :attr:`universes(cumulative=no) <universes(cumulative)>`.
+ Attributes :attr:`program` and :attr:`canonical` are also affected,
+ with the syntax :n:`@ident__attr(false)` being deprecated in favor of
+ :n:`@ident__attr=no`.
+
+ (`#13312 <https://github.com/coq/coq/pull/13312>`_,
+ by Emilio Jesus Gallego Arias).
diff --git a/doc/changelog/02-specification-language/13386-master+fix9971-primproj-canonical-structure-on-evar-type.rst b/doc/changelog/02-specification-language/13386-master+fix9971-primproj-canonical-structure-on-evar-type.rst
new file mode 100644
index 0000000000..4bd214d7be
--- /dev/null
+++ b/doc/changelog/02-specification-language/13386-master+fix9971-primproj-canonical-structure-on-evar-type.rst
@@ -0,0 +1,6 @@
+- **Fixed:**
+ issue when two expressions involving different projections and one is
+ primitive need to be unified
+ (`#13386 <https://github.com/coq/coq/pull/13386>`_,
+ fixes `#9971 <https://github.com/coq/coq/issues/9971>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/12765-master+partial-app-in-recursive-notation.rst b/doc/changelog/03-notations/12765-master+partial-app-in-recursive-notation.rst
new file mode 100644
index 0000000000..82cbefc60b
--- /dev/null
+++ b/doc/changelog/03-notations/12765-master+partial-app-in-recursive-notation.rst
@@ -0,0 +1,4 @@
+- **Added:**
+ Added support for encoding notations of the form :g:`x ⪯ y ⪯ .. ⪯ z ⪯ t`
+ (`#12765 <https://github.com/coq/coq/pull/12765>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/12984-master+import-notation-make-active-again.rst b/doc/changelog/03-notations/12984-master+import-notation-make-active-again.rst
new file mode 100644
index 0000000000..d472e6fdf0
--- /dev/null
+++ b/doc/changelog/03-notations/12984-master+import-notation-make-active-again.rst
@@ -0,0 +1,12 @@
+- **Changed:**
+ Redeclaring a notation reactivates also its printing rule; in
+ particular a second :cmd:`Import` of the same module reactivates the
+ printing rules declared in this module. In theory, this leads to
+ changes of behavior for printing. However, this is mitigated in
+ general by the adoption in `#12986
+ <https://github.com/coq/coq/pull/12986>`_ of a priority given to
+ notations which match a larger part of the term to print
+ (`#12984 <https://github.com/coq/coq/pull/12984>`_,
+ fixes `#7443 <https://github.com/coq/coq/issues/7443>`_
+ and `#10824 <https://github.com/coq/coq/issues/10824>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/12986-master+ordering-notation-by-precision.rst b/doc/changelog/03-notations/12986-master+ordering-notation-by-precision.rst
new file mode 100644
index 0000000000..8b233972bf
--- /dev/null
+++ b/doc/changelog/03-notations/12986-master+ordering-notation-by-precision.rst
@@ -0,0 +1,5 @@
+- **Changed:**
+ Use of notations for printing now gives preference
+ to notations which match a larger part of the term to abbreviate
+ (`#12986 <https://github.com/coq/coq/pull/12986>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/04-tactics/13381-bfs_eauto.rst b/doc/changelog/04-tactics/13381-bfs_eauto.rst
index a51f96d0a2..f37fbfe52b 100644
--- a/doc/changelog/04-tactics/13381-bfs_eauto.rst
+++ b/doc/changelog/04-tactics/13381-bfs_eauto.rst
@@ -1,6 +1,6 @@
- **Deprecated:**
Undocumented :n:`eauto @int_or_var @int_or_var` syntax in favor of new ``bfs eauto``.
- Also deprecated 2-integer syntax for ``debug eauto`` and ``info_eauto``;
- replacement TBD.
+ Also deprecated 2-integer syntax for ``debug eauto`` and ``info_eauto``.
+ (Use ``bfs eauto`` with the :flag:`Info Eauto` or :flag:`Debug Eauto` flags instead.)
(`#13381 <https://github.com/coq/coq/pull/13381>`_,
by Jim Fehrle).
diff --git a/doc/sphinx/addendum/program.rst b/doc/sphinx/addendum/program.rst
index 298ea4b4ab..104f84a253 100644
--- a/doc/sphinx/addendum/program.rst
+++ b/doc/sphinx/addendum/program.rst
@@ -99,15 +99,15 @@ coercions.
Enables the program mode, in which 1) typechecking allows subset coercions and
2) the elaboration of pattern matching of :cmd:`Fixpoint` and
- :cmd:`Definition` act as if the :attr:`program` attribute had been
+ :cmd:`Definition` acts as if the :attr:`program` attribute has been
used, generating obligations if there are unresolved holes after
typechecking.
-.. attr:: program
+.. attr:: program{? = {| yes | no } }
:name: program; Program
- Allows using the Program mode on a specific
- definition. An alternative syntax is to use the legacy ``Program``
+ This :term:`boolean attribute` allows using or disabling the Program mode on a specific
+ definition. An alternative and commonly used syntax is to use the legacy ``Program``
prefix (cf. :n:`@legacy_attr`) as it is elsewhere in this chapter.
.. _syntactic_control:
diff --git a/doc/sphinx/addendum/type-classes.rst b/doc/sphinx/addendum/type-classes.rst
index 2474c784b8..22527dc379 100644
--- a/doc/sphinx/addendum/type-classes.rst
+++ b/doc/sphinx/addendum/type-classes.rst
@@ -320,10 +320,9 @@ Summary of the commands
maintained.
Like any command declaring a record, this command supports the
- :attr:`universes(polymorphic)`, :attr:`universes(monomorphic)`,
- :attr:`universes(template)`, :attr:`universes(notemplate)`,
- :attr:`universes(cumulative)`, :attr:`universes(noncumulative)` and
- :attr:`private(matching)` attributes.
+ :attr:`universes(polymorphic)`, :attr:`universes(template)`,
+ :attr:`universes(cumulative)`, and :attr:`private(matching)`
+ attributes.
.. cmd:: Existing Class @qualid
diff --git a/doc/sphinx/addendum/universe-polymorphism.rst b/doc/sphinx/addendum/universe-polymorphism.rst
index 1fb337b30a..4615a8dfca 100644
--- a/doc/sphinx/addendum/universe-polymorphism.rst
+++ b/doc/sphinx/addendum/universe-polymorphism.rst
@@ -122,33 +122,37 @@ in a universe strictly higher than :g:`Set`.
Polymorphic, Monomorphic
-------------------------
-.. attr:: universes(polymorphic)
- :name: universes(polymorphic); Polymorphic
+.. attr:: universes(polymorphic{? = {| yes | no } })
+ :name: universes(polymorphic); Polymorphic; Monomorphic
+
+ This :term:`boolean attribute` can be used to control whether universe
+ polymorphism is enabled in the definition of an inductive type.
+ There is also a legacy syntax using the ``Polymorphic`` prefix (see
+ :n:`@legacy_attr`) which, as shown in the examples, is more
+ commonly used.
+
+ When ``universes(polymorphic=no)`` is used, global universe constraints
+ are produced, even when the :flag:`Universe Polymorphism` flag is
+ on. There is also a legacy syntax using the ``Monomorphic`` prefix
+ (see :n:`@legacy_attr`).
- This attribute can be used to declare universe polymorphic
- definitions and inductive types. There is also a legacy syntax
- using the ``Polymorphic`` prefix (see :n:`@legacy_attr`) which, as
- shown in the examples, is more commonly used.
+.. attr:: universes(monomorphic)
-.. flag:: Universe Polymorphism
+ .. deprecated:: 8.13
- This flag is off by default. When it is on, new declarations are
- polymorphic unless the :attr:`universes(monomorphic)` attribute is
- used.
+ Use :attr:`universes(polymorphic=no) <universes(polymorphic)>`
+ instead.
-.. attr:: universes(monomorphic)
- :name: universes(monomorphic); Monomorphic
+.. flag:: Universe Polymorphism
- This attribute can be used to declare universe monomorphic
- definitions and inductive types (i.e. global universe constraints
- are produced), even when the :flag:`Universe Polymorphism` flag is
- on. There is also a legacy syntax using the ``Monomorphic`` prefix
- (see :n:`@legacy_attr`).
+ This flag is off by default. When it is on, new declarations are
+ polymorphic unless the :attr:`universes(polymorphic=no) <universes(polymorphic)>`
+ attribute is used to override the default.
Many other commands can be used to declare universe polymorphic or
monomorphic constants depending on whether the :flag:`Universe
-Polymorphism` flag is on or the :attr:`universes(polymorphic)` or
-:attr:`universes(monomorphic)` attributes are used:
+Polymorphism` flag is on or the :attr:`universes(polymorphic)`
+attribute is used:
- :cmd:`Lemma`, :cmd:`Axiom`, etc. can be used to declare universe
polymorphic constants.
@@ -171,19 +175,27 @@ Polymorphism` flag is on or the :attr:`universes(polymorphic)` or
Cumulative, NonCumulative
-------------------------
-.. attr:: universes(cumulative)
- :name: universes(cumulative); Cumulative
+.. attr:: universes(cumulative{? = {| yes | no } })
+ :name: universes(cumulative); Cumulative; NonCumulative
Polymorphic inductive types, coinductive types, variants and
- records can be declared cumulative using this attribute or the
- legacy ``Cumulative`` prefix (see :n:`@legacy_attr`) which, as
+ records can be declared cumulative using this :term:`boolean attribute`
+ or the legacy ``Cumulative`` prefix (see :n:`@legacy_attr`) which, as
shown in the examples, is more commonly used.
This means that two instances of the same inductive type (family)
are convertible based on the universe variances; they do not need
to be equal.
- .. exn:: The cumulative and noncumulative attributes can only be used in a polymorphic context.
+ When the attribtue is off, the inductive type is non-cumulative
+ even if the :flag:`Polymorphic Inductive Cumulativity` flag is on.
+ There is also a legacy syntax using the ``NonCumulative`` prefix
+ (see :n:`@legacy_attr`).
+
+ This means that two instances of the same inductive type (family)
+ are convertible only if all the universes are equal.
+
+ .. exn:: The cumulative attribute can only be used in a polymorphic context.
Using this attribute requires being in a polymorphic context,
i.e. either having the :flag:`Universe Polymorphism` flag on, or
@@ -192,26 +204,21 @@ Cumulative, NonCumulative
.. note::
- ``#[ universes(polymorphic), universes(cumulative) ]`` can be
- abbreviated into ``#[ universes(polymorphic, cumulative) ]``.
+ :n:`#[ universes(polymorphic{? = yes }), universes(cumulative{? = {| yes | no } }) ]` can be
+ abbreviated into :n:`#[ universes(polymorphic{? = yes }, cumulative{? = {| yes | no } }) ]`.
-.. flag:: Polymorphic Inductive Cumulativity
+.. attr:: universes(noncumulative)
- When this flag is on (it is off by default), it makes all
- subsequent *polymorphic* inductive definitions cumulative, unless
- the :attr:`universes(noncumulative)` attribute is used. It has no
- effect on *monomorphic* inductive definitions.
+ .. deprecated:: 8.13
-.. attr:: universes(noncumulative)
- :name: universes(noncumulative); NonCumulative
+ Use :attr:`universes(cumulative=no) <universes(cumulative)>` instead.
- Declares the inductive type as non-cumulative even if the
- :flag:`Polymorphic Inductive Cumulativity` flag is on. There is
- also a legacy syntax using the ``NonCumulative`` prefix (see
- :n:`@legacy_attr`).
+.. flag:: Polymorphic Inductive Cumulativity
- This means that two instances of the same inductive type (family)
- are convertible only if all the universes are equal.
+ When this flag is on (it is off by default), it makes all
+ subsequent *polymorphic* inductive definitions cumulative, unless
+ the :attr:`universes(cumulative=no) <universes(cumulative)>` attribute is
+ used to override the default. It has no effect on *monomorphic* inductive definitions.
Consider the examples below.
@@ -246,6 +253,7 @@ The following is an example of a record with non-trivial subtyping relation:
.. coqtop:: all
Polymorphic Cumulative Record packType := {pk : Type}.
+ About packType.
:g:`packType` binds a covariant universe, i.e.
@@ -254,6 +262,27 @@ The following is an example of a record with non-trivial subtyping relation:
E[Γ] ⊢ \mathsf{packType}@\{i\} =_{βδιζη}
\mathsf{packType}@\{j\}~\mbox{ whenever }~i ≤ j
+Specifying cumulativity
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The variance of the universe parameters for a cumulative inductive may be specified by the user.
+
+For the following type, universe ``a`` has its variance automatically
+inferred (it is irrelevant), ``b`` is required to be irrelevant,
+``c`` is covariant and ``d`` is invariant. With these annotations
+``c`` and ``d`` have less general variances than would be inferred.
+
+.. coqtop:: all
+
+ Polymorphic Cumulative Inductive Dummy@{a *b +c =d} : Prop := dummy.
+ About Dummy.
+
+Insufficiently restrictive variance annotations lead to errors:
+
+.. coqtop:: all
+
+ Fail Polymorphic Cumulative Record bad@{*a} := {p : Type@{a}}.
+
An example of a proof using cumulativity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -280,7 +309,7 @@ An example of a proof using cumulativity
End down.
Cumulativity Weak Constraints
------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. flag:: Cumulativity Weak Constraints
@@ -383,6 +412,7 @@ Explicit Universes
| _
| @qualid
univ_decl ::= @%{ {* @ident } {? + } {? %| {*, @univ_constraint } {? + } } %}
+ cumul_univ_decl ::= @%{ {* {? {| = | + | * } } @ident } {? + } {? %| {*, @univ_constraint } {? + } } %}
univ_constraint ::= @universe_name {| < | = | <= } @universe_name
The syntax has been extended to allow users to explicitly bind names
diff --git a/doc/sphinx/changes.rst b/doc/sphinx/changes.rst
index de5dbe79cc..24fa71059c 100644
--- a/doc/sphinx/changes.rst
+++ b/doc/sphinx/changes.rst
@@ -147,7 +147,7 @@ Specification language, type inference
This makes typeclasses with declared modes more robust with respect to the
order of resolution.
(`#10858 <https://github.com/coq/coq/pull/10858>`_,
- fixes `#9058 <https://github.com/coq/coq/issues/9058>_`, by Matthieu Sozeau).
+ fixes `#9058 <https://github.com/coq/coq/issues/9058>`_, by Matthieu Sozeau).
- **Added:**
Warn when manual implicit arguments are used in unexpected positions
of a term (e.g. in `Check id (forall {x}, x)`) or when an implicit
@@ -533,8 +533,8 @@ Flags, options and attributes
- **Removed:**
Unqualified ``polymorphic``, ``monomorphic``, ``template``,
``notemplate`` attributes (they were deprecated since Coq 8.10).
- Use :attr:`universes(polymorphic)`, :attr:`universes(monomorphic)`,
- :attr:`universes(template)` and :attr:`universes(notemplate)` instead
+ Use :attr:`universes(polymorphic)`, ``universes(monomorphic)``,
+ :attr:`universes(template)` and ``universes(notemplate)`` instead
(`#11663 <https://github.com/coq/coq/pull/11663>`_, by Théo Zimmermann).
- **Deprecated:**
:flag:`Hide Obligations` flag
@@ -545,7 +545,7 @@ Flags, options and attributes
<https://github.com/coq/coq/pull/11162>`_, by Enrico Tassi).
- **Added:**
New attributes supported when defining an inductive type
- :attr:`universes(cumulative)`, :attr:`universes(noncumulative)` and
+ :attr:`universes(cumulative)`, ``universes(noncumulative)`` and
:attr:`private(matching)`, which correspond to legacy attributes
``Cumulative``, ``NonCumulative``, and the previously undocumented
``Private`` (`#11665 <https://github.com/coq/coq/pull/11665>`_, by
diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py
index 75ac2a76cd..af5d1e3a00 100755
--- a/doc/sphinx/conf.py
+++ b/doc/sphinx/conf.py
@@ -221,7 +221,8 @@ html_context = {
'versions': [
("dev", "https://coq.github.io/doc/master/refman/"),
("stable", "https://coq.inria.fr/distrib/current/refman/"),
- ("v8.12", "https://coq.github.io/doc/v8.12/refman/"),
+ ("v8.13", "https://coq.github.io/doc/v8.13/refman/"),
+ ("8.12", "https://coq.inria.fr/distrib/V8.12.1/refman/"),
("8.11", "https://coq.inria.fr/distrib/V8.11.2/refman/"),
("8.10", "https://coq.inria.fr/distrib/V8.10.2/refman/"),
("8.9", "https://coq.inria.fr/distrib/V8.9.1/refman/"),
diff --git a/doc/sphinx/language/core/basic.rst b/doc/sphinx/language/core/basic.rst
index 5406da38a1..2b262b89c0 100644
--- a/doc/sphinx/language/core/basic.rst
+++ b/doc/sphinx/language/core/basic.rst
@@ -369,6 +369,7 @@ this attribute`.
attributes ::= {* #[ {*, @attribute } ] } {* @legacy_attr }
attribute ::= @ident {? @attr_value }
attr_value ::= = @string
+ | = @ident
| ( {*, @attribute } )
legacy_attr ::= {| Local | Global }
| {| Polymorphic | Monomorphic }
@@ -379,21 +380,22 @@ this attribute`.
The order of top-level attributes doesn't affect their meaning. ``#[foo,bar]``, ``#[bar,foo]``,
``#[foo]#[bar]`` and ``#[bar]#[foo]`` are equivalent.
+:gdef:`Boolean attributes <boolean attribute>` take the form :n:`@ident__attr{? = {| yes | no } }`.
+When the :n:`{| yes | no }` value is omitted, the default is :n:`yes`.
+
The legacy attributes (:n:`@legacy_attr`) provide an older, alternate syntax
for certain attributes. They are equivalent to new attributes as follows:
-================ ================================
-Legacy attribute New attribute
-================ ================================
-`Local` :attr:`local`
-`Global` :attr:`global`
-`Polymorphic` :attr:`universes(polymorphic)`
-`Monomorphic` :attr:`universes(monomorphic)`
-`Cumulative` :attr:`universes(cumulative)`
-`NonCumulative` :attr:`universes(noncumulative)`
-`Private` :attr:`private(matching)`
-`Program` :attr:`program`
-================ ================================
+============================= ================================
+Legacy attribute New attribute
+============================= ================================
+`Local` :attr:`local`
+`Global` :attr:`global`
+`Polymorphic`, `Monomorphic` :attr:`universes(polymorphic)`
+`Cumulative`, `NonCumulative` :attr:`universes(cumulative)`
+`Private` :attr:`private(matching)`
+`Program` :attr:`program`
+============================= ================================
Attributes appear in the HTML documentation in blue or gray boxes
after the label "Attribute". In the pdf, they appear after the
diff --git a/doc/sphinx/language/core/coinductive.rst b/doc/sphinx/language/core/coinductive.rst
index 3e2ecdc0f0..43bbc8b40d 100644
--- a/doc/sphinx/language/core/coinductive.rst
+++ b/doc/sphinx/language/core/coinductive.rst
@@ -26,10 +26,8 @@ More information on co-inductive definitions can be found in
For co-inductive types, the only elimination principle is case analysis.
This command supports the :attr:`universes(polymorphic)`,
- :attr:`universes(monomorphic)`, :attr:`universes(template)`,
- :attr:`universes(notemplate)`, :attr:`universes(cumulative)`,
- :attr:`universes(noncumulative)`, :attr:`private(matching)`
- and :attr:`using` attributes.
+ :attr:`universes(template)`, :attr:`universes(cumulative)`,
+ :attr:`private(matching)`, and :attr:`using` attributes.
.. example::
diff --git a/doc/sphinx/language/core/definitions.rst b/doc/sphinx/language/core/definitions.rst
index 79489c85f6..57771c9036 100644
--- a/doc/sphinx/language/core/definitions.rst
+++ b/doc/sphinx/language/core/definitions.rst
@@ -90,7 +90,7 @@ Section :ref:`typing-rules`.
computation on :n:`@term`.
These commands also support the :attr:`universes(polymorphic)`,
- :attr:`universes(monomorphic)`, :attr:`program` (see :ref:`program_definition`),
+ :attr:`program` (see :ref:`program_definition`),
:attr:`canonical` and :attr:`using` attributes.
If :n:`@term` is omitted, :n:`@type` is required and Coq enters proof editing mode.
diff --git a/doc/sphinx/language/core/inductive.rst b/doc/sphinx/language/core/inductive.rst
index d3bd787587..251b5e4955 100644
--- a/doc/sphinx/language/core/inductive.rst
+++ b/doc/sphinx/language/core/inductive.rst
@@ -8,13 +8,14 @@ Inductive types
.. cmd:: Inductive @inductive_definition {* with @inductive_definition }
- .. insertprodn inductive_definition constructor
+ .. insertprodn inductive_definition cumul_ident_decl
.. prodn::
- inductive_definition ::= {? > } @ident_decl {* @binder } {? %| {* @binder } } {? : @type } {? := {? @constructors_or_record } } {? @decl_notations }
+ inductive_definition ::= {? > } @cumul_ident_decl {* @binder } {? %| {* @binder } } {? : @type } {? := {? @constructors_or_record } } {? @decl_notations }
constructors_or_record ::= {? %| } {+| @constructor }
| {? @ident } %{ {*; @record_field } {? ; } %}
constructor ::= @ident {* @binder } {? @of_type }
+ cumul_ident_decl ::= @ident {? @cumul_univ_decl }
This command defines one or more
inductive types and its constructors. Coq generates destructors
@@ -31,10 +32,8 @@ Inductive types
proposition).
This command supports the :attr:`universes(polymorphic)`,
- :attr:`universes(monomorphic)`, :attr:`universes(template)`,
- :attr:`universes(notemplate)`, :attr:`universes(cumulative)`,
- :attr:`universes(noncumulative)` and :attr:`private(matching)`
- attributes.
+ :attr:`universes(template)`, :attr:`universes(cumulative)`, and
+ :attr:`private(matching)` attributes.
Mutually inductive types can be defined by including multiple :n:`@inductive_definition`\s.
The :n:`@ident`\s are simultaneously added to the environment before the types of constructors are checked.
@@ -1057,7 +1056,7 @@ Conversion is preserved as any (partial) instance :math:`I_j~q_1 … q_r` or
at level :math:`\Type` (without annotations or hiding it behind a
definition) template polymorphic if possible.
- This can be prevented using the :attr:`universes(notemplate)`
+ This can be prevented using the :attr:`universes(template=no) <universes(template)>`
attribute.
Template polymorphism and full universe polymorphism (see Chapter
@@ -1076,11 +1075,12 @@ Conversion is preserved as any (partial) instance :math:`I_j~q_1 … q_r` or
the :attr:`universes(template)` attribute: in this case, the
warning is not emitted.
-.. attr:: universes(template)
+.. attr:: universes(template{? = {| yes | no } })
+ :name: universes(template)
- This attribute can be used to explicitly declare an inductive type
- as template polymorphic, whether the :flag:`Auto Template
- Polymorphism` flag is on or off.
+ This :term:`boolean attribute` can be used to explicitly declare an
+ inductive type as template polymorphic, whether the :flag:`Auto
+ Template Polymorphism` flag is on or off.
.. exn:: template and polymorphism not compatible
@@ -1093,11 +1093,15 @@ Conversion is preserved as any (partial) instance :math:`I_j~q_1 … q_r` or
The attribute was used but the inductive definition does not
satisfy the criterion to be template polymorphic.
+ When ``universes(template=no)`` is used, it will prevent an
+ inductive type to be template polymorphic, even if the :flag:`Auto
+ Template Polymorphism` flag is on.
+
.. attr:: universes(notemplate)
- This attribute can be used to prevent an inductive type to be
- template polymorphic, even if the :flag:`Auto Template
- Polymorphism` flag is on.
+ .. deprecated:: 8.13
+
+ Use :attr:`universes(template=no) <universes(template)>` instead.
In practice, the rule **Ind-Family** is used by Coq only when all the
inductive types of the inductive definition are declared with an arity
diff --git a/doc/sphinx/language/core/records.rst b/doc/sphinx/language/core/records.rst
index e6df3ee9f5..7eedbcd59a 100644
--- a/doc/sphinx/language/core/records.rst
+++ b/doc/sphinx/language/core/records.rst
@@ -53,10 +53,8 @@ expressions. In this sense, the :cmd:`Record` construction allows defining
:cmd:`Record` and :cmd:`Structure` are synonyms.
This command supports the :attr:`universes(polymorphic)`,
- :attr:`universes(monomorphic)`, :attr:`universes(template)`,
- :attr:`universes(notemplate)`, :attr:`universes(cumulative)`,
- :attr:`universes(noncumulative)` and :attr:`private(matching)`
- attributes.
+ :attr:`universes(template)`, :attr:`universes(cumulative)`, and
+ :attr:`private(matching)` attributes.
More generally, a record may have explicitly defined (a.k.a. manifest)
fields. For instance, we might have:
diff --git a/doc/sphinx/language/core/variants.rst b/doc/sphinx/language/core/variants.rst
index 645986be9c..6ac6626dbe 100644
--- a/doc/sphinx/language/core/variants.rst
+++ b/doc/sphinx/language/core/variants.rst
@@ -17,10 +17,8 @@ Variants
this variant, unless the :flag:`Nonrecursive Elimination Schemes` flag is on.
This command supports the :attr:`universes(polymorphic)`,
- :attr:`universes(monomorphic)`, :attr:`universes(template)`,
- :attr:`universes(notemplate)`, :attr:`universes(cumulative)`,
- :attr:`universes(noncumulative)` and :attr:`private(matching)`
- attributes.
+ :attr:`universes(template)`, :attr:`universes(cumulative)`, and
+ :attr:`private(matching)` attributes.
.. exn:: The @natural th argument of @ident must be @ident in @type.
:undocumented:
diff --git a/doc/sphinx/language/extensions/canonical.rst b/doc/sphinx/language/extensions/canonical.rst
index 48120503af..f7ce7f1c6c 100644
--- a/doc/sphinx/language/extensions/canonical.rst
+++ b/doc/sphinx/language/extensions/canonical.rst
@@ -87,29 +87,27 @@ in :ref:`canonicalstructures`; here only a simple example is given.
If a same field occurs in several canonical structures, then
only the structure declared first as canonical is considered.
- .. attr:: canonical(false)
+.. attr:: canonical{? = {| yes | no } }
+ :name: canonical
- To prevent a field from being involved in the inference of
- canonical instances, its declaration can be annotated with the
- :attr:`canonical(false)` attribute (cf. the syntax of
- :n:`@record_field`).
+ This boolean attribute can decorate a :cmd:`Definition` or
+ :cmd:`Let` command. It is equivalent to having a :cmd:`Canonical
+ Structure` declaration just after the command.
- .. example::
+ To prevent a field from being involved in the inference of
+ canonical instances, its declaration can be annotated with
+ ``canonical=no`` (cf. the syntax of :n:`@record_field`).
- For instance, when declaring the :g:`Setoid` structure above, the
- :g:`Prf_equiv` field declaration could be written as follows.
-
- .. coqdoc::
+ .. example::
- #[canonical(false)] Prf_equiv : equivalence Carrier Equal
+ For instance, when declaring the :g:`Setoid` structure above, the
+ :g:`Prf_equiv` field declaration could be written as follows.
- See :ref:`canonicalstructures` for a more realistic example.
+ .. coqdoc::
-.. attr:: canonical
+ #[canonical=no] Prf_equiv : equivalence Carrier Equal
- This attribute can decorate a :cmd:`Definition` or :cmd:`Let` command.
- It is equivalent to having a :cmd:`Canonical Structure` declaration just
- after the command.
+ See :ref:`hierarchy_of_structures` for a more realistic example.
.. cmd:: Print Canonical Projections {* @reference }
@@ -248,6 +246,8 @@ for each component of the pair. The declaration associates to the key ``*``
relation ``pair_eq`` whenever the type constructor ``*`` is applied to two
types being themselves in the ``EQ`` class.
+.. _hierarchy_of_structures:
+
Hierarchy of structures
----------------------------
@@ -331,7 +331,7 @@ We need to define a new class that inherits from both ``EQ`` and ``LE``.
LE_class : LE.class T;
extra : mixin (EQ.Pack T EQ_class) (LE.cmp T LE_class) }.
- Structure type := _Pack { obj : Type; #[canonical(false)] class_of : class obj }.
+ Structure type := _Pack { obj : Type; #[canonical=no] class_of : class obj }.
Arguments Mixin {e le} _.
diff --git a/doc/sphinx/practical-tools/utilities.rst b/doc/sphinx/practical-tools/utilities.rst
index ec3689bbbe..5d36ec3cf9 100644
--- a/doc/sphinx/practical-tools/utilities.rst
+++ b/doc/sphinx/practical-tools/utilities.rst
@@ -92,14 +92,54 @@ CoqMakefile
is a makefile for ``GNU Make`` with targets to build the project
(e.g. generate .vo or .html files from .v or compile .ml* files)
and install it in the ``user-contrib`` directory where the Coq
- library is installed. Run ``make`` with the ``-f CoqMakefile``
- option to use ``CoqMakefile``.
+ library is installed.
CoqMakefile.conf
contains make variables assignments that reflect
the contents of the ``_CoqProject`` file as well as the path relevant to
Coq.
+The recommended approach is to invoke ``CoqMakefile`` from a standard
+``Makefile`` of the following form:
+
+.. example::
+
+ ::
+
+ # KNOWNTARGETS will not be passed along to CoqMakefile
+ KNOWNTARGETS := CoqMakefile extra-stuff extra-stuff2
+ # KNOWNFILES will not get implicit targets from the final rule, and so
+ # depending on them won't invoke the submake
+ # Warning: These files get declared as PHONY, so any targets depending
+ # on them always get rebuilt
+ KNOWNFILES := Makefile _CoqProject
+
+ .DEFAULT_GOAL := invoke-coqmakefile
+
+ CoqMakefile: Makefile _CoqProject
+ $(COQBIN)coq_makefile -f _CoqProject -o CoqMakefile
+
+ invoke-coqmakefile: CoqMakefile
+ $(MAKE) --no-print-directory -f CoqMakefile $(filter-out $(KNOWNTARGETS),$(MAKECMDGOALS))
+
+ .PHONY: invoke-coqmakefile $(KNOWNFILES)
+
+ ####################################################################
+ ## Your targets here ##
+ ####################################################################
+
+ # This should be the last rule, to handle any targets not declared above
+ %: invoke-coqmakefile
+ @true
+
+The advantage of a wrapper, compared to directly calling the generated
+``Makefile``, is that it
+provides a target independent of the version of Coq to regenerate a
+``Makefile`` specific to the current version of Coq. Additionally, the
+master ``Makefile`` can be extended with targets not specific to Coq.
+Including the generated makefile with an include directive is
+discouraged, since the contents of this file, including variable names and
+status of rules, may change in the future.
An optional file ``CoqMakefile.local`` can be provided by the user in order to
extend ``CoqMakefile``. In particular one can declare custom actions to be
@@ -453,50 +493,6 @@ line timing data:
This target requires python to build the table.
-Reusing/extending the generated Makefile
-++++++++++++++++++++++++++++++++++++++++
-
-Including the generated makefile with an include directive is
-discouraged. The contents of this file, including variable names and
-status of rules shall change in the future. Users are advised to
-include ``Makefile.conf`` or call a target of the generated Makefile as in
-``make -f Makefile target`` from another Makefile.
-
-One way to get access to all targets of the generated ``CoqMakefile`` is to
-have a generic target for invoking unknown targets.
-
-.. example::
-
- ::
-
- # KNOWNTARGETS will not be passed along to CoqMakefile
- KNOWNTARGETS := CoqMakefile extra-stuff extra-stuff2
- # KNOWNFILES will not get implicit targets from the final rule, and so
- # depending on them won't invoke the submake
- # Warning: These files get declared as PHONY, so any targets depending
- # on them always get rebuilt
- KNOWNFILES := Makefile _CoqProject
-
- .DEFAULT_GOAL := invoke-coqmakefile
-
- CoqMakefile: Makefile _CoqProject
- $(COQBIN)coq_makefile -f _CoqProject -o CoqMakefile
-
- invoke-coqmakefile: CoqMakefile
- $(MAKE) --no-print-directory -f CoqMakefile $(filter-out $(KNOWNTARGETS),$(MAKECMDGOALS))
-
- .PHONY: invoke-coqmakefile $(KNOWNFILES)
-
- ####################################################################
- ## Your targets here ##
- ####################################################################
-
- # This should be the last rule, to handle any targets not declared above
- %: invoke-coqmakefile
- @true
-
-
-
Building a subset of the targets with ``-j``
++++++++++++++++++++++++++++++++++++++++++++
diff --git a/doc/sphinx/user-extensions/syntax-extensions.rst b/doc/sphinx/user-extensions/syntax-extensions.rst
index f36767b207..16c8586a9f 100644
--- a/doc/sphinx/user-extensions/syntax-extensions.rst
+++ b/doc/sphinx/user-extensions/syntax-extensions.rst
@@ -214,7 +214,7 @@ have to be observed for notations starting with a symbol, e.g., rules
starting with “\ ``{``\ ” or “\ ``(``\ ” should be put at level 0. The list
of Coq predefined notations can be found in the chapter on :ref:`thecoqlibrary`.
-Displaying symbolic notations
+Use of notations for printing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The command :cmd:`Notation` has an effect both on the Coq parser and on the
@@ -323,6 +323,26 @@ at the time of use of the notation.
scope. Obviously, expressions printed by means of such extra
printing rules will not be reparsed to the same form.
+.. note::
+
+ When several notations can be used to print a given term, the
+ notations which capture the largest subterm of the term are used
+ preferentially. Here is an example:
+
+ .. coqtop:: in
+
+ Notation "x < y" := (lt x y) (at level 70).
+ Notation "x < y < z" := (lt x y /\ lt y z) (at level 70, y at next level).
+
+ Check (0 < 1 /\ 1 < 2).
+
+ When several notations match the same subterm, or incomparable
+ subterms of the term to print, the notation declared most recently
+ is selected. Moreover, reimporting a library or module declares the
+ notations of this library or module again. If the notation is in a
+ scope (see :ref:`Scopes`), either the scope has to be opened or a
+ delimiter has to exist in the scope for the notation to be usable.
+
The Infix command
~~~~~~~~~~~~~~~~~~
@@ -787,20 +807,39 @@ nested iterating pattern, the second placeholder is finally filled with the
terminating expression.
In the example above, the iterator :math:`φ([~]_E , [~]_I)` is :math:`cons [~]_E\, [~]_I`
-and the terminating expression is ``nil``. Here are other examples:
+and the terminating expression is ``nil``.
+
+Here is another example with the pattern associating on the left:
.. coqtop:: in
Notation "( x , y , .. , z )" := (pair .. (pair x y) .. z) (at level 0).
+Here is an example with more involved recursive patterns:
+
+.. coqtop:: in
+
Notation "[| t * ( x , y , .. , z ) ; ( a , b , .. , c ) * u |]" :=
(pair (pair .. (pair (pair t x) (pair t y)) .. (pair t z))
(pair .. (pair (pair a u) (pair b u)) .. (pair c u)))
(t at level 39).
-Notations with recursive patterns can be reserved like standard
-notations, they can also be declared within
-:ref:`notation scopes <Scopes>`.
+To give a flavor of the extent and limits of the mechanism, here is an
+example showing a notation for a chain of equalities. It relies on an
+artificial expansion of the intended denotation so as to expose a
+``φ(x, .. φ(y,t) ..)`` structure, with the drawback that if ever the
+beta-redexes are contracted, the notations stops to be used for
+printing.
+
+.. coqtop:: in
+
+ Notation "x ⪯ y ⪯ .. ⪯ z ⪯ t" :=
+ ((fun b A a => a <= b /\ A b) y .. ((fun b A a => a <= b /\ A b) z (fun b => b <= t)) .. x)
+ (at level 70, y at next level, z at next level, t at next level).
+
+Note finally that notations with recursive patterns can be reserved like
+standard notations, they can also be declared within :ref:`notation
+scopes <Scopes>`.
.. _RecursiveNotationsWithBinders:
diff --git a/doc/tools/docgram/fullGrammar b/doc/tools/docgram/fullGrammar
index e493f3e318..03a20d621b 100644
--- a/doc/tools/docgram/fullGrammar
+++ b/doc/tools/docgram/fullGrammar
@@ -765,6 +765,7 @@ attribute: [
attr_value: [
| "=" string
+| "=" IDENT
| "(" attribute_list ")"
|
]
diff --git a/doc/tools/docgram/orderedGrammar b/doc/tools/docgram/orderedGrammar
index dddf0a908b..0209cf762a 100644
--- a/doc/tools/docgram/orderedGrammar
+++ b/doc/tools/docgram/orderedGrammar
@@ -383,6 +383,7 @@ attribute: [
attr_value: [
| "=" string
+| "=" ident
| "(" LIST0 attribute SEP "," ")"
]
@@ -434,6 +435,10 @@ univ_decl: [
| "@{" LIST0 ident OPT "+" OPT [ "|" LIST0 univ_constraint SEP "," OPT "+" ] "}"
]
+cumul_univ_decl: [
+| "@{" LIST0 ( OPT [ "=" | "+" | "*" ] ident ) OPT "+" OPT [ "|" LIST0 univ_constraint SEP "," OPT "+" ] "}"
+]
+
univ_constraint: [
| universe_name [ "<" | "=" | "<=" ] universe_name
]
@@ -695,7 +700,7 @@ field_def: [
]
inductive_definition: [
-| OPT ">" ident_decl LIST0 binder OPT [ "|" LIST0 binder ] OPT [ ":" type ] OPT ( ":=" OPT constructors_or_record ) OPT decl_notations
+| OPT ">" cumul_ident_decl LIST0 binder OPT [ "|" LIST0 binder ] OPT [ ":" type ] OPT ( ":=" OPT constructors_or_record ) OPT decl_notations
]
constructors_or_record: [
@@ -707,6 +712,10 @@ constructor: [
| ident LIST0 binder OPT of_type
]
+cumul_ident_decl: [
+| ident OPT cumul_univ_decl
+]
+
filtered_import: [
| qualid OPT [ "(" LIST1 ( qualid OPT [ "(" ".." ")" ] ) SEP "," ")" ]
]
diff --git a/interp/constrexpr.ml b/interp/constrexpr.ml
index 235310660b..977cbbccf2 100644
--- a/interp/constrexpr.ml
+++ b/interp/constrexpr.ml
@@ -15,8 +15,11 @@ open Libnames
(** [constr_expr] is the abstract syntax tree produced by the parser *)
type universe_decl_expr = (lident list, Glob_term.glob_constraint list) UState.gen_universe_decl
+type cumul_univ_decl_expr =
+ ((lident * Univ.Variance.t option) list, Glob_term.glob_constraint list) UState.gen_universe_decl
type ident_decl = lident * universe_decl_expr option
+type cumul_ident_decl = lident * cumul_univ_decl_expr option
type name_decl = lname * universe_decl_expr option
type notation_with_optional_scope = LastLonelyNotation | NotationInScope of string
diff --git a/interp/constrintern.ml b/interp/constrintern.ml
index 02c3c047d5..b86ad7175a 100644
--- a/interp/constrintern.ml
+++ b/interp/constrintern.ml
@@ -2409,8 +2409,9 @@ let internalize globalenv env pattern_mode (_, ntnvars as lvar) c =
and intern_args env subscopes = function
| [] -> []
| a::args ->
- let (enva,subscopes) = apply_scope_env env subscopes in
- (intern_no_implicit enva a) :: (intern_args env subscopes args)
+ let (enva,subscopes) = apply_scope_env env subscopes in
+ let a = intern_no_implicit enva a in
+ a :: (intern_args env subscopes args)
in
intern env c
@@ -2648,13 +2649,34 @@ let interp_univ_decl env decl =
let binders : lident list = decl.univdecl_instance in
let evd = Evd.from_env ~binders env in
let evd, cstrs = interp_univ_constraints env evd decl.univdecl_constraints in
- let decl = { univdecl_instance = binders;
+ let decl = {
+ univdecl_instance = binders;
univdecl_extensible_instance = decl.univdecl_extensible_instance;
univdecl_constraints = cstrs;
- univdecl_extensible_constraints = decl.univdecl_extensible_constraints }
+ univdecl_extensible_constraints = decl.univdecl_extensible_constraints;
+ }
in evd, decl
+let interp_cumul_univ_decl env decl =
+ let open UState in
+ let binders = List.map fst decl.univdecl_instance in
+ let variances = Array.map_of_list snd decl.univdecl_instance in
+ let evd = Evd.from_ctx (UState.from_env ~binders env) in
+ let evd, cstrs = interp_univ_constraints env evd decl.univdecl_constraints in
+ let decl = {
+ univdecl_instance = binders;
+ univdecl_extensible_instance = decl.univdecl_extensible_instance;
+ univdecl_constraints = cstrs;
+ univdecl_extensible_constraints = decl.univdecl_extensible_constraints;
+ }
+ in
+ evd, decl, variances
+
let interp_univ_decl_opt env l =
match l with
| None -> Evd.from_env env, UState.default_univ_decl
| Some decl -> interp_univ_decl env decl
+
+let interp_cumul_univ_decl_opt env = function
+ | None -> Evd.from_env env, UState.default_univ_decl, [| |]
+ | Some decl -> interp_cumul_univ_decl env decl
diff --git a/interp/constrintern.mli b/interp/constrintern.mli
index 9037ed5414..0de6c3e89d 100644
--- a/interp/constrintern.mli
+++ b/interp/constrintern.mli
@@ -204,3 +204,8 @@ val interp_univ_decl : Environ.env -> universe_decl_expr ->
val interp_univ_decl_opt : Environ.env -> universe_decl_expr option ->
Evd.evar_map * UState.universe_decl
+
+val interp_cumul_univ_decl_opt : Environ.env -> cumul_univ_decl_expr option ->
+ Evd.evar_map * UState.universe_decl * Entries.variance_entry
+(** BEWARE the variance entry needs to be adjusted by
+ [ComInductive.variance_of_entry] if the instance is extensible. *)
diff --git a/interp/notation.ml b/interp/notation.ml
index 948ebe9640..286ece6cb6 100644
--- a/interp/notation.ml
+++ b/interp/notation.ml
@@ -345,11 +345,23 @@ let also_cases_notation_rule_eq (also_cases1,rule1) (also_cases2,rule2) =
(* No need in principle to compare also_cases as it is inferred *)
also_cases1 = also_cases2 && notation_rule_eq rule1 rule2
+let adjust_application c1 c2 =
+ match c1, c2 with
+ | NApp (t1, a1), (NList (_,_,NApp (_, a2),_,_) | NApp (_, a2)) when List.length a1 >= List.length a2 ->
+ NApp (t1, List.firstn (List.length a2) a1)
+ | NApp (t1, a1), _ ->
+ t1
+ | _ -> c1
+
+let strictly_finer_interpretation_than (_,(_,(vars1,c1),_)) (_,(_,(vars2,c2),_)) =
+ let c1 = adjust_application c1 c2 in
+ Notation_ops.strictly_finer_notation_constr (List.map fst vars1, List.map fst vars2) c1 c2
+
let keymap_add key interp map =
let old = try KeyMap.find key map with Not_found -> [] in
- (* In case of re-import, no need to keep the previous copy *)
- let old = try List.remove_first (also_cases_notation_rule_eq interp) old with Not_found -> old in
- KeyMap.add key (interp :: old) map
+ (* strictly finer interpretation are kept in front *)
+ let strictly_finer, rest = List.partition (fun c -> strictly_finer_interpretation_than c interp) old in
+ KeyMap.add key (strictly_finer @ interp :: rest) map
let keymap_remove key interp map =
let old = try KeyMap.find key map with Not_found -> [] in
@@ -391,6 +403,10 @@ let notation_constr_key = function (* Rem: NApp(NRef ref,[]) stands for @ref *)
| NBinderList (_,_,NApp (NRef ref,args),_,_) ->
RefKey (canonical_gr ref), AppBoundedNotation (List.length args)
| NRef ref -> RefKey(canonical_gr ref), NotAppNotation
+ | NApp (NList (_,_,NApp (NRef ref,args),_,_), args') ->
+ RefKey (canonical_gr ref), AppBoundedNotation (List.length args + List.length args')
+ | NApp (NList (_,_,NApp (_,args),_,_), args') ->
+ Oth, AppBoundedNotation (List.length args + List.length args')
| NApp (_,args) -> Oth, AppBoundedNotation (List.length args)
| NList (_,_,NApp (NVar x,_),_,_) when x = Notation_ops.ldots_var -> Oth, AppUnboundedNotation
| _ -> Oth, NotAppNotation
@@ -1415,12 +1431,12 @@ let check_parsing_override (scopt,ntn) data = function
| OnlyParsingData (_,old_data) ->
let overridden = not (interpretation_eq data.not_interp old_data.not_interp) in
warn_override_if_needed (scopt,ntn) overridden data old_data;
- None, not overridden
+ None
| ParsingAndPrintingData (_,on_printing,old_data) ->
let overridden = not (interpretation_eq data.not_interp old_data.not_interp) in
warn_override_if_needed (scopt,ntn) overridden data old_data;
- (if on_printing then Some old_data.not_interp else None), not overridden
- | NoParsingData -> None, false
+ if on_printing then Some old_data.not_interp else None
+ | NoParsingData -> None
let check_printing_override (scopt,ntn) data parsingdata printingdata =
let parsing_update = match parsingdata with
@@ -1449,15 +1465,15 @@ let update_notation_data (scopt,ntn) use data table =
try NotationMap.find ntn table with Not_found -> (NoParsingData, []) in
match use with
| OnlyParsing ->
- let printing_update, exists = check_parsing_override (scopt,ntn) data parsingdata in
- NotationMap.add ntn (OnlyParsingData (true,data), printingdata) table, printing_update, exists
+ let printing_update = check_parsing_override (scopt,ntn) data parsingdata in
+ NotationMap.add ntn (OnlyParsingData (true,data), printingdata) table, printing_update
| ParsingAndPrinting ->
- let printing_update, exists = check_parsing_override (scopt,ntn) data parsingdata in
- NotationMap.add ntn (ParsingAndPrintingData (true,true,data), printingdata) table, printing_update, exists
+ let printing_update = check_parsing_override (scopt,ntn) data parsingdata in
+ NotationMap.add ntn (ParsingAndPrintingData (true,true,data), printingdata) table, printing_update
| OnlyPrinting ->
let parsingdata, exists = check_printing_override (scopt,ntn) data parsingdata printingdata in
let printingdata = if exists then printingdata else (true,data) :: printingdata in
- NotationMap.add ntn (parsingdata, printingdata) table, None, exists
+ NotationMap.add ntn (parsingdata, printingdata) table, None
let rec find_interpretation ntn find = function
| [] -> raise Not_found
@@ -1730,23 +1746,22 @@ let declare_notation (scopt,ntn) pat df ~use ~also_in_cases_pattern coe deprecat
not_location = df;
not_deprecation = deprecation;
} in
- let notation_update,printing_update, exists = update_notation_data (scopt,ntn) use notdata sc.notations in
- if not exists then
- let sc = { sc with notations = notation_update } in
- scope_map := String.Map.add scope sc !scope_map;
+ let notation_update,printing_update = update_notation_data (scopt,ntn) use notdata sc.notations in
+ let sc = { sc with notations = notation_update } in
+ scope_map := String.Map.add scope sc !scope_map;
(* Update the uninterpretation cache *)
begin match printing_update with
| Some pat -> remove_uninterpretation (NotationRule (scopt,ntn)) also_in_cases_pattern pat
| None -> ()
end;
- if not exists && use <> OnlyParsing then declare_uninterpretation ~also_in_cases_pattern (NotationRule (scopt,ntn)) pat;
+ if use <> OnlyParsing then declare_uninterpretation ~also_in_cases_pattern (NotationRule (scopt,ntn)) pat;
(* Register visibility of lonely notations *)
- if not exists then begin match scopt with
+ begin match scopt with
| LastLonelyNotation -> scope_stack := LonelyNotationItem ntn :: !scope_stack
| NotationInScope _ -> ()
end;
(* Declare a possible coercion *)
- if not exists then begin match coe with
+ begin match coe with
| Some (IsEntryCoercion entry) ->
let (_,level,_) = level_of_notation ntn in
let level = match fst ntn with
diff --git a/interp/notation_ops.ml b/interp/notation_ops.ml
index 2e3fa0aa0e..d393dcaecb 100644
--- a/interp/notation_ops.ml
+++ b/interp/notation_ops.ml
@@ -24,82 +24,182 @@ open Notation_term
(**********************************************************************)
(* Utilities *)
-(* helper for NVar, NVar case in eq_notation_constr *)
-let get_var_ndx id vs = try Some (List.index Id.equal id vs) with Not_found -> None
-
-let rec eq_notation_constr (vars1,vars2 as vars) t1 t2 =
-(vars1 == vars2 && t1 == t2) ||
-match t1, t2 with
-| NRef gr1, NRef gr2 -> GlobRef.equal gr1 gr2
-| NVar id1, NVar id2 -> (
- match (get_var_ndx id1 vars1,get_var_ndx id2 vars2) with
- | Some n,Some m -> Int.equal n m
- | None ,None -> Id.equal id1 id2
- | _ -> false)
-| NApp (t1, a1), NApp (t2, a2) ->
- (eq_notation_constr vars) t1 t2 && List.equal (eq_notation_constr vars) a1 a2
-| NHole (_, _, _), NHole (_, _, _) -> true (* FIXME? *)
-| NList (i1, j1, t1, u1, b1), NList (i2, j2, t2, u2, b2) ->
- Id.equal i1 i2 && Id.equal j1 j2 && (eq_notation_constr vars) t1 t2 &&
- (eq_notation_constr vars) u1 u2 && b1 == b2
-| NLambda (na1, t1, u1), NLambda (na2, t2, u2) ->
- Name.equal na1 na2 && (eq_notation_constr vars) t1 t2 && (eq_notation_constr vars) u1 u2
-| NProd (na1, t1, u1), NProd (na2, t2, u2) ->
- Name.equal na1 na2 && (eq_notation_constr vars) t1 t2 && (eq_notation_constr vars) u1 u2
-| NBinderList (i1, j1, t1, u1, b1), NBinderList (i2, j2, t2, u2, b2) ->
- Id.equal i1 i2 && Id.equal j1 j2 && (eq_notation_constr vars) t1 t2 &&
- (eq_notation_constr vars) u1 u2 && b1 == b2
-| NLetIn (na1, b1, t1, u1), NLetIn (na2, b2, t2, u2) ->
- Name.equal na1 na2 && eq_notation_constr vars b1 b2 &&
- Option.equal (eq_notation_constr vars) t1 t2 && (eq_notation_constr vars) u1 u2
-| NCases (_, o1, r1, p1), NCases (_, o2, r2, p2) -> (* FIXME? *)
- let eqpat (p1, t1) (p2, t2) =
- List.equal cases_pattern_eq p1 p2 &&
- (eq_notation_constr vars) t1 t2
- in
- let eqf (t1, (na1, o1)) (t2, (na2, o2)) =
- let eq (i1, n1) (i2, n2) = Ind.CanOrd.equal i1 i2 && List.equal Name.equal n1 n2 in
- (eq_notation_constr vars) t1 t2 && Name.equal na1 na2 && Option.equal eq o1 o2
- in
- Option.equal (eq_notation_constr vars) o1 o2 &&
- List.equal eqf r1 r2 &&
- List.equal eqpat p1 p2
-| NLetTuple (nas1, (na1, o1), t1, u1), NLetTuple (nas2, (na2, o2), t2, u2) ->
- List.equal Name.equal nas1 nas2 &&
- Name.equal na1 na2 &&
- Option.equal (eq_notation_constr vars) o1 o2 &&
- (eq_notation_constr vars) t1 t2 &&
- (eq_notation_constr vars) u1 u2
-| NIf (t1, (na1, o1), u1, r1), NIf (t2, (na2, o2), u2, r2) ->
- (eq_notation_constr vars) t1 t2 &&
- Name.equal na1 na2 &&
- Option.equal (eq_notation_constr vars) o1 o2 &&
- (eq_notation_constr vars) u1 u2 &&
- (eq_notation_constr vars) r1 r2
-| NRec (_, ids1, ts1, us1, rs1), NRec (_, ids2, ts2, us2, rs2) -> (* FIXME? *)
- let eq (na1, o1, t1) (na2, o2, t2) =
- Name.equal na1 na2 &&
- Option.equal (eq_notation_constr vars) o1 o2 &&
- (eq_notation_constr vars) t1 t2
- in
- Array.equal Id.equal ids1 ids2 &&
- Array.equal (List.equal eq) ts1 ts2 &&
- Array.equal (eq_notation_constr vars) us1 us2 &&
- Array.equal (eq_notation_constr vars) rs1 rs2
-| NSort s1, NSort s2 ->
- glob_sort_eq s1 s2
-| NCast (t1, c1), NCast (t2, c2) ->
- (eq_notation_constr vars) t1 t2 && cast_type_eq (eq_notation_constr vars) c1 c2
-| NInt i1, NInt i2 ->
- Uint63.equal i1 i2
-| NFloat f1, NFloat f2 ->
- Float64.equal f1 f2
-| NArray(t1,def1,ty1), NArray(t2,def2,ty2) ->
- Array.equal (eq_notation_constr vars) t1 t2 && (eq_notation_constr vars) def1 def2
- && eq_notation_constr vars ty1 ty2
-| (NRef _ | NVar _ | NApp _ | NHole _ | NList _ | NLambda _ | NProd _
- | NBinderList _ | NLetIn _ | NCases _ | NLetTuple _ | NIf _
- | NRec _ | NSort _ | NCast _ | NInt _ | NFloat _ | NArray _), _ -> false
+let ldots_var = Id.of_string ".."
+
+let rec alpha_var id1 id2 = function
+ | (i1,i2)::_ when Id.equal i1 id1 -> Id.equal i2 id2
+ | (i1,i2)::_ when Id.equal i2 id2 -> Id.equal i1 id1
+ | _::idl -> alpha_var id1 id2 idl
+ | [] -> Id.equal id1 id2
+
+let cast_type_iter2 f t1 t2 = match t1, t2 with
+ | CastConv t1, CastConv t2 -> f t1 t2
+ | CastVM t1, CastVM t2 -> f t1 t2
+ | CastCoerce, CastCoerce -> ()
+ | CastNative t1, CastNative t2 -> f t1 t2
+ | (CastConv _ | CastVM _ | CastCoerce | CastNative _), _ -> raise Exit
+
+(* used to update the notation variable with the local variables used
+ in NList and NBinderList, since the iterator has its own variable *)
+let replace_var i j var = j :: List.remove Id.equal i var
+
+(* When [lt] is [true], tell if [t1] is a strict refinement of [t2]
+ (this is a partial order, so returning [false] does not mean that
+ [t2] is finer than [t1]); when [lt] is false, tell if [t1] is the
+ same pattern as [t2] *)
+
+let compare_notation_constr lt (vars1,vars2) t1 t2 =
+ (* this is used to reason up to order of notation variables *)
+ let alphameta = ref [] in
+ (* this becomes true when at least one subterm is detected as strictly smaller *)
+ let strictly_lt = ref false in
+ (* this is the stack of inner of iter patterns for comparison with a
+ new iteration or the tail of a recursive pattern *)
+ let tail = ref [] in
+ let check_alphameta id1 id2 =
+ try if not (Id.equal (List.assoc id1 !alphameta) id2) then raise Exit
+ with Not_found ->
+ if (List.mem_assoc id1 !alphameta) then raise Exit;
+ alphameta := (id1,id2) :: !alphameta in
+ let check_eq_id (vars1,vars2) renaming id1 id2 =
+ let ismeta1 = List.mem_f Id.equal id1 vars1 in
+ let ismeta2 = List.mem_f Id.equal id2 vars2 in
+ match ismeta1, ismeta2 with
+ | true, true -> check_alphameta id1 id2
+ | false, false -> if not (alpha_var id1 id2 renaming) then raise Exit
+ | false, true ->
+ if not lt then raise Exit
+ else
+ (* a binder which is not bound in the notation can be
+ considered as strictly more precise since it prevents the
+ notation variables in its scope to be bound by this binder;
+ i.e. it is strictly more precise in the sense that it
+ covers strictly less patterns than a notation where the
+ same binder is bound in the notation; this is hawever
+ disputable *)
+ strictly_lt := true
+ | true, false -> if not lt then raise Exit in
+ let check_eq_name vars renaming na1 na2 =
+ match na1, na2 with
+ | Name id1, Name id2 -> check_eq_id vars renaming id1 id2; (id1,id2)::renaming
+ | Anonymous, Anonymous -> renaming
+ | Anonymous, Name _ when lt -> renaming
+ | _ -> raise Exit in
+ let rec aux (vars1,vars2 as vars) renaming t1 t2 = match t1, t2 with
+ | NVar id1, NVar id2 when id1 = ldots_var && id2 = ldots_var -> ()
+ | _, NVar id2 when lt && id2 = ldots_var -> tail := t1 :: !tail
+ | NVar id1, _ when lt && id1 = ldots_var -> tail := t2 :: !tail
+ | NVar id1, NVar id2 -> check_eq_id vars renaming id1 id2
+ | NHole _, NVar id2 when lt && List.mem_f Id.equal id2 vars2 -> ()
+ | NVar id1, NHole (_, _, _) when lt && List.mem_f Id.equal id1 vars1 -> ()
+ | _, NVar id2 when lt && List.mem_f Id.equal id2 vars2 -> strictly_lt := true
+ | NRef gr1, NRef gr2 when GlobRef.equal gr1 gr2 -> ()
+ | NHole (_, _, _), NHole (_, _, _) -> () (* FIXME? *)
+ | _, NHole (_, _, _) when lt -> strictly_lt := true
+ | NList (i1, j1, iter1, tail1, b1), NList (i2, j2, iter2, tail2, b2)
+ | NBinderList (i1, j1, iter1, tail1, b1), NBinderList (i2, j2, iter2, tail2, b2) ->
+ if b1 <> b2 then raise Exit;
+ let vars1 = replace_var i1 j1 vars1 in
+ let vars2 = replace_var i2 j2 vars2 in
+ check_alphameta i1 i2; aux (vars1,vars2) renaming iter1 iter2; aux vars renaming tail1 tail2;
+ | NBinderList (i1, j1, iter1, tail1, b1), NList (i2, j2, iter2, tail2, b2)
+ | NList (i1, j1, iter1, tail1, b1), NBinderList (i2, j2, iter2, tail2, b2) ->
+ (* They may overlap on a unique iteration of them *)
+ let vars1 = replace_var i1 j1 vars1 in
+ let vars2 = replace_var i2 j2 vars2 in
+ aux (vars1,vars2) renaming iter1 iter2;
+ aux vars renaming tail1 tail2
+ | t1, NList (i2, j2, iter2, tail2, b2)
+ | t1, NBinderList (i2, j2, iter2, tail2, b2) when lt ->
+ (* checking if t1 is a finite iteration of the pattern *)
+ let vars2 = replace_var i2 j2 vars2 in
+ aux (vars1,vars2) renaming t1 iter2;
+ let t1 = List.hd !tail in
+ tail := List.tl !tail;
+ (* either matching a new iteration, or matching the tail *)
+ (try aux vars renaming t1 tail2 with Exit -> aux vars renaming t1 t2)
+ | NList (i1, j1, iter1, tail1, b1), t2
+ | NBinderList (i1, j1, iter1, tail1, b1), t2 when lt ->
+ (* we see the NList as a single iteration *)
+ let vars1 = replace_var i1 j1 vars1 in
+ aux (vars1,vars2) renaming iter1 t2;
+ let t2 = match !tail with
+ | t::rest -> tail := rest; t
+ | _ -> (* ".." is in a discarded fine-grained position *) raise Exit in
+ (* it had to be a single iteration of iter1 *)
+ aux vars renaming tail1 t2
+ | NApp (t1, a1), NApp (t2, a2) -> aux vars renaming t1 t2; List.iter2 (aux vars renaming) a1 a2
+ | NLambda (na1, t1, u1), NLambda (na2, t2, u2)
+ | NProd (na1, t1, u1), NProd (na2, t2, u2) ->
+ aux vars renaming t1 t2;
+ let renaming = check_eq_name vars renaming na1 na2 in
+ aux vars renaming u1 u2
+ | NLetIn (na1, b1, t1, u1), NLetIn (na2, b2, t2, u2) ->
+ aux vars renaming b1 b2;
+ Option.iter2 (aux vars renaming) t1 t2;(* TODO : subtyping? *)
+ let renaming = check_eq_name vars renaming na1 na2 in
+ aux vars renaming u1 u2
+ | NCases (_, o1, r1, p1), NCases (_, o2, r2, p2) -> (* FIXME? *)
+ let check_pat (p1, t1) (p2, t2) =
+ if not (List.equal cases_pattern_eq p1 p2) then raise Exit; (* TODO: subtyping and renaming *)
+ aux vars renaming t1 t2
+ in
+ let eqf renaming (t1, (na1, o1)) (t2, (na2, o2)) =
+ aux vars renaming t1 t2;
+ let renaming = check_eq_name vars renaming na1 na2 in
+ let eq renaming (i1, n1) (i2, n2) =
+ if not (Ind.CanOrd.equal i1 i2) then raise Exit;
+ List.fold_left2 (check_eq_name vars) renaming n1 n2 in
+ Option.fold_left2 eq renaming o1 o2 in
+ let renaming = List.fold_left2 eqf renaming r1 r2 in
+ Option.iter2 (aux vars renaming) o1 o2;
+ List.iter2 check_pat p1 p2
+ | NLetTuple (nas1, (na1, o1), t1, u1), NLetTuple (nas2, (na2, o2), t2, u2) ->
+ aux vars renaming t1 t2;
+ let renaming = check_eq_name vars renaming na1 na2 in
+ Option.iter2 (aux vars renaming) o1 o2;
+ let renaming' = List.fold_left2 (check_eq_name vars) renaming nas1 nas2 in
+ aux vars renaming' u1 u2
+ | NIf (t1, (na1, o1), u1, r1), NIf (t2, (na2, o2), u2, r2) ->
+ aux vars renaming t1 t2;
+ aux vars renaming u1 u2;
+ aux vars renaming r1 r2;
+ let renaming = check_eq_name vars renaming na1 na2 in
+ Option.iter2 (aux vars renaming) o1 o2
+ | NRec (_, ids1, ts1, us1, rs1), NRec (_, ids2, ts2, us2, rs2) -> (* FIXME? *)
+ let eq renaming (na1, o1, t1) (na2, o2, t2) =
+ Option.iter2 (aux vars renaming) o1 o2;
+ aux vars renaming t1 t2;
+ check_eq_name vars renaming na1 na2
+ in
+ let renaming = Array.fold_left2 (fun r id1 id2 -> check_eq_id vars r id1 id2; (id1,id2)::r) renaming ids1 ids2 in
+ let renamings = Array.map2 (List.fold_left2 eq renaming) ts1 ts2 in
+ Array.iter3 (aux vars) renamings us1 us2;
+ Array.iter3 (aux vars) (Array.map ((@) renaming) renamings) rs1 rs2
+ | NSort s1, NSort s2 when glob_sort_eq s1 s2 -> ()
+ | NCast (t1, c1), NCast (t2, c2) ->
+ aux vars renaming t1 t2;
+ cast_type_iter2 (aux vars renaming) c1 c2
+ | NInt i1, NInt i2 when Uint63.equal i1 i2 -> ()
+ | NFloat f1, NFloat f2 when Float64.equal f1 f2 -> ()
+ | NArray(t1,def1,ty1), NArray(t2,def2,ty2) ->
+ Array.iter2 (aux vars renaming) t1 t2;
+ aux vars renaming def1 def2;
+ aux vars renaming ty1 ty2
+ | (NRef _ | NVar _ | NApp _ | NHole _ | NList _ | NLambda _ | NProd _
+ | NBinderList _ | NLetIn _ | NCases _ | NLetTuple _ | NIf _
+ | NRec _ | NSort _ | NCast _ | NInt _ | NFloat _ | NArray _), _ -> raise Exit in
+ try
+ let _ = aux (vars1,vars2) [] t1 t2 in
+ if not lt then
+ (* Check that order of notation metavariables does not matter *)
+ List.iter2 check_alphameta vars1 vars2;
+ not lt || !strictly_lt
+ with Exit | (* Option.iter2: *) Option.Heterogeneous | Invalid_argument _ -> false
+
+let eq_notation_constr vars t1 t2 = t1 == t2 || compare_notation_constr false vars t1 t2
+
+let strictly_finer_notation_constr vars t1 t2 = compare_notation_constr true vars t1 t2
(**********************************************************************)
(* Re-interpret a notation as a glob_constr, taking care of binders *)
@@ -154,8 +254,6 @@ let rec subst_glob_vars l gc = DAst.map (function
| _ -> DAst.get (map_glob_constr (subst_glob_vars l) gc) (* assume: id is not binding *)
) gc
-let ldots_var = Id.of_string ".."
-
type 'a binder_status_fun = {
no : 'a -> 'a;
restart_prod : 'a -> 'a;
@@ -275,6 +373,12 @@ type found_variables = {
let add_id r id = r := { !r with vars = id :: (!r).vars }
let add_name r = function Anonymous -> () | Name id -> add_id r id
+let mkNApp1 (g,a) =
+ match g with
+ (* Ensure flattening of nested applicative nodes *)
+ | NApp (g,args') -> NApp (g,args'@[a])
+ | _ -> NApp (g,[a])
+
let is_gvar id c = match DAst.get c with
| GVar id' -> Id.equal id id'
| _ -> false
@@ -443,7 +547,10 @@ let notation_constr_and_vars_of_glob_constr recvars a =
aux' c
and aux' x = DAst.with_val (function
| GVar id -> if not (Id.equal id ldots_var) then add_id found id; NVar id
- | GApp (g,args) -> NApp (aux g, List.map aux args)
+ | GApp (g,[]) -> NApp (aux g,[]) (* Encoding @foo *)
+ | GApp (g,args) ->
+ (* Treat applicative notes as binary nodes *)
+ let a,args = List.sep_last args in mkNApp1 (aux (DAst.make (GApp (g, args))), aux a)
| GLambda (na,bk,ty,c) -> add_name found na; NLambda (na,aux ty,aux c)
| GProd (na,bk,ty,c) -> add_name found na; NProd (na,aux ty,aux c)
| GLetIn (na,b,t,c) -> add_name found na; NLetIn (na,aux b,Option.map aux t, aux c)
@@ -740,12 +847,6 @@ let is_bindinglist_meta id metas =
exception No_match
-let rec alpha_var id1 id2 = function
- | (i1,i2)::_ when Id.equal i1 id1 -> Id.equal i2 id2
- | (i1,i2)::_ when Id.equal i2 id2 -> Id.equal i1 id1
- | _::idl -> alpha_var id1 id2 idl
- | [] -> Id.equal id1 id2
-
let alpha_rename alpmetas v =
if alpmetas == [] then v
else try rename_glob_vars alpmetas v with UnsoundRenaming -> raise No_match
diff --git a/interp/notation_ops.mli b/interp/notation_ops.mli
index 3cc6f82ec8..3182ea96d7 100644
--- a/interp/notation_ops.mli
+++ b/interp/notation_ops.mli
@@ -16,6 +16,11 @@ open Glob_term
val eq_notation_constr : Id.t list * Id.t list -> notation_constr -> notation_constr -> bool
+val strictly_finer_notation_constr : Id.t list * Id.t list -> notation_constr -> notation_constr -> bool
+(** Tell if [t1] is a strict refinement of [t2]
+ (this is a partial order and returning [false] does not mean that
+ [t2] is finer than [t1]) *)
+
(** Substitution of kernel names in interpretation data *)
val subst_interpretation :
diff --git a/kernel/byterun/coq_fix_code.c b/kernel/byterun/coq_fix_code.c
index 9118410549..1ba6a8c8fe 100644
--- a/kernel/byterun/coq_fix_code.c
+++ b/kernel/byterun/coq_fix_code.c
@@ -43,9 +43,7 @@ void init_arity () {
arity[CONST0]=arity[CONST1]=arity[CONST2]=arity[CONST3]=
arity[PUSHCONST0]=arity[PUSHCONST1]=arity[PUSHCONST2]=arity[PUSHCONST3]=
arity[ACCUMULATE]=arity[STOP]=arity[MAKEPROD]=
- arity[ADDINT63]=arity[SUBINT63]=arity[LTINT63]=arity[LEINT63]=
- arity[LTFLOAT]=arity[LEFLOAT]=
- arity[ISINT]=arity[AREINT2]=0;
+ 0;
/* instruction with one operand */
arity[ACC]=arity[PUSHACC]=arity[POP]=arity[ENVACC]=arity[PUSHENVACC]=
arity[PUSH_RETADDR]=arity[APPLY]=arity[APPTERM1]=arity[APPTERM2]=
@@ -75,9 +73,10 @@ void init_arity () {
arity[CHECKNEXTUPFLOAT]=arity[CHECKNEXTDOWNFLOAT]=1;
/* instruction with two operands */
arity[APPTERM]=arity[MAKEBLOCK]=arity[CLOSURE]=
- arity[ISARRAY_CAML_CALL1]=arity[ISINT_CAML_CALL2]=
- arity[ISARRAY_INT_CAML_CALL2]=arity[ISARRAY_INT_CAML_CALL3]=
- arity[PROJ]=2;
+ arity[CHECKCAMLCALL1]=arity[CHECKCAMLCALL2_1]=
+ arity[CHECKCAMLCALL2]=arity[CHECKCAMLCALL3_1]=
+ arity[PROJ]=
+ 2;
/* instruction with four operands */
arity[MAKESWITCHBLOCK]=4;
/* instruction with arbitrary operands */
diff --git a/kernel/byterun/coq_float64.h b/kernel/byterun/coq_float64.c
index 84a3edf1c7..bea47dd47e 100644
--- a/kernel/byterun/coq_float64.h
+++ b/kernel/byterun/coq_float64.c
@@ -8,19 +8,40 @@
/* * (see LICENSE file for the text of the license) */
/************************************************************************/
-#ifndef _COQ_FLOAT64_
-#define _COQ_FLOAT64_
-
#include <math.h>
+#include <stdint.h>
-#define DECLARE_FREL(name, e) \
- int coq_##name(double x, double y) { \
- return e; \
- } \
- \
- value coq_##name##_byte(value x, value y) { \
- return coq_##name(Double_val(x), Double_val(y)); \
- }
+#define CAML_INTERNALS
+#include <caml/alloc.h>
+
+#include "coq_values.h"
+
+union double_bits {
+ double d;
+ uint64_t u;
+};
+
+static double next_up(double x) {
+ union double_bits bits;
+ if (!(x < INFINITY)) return x; // x is +oo or NaN
+ bits.d = x;
+ int64_t i = bits.u;
+ if (i >= 0) ++bits.u; // x >= +0.0, go away from zero
+ else if (bits.u + bits.u == 0) bits.u = 1; // x is -0.0, should almost never happen
+ else --bits.u; // x < 0.0, go toward zero
+ return bits.d;
+}
+
+static double next_down(double x) {
+ union double_bits bits;
+ if (!(x > -INFINITY)) return x; // x is -oo or NaN
+ bits.d = x;
+ int64_t i = bits.u;
+ if (i == 0) bits.u = INT64_MIN + 1; // x is +0.0
+ else if (i < 0) ++bits.u; // x <= -0.0, go away from zero
+ else --bits.u; // x > 0.0, go toward zero
+ return bits.d;
+}
#define DECLARE_FBINOP(name, e) \
double coq_##name(double x, double y) { \
@@ -40,19 +61,14 @@
return caml_copy_double(coq_##name(Double_val(x))); \
}
-DECLARE_FREL(feq, x == y)
-DECLARE_FREL(flt, x < y)
-DECLARE_FREL(fle, x <= y)
DECLARE_FBINOP(fmul, x * y)
DECLARE_FBINOP(fadd, x + y)
DECLARE_FBINOP(fsub, x - y)
DECLARE_FBINOP(fdiv, x / y)
DECLARE_FUNOP(fsqrt, sqrt(x))
-DECLARE_FUNOP(next_up, nextafter(x, INFINITY))
-DECLARE_FUNOP(next_down, nextafter(x, -INFINITY))
+DECLARE_FUNOP(next_up, next_up(x))
+DECLARE_FUNOP(next_down, next_down(x))
value coq_is_double(value x) {
return Val_long(Is_double(x));
}
-
-#endif /* _COQ_FLOAT64_ */
diff --git a/kernel/byterun/coq_interp.c b/kernel/byterun/coq_interp.c
index 1b6da7dd6f..8990743de2 100644
--- a/kernel/byterun/coq_interp.c
+++ b/kernel/byterun/coq_interp.c
@@ -28,7 +28,6 @@
#include "coq_fix_code.h"
#include "coq_memory.h"
#include "coq_values.h"
-#include "coq_float64.h"
#if OCAML_VERSION < 41000
extern void caml_minor_collection(void);
@@ -113,7 +112,7 @@ if (sp - num_args < coq_stack_threshold) { \
#define Setup_for_gc { sp -= 2; sp[0] = accu; sp[1] = coq_env; coq_sp = sp; }
#define Restore_after_gc { accu = sp[0]; coq_env = sp[1]; sp += 2; }
#define Setup_for_caml_call { *--sp = coq_env; coq_sp = sp; }
-#define Restore_after_caml_call { sp = coq_sp; coq_env = *sp++; }
+#define Restore_after_caml_call coq_env = *sp++;
/* Register optimization.
Some compilers underestimate the use of the local variables representing
@@ -193,7 +192,9 @@ if (sp - num_args < coq_stack_threshold) { \
#endif
#endif
-#define Is_accu(v) (Is_block(v) && Tag_val(v) == Closure_tag && Code_val(v) == accumulate)
+/* We should also check "Code_val(v) == accumulate" to be sure,
+ but Is_accu is only used in places where closures cannot occur. */
+#define Is_accu(v) (Is_block(v) && Tag_val(v) == Closure_tag)
#define CheckPrimArgs(cond, apply_lbl) do{ \
if (cond) pc++; \
@@ -237,6 +238,9 @@ extern intnat volatile caml_pending_signals[];
extern void caml_process_pending_signals(void);
#endif
+extern double coq_next_up(double);
+extern double coq_next_down(double);
+
/* The interpreter itself */
value coq_interprete
@@ -1271,11 +1275,8 @@ value coq_interprete
Instruct(CHECKADDINT63){
print_instr("CHECKADDINT63");
CheckInt2();
- }
- Instruct(ADDINT63) {
/* Adds the integer in the accumulator with
the one ontop of the stack (which is poped)*/
- print_instr("ADDINT63");
Uint63_add(accu, *sp++);
Next;
}
@@ -1309,9 +1310,6 @@ value coq_interprete
Instruct (CHECKSUBINT63) {
print_instr("CHECKSUBINT63");
CheckInt2();
- }
- Instruct (SUBINT63) {
- print_instr("SUBINT63");
/* returns the subtraction */
Uint63_sub(accu, *sp++);
Next;
@@ -1517,9 +1515,6 @@ value coq_interprete
Instruct (CHECKLTINT63) {
print_instr("CHECKLTINT63");
CheckInt2();
- }
- Instruct (LTINT63) {
- print_instr("LTINT63");
int b;
Uint63_lt(b,accu,*sp++);
accu = b ? coq_true : coq_false;
@@ -1529,9 +1524,6 @@ value coq_interprete
Instruct (CHECKLEINT63) {
print_instr("CHECKLEINT63");
CheckInt2();
- }
- Instruct (LEINT63) {
- print_instr("LEINT63");
int b;
Uint63_leq(b,accu,*sp++);
accu = b ? coq_true : coq_false;
@@ -1570,20 +1562,6 @@ value coq_interprete
Next;
}
- Instruct (ISINT){
- print_instr("ISINT");
- accu = (Is_uint63(accu)) ? coq_true : coq_false;
- Next;
- }
-
- Instruct (AREINT2){
- print_instr("AREINT2");
- accu = (Is_uint63(accu) && Is_uint63(sp[0])) ? coq_true : coq_false;
- sp++;
- Next;
- }
-
-
Instruct (CHECKOPPFLOAT) {
print_instr("CHECKOPPFLOAT");
CheckFloat1();
@@ -1601,27 +1579,21 @@ value coq_interprete
Instruct (CHECKEQFLOAT) {
print_instr("CHECKEQFLOAT");
CheckFloat2();
- accu = coq_feq(Double_val(accu), Double_val(*sp++)) ? coq_true : coq_false;
+ accu = Double_val(accu) == Double_val(*sp++) ? coq_true : coq_false;
Next;
}
Instruct (CHECKLTFLOAT) {
print_instr("CHECKLTFLOAT");
CheckFloat2();
- }
- Instruct (LTFLOAT) {
- print_instr("LTFLOAT");
- accu = coq_flt(Double_val(accu), Double_val(*sp++)) ? coq_true : coq_false;
+ accu = Double_val(accu) < Double_val(*sp++) ? coq_true : coq_false;
Next;
}
Instruct (CHECKLEFLOAT) {
print_instr("CHECKLEFLOAT");
CheckFloat2();
- }
- Instruct (LEFLOAT) {
- print_instr("LEFLOAT");
- accu = coq_fle(Double_val(accu), Double_val(*sp++)) ? coq_true : coq_false;
+ accu = Double_val(accu) <= Double_val(*sp++) ? coq_true : coq_false;
Next;
}
@@ -1674,35 +1646,35 @@ value coq_interprete
Instruct (CHECKADDFLOAT) {
print_instr("CHECKADDFLOAT");
CheckFloat2();
- Coq_copy_double(coq_fadd(Double_val(accu), Double_val(*sp++)));
+ Coq_copy_double(Double_val(accu) + Double_val(*sp++));
Next;
}
Instruct (CHECKSUBFLOAT) {
print_instr("CHECKSUBFLOAT");
CheckFloat2();
- Coq_copy_double(coq_fsub(Double_val(accu), Double_val(*sp++)));
+ Coq_copy_double(Double_val(accu) - Double_val(*sp++));
Next;
}
Instruct (CHECKMULFLOAT) {
print_instr("CHECKMULFLOAT");
CheckFloat2();
- Coq_copy_double(coq_fmul(Double_val(accu), Double_val(*sp++)));
+ Coq_copy_double(Double_val(accu) * Double_val(*sp++));
Next;
}
Instruct (CHECKDIVFLOAT) {
print_instr("CHECKDIVFLOAT");
CheckFloat2();
- Coq_copy_double(coq_fdiv(Double_val(accu), Double_val(*sp++)));
+ Coq_copy_double(Double_val(accu) / Double_val(*sp++));
Next;
}
Instruct (CHECKSQRTFLOAT) {
print_instr("CHECKSQRTFLOAT");
CheckFloat1();
- Coq_copy_double(coq_fsqrt(Double_val(accu)));
+ Coq_copy_double(sqrt(Double_val(accu)));
Next;
}
@@ -1784,11 +1756,25 @@ value coq_interprete
Next;
}
+ Instruct (CHECKNEXTUPFLOATINPLACE) {
+ print_instr("CHECKNEXTUPFLOATINPLACE");
+ CheckFloat1();
+ Store_double_val(accu, coq_next_up(Double_val(accu)));
+ Next;
+ }
+
+ Instruct (CHECKNEXTDOWNFLOATINPLACE) {
+ print_instr("CHECKNEXTDOWNFLOATINPLACE");
+ CheckFloat1();
+ Store_double_val(accu, coq_next_down(Double_val(accu)));
+ Next;
+ }
- Instruct(ISINT_CAML_CALL2) {
+ Instruct(CHECKCAMLCALL2_1) {
+ // arity-2 callback, the last argument can be an accumulator
value arg;
- print_instr("ISINT_CAML_CALL2");
- if (Is_uint63(accu)) {
+ print_instr("CHECKCAMLCALL2_1");
+ if (!Is_accu(accu)) {
pc++;
print_int(*pc);
arg = sp[0];
@@ -1801,47 +1787,50 @@ value coq_interprete
Next;
}
- Instruct(ISARRAY_CAML_CALL1) {
- print_instr("ISARRAY_CAML_CALL1");
- if (Is_coq_array(accu)) {
- pc++;
- Setup_for_caml_call;
- print_int(*pc);
- accu = caml_callback(Field(coq_global_data, *pc),accu);
- Restore_after_caml_call;
- pc++;
- }
- else pc += *pc;
- Next;
+ Instruct(CHECKCAMLCALL1) {
+ // arity-1 callback, no argument can be an accumulator
+ print_instr("CHECKCAMLCALL1");
+ if (!Is_accu(accu)) {
+ pc++;
+ Setup_for_caml_call;
+ print_int(*pc);
+ accu = caml_callback(Field(coq_global_data, *pc), accu);
+ Restore_after_caml_call;
+ pc++;
+ }
+ else pc += *pc;
+ Next;
}
- Instruct(ISARRAY_INT_CAML_CALL2) {
+ Instruct(CHECKCAMLCALL2) {
+ // arity-2 callback, no argument can be an accumulator
value arg;
- print_instr("ISARRAY_INT_CAML_CALL2");
- if (Is_coq_array(accu) && Is_uint63(sp[0])) {
- pc++;
- arg = sp[0];
- Setup_for_caml_call;
- print_int(*pc);
- accu = caml_callback2(Field(coq_global_data, *pc), accu, arg);
- Restore_after_caml_call;
- sp += 1;
- pc++;
- } else pc += *pc;
- Next;
+ print_instr("CHECKCAMLCALL2");
+ if (!Is_accu(accu) && !Is_accu(sp[0])) {
+ pc++;
+ arg = sp[0];
+ Setup_for_caml_call;
+ print_int(*pc);
+ accu = caml_callback2(Field(coq_global_data, *pc), accu, arg);
+ Restore_after_caml_call;
+ sp += 1;
+ pc++;
+ } else pc += *pc;
+ Next;
}
- Instruct(ISARRAY_INT_CAML_CALL3) {
+ Instruct(CHECKCAMLCALL3_1) {
+ // arity-3 callback, the last argument can be an accumulator
value arg1;
value arg2;
- print_instr("ISARRAY_INT_CAML_CALL3");
- if (Is_coq_array(accu) && Is_uint63(sp[0])) {
+ print_instr("CHECKCAMLCALL3_1");
+ if (!Is_accu(accu) && !Is_accu(sp[0])) {
pc++;
arg1 = sp[0];
arg2 = sp[1];
Setup_for_caml_call;
print_int(*pc);
- accu = caml_callback3(Field(coq_global_data, *pc),accu, arg1, arg2);
+ accu = caml_callback3(Field(coq_global_data, *pc), accu, arg1, arg2);
Restore_after_caml_call;
sp += 2;
pc++;
diff --git a/kernel/byterun/coq_memory.c b/kernel/byterun/coq_memory.c
index ae5251c252..fe076f8f04 100644
--- a/kernel/byterun/coq_memory.c
+++ b/kernel/byterun/coq_memory.c
@@ -65,9 +65,10 @@ static void coq_scan_roots(scanning_action action)
register value * i;
/* Scan the stack */
for (i = coq_sp; i < coq_stack_high; i++) {
+ if (!Is_block(*i)) continue;
#ifdef NO_NAKED_POINTERS
/* The VM stack may contain C-allocated bytecode */
- if (Is_block(*i) && !Is_in_heap_or_young(*i)) continue;
+ if (!Is_in_heap_or_young(*i)) continue;
#endif
(*action) (*i, i);
};
diff --git a/kernel/byterun/coq_values.h b/kernel/byterun/coq_values.h
index f07018711b..0cdef34050 100644
--- a/kernel/byterun/coq_values.h
+++ b/kernel/byterun/coq_values.h
@@ -30,9 +30,6 @@
#define Is_double(v) (Tag_val(v) == Double_tag)
#define Is_tailrec_switch(v) (Field(v,1) == Val_true)
-/* coq array */
-#define Is_coq_array(v) (Is_block(v) && (Wosize_val(v) == 1))
-
/* coq values for primitive operations */
#define coq_tag_C1 2
#define coq_tag_C0 1
diff --git a/kernel/byterun/dune b/kernel/byterun/dune
index 2998178be2..d3e2a2fa7f 100644
--- a/kernel/byterun/dune
+++ b/kernel/byterun/dune
@@ -4,7 +4,7 @@
(public_name coq.vm)
(foreign_stubs
(language c)
- (names coq_fix_code coq_memory coq_values coq_interp)
+ (names coq_fix_code coq_float64 coq_memory coq_values coq_interp)
(flags (:include %{project_root}/config/dune.c_flags))))
(rule
diff --git a/kernel/context.ml b/kernel/context.ml
index 6a99f201f3..ab66898b59 100644
--- a/kernel/context.ml
+++ b/kernel/context.ml
@@ -365,6 +365,15 @@ struct
let ty' = f ty in
if v == v' && ty == ty' then decl else LocalDef (id, v', ty')
+ let map_constr_het f = function
+ | LocalAssum (id, ty) ->
+ let ty' = f ty in
+ LocalAssum (id, ty')
+ | LocalDef (id, v, ty) ->
+ let v' = f v in
+ let ty' = f ty in
+ LocalDef (id, v', ty')
+
(** Perform a given action on all terms in a given declaration. *)
let iter_constr f = function
| LocalAssum (_, ty) -> f ty
diff --git a/kernel/context.mli b/kernel/context.mli
index 76c4461760..29309daf34 100644
--- a/kernel/context.mli
+++ b/kernel/context.mli
@@ -231,6 +231,9 @@ sig
(** Map all terms in a given declaration. *)
val map_constr : ('c -> 'c) -> ('c, 'c) pt -> ('c, 'c) pt
+ (** Map all terms, with an heterogeneous function. *)
+ val map_constr_het : ('a -> 'b) -> ('a, 'a) pt -> ('b, 'b) pt
+
(** Perform a given action on all terms in a given declaration. *)
val iter_constr : ('c -> unit) -> ('c, 'c) pt -> unit
diff --git a/kernel/entries.ml b/kernel/entries.ml
index ae64112e33..1bfc740017 100644
--- a/kernel/entries.ml
+++ b/kernel/entries.ml
@@ -20,6 +20,8 @@ type universes_entry =
| Monomorphic_entry of Univ.ContextSet.t
| Polymorphic_entry of Name.t array * Univ.UContext.t
+type variance_entry = Univ.Variance.t option array
+
type 'a in_universes_entry = 'a * universes_entry
(** {6 Declaration of inductive types. } *)
@@ -50,9 +52,10 @@ type mutual_inductive_entry = {
mind_entry_inds : one_inductive_entry list;
mind_entry_universes : universes_entry;
mind_entry_template : bool; (* Use template polymorphism *)
- mind_entry_cumulative : bool;
- (* universe constraints and the constraints for subtyping of
- inductive types in the block. *)
+ mind_entry_variance : variance_entry option;
+ (* [None] if non-cumulative, otherwise associates each universe of
+ the entry to [None] if to be inferred or [Some v] if to be
+ checked. *)
mind_entry_private : bool option;
}
diff --git a/kernel/genOpcodeFiles.ml b/kernel/genOpcodeFiles.ml
index f052e03cde..dc2cd349ce 100644
--- a/kernel/genOpcodeFiles.ml
+++ b/kernel/genOpcodeFiles.ml
@@ -104,11 +104,9 @@ let opcodes =
"MAKEPROD";
"BRANCH";
"CHECKADDINT63";
- "ADDINT63";
"CHECKADDCINT63";
"CHECKADDCARRYCINT63";
"CHECKSUBINT63";
- "SUBINT63";
"CHECKSUBCINT63";
"CHECKSUBCARRYCINT63";
"CHECKMULINT63";
@@ -127,21 +125,15 @@ let opcodes =
"CHECKLSRINT63CONST1";
"CHECKEQINT63";
"CHECKLTINT63";
- "LTINT63";
"CHECKLEINT63";
- "LEINT63";
"CHECKCOMPAREINT63";
"CHECKHEAD0INT63";
"CHECKTAIL0INT63";
- "ISINT";
- "AREINT2";
"CHECKOPPFLOAT";
"CHECKABSFLOAT";
"CHECKEQFLOAT";
"CHECKLTFLOAT";
- "LTFLOAT";
"CHECKLEFLOAT";
- "LEFLOAT";
"CHECKCOMPAREFLOAT";
"CHECKCLASSIFYFLOAT";
"CHECKADDFLOAT";
@@ -155,10 +147,12 @@ let opcodes =
"CHECKLDSHIFTEXP";
"CHECKNEXTUPFLOAT";
"CHECKNEXTDOWNFLOAT";
- "ISINT_CAML_CALL2";
- "ISARRAY_CAML_CALL1";
- "ISARRAY_INT_CAML_CALL2";
- "ISARRAY_INT_CAML_CALL3";
+ "CHECKNEXTUPFLOATINPLACE";
+ "CHECKNEXTDOWNFLOATINPLACE";
+ "CHECKCAMLCALL2_1";
+ "CHECKCAMLCALL1";
+ "CHECKCAMLCALL2";
+ "CHECKCAMLCALL3_1";
"STOP"
|]
diff --git a/kernel/indTyping.ml b/kernel/indTyping.ml
index b2520b780f..33ee8c325a 100644
--- a/kernel/indTyping.ml
+++ b/kernel/indTyping.ml
@@ -369,15 +369,20 @@ let typecheck_inductive env ~sec_univs (mie:mutual_inductive_entry) =
data, Some None
in
- let variance = if not mie.mind_entry_cumulative then None
- else match mie.mind_entry_universes with
+ let variance = match mie.mind_entry_variance with
+ | None -> None
+ | Some variances ->
+ match mie.mind_entry_universes with
| Monomorphic_entry _ ->
CErrors.user_err Pp.(str "Inductive cannot be both monomorphic and universe cumulative.")
| Polymorphic_entry (_,uctx) ->
let univs = Instance.to_array @@ UContext.instance uctx in
+ let univs = Array.map2 (fun a b -> a,b) univs variances in
let univs = match sec_univs with
| None -> univs
- | Some sec_univs -> Array.append sec_univs univs
+ | Some sec_univs ->
+ let sec_univs = Array.map (fun u -> u, None) sec_univs in
+ Array.append sec_univs univs
in
let variances = InferCumulativity.infer_inductive ~env_params univs mie.mind_entry_inds in
Some variances
diff --git a/kernel/inferCumulativity.ml b/kernel/inferCumulativity.ml
index 8191a5b0f3..d02f92ef26 100644
--- a/kernel/inferCumulativity.ml
+++ b/kernel/inferCumulativity.ml
@@ -15,30 +15,82 @@ open Univ
open Variance
open Util
-type inferred = IrrelevantI | CovariantI
-
-(** Throughout this module we modify a map [variances] from local
- universes to [inferred]. It starts as a trivial mapping to
- [Irrelevant] and every time we encounter a local universe we
- restrict it accordingly.
- [Invariant] universes are removed from the map.
-*)
exception TrivialVariance
-let maybe_trivial variances =
- if LMap.is_empty variances then raise TrivialVariance
- else variances
+(** Not the same as Type_errors.BadVariance because we don't have the env where we raise. *)
+exception BadVariance of Level.t * Variance.t * Variance.t
+(* some ocaml bug is triggered if we make this an inline record *)
-let infer_level_eq u variances =
- maybe_trivial (LMap.remove u variances)
+module Inf : sig
+ type variances
+ val infer_level_eq : Level.t -> variances -> variances
+ val infer_level_leq : Level.t -> variances -> variances
+ val start : (Level.t * Variance.t option) array -> variances
+ val finish : variances -> Variance.t array
+end = struct
+ type inferred = IrrelevantI | CovariantI
+ type mode = Check | Infer
-let infer_level_leq u variances =
- (* can only set Irrelevant -> Covariant so nontrivial *)
- LMap.update u (function
- | None -> None
- | Some CovariantI as x -> x
- | Some IrrelevantI -> Some CovariantI)
- variances
+ (**
+ Each local universe is either in the [univs] map or is Invariant.
+
+ If [univs] is empty all universes are Invariant and there is nothing more to do,
+ so we stop by raising [TrivialVariance]. The [soft] check comes before that.
+ *)
+ type variances = {
+ orig_array : (Level.t * Variance.t option) array;
+ univs : (mode * inferred) LMap.t;
+ }
+
+ let to_variance = function
+ | IrrelevantI -> Irrelevant
+ | CovariantI -> Covariant
+
+ let to_variance_opt o = Option.cata to_variance Invariant o
+
+ let infer_level_eq u variances =
+ match LMap.find_opt u variances.univs with
+ | None -> variances
+ | Some (Check, expected) ->
+ let expected = to_variance expected in
+ raise (BadVariance (u, expected, Invariant))
+ | Some (Infer, _) ->
+ let univs = LMap.remove u variances.univs in
+ if LMap.is_empty univs then raise TrivialVariance;
+ {variances with univs}
+
+ let infer_level_leq u variances =
+ (* can only set Irrelevant -> Covariant so no TrivialVariance *)
+ let univs =
+ LMap.update u (function
+ | None -> None
+ | Some (_,CovariantI) as x -> x
+ | Some (Infer,IrrelevantI) -> Some (Infer,CovariantI)
+ | Some (Check,IrrelevantI) ->
+ raise (BadVariance (u, Irrelevant, Covariant)))
+ variances.univs
+ in
+ if univs == variances.univs then variances else {variances with univs}
+
+ let start us =
+ let univs = Array.fold_left (fun univs (u,variance) ->
+ match variance with
+ | None -> LMap.add u (Infer,IrrelevantI) univs
+ | Some Invariant -> univs
+ | Some Covariant -> LMap.add u (Check,CovariantI) univs
+ | Some Irrelevant -> LMap.add u (Check,IrrelevantI) univs)
+ LMap.empty us
+ in
+ if LMap.is_empty univs then raise TrivialVariance;
+ {univs; orig_array=us}
+
+ let finish variances =
+ Array.map
+ (fun (u,_check) -> to_variance_opt (Option.map snd (LMap.find_opt u variances.univs)))
+ variances.orig_array
+
+end
+open Inf
let infer_generic_instance_eq variances u =
Array.fold_left (fun variances u -> infer_level_eq u variances)
@@ -204,11 +256,7 @@ let infer_arity_constructor is_arity env variances arcn =
open Entries
let infer_inductive_core env univs entries =
- if Array.is_empty univs then raise TrivialVariance;
- let variances =
- Array.fold_left (fun variances u -> LMap.add u IrrelevantI variances)
- LMap.empty univs
- in
+ let variances = Inf.start univs in
let variances = List.fold_left (fun variances entry ->
let variances = infer_arity_constructor true
env variances entry.mind_entry_arity
@@ -218,12 +266,11 @@ let infer_inductive_core env univs entries =
variances
entries
in
- Array.map (fun u -> match LMap.find u variances with
- | exception Not_found -> Invariant
- | IrrelevantI -> Irrelevant
- | CovariantI -> Covariant)
- univs
+ Inf.finish variances
let infer_inductive ~env_params univs entries =
try infer_inductive_core env_params univs entries
- with TrivialVariance -> Array.make (Array.length univs) Invariant
+ with
+ | TrivialVariance -> Array.make (Array.length univs) Invariant
+ | BadVariance (lev, expected, actual) ->
+ Type_errors.error_bad_variance env_params ~lev ~expected ~actual
diff --git a/kernel/inferCumulativity.mli b/kernel/inferCumulativity.mli
index db5539a0ff..99d8f0c98d 100644
--- a/kernel/inferCumulativity.mli
+++ b/kernel/inferCumulativity.mli
@@ -12,8 +12,8 @@ val infer_inductive
: env_params:Environ.env
(** Environment containing the polymorphic universes and the
parameters. *)
- -> Univ.Level.t array
- (** Universes whose cumulativity we want to infer. *)
+ -> (Univ.Level.t * Univ.Variance.t option) array
+ (** Universes whose cumulativity we want to infer or check. *)
-> Entries.one_inductive_entry list
(** The inductive block data we want to infer cumulativity for.
NB: we ignore the template bool and the names, only the terms
diff --git a/kernel/type_errors.ml b/kernel/type_errors.ml
index ae5c4b6880..bcb7aa88ca 100644
--- a/kernel/type_errors.ml
+++ b/kernel/type_errors.ml
@@ -69,6 +69,7 @@ type ('constr, 'types) ptype_error =
| DisallowedSProp
| BadRelevance
| BadInvert
+ | BadVariance of { lev : Level.t; expected : Variance.t; actual : Variance.t }
type type_error = (constr, types) ptype_error
@@ -163,6 +164,9 @@ let error_bad_relevance env =
let error_bad_invert env =
raise (TypeError (env, BadInvert))
+let error_bad_variance env ~lev ~expected ~actual =
+ raise (TypeError (env, BadVariance {lev;expected;actual}))
+
let map_pguard_error f = function
| NotEnoughAbstractionInFixBody -> NotEnoughAbstractionInFixBody
| RecursionNotOnInductiveType c -> RecursionNotOnInductiveType (f c)
@@ -207,3 +211,4 @@ let map_ptype_error f = function
| DisallowedSProp -> DisallowedSProp
| BadRelevance -> BadRelevance
| BadInvert -> BadInvert
+| BadVariance u -> BadVariance u
diff --git a/kernel/type_errors.mli b/kernel/type_errors.mli
index b1f7eb8a34..bcdcab9db7 100644
--- a/kernel/type_errors.mli
+++ b/kernel/type_errors.mli
@@ -70,6 +70,7 @@ type ('constr, 'types) ptype_error =
| DisallowedSProp
| BadRelevance
| BadInvert
+ | BadVariance of { lev : Level.t; expected : Variance.t; actual : Variance.t }
type type_error = (constr, types) ptype_error
@@ -146,5 +147,7 @@ val error_bad_relevance : env -> 'a
val error_bad_invert : env -> 'a
+val error_bad_variance : env -> lev:Level.t -> expected:Variance.t -> actual:Variance.t -> 'a
+
val map_pguard_error : ('c -> 'd) -> 'c pguard_error -> 'd pguard_error
val map_ptype_error : ('c -> 'd) -> ('c, 'c) ptype_error -> ('d, 'd) ptype_error
diff --git a/kernel/vmbytecodes.ml b/kernel/vmbytecodes.ml
index c156a21c86..4977aec00a 100644
--- a/kernel/vmbytecodes.ml
+++ b/kernel/vmbytecodes.ml
@@ -56,13 +56,12 @@ type instruction =
| Kfield of int
| Ksetfield of int
| Kstop
- | Ksequence of bytecodes * bytecodes
+ | Ksequence of bytecodes
| Kproj of Projection.Repr.t
| Kensurestackcapacity of int
| Kbranch of Label.t (* jump to label *)
- | Kprim of CPrimitives.t * pconstant option
+ | Kprim of CPrimitives.t * pconstant
| Kcamlprim of CPrimitives.t * Label.t
- | Kareint of int
and bytecodes = instruction list
@@ -146,21 +145,19 @@ let rec pp_instr i =
| Kensurestackcapacity size -> str "growstack " ++ int size
| Kprim (op, id) -> str (CPrimitives.to_string op) ++ str " " ++
- (match id with Some (id,_u) -> Constant.print id | None -> str "")
+ (Constant.print (fst id))
| Kcamlprim (op, lbl) ->
str "camlcall " ++ str (CPrimitives.to_string op) ++ spc () ++
pp_lbl lbl
- | Kareint n -> str "areint " ++ int n
-
and pp_bytecodes c =
match c with
| [] -> str ""
| Klabel lbl :: c ->
str "L" ++ int lbl ++ str ":" ++ fnl () ++
pp_bytecodes c
- | Ksequence (l1, l2) :: c ->
- pp_bytecodes l1 ++ pp_bytecodes l2 ++ pp_bytecodes c
+ | Ksequence l :: c ->
+ pp_bytecodes l ++ pp_bytecodes c
| i :: c ->
pp_instr i ++ fnl () ++ pp_bytecodes c
diff --git a/kernel/vmbytecodes.mli b/kernel/vmbytecodes.mli
index b703058fb7..003a77ab78 100644
--- a/kernel/vmbytecodes.mli
+++ b/kernel/vmbytecodes.mli
@@ -54,14 +54,13 @@ type instruction =
| Kfield of int (** accu = accu[n] *)
| Ksetfield of int (** accu[n] = sp[0] ; sp = pop sp *)
| Kstop
- | Ksequence of bytecodes * bytecodes
+ | Ksequence of bytecodes
| Kproj of Projection.Repr.t
| Kensurestackcapacity of int
| Kbranch of Label.t (** jump to label, is it needed ? *)
- | Kprim of CPrimitives.t * pconstant option
+ | Kprim of CPrimitives.t * pconstant
| Kcamlprim of CPrimitives.t * Label.t
- | Kareint of int
and bytecodes = instruction list
diff --git a/kernel/vmbytegen.ml b/kernel/vmbytegen.ml
index 16a0f42664..70c92fd8f0 100644
--- a/kernel/vmbytegen.ml
+++ b/kernel/vmbytegen.ml
@@ -315,12 +315,10 @@ let pos_evar evk r =
(* non-terminating instruction (branch, raise, return, appterm) *)
(* in front of it. *)
-let discard_dead_code cont = cont
-(*function
- [] -> []
+let rec discard_dead_code = function
+ | [] -> []
| (Klabel _ | Krestart ) :: _ as cont -> cont
| _ :: cont -> discard_dead_code cont
-*)
(* Return a label to the beginning of the given continuation. *)
(* If the sequence starts with a branch, use the target of that branch *)
@@ -581,7 +579,7 @@ let rec compile_lam env cenv lam sz cont =
let cont_fun =
ensure_stack_capacity (compile_lam env r_fun body arity) [Kreturn arity]
in
- fun_code := [Ksequence(add_grab arity lbl_fun cont_fun,!fun_code)];
+ fun_code := Ksequence (add_grab arity lbl_fun cont_fun) :: !fun_code;
let fv = fv r_fun in
compile_fv cenv fv.fv_rev sz (Kclosure(lbl_fun,fv.size) :: cont)
@@ -604,7 +602,7 @@ let rec compile_lam env cenv lam sz cont =
in
let lbl,fcode = label_code fcode in
lbl_types.(i) <- lbl;
- fun_code := [Ksequence(fcode,!fun_code)]
+ fun_code := Ksequence fcode :: !fun_code
done;
(* Compiling bodies *)
for i = 0 to ndef - 1 do
@@ -617,7 +615,7 @@ let rec compile_lam env cenv lam sz cont =
let lbl = Label.create () in
lbl_bodies.(i) <- lbl;
let fcode = add_grabrec rec_args.(i) arity lbl cont1 in
- fun_code := [Ksequence(fcode,!fun_code)]
+ fun_code := Ksequence fcode :: !fun_code
done;
let fv = !rfv in
compile_fv cenv fv.fv_rev sz
@@ -637,7 +635,7 @@ let rec compile_lam env cenv lam sz cont =
in
let lbl,fcode = label_code fcode in
lbl_types.(i) <- lbl;
- fun_code := [Ksequence(fcode,!fun_code)]
+ fun_code := Ksequence fcode :: !fun_code
done;
(* Compiling bodies *)
for i = 0 to ndef - 1 do
@@ -652,25 +650,13 @@ let rec compile_lam env cenv lam sz cont =
in
let cont = ensure_stack_capacity comp arity in
lbl_bodies.(i) <- lbl;
- fun_code := [Ksequence(add_grab (arity+1) lbl cont,!fun_code)];
+ fun_code := Ksequence (add_grab (arity+1) lbl cont) :: !fun_code;
done;
let fv = !rfv in
set_max_stack_size (sz + fv.size + ndef + 2);
compile_fv cenv fv.fv_rev sz
(Kclosurecofix(fv.size, init, lbl_types, lbl_bodies) :: cont)
- | Lif(t, bt, bf) ->
- let branch, cont = make_branch cont in
- let lbl_true = Label.create() in
- let lbl_false = Label.create() in
- compile_lam env cenv t sz
- (Kswitch([|lbl_true;lbl_false|],[||]) ::
- Klabel lbl_false ::
- compile_lam env cenv bf sz
- (branch ::
- Klabel lbl_true ::
- compile_lam env cenv bt sz cont))
-
| Lcase(ci,rtbl,t,a,branches) ->
let ind = ci.ci_ind in
let mib = lookup_mind (fst ind) env in
@@ -688,7 +674,7 @@ let rec compile_lam env cenv lam sz cont =
ensure_stack_capacity (compile_lam env cenv t sz) [Kpop sz; Kstop]
in
let lbl_typ,fcode = label_code fcode in
- fun_code := [Ksequence(fcode,!fun_code)];
+ fun_code := Ksequence fcode :: !fun_code;
(* Compilation of the branches *)
let lbl_sw = Label.create () in
let sz_b,branch,is_tailcall =
@@ -700,6 +686,7 @@ let rec compile_lam env cenv lam sz cont =
| _ -> assert false
in
+ let cont = discard_dead_code cont in
let c = ref cont in
(* Perform the extra match if needed (too many block constructors) *)
if neblock <> 0 then begin
@@ -770,7 +757,7 @@ let rec compile_lam env cenv lam sz cont =
let cont = code_makeblock ~stack_size:(sz+arity-1) ~arity ~tag cont in
comp_args (compile_lam env) cenv args sz cont
- | Lprim (Some (kn,u), op, args) when is_caml_prim op ->
+ | Lprim ((kn,u), op, args) when is_caml_prim op ->
let arity = CPrimitives.arity op in
let nparams = CPrimitives.nparams op in
let nargs = arity - nparams in
@@ -788,7 +775,7 @@ let rec compile_lam env cenv lam sz cont =
if Int.equal nparams 0 then cont
else comp_args (compile_lam env) cenv (Array.sub args 0 nparams) (sz + nargs) (Kpush::cont)
in
- fun_code := [Ksequence(default, !fun_code)];
+ fun_code := Ksequence default :: !fun_code;
comp_args (compile_lam env) cenv (Array.sub args nparams nargs) sz (Kcamlprim (op, lbl_default) :: cont)
| Lprim (kn, op, args) ->
@@ -878,7 +865,7 @@ let compile ~fail_on_error ?universes:(universes=0) env c =
ensure_stack_capacity (compile_lam env r_fun body full_arity)
[Kreturn full_arity]
in
- fun_code := [Ksequence(add_grab full_arity lbl_fun cont_fun,!fun_code)];
+ fun_code := Ksequence (add_grab full_arity lbl_fun cont_fun) :: !fun_code;
let fv = fv r_fun in
let init_code =
ensure_stack_capacity (compile_fv cenv fv.fv_rev 0)
diff --git a/kernel/vmemitcodes.ml b/kernel/vmemitcodes.ml
index babc57794b..c1d8fcb855 100644
--- a/kernel/vmemitcodes.ml
+++ b/kernel/vmemitcodes.ml
@@ -208,14 +208,6 @@ let slot_for_caml_prim env op =
(* Emission of one instruction *)
-let nocheck_prim_op = function
- | Int63add -> opADDINT63
- | Int63sub -> opSUBINT63
- | Int63lt -> opLTINT63
- | Int63le -> opLEINT63
- | _ -> assert false
-
-
let check_prim_op = function
| Int63head0 -> opCHECKHEAD0INT63
| Int63tail0 -> opCHECKTAIL0INT63
@@ -259,11 +251,20 @@ let check_prim_op = function
| Float64ldshiftexp -> opCHECKLDSHIFTEXP
| Float64next_up -> opCHECKNEXTUPFLOAT
| Float64next_down -> opCHECKNEXTDOWNFLOAT
- | Arraymake -> opISINT_CAML_CALL2
- | Arrayget -> opISARRAY_INT_CAML_CALL2
- | Arrayset -> opISARRAY_INT_CAML_CALL3
+ | Arraymake -> opCHECKCAMLCALL2_1
+ | Arrayget -> opCHECKCAMLCALL2
+ | Arrayset -> opCHECKCAMLCALL3_1
| Arraydefault | Arraycopy | Arraylength ->
- opISARRAY_CAML_CALL1
+ opCHECKCAMLCALL1
+
+let inplace_prim_op = function
+ | Float64next_up | Float64next_down -> true
+ | _ -> false
+
+let check_prim_op_inplace = function
+ | Float64next_up -> opCHECKNEXTUPFLOATINPLACE
+ | Float64next_down -> opCHECKNEXTDOWNFLOATINPLACE
+ | _ -> assert false
let emit_instr env = function
| Klabel lbl -> define_label env lbl
@@ -354,10 +355,7 @@ let emit_instr env = function
| Kproj p -> out env opPROJ; out_int env (Projection.Repr.arg p); slot_for_proj_name env p
| Kensurestackcapacity size -> out env opENSURESTACKCAPACITY; out_int env size
| Kbranch lbl -> out env opBRANCH; out_label env lbl
- | Kprim (op,None) ->
- out env (nocheck_prim_op op)
-
- | Kprim(op,Some (q,_u)) ->
+ | Kprim (op, (q,_u)) ->
out env (check_prim_op op);
slot_for_getglobal env q
@@ -366,13 +364,8 @@ let emit_instr env = function
out_label env lbl;
slot_for_caml_prim env op
- | Kareint 1 -> out env opISINT
- | Kareint 2 -> out env opAREINT2;
-
| Kstop -> out env opSTOP
- | Kareint _ -> assert false
-
(* Emission of a current list and remaining lists of instructions. Include some peephole optimization. *)
let rec emit env insns remaining = match insns with
@@ -406,8 +399,14 @@ let rec emit env insns remaining = match insns with
emit env c remaining
| Kpop n :: Kjump :: c ->
out env opRETURN; out_int env n; emit env c remaining
- | Ksequence(c1,c2)::c ->
- emit env c1 (c2::c::remaining)
+ | Ksequence c1 :: c ->
+ emit env c1 (c :: remaining)
+ | Kprim (op1, (q1, _)) :: Kprim (op2, (q2, _)) :: c when inplace_prim_op op2 ->
+ out env (check_prim_op op1);
+ slot_for_getglobal env q1;
+ out env (check_prim_op_inplace op2);
+ slot_for_getglobal env q2;
+ emit env c remaining
(* Default case *)
| instr :: c ->
emit_instr env instr; emit env c remaining
diff --git a/kernel/vmlambda.ml b/kernel/vmlambda.ml
index 332a331a7a..9cca204e8c 100644
--- a/kernel/vmlambda.ml
+++ b/kernel/vmlambda.ml
@@ -19,10 +19,8 @@ type lambda =
| Llet of Name.t Context.binder_annot * lambda * lambda
| Lapp of lambda * lambda array
| Lconst of pconstant
- | Lprim of pconstant option * CPrimitives.t * lambda array
- (* No check if None *)
+ | Lprim of pconstant * CPrimitives.t * lambda array
| Lcase of case_info * reloc_table * lambda * lambda * lam_branches
- | Lif of lambda * lambda * lambda
| Lfix of (int array * int) * fix_decl
| Lcofix of int * fix_decl
| Lint of int
@@ -112,10 +110,6 @@ let rec pp_lam lam =
pp_names ids ++ str " => " ++ pp_lam c)
(Array.to_list branches.nonconstant_branches)))
++ cut() ++ str "end")
- | Lif (t, bt, bf) ->
- v 0 (str "(if " ++ pp_lam t ++
- cut () ++ str "then " ++ pp_lam bt ++
- cut() ++ str "else " ++ pp_lam bf ++ str ")")
| Lfix((t,i),(lna,tl,bl)) ->
let fixl = Array.mapi (fun i id -> (id,t.(i),tl.(i),bl.(i))) lna in
hov 1
@@ -148,16 +142,11 @@ let rec pp_lam lam =
| Lval _ -> str "values"
| Lsort s -> pp_sort s
| Lind ((mind,i), _) -> MutInd.print mind ++ str"#" ++ int i
- | Lprim(Some (kn,_u),_op,args) ->
+ | Lprim ((kn,_u),_op,args) ->
hov 1
(str "(PRIM " ++ pr_con kn ++ spc() ++
prlist_with_sep spc pp_lam (Array.to_list args) ++
str")")
- | Lprim(None,op,args) ->
- hov 1
- (str "(PRIM_NC " ++ str (CPrimitives.to_string op) ++ spc() ++
- prlist_with_sep spc pp_lam (Array.to_list args) ++
- str")")
| Lproj(p,arg) ->
hov 1
(str "(proj " ++ Projection.Repr.print p ++ str "(" ++ pp_lam arg
@@ -237,11 +226,6 @@ let map_lam_with_binders g f n lam =
in
if t == t' && a == a' && branches == branches' then lam else
Lcase(ci,rtbl,t',a',branches')
- | Lif(t,bt,bf) ->
- let t' = f n t in
- let bt' = f n bt in
- let bf' = f n bf in
- if t == t' && bt == bt' && bf == bf' then lam else Lif(t',bt',bf')
| Lfix(init,(ids,ltypes,lbodies)) ->
let ltypes' = Array.Smart.map (f n) ltypes in
let lbodies' = Array.Smart.map (f (g (Array.length ids) n)) lbodies in
@@ -312,28 +296,6 @@ let can_subst lam =
| Lval _ | Lsort _ | Lind _ -> true
| _ -> false
-
-let can_merge_if bt bf =
- match bt, bf with
- | Llam(_idst,_), Llam(_idsf,_) -> true
- | _ -> false
-
-let merge_if t bt bf =
- let (idst,bodyt) = decompose_Llam bt in
- let (idsf,bodyf) = decompose_Llam bf in
- let nt = Array.length idst in
- let nf = Array.length idsf in
- let common,idst,idsf =
- if nt = nf then idst, [||], [||]
- else
- if nt < nf then idst,[||], Array.sub idsf nt (nf - nt)
- else idsf, Array.sub idst nf (nt - nf), [||] in
- Llam(common,
- Lif(lam_lift (Array.length common) t,
- mkLlam idst bodyt,
- mkLlam idsf bodyf))
-
-
let rec simplify subst lam =
match lam with
| Lrel(id,i) -> lam_subst_rel lam id i subst
@@ -352,14 +314,6 @@ let rec simplify subst lam =
| lam' -> lam'
end
- | Lif(t,bt,bf) ->
- let t' = simplify subst t in
- let bt' = simplify subst bt in
- let bf' = simplify subst bf in
- if can_merge_if bt' bf' then merge_if t' bt' bf'
- else
- if t == t' && bt == bt' && bf == bf' then lam
- else Lif(t',bt',bf')
| _ -> map_lam_with_binders liftn simplify subst lam
and simplify_app substf f substa args =
@@ -442,9 +396,6 @@ let rec occurrence k kind lam =
in
Array.iter on_b branches.nonconstant_branches;
!r
- | Lif (t, bt, bf) ->
- let kind = occurrence k kind t in
- kind && occurrence k kind bt && occurrence k kind bf
| Lfix(_,(ids,ltypes,lbodies))
| Lcofix(_,(ids,ltypes,lbodies)) ->
let kind = occurrence_args k kind ltypes in
@@ -566,7 +517,7 @@ let rec get_alias env kn =
(* Compilation of primitive *)
let prim kn p args =
- Lprim(Some kn, p, args)
+ Lprim (kn, p, args)
let expand_prim kn op arity =
(* primitives are always Relevant *)
diff --git a/kernel/vmlambda.mli b/kernel/vmlambda.mli
index bd11c2667f..ad5f81638f 100644
--- a/kernel/vmlambda.mli
+++ b/kernel/vmlambda.mli
@@ -12,10 +12,8 @@ type lambda =
| Llet of Name.t Context.binder_annot * lambda * lambda
| Lapp of lambda * lambda array
| Lconst of pconstant
- | Lprim of pconstant option * CPrimitives.t * lambda array
- (* No check if None *)
+ | Lprim of pconstant * CPrimitives.t * lambda array
| Lcase of case_info * reloc_table * lambda * lambda * lam_branches
- | Lif of lambda * lambda * lambda
| Lfix of (int array * int) * fix_decl
| Lcofix of int * fix_decl
| Lint of int
diff --git a/kernel/vmvalues.ml b/kernel/vmvalues.ml
index 7b4101b9d0..9944458d6b 100644
--- a/kernel/vmvalues.ml
+++ b/kernel/vmvalues.ml
@@ -381,7 +381,15 @@ let rec whd_accu a stk =
CErrors.anomaly
Pp.(strbrk "Failed to parse VM value. Tag = " ++ int tg ++ str ".")
-external kind_of_closure : Obj.t -> int = "coq_kind_of_closure"
+[@@@warning "-37"]
+type vm_closure_kind =
+ | VCfun (** closure, or fixpoint applied past the recursive argument *)
+ | VCfix (** unapplied fixpoint *)
+ | VCfix_partial (** partially applied fixpoint, but not sufficiently for recursion *)
+ | VCaccu (** accumulator *)
+[@@@warning "+37"]
+
+external kind_of_closure : Obj.t -> vm_closure_kind = "coq_kind_of_closure"
external is_accumulate : tcode -> bool = "coq_is_accumulate_code"
external int_tcode : tcode -> int -> int = "coq_int_tcode"
external accumulate : unit -> tcode = "accumulate_code"
@@ -400,12 +408,11 @@ let whd_val (v: values) =
else if Int.equal tag Obj.closure_tag && is_accumulate (fun_code o) then
whd_accu o []
else if Int.equal tag Obj.closure_tag || Int.equal tag Obj.infix_tag then
- (match kind_of_closure o with
- | 0 -> Vfun(Obj.obj o)
- | 1 -> Vfix(Obj.obj o, None)
- | 2 -> Vfix(Obj.obj (Obj.field o 2), Some (Obj.obj o))
- | 3 -> Vatom_stk(Aid(RelKey(int_tcode (fun_code o) 1)), [])
- | _ -> CErrors.anomaly ~label:"Vm.whd " (Pp.str "kind_of_closure does not work."))
+ match kind_of_closure o with
+ | VCfun -> Vfun (Obj.obj o)
+ | VCfix -> Vfix (Obj.obj o, None)
+ | VCfix_partial -> Vfix (Obj.obj (Obj.field o 2), Some (Obj.obj o))
+ | VCaccu -> Vatom_stk (Aid (RelKey (int_tcode (fun_code o) 1)), [])
else if Int.equal tag Obj.custom_tag then Vint64 (Obj.magic v)
else if Int.equal tag Obj.double_tag then Vfloat64 (Obj.magic v)
else
diff --git a/plugins/ltac/rewrite.ml b/plugins/ltac/rewrite.ml
index 26e2b18a02..77162ce89a 100644
--- a/plugins/ltac/rewrite.ml
+++ b/plugins/ltac/rewrite.ml
@@ -13,7 +13,6 @@ open CErrors
open Util
open Names
open Nameops
-open Namegen
open Constr
open Context
open EConstr
@@ -485,7 +484,7 @@ let rec decompose_app_rel env evd t =
let (f', argl, argr) = decompose_app_rel env evd arg in
let ty = Retyping.get_type_of env evd argl in
let r = Retyping.relevance_of_type env evd ty in
- let f'' = mkLambda (make_annot (Name default_dependent_ident) r, ty,
+ let f'' = mkLambda (make_annot (Name Namegen.default_dependent_ident) r, ty,
mkLambda (make_annot (Name (Id.of_string "y")) r, lift 1 ty,
mkApp (lift 2 f, [| mkApp (lift 2 f', [| mkRel 2; mkRel 1 |]) |])))
in (f'', argl, argr)
@@ -1119,7 +1118,14 @@ let subterm all flags (s : 'a pure_strategy) : 'a pure_strategy =
*)
| Lambda (n, t, b) when flags.under_lambdas ->
- let n' = map_annot (Nameops.Name.map (fun id -> Tactics.fresh_id_in_env unfresh id env)) n in
+ let unfresh, n' =
+ let id = match n.binder_name with
+ | Anonymous -> Namegen.default_dependent_ident
+ | Name id -> id
+ in
+ let id = Tactics.fresh_id_in_env unfresh id env in
+ Id.Set.add id unfresh, {n with binder_name = Name id}
+ in
let unfresh = match n'.binder_name with
| Anonymous -> unfresh
| Name id -> Id.Set.add id unfresh
@@ -1542,7 +1548,7 @@ let cl_rewrite_clause_newtac ?abs ?origsigma ~progress strat clause =
(* For compatibility *)
let beta = Tactics.reduct_in_concl ~check:false (Reductionops.nf_betaiota, DEFAULTcast) in
let beta_hyp id = Tactics.reduct_in_hyp ~check:false ~reorder:false Reductionops.nf_betaiota (id, InHyp) in
- let treat sigma res =
+ let treat sigma res state =
match res with
| None -> newfail 0 (str "Nothing to rewrite")
| Some None ->
@@ -1553,7 +1559,7 @@ let cl_rewrite_clause_newtac ?abs ?origsigma ~progress strat clause =
let (undef, prf, newt) = res in
let fold ev _ accu = if Evd.mem sigma ev then accu else ev :: accu in
let gls = List.rev (Evd.fold_undefined fold undef []) in
- let gls = List.map Proofview.with_empty_state gls in
+ let gls = List.map (fun gl -> Proofview.goal_with_state gl state) gls in
match clause, prf with
| Some id, Some p ->
let tac = tclTHENLIST [
@@ -1583,6 +1589,7 @@ let cl_rewrite_clause_newtac ?abs ?origsigma ~progress strat clause =
Proofview.Goal.enter begin fun gl ->
let concl = Proofview.Goal.concl gl in
let env = Proofview.Goal.env gl in
+ let state = Proofview.Goal.state gl in
let sigma = Tacmach.New.project gl in
let ty = match clause with
| None -> concl
@@ -1602,7 +1609,7 @@ let cl_rewrite_clause_newtac ?abs ?origsigma ~progress strat clause =
cl_rewrite_clause_aux ?abs strat env Id.Set.empty sigma ty clause
in
let sigma = match origsigma with None -> sigma | Some sigma -> sigma in
- treat sigma res <*>
+ treat sigma res state <*>
(* For compatibility *)
beta <*> Proofview.shelve_unifiable
with
diff --git a/plugins/micromega/persistent_cache.ml b/plugins/micromega/persistent_cache.ml
index 3360a9a51c..21178a64a5 100644
--- a/plugins/micromega/persistent_cache.ml
+++ b/plugins/micromega/persistent_cache.ml
@@ -36,10 +36,8 @@ module PHashtable (Key : HashedType) : PHashtable with type key = Key.t = struct
module Table = Hashtbl.Make (Key)
exception InvalidTableFormat
- exception UnboundTable
- type mode = Closed | Open
- type 'a t = {outch : out_channel; mutable status : mode; htbl : 'a Table.t}
+ type 'a t = {outch : out_channel; htbl : 'a Table.t}
(* XXX: Move to Fun.protect once in Ocaml 4.08 *)
let fun_protect ~(finally : unit -> unit) work =
@@ -118,7 +116,6 @@ module PHashtable (Key : HashedType) : PHashtable with type key = Key.t = struct
close_in_noerr inch;
{ outch =
out_channel_of_descr (openfile f [O_WRONLY; O_APPEND; O_CREAT] 0o666)
- ; status = Open
; htbl }
with InvalidTableFormat ->
(* The file is corrupted *)
@@ -131,24 +128,20 @@ module PHashtable (Key : HashedType) : PHashtable with type key = Key.t = struct
(fun k e -> Marshal.to_channel outch (k, e) [Marshal.No_sharing])
htbl;
flush outch);
- {outch; status = Open; htbl}
+ {outch; htbl}
let add t k e =
- let {outch; status; htbl = tbl} = t in
- if status == Closed then raise UnboundTable
- else
- let fd = descr_of_out_channel outch in
- Table.add tbl k e;
- do_under_lock Write fd (fun _ ->
- Marshal.to_channel outch (k, e) [Marshal.No_sharing];
- flush outch)
+ let {outch; htbl = tbl} = t in
+ let fd = descr_of_out_channel outch in
+ Table.add tbl k e;
+ do_under_lock Write fd (fun _ ->
+ Marshal.to_channel outch (k, e) [Marshal.No_sharing];
+ flush outch)
let find t k =
- let {outch; status; htbl = tbl} = t in
- if status == Closed then raise UnboundTable
- else
- let res = Table.find tbl k in
- res
+ let {outch; htbl = tbl} = t in
+ let res = Table.find tbl k in
+ res
let memo cache f =
let tbl = lazy (try Some (open_in cache) with _ -> None) in
diff --git a/plugins/ssrmatching/ssrmatching.ml b/plugins/ssrmatching/ssrmatching.ml
index bd514f15d5..a4aa08300d 100644
--- a/plugins/ssrmatching/ssrmatching.ml
+++ b/plugins/ssrmatching/ssrmatching.ml
@@ -454,7 +454,7 @@ let ungen_upat lhs (sigma, uc, t) u =
let nb_cs_proj_args pc f u =
let na k =
- List.length (snd (lookup_canonical_conversion (GlobRef.ConstRef pc, k))).o_TCOMPS in
+ List.length (snd (lookup_canonical_conversion (Global.env()) (GlobRef.ConstRef pc, k))).o_TCOMPS in
let nargs_of_proj t = match kind t with
| App(_,args) -> Array.length args
| Proj _ -> 0 (* if splay_app calls expand_projection, this has to be
diff --git a/pretyping/evarconv.ml b/pretyping/evarconv.ml
index 00d4c7b3d8..cdf2922516 100644
--- a/pretyping/evarconv.ml
+++ b/pretyping/evarconv.ml
@@ -244,24 +244,20 @@ let check_conv_record env sigma (t1,sk1) (t2,sk2) =
Prod (_,a,b) -> (* assert (l2=[]); *)
let _, a, b = destProd sigma t2 in
if noccurn sigma 1 b then
- lookup_canonical_conversion (proji, Prod_cs),
+ lookup_canonical_conversion env (proji, Prod_cs),
(Stack.append_app [|a;pop b|] Stack.empty)
else raise Not_found
| Sort s ->
let s = ESorts.kind sigma s in
- lookup_canonical_conversion
+ lookup_canonical_conversion env
(proji, Sort_cs (Sorts.family s)),[]
| Proj (p, c) ->
- let c2 = GlobRef.ConstRef (Projection.constant p) in
- let c = Retyping.expand_projection env sigma p c [] in
- let _, args = destApp sigma c in
- let sk2 = Stack.append_app args sk2 in
- lookup_canonical_conversion (proji, Const_cs c2), sk2
+ lookup_canonical_conversion env (proji, Proj_cs (Projection.repr p)), Stack.append_app [|c|] sk2
| _ ->
let (c2, _) = try destRef sigma t2 with DestKO -> raise Not_found in
- lookup_canonical_conversion (proji, Const_cs c2),sk2
+ lookup_canonical_conversion env (proji, Const_cs c2),sk2
with Not_found ->
- let (c, cs) = lookup_canonical_conversion (proji,Default_cs) in
+ let (c, cs) = lookup_canonical_conversion env (proji,Default_cs) in
(c,cs),[]
in
let t', { o_DEF = c; o_CTX = ctx; o_INJ=n; o_TABS = bs;
@@ -273,6 +269,7 @@ let check_conv_record env sigma (t1,sk1) (t2,sk2) =
| Some c -> (* A primitive projection applied to c *)
let ty = Retyping.get_type_of ~lax:true env sigma c in
let (i,u), ind_args =
+ (* Are we sure that ty is not an evar? *)
try Inductiveops.find_mrectype env sigma ty
with _ -> raise Not_found
in Stack.append_app_list ind_args Stack.empty, c, sk1
diff --git a/pretyping/recordops.ml b/pretyping/recordops.ml
index e6e5ad8dd4..b6e44265ae 100644
--- a/pretyping/recordops.ml
+++ b/pretyping/recordops.ml
@@ -144,19 +144,21 @@ type obj_typ = {
type cs_pattern =
Const_cs of GlobRef.t
+ | Proj_cs of Projection.Repr.t
| Prod_cs
| Sort_cs of Sorts.family
| Default_cs
-let eq_cs_pattern p1 p2 = match p1, p2 with
-| Const_cs gr1, Const_cs gr2 -> GlobRef.equal gr1 gr2
+let eq_cs_pattern env p1 p2 = match p1, p2 with
+| Const_cs gr1, Const_cs gr2 -> Environ.QGlobRef.equal env gr1 gr2
+| Proj_cs p1, Proj_cs p2 -> Environ.QProjection.Repr.equal env p1 p2
| Prod_cs, Prod_cs -> true
| Sort_cs s1, Sort_cs s2 -> Sorts.family_equal s1 s2
| Default_cs, Default_cs -> true
| _ -> false
-let rec assoc_pat a = function
- | ((pat, t), e) :: xs -> if eq_cs_pattern pat a then (t, e) else assoc_pat a xs
+let rec assoc_pat env a = function
+ | ((pat, t), e) :: xs -> if eq_cs_pattern env pat a then (t, e) else assoc_pat env a xs
| [] -> raise Not_found
@@ -179,10 +181,7 @@ let rec cs_pattern_of_constr env t =
patt, n, args @ Array.to_list vargs
| Rel n -> Default_cs, Some n, []
| Prod (_,a,b) when Vars.noccurn 1 b -> Prod_cs, None, [a; Vars.lift (-1) b]
- | Proj (p, c) ->
- let ty = Retyping.get_type_of_constr env c in
- let _, params = Inductive.find_rectype env ty in
- Const_cs (GlobRef.ConstRef (Projection.constant p)), None, params @ [c]
+ | Proj (p, c) -> Proj_cs (Projection.repr p), None, [c]
| Sort s -> Sort_cs (Sorts.family s), None, []
| _ -> Const_cs (fst @@ destRef t) , None, []
@@ -238,6 +237,7 @@ let compute_canonical_projections env ~warn (gref,ind) =
let pr_cs_pattern = function
Const_cs c -> Nametab.pr_global_env Id.Set.empty c
+ | Proj_cs p -> Nametab.pr_global_env Id.Set.empty (GlobRef.ConstRef (Projection.Repr.constant p))
| Prod_cs -> str "_ -> _"
| Default_cs -> str "_"
| Sort_cs s -> Sorts.pr_sort_family s
@@ -253,7 +253,7 @@ let register_canonical_structure ~warn env sigma o =
compute_canonical_projections env ~warn o |>
List.iter (fun ((proj, (cs_pat, _ as pat)), s) ->
let l = try GlobRef.Map.find proj !object_table with Not_found -> [] in
- match assoc_pat cs_pat l with
+ match assoc_pat env cs_pat l with
| exception Not_found ->
object_table := GlobRef.Map.add proj ((pat, s) :: l) !object_table
| _, cs ->
@@ -320,8 +320,8 @@ let check_and_decompose_canonical_structure env sigma ref =
error_not_structure ref (str "Got too few arguments to the record or structure constructor.");
(ref,indsp)
-let lookup_canonical_conversion (proj,pat) =
- assoc_pat pat (GlobRef.Map.find proj !object_table)
+let lookup_canonical_conversion env (proj,pat) =
+ assoc_pat env pat (GlobRef.Map.find proj !object_table)
let decompose_projection sigma c args =
match EConstr.kind sigma c with
diff --git a/pretyping/recordops.mli b/pretyping/recordops.mli
index 3be60d5e62..5b8dc8184a 100644
--- a/pretyping/recordops.mli
+++ b/pretyping/recordops.mli
@@ -67,6 +67,7 @@ val find_primitive_projection : Constant.t -> Projection.Repr.t option
(** A cs_pattern characterizes the form of a component of canonical structure *)
type cs_pattern =
Const_cs of GlobRef.t
+ | Proj_cs of Projection.Repr.t
| Prod_cs
| Sort_cs of Sorts.family
| Default_cs
@@ -88,7 +89,7 @@ val pr_cs_pattern : cs_pattern -> Pp.t
type cs = GlobRef.t * inductive
-val lookup_canonical_conversion : (GlobRef.t * cs_pattern) -> constr * obj_typ
+val lookup_canonical_conversion : Environ.env -> (GlobRef.t * cs_pattern) -> constr * obj_typ
val register_canonical_structure : warn:bool -> Environ.env -> Evd.evar_map ->
cs -> unit
val subst_canonical_structure : Mod_subst.substitution -> cs -> cs
diff --git a/pretyping/retyping.ml b/pretyping/retyping.ml
index 4bd22e76cb..34bcd0982c 100644
--- a/pretyping/retyping.ml
+++ b/pretyping/retyping.ml
@@ -67,6 +67,14 @@ let get_type_from_constraints env sigma t =
| _ -> raise Not_found
else raise Not_found
+let sort_of_arity_with_constraints env sigma t =
+ try Reductionops.sort_of_arity env sigma t
+ with Reduction.NotArity ->
+ try
+ let t = get_type_from_constraints env sigma t in
+ Reductionops.sort_of_arity env sigma t
+ with Not_found | Reduction.NotArity -> retype_error NotAnArity
+
let rec subst_type env sigma typ = function
| [] -> typ
| h::rest ->
@@ -187,9 +195,7 @@ let retype ?(polyprop=true) sigma =
let mip = lookup_mind_specif env ind in
let paramtyps = Array.map_to_list (fun arg () ->
let t = type_of env arg in
- let s = try Reductionops.sort_of_arity env sigma t
- with Reduction.NotArity -> retype_error NotAnArity
- in
+ let s = sort_of_arity_with_constraints env sigma t in
Sorts.univ_of_sort (ESorts.kind sigma s))
args
in
diff --git a/test-suite/bugs/closed/bug_13246.v b/test-suite/bugs/closed/bug_13246.v
new file mode 100644
index 0000000000..11f5baaaf4
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13246.v
@@ -0,0 +1,69 @@
+Axiom _0: Prop.
+
+From Coq Require Export Morphisms Setoid Utf8.
+
+Class Equiv A := equiv: relation A.
+
+Reserved Notation "P ⊢ Q" (at level 99, Q at level 200, right associativity).
+Reserved Notation "P ⊣⊢ Q" (at level 95, no associativity).
+Reserved Notation "■ P" (at level 20, right associativity).
+
+(** Define the scope *)
+Declare Scope bi_scope.
+Delimit Scope bi_scope with I.
+
+Structure bi :=
+ Bi { bi_car :> Type;
+ bi_entails : bi_car → bi_car → Prop;
+ bi_impl : bi_car → bi_car → bi_car;
+ bi_forall : ∀ A, (A → bi_car) → bi_car; }.
+
+Declare Instance bi_equiv `{PROP:bi} : Equiv (bi_car PROP).
+
+Arguments bi_car : simpl never.
+Arguments bi_entails {PROP} _%I _%I : simpl never, rename.
+Arguments bi_impl {PROP} _%I _%I : simpl never, rename.
+Arguments bi_forall {PROP _} _%I : simpl never, rename.
+
+Notation "P ⊢ Q" := (bi_entails P%I Q%I) .
+Notation "P ⊣⊢ Q" := (equiv (A:=bi_car _) P%I Q%I) .
+
+Infix "→" := bi_impl : bi_scope.
+Notation "∀ x .. y , P" :=
+ (bi_forall (λ x, .. (bi_forall (λ y, P)) ..)%I) : bi_scope.
+
+(* bug disappears if definitional class *)
+Class Plainly (PROP : bi) := { plainly : PROP -> PROP; }.
+Notation "■ P" := (plainly P) : bi_scope.
+
+Section S.
+ Context {I : Type} {PROP : bi} `(Plainly PROP).
+
+ Lemma plainly_forall `{Plainly PROP} {A} (Ψ : A → PROP) : (∀ a, ■ (Ψ a)) ⊣⊢ ■ (∀ a, Ψ a).
+ Proof. Admitted.
+
+ Global Instance entails_proper :
+ Proper (equiv ==> equiv ==> iff) (bi_entails : relation PROP).
+ Proof. Admitted.
+
+ Global Instance impl_proper :
+ Proper (equiv ==> equiv ==> equiv) (@bi_impl PROP).
+ Proof. Admitted.
+
+ Global Instance forall_proper A :
+ Proper (pointwise_relation _ equiv ==> equiv) (@bi_forall PROP A).
+ Proof. Admitted.
+
+ Declare Instance PROP_Equivalence: Equivalence (@equiv PROP _).
+
+ Set Mangle Names.
+ Lemma foo (P : I -> PROP) K:
+ K ⊢ ∀ (j : I)
+ (_ : Prop) (* bug disappears if this is removed *)
+ , (∀ i0, ■ P i0) → P j.
+ Proof.
+ setoid_rewrite plainly_forall.
+ (* retype in case the tactic did some nonsense *)
+ match goal with |- ?T => let _ := type of T in idtac end.
+ Abort.
+End S.
diff --git a/test-suite/bugs/closed/bug_13366.v b/test-suite/bugs/closed/bug_13366.v
new file mode 100644
index 0000000000..06918a9266
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13366.v
@@ -0,0 +1,5 @@
+Class Functor (F : Type -> Type) : Type :=
+ fmap : F nat.
+
+Fail Definition blah := sum fmap.
+(* used to be anomaly not an arity *)
diff --git a/test-suite/bugs/closed/bug_9809.v b/test-suite/bugs/closed/bug_9809.v
new file mode 100644
index 0000000000..4a7d2c7fac
--- /dev/null
+++ b/test-suite/bugs/closed/bug_9809.v
@@ -0,0 +1,30 @@
+Section FreeMonad.
+
+ Variable S : Type.
+ Variable P : S -> Type.
+
+ Inductive FreeF A : Type :=
+ | retFree : A -> FreeF A
+ | opr : forall s, (P s -> FreeF A) -> FreeF A.
+
+End FreeMonad.
+
+Section Fibonnacci.
+
+ Inductive gen_op := call_op : nat -> gen_op.
+ Definition gen_ty (op : gen_op) :=
+ match op with
+ | call_op _ => nat
+ end.
+
+ Fail Definition fib0 (n:nat) : FreeF gen_op gen_ty nat :=
+ match n with
+ | 0
+ | 1 => retFree _ _ _ 1
+ | S (S k) =>
+ opr _ _ _ (call_op (S k))
+ (fun r1 => opr _ _ _ (call_op k)
+ (fun r0 => retFree (* _ _ _ *) (r1 + r0)))
+ end.
+
+End Fibonnacci.
diff --git a/test-suite/bugs/closed/bug_9971.v b/test-suite/bugs/closed/bug_9971.v
new file mode 100644
index 0000000000..ef526dcd7d
--- /dev/null
+++ b/test-suite/bugs/closed/bug_9971.v
@@ -0,0 +1,27 @@
+(* Test that it raises a normal error and not an anomaly *)
+Set Primitive Projections.
+Record prod A B := pair { fst : A ; snd : B }.
+Arguments fst {A B} _.
+Arguments snd {A B} _.
+Arguments pair {A B} _ _.
+Record piis := { dep_types : Type; indep_args : dep_types -> Type }.
+Import EqNotations.
+Goal forall (id : Set) (V : id) (piiio : id -> piis)
+ (Z : {ridc : id & prod (dep_types (piiio ridc)) True})
+ (P : dep_types (piiio V) -> Type) (W : {x : dep_types (piiio V) & P x}),
+ let ida := fun (x : id) (y : dep_types (piiio x)) => indep_args (piiio x) y in
+ prod True (ida V (projT1 W)) ->
+ Z = existT _ V (pair (projT1 W) I) ->
+ ida (projT1 Z) (fst (projT2 Z)).
+ intros.
+ refine (rew <- [fun k' => ida (projT1 k') (fst (projT2 k'))]
+ H in
+ let v := I in
+ _);
+ refine (snd X).
+ Undo.
+Fail refine (rew <- [fun k' => ida (projT1 k') (fst (projT2 k'))]
+ H in
+ let v := I in
+ snd X).
+Abort.
diff --git a/test-suite/output/Notations3.out b/test-suite/output/Notations3.out
index bd22d45059..a9bed49922 100644
--- a/test-suite/output/Notations3.out
+++ b/test-suite/output/Notations3.out
@@ -120,14 +120,14 @@ where
letpair x [1] = {0};
return (1, 2, 3, 4)
: nat * nat * nat * nat
-{{ 1 | 1 // 1 }}
- : nat
-!!! _ _ : nat, True
- : (nat -> Prop) * ((nat -> Prop) * Prop)
((*1).2).3
: nat
*(1.2)
: nat
+{{ 1 | 1 // 1 }}
+ : nat
+!!! _ _ : nat, True
+ : (nat -> Prop) * ((nat -> Prop) * Prop)
! '{{x, y}}, x.y = 0
: Prop
exists x : nat,
@@ -249,3 +249,5 @@ myfoo01 tt
: nat
myfoo01 tt
: nat
+1 ⪯ 2 ⪯ 3 ⪯ 4
+ : Prop
diff --git a/test-suite/output/Notations3.v b/test-suite/output/Notations3.v
index 839df99ea7..04a91c14d9 100644
--- a/test-suite/output/Notations3.v
+++ b/test-suite/output/Notations3.v
@@ -181,6 +181,13 @@ Notation "'letpair' x [1] = { a } ; 'return' ( b0 , b1 , .. , b2 )" :=
(let x:=a in ( .. (b0,b1) .., b2)).
Check letpair x [1] = {0}; return (1,2,3,4).
+(* Allow level for leftmost nonterminal when printing-only, BZ#5739 *)
+
+Notation "* x" := (id x) (only printing, at level 15, format "* x").
+Notation "x . y" := (x + y) (only printing, at level 20, x at level 14, left associativity, format "x . y").
+Check (((id 1) + 2) + 3).
+Check (id (1 + 2)).
+
(* Test spacing in #5569 *)
Notation "{ { xL | xR // xcut } }" := (xL+xR+xcut)
@@ -191,13 +198,6 @@ Check 1+1+1.
Notation "!!! x .. y , b" := ((fun x => b), .. ((fun y => b), True) ..) (at level 200, x binder).
Check !!! (x y:nat), True.
-(* Allow level for leftmost nonterminal when printing-only, BZ#5739 *)
-
-Notation "* x" := (id x) (only printing, at level 15, format "* x").
-Notation "x . y" := (x + y) (only printing, at level 20, x at level 14, left associativity, format "x . y").
-Check (((id 1) + 2) + 3).
-Check (id (1 + 2)).
-
(* Test contraction of "forall x, let 'pat := x in ..." into "forall 'pat, ..." *)
(* for isolated "forall" (was not working already in 8.6) *)
Notation "! x .. y , A" := (id (forall x, .. (id (forall y, A)) .. )) (at level 200, x binder).
@@ -410,3 +410,13 @@ Check myfoo0 1 tt. (* was printing [myfoo0 1 HI], but should print [myfoo01 HI]
Check myfoo01 tt. (* was printing [myfoo0 1 HI], but should print [myfoo01 HI] *)
End Issue8126.
+
+Module RecursiveNotationPartialApp.
+
+(* Discussed on Coq Club, 28 July 2020 *)
+Notation "x ⪯ y ⪯ .. ⪯ z ⪯ t" :=
+ ((fun b A a => a <= b /\ A b) y .. ((fun b A a => a <= b /\ A b) z (fun b => b <= t)) .. x)
+ (at level 70, y at next level, z at next level, t at next level).
+Check 1 ⪯ 2 ⪯ 3 ⪯ 4.
+
+End RecursiveNotationPartialApp.
diff --git a/test-suite/output/Notations4.out b/test-suite/output/Notations4.out
index a6fd39c29b..86c4b3cccc 100644
--- a/test-suite/output/Notations4.out
+++ b/test-suite/output/Notations4.out
@@ -179,3 +179,21 @@ Found an inductive type while a pattern was expected.
: Prop
!!!! (nat, id), nat = true /\ id = false
: Prop
+∀ x : nat, x = 0
+ : Prop
+∀₁ x, x = 0
+ : Prop
+∀₁ x, x = 0
+ : Prop
+∀₂ x y, x + y = 0
+ : Prop
+((1, 2))
+ : nat * nat
+%% [x == 1]
+ : Prop
+%%% [1]
+ : Prop
+[[2]]
+ : nat * nat
+%%%
+ : Type
diff --git a/test-suite/output/Notations4.v b/test-suite/output/Notations4.v
index 0731819bba..6af192ea82 100644
--- a/test-suite/output/Notations4.v
+++ b/test-suite/output/Notations4.v
@@ -414,3 +414,76 @@ Module P.
End NotationBinderNotMixedWithTerms.
End P.
+
+Module MorePrecise1.
+
+(* A notation with limited iteration is strictly more precise than a
+ notation with unlimited iteration *)
+
+Notation "∀ x .. y , P" := (forall x, .. (forall y, P) ..)
+ (at level 200, x binder, y binder, right associativity,
+ format "'[ ' '[ ' ∀ x .. y ']' , '/' P ']'") : type_scope.
+
+Check forall x, x = 0.
+
+Notation "∀₁ z , P" := (forall z, P)
+ (at level 200, right associativity) : type_scope.
+
+Check forall x, x = 0.
+
+Notation "∀₂ y x , P" := (forall y x, P)
+ (at level 200, right associativity) : type_scope.
+
+Check forall x, x = 0.
+Check forall x y, x + y = 0.
+
+Notation "(( x , y ))" := (x,y) : core_scope.
+
+Check ((1,2)).
+
+End MorePrecise1.
+
+Module MorePrecise2.
+
+(* Case of a bound binder *)
+Notation "%% [ x == y ]" := (forall x, S x = y) (at level 0, x pattern, y at level 60).
+
+(* Case of an internal binder *)
+Notation "%%% [ y ]" := (forall x : nat, x = y) (at level 0).
+
+(* Check that the two previous notations are indeed finer *)
+Notation "∀ x .. y , P" := (forall x, .. (forall y, P) ..)
+ (at level 200, x binder, y binder, right associativity,
+ format "'[ ' '[ ' ∀ x .. y ']' , '/' P ']'").
+Notation "∀' x .. y , P" := (forall y, .. (forall x, P) ..)
+ (at level 200, x binder, y binder, right associativity,
+ format "'[ ' '[ ' ∀' x .. y ']' , '/' P ']'").
+
+Check %% [x == 1].
+Check %%% [1].
+
+Notation "[[ x ]]" := (pair 1 x).
+
+Notation "( x ; y ; .. ; z )" := (pair .. (pair x y) .. z).
+Notation "[ x ; y ; .. ; z ]" := (pair .. (pair x z) .. y).
+
+(* Check which is finer *)
+Check [[ 2 ]].
+
+End MorePrecise2.
+
+Module MorePrecise3.
+
+(* This is about a binder not bound in a notation being strictly more
+ precise than a binder bound in the notation (since the notation
+ applies - a priori - stricly less often) *)
+
+Notation "%%%" := (forall x, x) (at level 0).
+
+Notation "∀ x .. y , P" := (forall x, .. (forall y, P) ..)
+ (at level 200, x binder, y binder, right associativity,
+ format "'[ ' '[ ' ∀ x .. y ']' , '/' P ']'").
+
+Check %%%.
+
+End MorePrecise3.
diff --git a/test-suite/output/UnboundRef.out b/test-suite/output/UnboundRef.out
new file mode 100644
index 0000000000..a574e97e0f
--- /dev/null
+++ b/test-suite/output/UnboundRef.out
@@ -0,0 +1,3 @@
+File "stdin", line 1, characters 11-12:
+Error: The reference a was not found in the current environment.
+
diff --git a/test-suite/output/UnboundRef.v b/test-suite/output/UnboundRef.v
new file mode 100644
index 0000000000..fd08ae0c5c
--- /dev/null
+++ b/test-suite/output/UnboundRef.v
@@ -0,0 +1,2 @@
+Check Prop a b.
+(* Prop is because we need a real head for the application *)
diff --git a/test-suite/output/attributes.out b/test-suite/output/attributes.out
new file mode 100644
index 0000000000..25572ee2aa
--- /dev/null
+++ b/test-suite/output/attributes.out
@@ -0,0 +1,11 @@
+The command has indeed failed with message:
+Attribute for canonical specified twice.
+The command has indeed failed with message:
+key 'polymorphic' has been already set.
+The command has indeed failed with message:
+Invalid value 'foo' for key polymorphic
+use one of {yes, no}
+The command has indeed failed with message:
+Invalid syntax polymorphic(foo), try polymorphic={yes, no} instead.
+The command has indeed failed with message:
+Invalid syntax polymorphic(foo, bar), try polymorphic={yes, no} instead.
diff --git a/test-suite/output/attributes.v b/test-suite/output/attributes.v
new file mode 100644
index 0000000000..aef05e6cd4
--- /dev/null
+++ b/test-suite/output/attributes.v
@@ -0,0 +1,9 @@
+Fail #[canonical=yes, canonical=no] Definition a := 3.
+
+Fail #[universes(polymorphic=yes,polymorphic=no)] Definition a := 3.
+
+Fail #[universes(polymorphic=foo)] Definition a := 3.
+
+Fail #[universes(polymorphic(foo))] Definition a := 3.
+
+Fail #[universes(polymorphic(foo,bar))] Definition a := 3.
diff --git a/test-suite/output/bug_10824.out b/test-suite/output/bug_10824.out
new file mode 100644
index 0000000000..4bc5aafbca
--- /dev/null
+++ b/test-suite/output/bug_10824.out
@@ -0,0 +1,4 @@
+!!
+ : Prop
+!!
+ : Prop
diff --git a/test-suite/output/bug_10824.v b/test-suite/output/bug_10824.v
new file mode 100644
index 0000000000..01271f7d61
--- /dev/null
+++ b/test-suite/output/bug_10824.v
@@ -0,0 +1,12 @@
+Module A.
+Notation F := False.
+Notation "!!" := False (at level 100).
+Check False.
+End A.
+
+Module B.
+Notation "!!" := False (at level 100).
+Notation F := False.
+Notation "!!" := False (at level 100).
+Check False.
+End B.
diff --git a/test-suite/output/bug_7443.out b/test-suite/output/bug_7443.out
new file mode 100644
index 0000000000..446ec6a1ad
--- /dev/null
+++ b/test-suite/output/bug_7443.out
@@ -0,0 +1,13 @@
+Literal 1
+ : Type
+[1]
+ : Type
+Literal 1
+ : Type
+[1]
+ : Type
+The command has indeed failed with message:
+The term "1" has type "Datatypes.nat" while it is expected to have type
+ "denote ?t".
+Literal 1
+ : Type
diff --git a/test-suite/output/bug_7443.v b/test-suite/output/bug_7443.v
new file mode 100644
index 0000000000..33f76dbcfa
--- /dev/null
+++ b/test-suite/output/bug_7443.v
@@ -0,0 +1,37 @@
+Inductive type := nat | bool.
+Definition denote (t : type)
+ := match t with
+ | nat => Datatypes.nat
+ | bool => Datatypes.bool
+ end.
+Ltac reify t :=
+ lazymatch eval cbv beta in t with
+ | Datatypes.nat => nat
+ | Datatypes.bool => bool
+ end.
+Notation reify t := (ltac:(let rt := reify t in exact rt)) (only parsing).
+Notation reify_type_of e := (reify ((fun t (_ : t) => t) _ e)) (only parsing).
+Axiom Literal : forall {t}, denote t -> Type.
+Declare Scope foo_scope.
+Delimit Scope foo_scope with foo.
+Open Scope foo_scope.
+Section A.
+ Notation "[ x ]" := (Literal (t:=reify_type_of x) x) (only parsing) : foo_scope.
+ Check [1]. (* Literal 1 : Type *) (* as expected *)
+ Notation "[ x ]" := (Literal x) : foo_scope.
+ Check @Literal nat 1. (* Incorred: gives Literal 1 : Type when it should give [1]. Fixed by #12950 *)
+ Notation "[ x ]" := (Literal (t:=reify_type_of x) x) (only parsing) : foo_scope.
+ Check [1]. (* Incorrect: gives Literal 1 : Type when it should give [1]. This is disputable:
+ #12950 considers that giving an only parsing a previous both-parsing-and-printing notation *)
+End A.
+Section B.
+ Notation "[ x ]" := (Literal x) : foo_scope.
+ Check @Literal nat 1. (* [1] : Type *)
+ Fail Check [1]. (* As expected: The command has indeed failed with message:
+ The term "1" has type "Datatypes.nat" while it is expected to have type
+ "denote ?t". *)
+ Notation "[ x ]" := (Literal (t:=reify_type_of x) x) (only parsing) : foo_scope.
+ Check [1]. (* Should succeed, but instead fails with: Error:
+ The term "1" has type "Datatypes.nat" while it is expected to have type
+ "denote ?t". Fixed by #12950, but previous declaration is cancelled by #12950. *)
+End B.
diff --git a/test-suite/primitive/float/next_up_down.v b/test-suite/primitive/float/next_up_down.v
index 4f8427dc5b..ea45fb3983 100644
--- a/test-suite/primitive/float/next_up_down.v
+++ b/test-suite/primitive/float/next_up_down.v
@@ -120,3 +120,46 @@ Check (eq_refl (SF64succ (Prim2SF f14)) <<: Prim2SF (next_up f14) = SF64succ (Pr
Check (eq_refl (SF64pred (Prim2SF f14)) <<: Prim2SF (next_down f14) = SF64pred (Prim2SF f14)).
Check (eq_refl (SF64succ (Prim2SF f15)) <<: Prim2SF (next_up f15) = SF64succ (Prim2SF f15)).
Check (eq_refl (SF64pred (Prim2SF f15)) <<: Prim2SF (next_down f15) = SF64pred (Prim2SF f15)).
+
+Check (eq_refl : next_up nan = nan).
+Check (eq_refl : next_down nan = nan).
+Check (eq_refl : next_up neg_infinity = -0x1.fffffffffffffp+1023).
+Check (eq_refl : next_down neg_infinity = neg_infinity).
+Check (eq_refl : next_up (-0x1.fffffffffffffp+1023) = -0x1.ffffffffffffep+1023).
+Check (eq_refl : next_down (-0x1.fffffffffffffp+1023) = neg_infinity).
+Check (eq_refl : next_up (-0x1.ffffffffffffap+1023) = -0x1.ffffffffffff9p+1023).
+Check (eq_refl : next_down (-0x1.ffffffffffffap+1023) = -0x1.ffffffffffffbp+1023).
+Check (eq_refl : next_up (-0x1.fffffffffffff) = -0x1.ffffffffffffe).
+Check (eq_refl : next_down (-0x1.fffffffffffff) = -0x1p+1).
+Check (eq_refl : next_up (-0x1p1) = -0x1.fffffffffffff).
+Check (eq_refl : next_down (-0x1p1) = -0x1.0000000000001p+1).
+Check (eq_refl : next_up (-0x1p-1022) = -0x0.fffffffffffffp-1022).
+Check (eq_refl : next_down (-0x1p-1022) = -0x1.0000000000001p-1022).
+Check (eq_refl : next_up (-0x0.fffffffffffffp-1022) = -0x0.ffffffffffffep-1022).
+Check (eq_refl : next_down (-0x0.fffffffffffffp-1022) = -0x1p-1022).
+Check (eq_refl : next_up (-0x0.01p-1022) = -0x0.00fffffffffffp-1022).
+Check (eq_refl : next_down (-0x0.01p-1022) = -0x0.0100000000001p-1022).
+Check (eq_refl : next_up (-0x0.0000000000001p-1022) = -0).
+Check (eq_refl : next_down (-0x0.0000000000001p-1022) = -0x0.0000000000002p-1022).
+Check (eq_refl : next_up (-0) = 0x0.0000000000001p-1022).
+Check (eq_refl : next_down (-0) = -0x0.0000000000001p-1022).
+Check (eq_refl : next_up 0 = 0x0.0000000000001p-1022).
+Check (eq_refl : next_down 0 = -0x0.0000000000001p-1022).
+Check (eq_refl : next_up 0x0.0000000000001p-1022 = 0x0.0000000000002p-1022).
+Check (eq_refl : next_down 0x0.0000000000001p-1022 = 0).
+Check (eq_refl : next_up 0x0.01p-1022 = 0x0.0100000000001p-1022).
+Check (eq_refl : next_down 0x0.01p-1022 = 0x0.00fffffffffffp-1022).
+Check (eq_refl : next_up 0x0.fffffffffffffp-1022 = 0x1p-1022).
+Check (eq_refl : next_down 0x0.fffffffffffffp-1022 = 0x0.ffffffffffffep-1022).
+Check (eq_refl : next_up 0x1p-1022 = 0x1.0000000000001p-1022).
+Check (eq_refl : next_down 0x1p-1022 = 0x0.fffffffffffffp-1022).
+Check (eq_refl : next_up 0x1p1 = 0x1.0000000000001p+1).
+Check (eq_refl : next_down 0x1p1 = 0x1.fffffffffffff).
+Check (eq_refl : next_up 0x1.fffffffffffff = 0x1p+1).
+Check (eq_refl : next_down 0x1.fffffffffffff = 0x1.ffffffffffffe).
+Check (eq_refl : next_up 0x1.ffffffffffffap+1023 = 0x1.ffffffffffffbp+1023).
+Check (eq_refl : next_down 0x1.ffffffffffffap+1023 = 0x1.ffffffffffff9p+1023).
+Check (eq_refl : next_up 0x1.fffffffffffffp+1023 = infinity).
+Check (eq_refl : next_down 0x1.fffffffffffffp+1023 = 0x1.ffffffffffffep+1023).
+Check (eq_refl : next_up infinity = infinity).
+Check (eq_refl : next_down infinity = 0x1.fffffffffffffp+1023).
diff --git a/test-suite/success/CumulInd.v b/test-suite/success/CumulInd.v
new file mode 100644
index 0000000000..f24d13b8af
--- /dev/null
+++ b/test-suite/success/CumulInd.v
@@ -0,0 +1,20 @@
+
+(* variances other than Invariant are forbidden for non-cumul inductives *)
+Fail Inductive foo@{+u} : Prop := .
+Fail Polymorphic Inductive foo@{*u} : Prop := .
+Inductive foo@{=u} : Prop := .
+
+Set Universe Polymorphism.
+Set Polymorphic Inductive Cumulativity.
+
+Inductive force_invariant@{=u} : Prop := .
+Fail Definition lift@{u v | u < v} (x:force_invariant@{u}) : force_invariant@{v} := x.
+
+Inductive force_covariant@{+u} : Prop := .
+Fail Definition lift@{u v | v < u} (x:force_covariant@{u}) : force_covariant@{v} := x.
+Definition lift@{u v | u < v} (x:force_covariant@{u}) : force_covariant@{v} := x.
+
+Fail Inductive not_irrelevant@{*u} : Prop := nirr (_ : Type@{u}).
+Inductive check_covariant@{+u} : Prop := cov (_ : Type@{u}).
+
+Fail Inductive not_covariant@{+u} : Prop := ncov (_ : Type@{u} -> nat).
diff --git a/test-suite/success/Template.v b/test-suite/success/Template.v
index 656362b8fc..d11ae20b8d 100644
--- a/test-suite/success/Template.v
+++ b/test-suite/success/Template.v
@@ -37,7 +37,7 @@ Module Yes.
End Yes.
Module No.
- #[universes(notemplate)]
+ #[universes(template=no)]
Inductive Box (A:Type) : Type := box : A -> Box A.
About Box.
diff --git a/test-suite/success/attribute_syntax.v b/test-suite/success/attribute_syntax.v
index b403fc120c..b866c4b074 100644
--- a/test-suite/success/attribute_syntax.v
+++ b/test-suite/success/attribute_syntax.v
@@ -16,11 +16,16 @@ Definition ι T (x: T) := x.
Check ι _ ι.
+#[universes(polymorphic=no)]
+Definition ιι T (x: T) := x.
+
+Fail Check ιι _ ιι.
+
#[program]
Fixpoint f (n: nat) {wf lt n} : nat := _.
Reset f.
-#[program(true)]
+#[program=yes]
Fixpoint f (n: nat) {wf lt n} : nat := _.
Reset f.
@@ -43,3 +48,14 @@ Export Set Foo.
Fail #[ export ] Export Foo.
(* Attribute for Locality specified twice *)
+
+(* Tests for deprecated attribute syntax *)
+Set Warnings "-deprecated-attribute-syntax".
+
+#[program(true)]
+Fixpoint f (n: nat) {wf lt n} : nat := _.
+Reset f.
+
+#[universes(monomorphic)]
+Definition ιιι T (x: T) := x.
+Fail Check ιιι _ ιιι.
diff --git a/vernac/attributes.ml b/vernac/attributes.ml
index efba6d332a..fdaeedef8c 100644
--- a/vernac/attributes.ml
+++ b/vernac/attributes.ml
@@ -11,13 +11,29 @@
open CErrors
(** The type of parsing attribute data *)
+type vernac_flag_type =
+ | FlagIdent of string
+ | FlagString of string
+
type vernac_flags = vernac_flag list
and vernac_flag = string * vernac_flag_value
and vernac_flag_value =
| VernacFlagEmpty
- | VernacFlagLeaf of string
+ | VernacFlagLeaf of vernac_flag_type
| VernacFlagList of vernac_flags
+let pr_vernac_flag_leaf = function
+ | FlagIdent b -> Pp.str b
+ | FlagString s -> Pp.(quote (str s))
+
+let rec pr_vernac_flag_value = let open Pp in function
+ | VernacFlagEmpty -> mt ()
+ | VernacFlagLeaf l -> str "=" ++ pr_vernac_flag_leaf l
+ | VernacFlagList s -> surround (prlist_with_sep pr_comma pr_vernac_flag s)
+and pr_vernac_flag (s, arguments) =
+ let open Pp in
+ str s ++ (pr_vernac_flag_value arguments)
+
let warn_unsupported_attributes =
CWarnings.create ~name:"unsupported-attributes" ~category:"parsing" ~default:CWarnings.AsError
(fun atts ->
@@ -105,16 +121,82 @@ let single_key_parser ~name ~key v prev args =
assert_once ~name prev;
v
-let bool_attribute ~name ~on ~off : bool option attribute =
- attribute_of_list [(on, single_key_parser ~name ~key:on true);
- (off, single_key_parser ~name ~key:off false)]
+let pr_possible_values ~values =
+ Pp.(str "{" ++ prlist_with_sep pr_comma str (List.map fst values) ++ str "}")
+
+(** [key_value_attribute ~key ~default ~values] parses a attribute [key=value]
+ with possible [key] [value] in [values], [default] is for compatibility for users
+ doing [qualif(key)] which is parsed as [qualif(key=default)] *)
+let key_value_attribute ~key ~default ~(values : (string * 'a) list) : 'a option attribute =
+ let parser = function
+ | Some v ->
+ CErrors.user_err Pp.(str "key '" ++ str key ++ str "' has been already set.")
+ | None ->
+ begin function
+ | VernacFlagLeaf (FlagIdent b) ->
+ begin match CList.assoc_f String.equal b values with
+ | exception Not_found ->
+ CErrors.user_err
+ Pp.(str "Invalid value '" ++ str b ++ str "' for key " ++ str key ++ fnl () ++
+ str "use one of " ++ pr_possible_values ~values)
+ | value -> value
+ end
+ | VernacFlagEmpty ->
+ default
+ | err ->
+ CErrors.user_err
+ Pp.(str "Invalid syntax " ++ pr_vernac_flag (key, err) ++ str ", try "
+ ++ str key ++ str "=" ++ pr_possible_values ~values ++ str " instead.")
+ end
+ in
+ attribute_of_list [key, parser]
+
+let bool_attribute ~name : bool option attribute =
+ let values = ["yes", true; "no", false] in
+ key_value_attribute ~key:name ~default:true ~values
+
+let legacy_bool_attribute ~name ~on ~off : bool option attribute =
+ attribute_of_list
+ [(on, single_key_parser ~name ~key:on true);
+ (off, single_key_parser ~name ~key:off false)]
+
+(* important note: we use on as the default for the new bool_attribute ! *)
+let deprecated_bool_attribute_warning =
+ CWarnings.create
+ ~name:"deprecated-attribute-syntax"
+ ~category:"parsing"
+ ~default:CWarnings.Enabled
+ (fun name ->
+ Pp.(str "Syntax for switching off boolean attributes has been updated, use " ++ str name ++ str "=no instead."))
+
+let deprecated_bool_attribute ~name ~on ~off : bool option attribute =
+ bool_attribute ~name:on ++ legacy_bool_attribute ~name ~on ~off |> map (function
+ | None, None ->
+ None
+ | None, Some v ->
+ deprecated_bool_attribute_warning name;
+ Some v
+ | Some v, None -> Some v
+ | Some v1, Some v2 ->
+ CErrors.user_err
+ Pp.(str "attribute " ++ str name ++
+ str ": cannot specify legacy and modern syntax at the same time.")
+ )
(* Variant of the [bool] attribute with only two values (bool has three). *)
let get_bool_value ~key ~default =
function
| VernacFlagEmpty -> default
- | VernacFlagList [ "true", VernacFlagEmpty ] -> true
- | VernacFlagList [ "false", VernacFlagEmpty ] -> false
+ | VernacFlagList [ "true", VernacFlagEmpty ] ->
+ deprecated_bool_attribute_warning key;
+ true
+ | VernacFlagList [ "false", VernacFlagEmpty ] ->
+ deprecated_bool_attribute_warning key;
+ false
+ | VernacFlagLeaf (FlagIdent "yes") ->
+ true
+ | VernacFlagLeaf (FlagIdent "no") ->
+ false
| _ -> user_err Pp.(str "Attribute " ++ str key ++ str " only accepts boolean values.")
let enable_attribute ~key ~default : bool attribute =
@@ -161,18 +243,37 @@ let () = let open Goptions in
let program =
enable_attribute ~key:"program" ~default:(fun () -> !program_mode)
-let locality = bool_attribute ~name:"Locality" ~on:"local" ~off:"global"
-
-let option_locality =
+(* This is a bit complex as the grammar in g_vernac.mlg doesn't
+ distingish between the boolean and ternary case.*)
+let option_locality_parser =
let name = "Locality" in
attribute_of_list [
- ("local", single_key_parser ~name ~key:"local" Goptions.OptLocal);
- ("global", single_key_parser ~name ~key:"global" Goptions.OptGlobal);
- ("export", single_key_parser ~name ~key:"export" Goptions.OptExport);
- ] >>= function
+ ("local", single_key_parser ~name ~key:"local" Goptions.OptLocal)
+ ; ("global", single_key_parser ~name ~key:"global" Goptions.OptGlobal)
+ ; ("export", single_key_parser ~name ~key:"export" Goptions.OptExport)
+ ]
+
+let option_locality =
+ option_locality_parser >>= function
| None -> return Goptions.OptDefault
| Some l -> return l
+(* locality is supposed to be true when local, false when global *)
+let locality =
+ let locality_to_bool =
+ function
+ | Goptions.OptLocal ->
+ true
+ | Goptions.OptGlobal ->
+ false
+ | Goptions.OptExport ->
+ CErrors.user_err Pp.(str "export attribute not supported here")
+ | Goptions.OptDefault ->
+ CErrors.user_err Pp.(str "default attribute not supported here")
+ in
+ option_locality_parser >>= function l ->
+ return (Option.map locality_to_bool l)
+
let ukey = "universes"
let universe_polymorphism_option_name = ["Universe"; "Polymorphism"]
@@ -188,12 +289,17 @@ let is_universe_polymorphism =
fun () -> !b
let polymorphic_base =
- bool_attribute ~name:"Polymorphism" ~on:"polymorphic" ~off:"monomorphic" >>= function
+ deprecated_bool_attribute
+ ~name:"Polymorphism"
+ ~on:"polymorphic" ~off:"monomorphic" >>= function
| Some b -> return b
| None -> return (is_universe_polymorphism())
let template =
- qualify_attribute ukey (bool_attribute ~name:"Template" ~on:"template" ~off:"notemplate")
+ qualify_attribute ukey
+ (deprecated_bool_attribute
+ ~name:"Template"
+ ~on:"template" ~off:"notemplate")
let polymorphic =
qualify_attribute ukey polymorphic_base
@@ -201,12 +307,12 @@ let polymorphic =
let deprecation_parser : Deprecation.t key_parser = fun orig args ->
assert_once ~name:"deprecation" orig;
match args with
- | VernacFlagList [ "since", VernacFlagLeaf since ; "note", VernacFlagLeaf note ]
- | VernacFlagList [ "note", VernacFlagLeaf note ; "since", VernacFlagLeaf since ] ->
+ | VernacFlagList [ "since", VernacFlagLeaf (FlagString since) ; "note", VernacFlagLeaf (FlagString note) ]
+ | VernacFlagList [ "note", VernacFlagLeaf (FlagString note) ; "since", VernacFlagLeaf (FlagString since) ] ->
Deprecation.make ~since ~note ()
- | VernacFlagList [ "since", VernacFlagLeaf since ] ->
+ | VernacFlagList [ "since", VernacFlagLeaf (FlagString since) ] ->
Deprecation.make ~since ()
- | VernacFlagList [ "note", VernacFlagLeaf note ] ->
+ | VernacFlagList [ "note", VernacFlagLeaf (FlagString note) ] ->
Deprecation.make ~note ()
| _ -> CErrors.user_err (Pp.str "Ill formed “deprecated” attribute")
@@ -218,7 +324,7 @@ let only_polymorphism atts = parse polymorphic atts
let vernac_polymorphic_flag = ukey, VernacFlagList ["polymorphic", VernacFlagEmpty]
-let vernac_monomorphic_flag = ukey, VernacFlagList ["monomorphic", VernacFlagEmpty]
+let vernac_monomorphic_flag = ukey, VernacFlagList ["polymorphic", VernacFlagLeaf (FlagIdent "no")]
let canonical_field =
enable_attribute ~key:"canonical" ~default:(fun () -> true)
@@ -228,7 +334,7 @@ let canonical_instance =
let uses_parser : string key_parser = fun orig args ->
assert_once ~name:"using" orig;
match args with
- | VernacFlagLeaf str -> str
+ | VernacFlagLeaf (FlagString str) -> str
| _ -> CErrors.user_err (Pp.str "Ill formed \"using\" attribute")
let using = attribute_of_list ["using",uses_parser]
diff --git a/vernac/attributes.mli b/vernac/attributes.mli
index 1969665082..03a14a03ff 100644
--- a/vernac/attributes.mli
+++ b/vernac/attributes.mli
@@ -9,13 +9,19 @@
(************************************************************************)
(** The type of parsing attribute data *)
+type vernac_flag_type =
+ | FlagIdent of string
+ | FlagString of string
+
type vernac_flags = vernac_flag list
and vernac_flag = string * vernac_flag_value
and vernac_flag_value =
| VernacFlagEmpty
- | VernacFlagLeaf of string
+ | VernacFlagLeaf of vernac_flag_type
| VernacFlagList of vernac_flags
+val pr_vernac_flag : vernac_flag -> Pp.t
+
type +'a attribute
(** The type of attributes. When parsing attributes if an ['a
attribute] is present then an ['a] value will be produced.
@@ -82,10 +88,19 @@ val attribute_of_list : (string * 'a key_parser) list -> 'a option attribute
(** Make an attribute from a list of key parsers together with their
associated key. *)
-val bool_attribute : name:string -> on:string -> off:string -> bool option attribute
-(** Define boolean attribute [name] with value [true] when [on] is
- provided and [false] when [off] is provided. The attribute may only
- be set once for a command. *)
+(** Define boolean attribute [name], of the form [name={yes,no}]. The
+ attribute may only be set once for a command. *)
+val bool_attribute : name:string -> bool option attribute
+
+val deprecated_bool_attribute
+ : name:string
+ -> on:string
+ -> off:string
+ -> bool option attribute
+(** Define boolean attribute [name] with will be set when [on] is
+ provided and unset when [off] is provided. The attribute may only
+ be set once for a command; this attribute both accepts the old [on]
+ [off] syntax and new attribute syntax [on=yes] [on=no] *)
val qualify_attribute : string -> 'a attribute -> 'a attribute
(** [qualified_attribute qual att] treats [#[qual(atts)]] like [att]
diff --git a/vernac/comInductive.ml b/vernac/comInductive.ml
index bb26ce652e..597e55a39e 100644
--- a/vernac/comInductive.ml
+++ b/vernac/comInductive.ml
@@ -367,7 +367,26 @@ let restrict_inductive_universes sigma ctx_params arities constructors =
let uvars = List.fold_right (fun (_,ctypes) -> List.fold_right merge_universes_of_constr ctypes) constructors uvars in
Evd.restrict_universe_context sigma uvars
-let interp_mutual_inductive_constr ~sigma ~template ~udecl ~ctx_params ~indnames ~arities ~arityconcl ~constructors ~env_ar_params ~cumulative ~poly ~private_ind ~finite =
+let check_trivial_variances variances =
+ Array.iter (function
+ | None | Some Univ.Variance.Invariant -> ()
+ | Some _ ->
+ CErrors.user_err
+ Pp.(strbrk "Universe variance was specified but this inductive will not be cumulative."))
+ variances
+
+let variance_of_entry ~cumulative ~variances uctx =
+ match uctx with
+ | Monomorphic_entry _ -> check_trivial_variances variances; None
+ | Polymorphic_entry (nas,_) ->
+ if not cumulative then begin check_trivial_variances variances; None end
+ else
+ let lvs = Array.length variances in
+ let lus = Array.length nas in
+ assert (lvs <= lus);
+ Some (Array.append variances (Array.make (lus - lvs) None))
+
+let interp_mutual_inductive_constr ~sigma ~template ~udecl ~variances ~ctx_params ~indnames ~arities ~arityconcl ~constructors ~env_ar_params ~cumulative ~poly ~private_ind ~finite =
(* Compute renewed arities *)
let sigma = Evd.minimize_universes sigma in
let nf = Evarutil.nf_evars_universes sigma in
@@ -429,13 +448,13 @@ let interp_mutual_inductive_constr ~sigma ~template ~udecl ~ctx_params ~indnames
mind_entry_private = if private_ind then Some false else None;
mind_entry_universes = uctx;
mind_entry_template = is_template;
- mind_entry_cumulative = poly && cumulative;
+ mind_entry_variance = variance_of_entry ~cumulative ~variances uctx;
}
in
mind_ent, Evd.universe_binders sigma
let interp_params env udecl uparamsl paramsl =
- let sigma, udecl = interp_univ_decl_opt env udecl in
+ let sigma, udecl, variances = interp_cumul_univ_decl_opt env udecl in
let sigma, (uimpls, ((env_uparams, ctx_uparams), useruimpls)) =
interp_context_evars ~program_mode:false env sigma uparamsl in
let sigma, (impls, ((env_params, ctx_params), userimpls)) =
@@ -443,7 +462,7 @@ let interp_params env udecl uparamsl paramsl =
in
(* Names of parameters as arguments of the inductive type (defs removed) *)
sigma, env_params, (ctx_params, env_uparams, ctx_uparams,
- userimpls, useruimpls, impls, udecl)
+ userimpls, useruimpls, impls, udecl, variances)
(* When a hole remains for a param, pretend the param is uniform and
do the unification.
@@ -485,7 +504,7 @@ let interp_mutual_inductive_gen env0 ~template udecl (uparamsl,paramsl,indl) not
(* In case of template polymorphism, we need to compute more constraints *)
let env0 = if poly then env0 else Environ.set_universes_lbound env0 UGraph.Bound.Prop in
- let sigma, env_params, (ctx_params, env_uparams, ctx_uparams, userimpls, useruimpls, impls, udecl) =
+ let sigma, env_params, (ctx_params, env_uparams, ctx_uparams, userimpls, useruimpls, impls, udecl, variances) =
interp_params env0 udecl uparamsl paramsl
in
@@ -563,7 +582,7 @@ let interp_mutual_inductive_gen env0 ~template udecl (uparamsl,paramsl,indl) not
userimpls @ impls) cimpls)
indimpls cimpls
in
- let mie, pl = interp_mutual_inductive_constr ~template ~sigma ~ctx_params ~udecl ~arities ~arityconcl ~constructors ~env_ar_params ~poly ~finite ~cumulative ~private_ind ~indnames in
+ let mie, pl = interp_mutual_inductive_constr ~template ~sigma ~ctx_params ~udecl ~variances ~arities ~arityconcl ~constructors ~env_ar_params ~poly ~finite ~cumulative ~private_ind ~indnames in
(mie, pl, impls)
diff --git a/vernac/comInductive.mli b/vernac/comInductive.mli
index 91e8f609d5..8bce884ba4 100644
--- a/vernac/comInductive.mli
+++ b/vernac/comInductive.mli
@@ -22,7 +22,7 @@ type uniform_inductive_flag =
val do_mutual_inductive
: template:bool option
- -> universe_decl_expr option
+ -> cumul_univ_decl_expr option
-> (one_inductive_expr * decl_notation list) list
-> cumulative:bool
-> poly:bool
@@ -45,6 +45,7 @@ val interp_mutual_inductive_constr
: sigma:Evd.evar_map
-> template:bool option
-> udecl:UState.universe_decl
+ -> variances:Entries.variance_entry
-> ctx_params:(EConstr.t, EConstr.t) Context.Rel.Declaration.pt list
-> indnames:Names.Id.t list
-> arities:EConstr.t list
@@ -86,3 +87,13 @@ val maybe_unify_params_in : Environ.env -> Evd.evar_map -> ninds:int -> nparams:
(** [nparams] is the number of parameters which aren't treated as
uniform, ie the length of params (including letins) where the env
is [uniform params, inductives, params, binders]. *)
+
+val variance_of_entry
+ : cumulative:bool
+ -> variances:Entries.variance_entry
+ -> Entries.universes_entry
+ -> Entries.variance_entry option
+(** Will return None if non-cumulative, and resize if there are more
+ universes than originally specified.
+ If monomorphic, [cumulative] is treated as [false].
+*)
diff --git a/vernac/g_vernac.mlg b/vernac/g_vernac.mlg
index 1c80d71ea5..116cfc6413 100644
--- a/vernac/g_vernac.mlg
+++ b/vernac/g_vernac.mlg
@@ -119,7 +119,8 @@ GRAMMAR EXTEND Gram
]
;
attr_value:
- [ [ "=" ; v = string -> { VernacFlagLeaf v }
+ [ [ "=" ; v = string -> { VernacFlagLeaf (FlagString v) }
+ | "=" ; v = IDENT -> { VernacFlagLeaf (FlagIdent v) }
| "(" ; a = attribute_list ; ")" -> { VernacFlagList a }
| -> { VernacFlagEmpty } ]
]
@@ -136,7 +137,7 @@ GRAMMAR EXTEND Gram
| IDENT "Cumulative" ->
{ ("universes", VernacFlagList ["cumulative", VernacFlagEmpty]) }
| IDENT "NonCumulative" ->
- { ("universes", VernacFlagList ["noncumulative", VernacFlagEmpty]) }
+ { ("universes", VernacFlagList ["cumulative", VernacFlagLeaf (FlagIdent "no")]) }
| IDENT "Private" ->
{ ("private", VernacFlagList ["matching", VernacFlagEmpty]) }
| IDENT "Program" ->
@@ -194,6 +195,12 @@ let lname_of_lident : lident -> lname =
let name_of_ident_decl : ident_decl -> name_decl =
on_fst lname_of_lident
+let test_variance_ident =
+ let open Pcoq.Lookahead in
+ to_entry "test_variance_ident" begin
+ lk_kws ["=";"+";"*"] >> lk_ident
+ end
+
}
(* Gallina declarations *)
@@ -283,7 +290,7 @@ GRAMMAR EXTEND Gram
[ [ l = universe_name; ord = [ "<" -> { Univ.Lt } | "=" -> { Univ.Eq } | "<=" -> { Univ.Le } ];
r = universe_name -> { (l, ord, r) } ] ]
;
- univ_decl :
+ univ_decl:
[ [ "@{" ; l = LIST0 identref; ext = [ "+" -> { true } | -> { false } ];
cs = [ "|"; l' = LIST0 univ_constraint SEP ",";
ext = [ "+" -> { true } | -> { false } ]; "}" -> { (l',ext) }
@@ -296,10 +303,40 @@ GRAMMAR EXTEND Gram
univdecl_extensible_constraints = snd cs } }
] ]
;
+ variance:
+ [ [ "+" -> { Univ.Variance.Covariant }
+ | "=" -> { Univ.Variance.Invariant }
+ | "*" -> { Univ.Variance.Irrelevant }
+ ] ]
+ ;
+ variance_identref:
+ [ [ id = identref -> { (id, None) }
+ | test_variance_ident; v = variance; id = identref -> { (id, Some v) }
+ (* We need this test to help the parser avoid the conflict
+ between "+" before ident (covariance) and trailing "+" (extra univs allowed) *)
+ ] ]
+ ;
+ cumul_univ_decl:
+ [ [ "@{" ; l = LIST0 variance_identref; ext = [ "+" -> { true } | -> { false } ];
+ cs = [ "|"; l' = LIST0 univ_constraint SEP ",";
+ ext = [ "+" -> { true } | -> { false } ]; "}" -> { (l',ext) }
+ | ext = [ "}" -> { true } | bar_cbrace -> { false } ] -> { ([], ext) } ]
+ ->
+ { let open UState in
+ { univdecl_instance = l;
+ univdecl_extensible_instance = ext;
+ univdecl_constraints = fst cs;
+ univdecl_extensible_constraints = snd cs } }
+ ] ]
+ ;
ident_decl:
[ [ i = identref; l = OPT univ_decl -> { (i, l) }
] ]
;
+ cumul_ident_decl:
+ [ [ i = identref; l = OPT cumul_univ_decl -> { (i, l) }
+ ] ]
+ ;
finite_token:
[ [ IDENT "Inductive" -> { Inductive_kw }
| IDENT "CoInductive" -> { CoInductive }
@@ -345,7 +382,7 @@ GRAMMAR EXTEND Gram
| -> { RecordDecl (None, []) } ] ]
;
inductive_definition:
- [ [ oc = opt_coercion; id = ident_decl; indpar = binders;
+ [ [ oc = opt_coercion; id = cumul_ident_decl; indpar = binders;
extrapar = OPT [ "|"; p = binders -> { p } ];
c = OPT [ ":"; c = lconstr -> { c } ];
lc=opt_constructors_or_fields; ntn = decl_notations ->
diff --git a/vernac/himsg.ml b/vernac/himsg.ml
index bef9e29ac2..9d86ea90e6 100644
--- a/vernac/himsg.ml
+++ b/vernac/himsg.ml
@@ -744,6 +744,11 @@ let explain_bad_relevance env =
let explain_bad_invert env =
strbrk "Bad case inversion (maybe a bugged tactic)."
+let explain_bad_variance env sigma ~lev ~expected ~actual =
+ str "Incorrect variance for universe " ++ Termops.pr_evd_level sigma lev ++
+ str": expected " ++ Univ.Variance.pr expected ++
+ str " but cannot be less restrictive than " ++ Univ.Variance.pr actual ++ str "."
+
let explain_type_error env sigma err =
let env = make_all_name_different env sigma in
match err with
@@ -788,6 +793,7 @@ let explain_type_error env sigma err =
| DisallowedSProp -> explain_disallowed_sprop ()
| BadRelevance -> explain_bad_relevance env
| BadInvert -> explain_bad_invert env
+ | BadVariance {lev;expected;actual} -> explain_bad_variance env sigma ~lev ~expected ~actual
let pr_position (cl,pos) =
let clpos = match cl with
diff --git a/vernac/ppvernac.ml b/vernac/ppvernac.ml
index 0e660bf20c..4cee4f7a47 100644
--- a/vernac/ppvernac.ml
+++ b/vernac/ppvernac.ml
@@ -68,10 +68,18 @@ let pr_univ_name_list = function
| Some l ->
str "@{" ++ prlist_with_sep spc pr_lname l ++ str"}"
+let pr_variance_lident (lid,v) =
+ let v = Option.cata Univ.Variance.pr (mt()) v in
+ v ++ pr_lident lid
+
let pr_univdecl_instance l extensible =
prlist_with_sep spc pr_lident l ++
(if extensible then str"+" else mt ())
+let pr_cumul_univdecl_instance l extensible =
+ prlist_with_sep spc pr_variance_lident l ++
+ (if extensible then str"+" else mt ())
+
let pr_univdecl_constraints l extensible =
if List.is_empty l && extensible then mt ()
else str"|" ++ spc () ++ prlist_with_sep (fun () -> str",") pr_uconstraint l ++
@@ -85,9 +93,20 @@ let pr_universe_decl l =
str"@{" ++ pr_univdecl_instance l.univdecl_instance l.univdecl_extensible_instance ++
pr_univdecl_constraints l.univdecl_constraints l.univdecl_extensible_constraints ++ str "}"
+let pr_cumul_univ_decl l =
+ let open UState in
+ match l with
+ | None -> mt ()
+ | Some l ->
+ str"@{" ++ pr_cumul_univdecl_instance l.univdecl_instance l.univdecl_extensible_instance ++
+ pr_univdecl_constraints l.univdecl_constraints l.univdecl_extensible_constraints ++ str "}"
+
let pr_ident_decl (lid, l) =
pr_lident lid ++ pr_universe_decl l
+let pr_cumul_ident_decl (lid, l) =
+ pr_lident lid ++ pr_cumul_univ_decl l
+
let string_of_fqid fqid =
String.concat "." (List.map Id.to_string fqid)
@@ -848,7 +867,7 @@ let pr_vernac_expr v =
let pr_oneind key (((coe,iddecl),(indupar,indpar),s,lc),ntn) =
hov 0 (
str key ++ spc() ++
- (if coe then str"> " else str"") ++ pr_ident_decl iddecl ++
+ (if coe then str"> " else str"") ++ pr_cumul_ident_decl iddecl ++
pr_and_type_binders_arg indupar ++
pr_opt (fun p -> str "|" ++ spc() ++ pr_and_type_binders_arg p) indpar ++
pr_opt (fun s -> str":" ++ spc() ++ pr_lconstr_expr s) s ++
@@ -1312,20 +1331,10 @@ let pr_control_flag (p : control_flag) =
let pr_vernac_control flags = Pp.prlist pr_control_flag flags
-let rec pr_vernac_flag (k, v) =
- let k = keyword k in
- let open Attributes in
- match v with
- | VernacFlagEmpty -> k
- | VernacFlagLeaf v -> k ++ str " = " ++ qs v
- | VernacFlagList m -> k ++ str "( " ++ pr_vernac_flags m ++ str " )"
-and pr_vernac_flags m =
- prlist_with_sep (fun () -> str ", ") pr_vernac_flag m
-
let pr_vernac_attributes =
function
| [] -> mt ()
- | flags -> str "#[" ++ pr_vernac_flags flags ++ str "]" ++ cut ()
+ | flags -> str "#[" ++ prlist_with_sep pr_comma Attributes.pr_vernac_flag flags ++ str "]" ++ cut ()
let pr_vernac ({v = {control; attrs; expr}} as v) =
tag_vernac v
diff --git a/vernac/record.ml b/vernac/record.ml
index 891d7fcebe..583164a524 100644
--- a/vernac/record.ml
+++ b/vernac/record.ml
@@ -190,11 +190,12 @@ type tc_result =
(* Part relative to closing the definitions *)
* UnivNames.universe_binders
* Entries.universes_entry
+ * Entries.variance_entry
* Constr.rel_context
* DataR.t list
(* ps = parameter list *)
-let typecheck_params_and_fields def poly pl ps (records : DataI.t list) : tc_result =
+let typecheck_params_and_fields def poly udecl ps (records : DataI.t list) : tc_result =
let env0 = Global.env () in
(* Special case elaboration for template-polymorphic inductives,
lower bound on introduced universes is Prop so that we do not miss
@@ -202,7 +203,7 @@ let typecheck_params_and_fields def poly pl ps (records : DataI.t list) : tc_res
let is_template =
List.exists (fun { DataI.arity; _} -> Option.cata check_anonymous_type true arity) records in
let env0 = if not poly && is_template then Environ.set_universes_lbound env0 UGraph.Bound.Prop else env0 in
- let sigma, decl = Constrintern.interp_univ_decl_opt env0 pl in
+ let sigma, decl, variances = Constrintern.interp_cumul_univ_decl_opt env0 udecl in
let () = List.iter check_parameters_must_be_named ps in
let sigma, (impls_env, ((env1,newps), imps)) =
Constrintern.interp_context_evars ~program_mode:false env0 sigma ps in
@@ -256,7 +257,7 @@ let typecheck_params_and_fields def poly pl ps (records : DataI.t list) : tc_res
let ubinders = Evd.universe_binders sigma in
let ce t = Pretyping.check_evars env0 sigma (EConstr.of_constr t) in
let () = List.iter (iter_constr ce) (List.rev newps) in
- template, imps, ubinders, univs, newps, ans
+ template, imps, ubinders, univs, variances, newps, ans
type record_error =
| MissingProj of Id.t * Id.t list
@@ -525,7 +526,7 @@ let declare_structure_entry o =
- prepares and declares the corresponding record projections, mainly taken care of by
[declare_projections]
*)
-let declare_structure ~cumulative finite ~ubind ~univs paramimpls params template ?(kind=Decls.StructureComponent) ?name (record_data : Data.t list) =
+let declare_structure ~cumulative finite ~ubind ~univs ~variances paramimpls params template ?(kind=Decls.StructureComponent) ?name (record_data : Data.t list) =
let nparams = List.length params in
let poly, ctx =
match univs with
@@ -568,7 +569,7 @@ let declare_structure ~cumulative finite ~ubind ~univs paramimpls params templat
mind_entry_private = None;
mind_entry_universes = univs;
mind_entry_template = template;
- mind_entry_cumulative = poly && cumulative;
+ mind_entry_variance = ComInductive.variance_of_entry ~cumulative ~variances univs;
}
in
let impls = List.map (fun _ -> paramimpls, []) record_data in
@@ -633,7 +634,8 @@ let build_class_constant ~univs ~rdata field implfs params paramimpls coers bind
} in
[cref, [m]]
-let build_record_constant ~rdata ~ubind ~univs ~cumulative ~template fields params paramimpls coers id idbuild binder_name =
+let build_record_constant ~rdata ~ubind ~univs ~variances ~cumulative ~template
+ fields params paramimpls coers id idbuild binder_name =
let record_data =
{ Data.id
; idbuild
@@ -641,7 +643,7 @@ let build_record_constant ~rdata ~ubind ~univs ~cumulative ~template fields para
; coers = List.map (fun _ -> { pf_subclass = false ; pf_canonical = true }) fields
; rdata
} in
- let inds = declare_structure ~cumulative Declarations.BiFinite ~ubind ~univs paramimpls
+ let inds = declare_structure ~cumulative Declarations.BiFinite ~ubind ~univs ~variances paramimpls
params template ~kind:Decls.Method ~name:[|binder_name|] [record_data]
in
let map ind =
@@ -677,7 +679,7 @@ let build_record_constant ~rdata ~ubind ~univs ~cumulative ~template fields para
2. declare the class, using the information from 1. in the form of [Classes.typeclass]
*)
-let declare_class def ~cumulative ~ubind ~univs id idbuild paramimpls params
+let declare_class def ~cumulative ~ubind ~univs ~variances id idbuild paramimpls params
rdata template ?(kind=Decls.StructureComponent) coers =
let implfs =
(* Make the class implicit in the projections, and the params if applicable. *)
@@ -694,7 +696,8 @@ let declare_class def ~cumulative ~ubind ~univs id idbuild paramimpls params
let binder = {binder with binder_name=Name binder_name} in
build_class_constant ~rdata ~univs field implfs params paramimpls coers binder id proj_name
| _ ->
- build_record_constant ~rdata ~ubind ~univs ~cumulative ~template fields params paramimpls coers id idbuild binder_name
+ build_record_constant ~rdata ~ubind ~univs ~variances ~cumulative ~template
+ fields params paramimpls coers id idbuild binder_name
in
let univs, params, fields =
match univs with
@@ -852,7 +855,8 @@ let class_struture ~cumulative ~template ~ubind ~impargs ~univs ~params def reco
declare_class def ~cumulative ~ubind ~univs name.CAst.v idbuild
impargs params rdata template coers
-let regular_structure ~cumulative ~template ~ubind ~impargs ~univs ~params ~finite records data =
+let regular_structure ~cumulative ~template ~ubind ~impargs ~univs ~variances ~params ~finite
+ records data =
let adjust_impls impls = impargs @ [CAst.make None] @ impls in
let data = List.map (fun ({ DataR.implfs; _ } as d) -> { d with DataR.implfs = List.map adjust_impls implfs }) data in
(* let map (min_univ, arity, fieldimpls, fields) { Ast.name; is_coercion; cfs; idbuild; _ } = *)
@@ -866,30 +870,36 @@ let regular_structure ~cumulative ~template ~ubind ~impargs ~univs ~params ~fini
{ Data.id = name.CAst.v; idbuild; rdata; is_coercion; coers }
in
let data = List.map2 map data records in
- let inds = declare_structure ~cumulative finite ~ubind ~univs impargs params template data in
+ let inds = declare_structure ~cumulative finite ~ubind ~univs ~variances
+ impargs params template data
+ in
List.map (fun ind -> GlobRef.IndRef ind) inds
(** [fs] corresponds to fields and [ps] to parameters; [coers] is a
list telling if the corresponding fields must me declared as coercions
or subinstances. *)
-let definition_structure udecl kind ~template ~cumulative ~poly finite (records : Ast.t list) =
+let definition_structure udecl kind ~template ~cumulative ~poly
+ finite (records : Ast.t list) : GlobRef.t list =
let () = check_unique_names records in
let () = check_priorities kind records in
let ps, data = extract_record_data records in
- let auto_template, impargs, ubind, univs, params, data =
+ let auto_template, impargs, ubind, univs, variances, params, data =
(* In theory we should be able to use
[Notation.with_notation_protection], due to the call to
Metasyntax.set_notation_for_interpretation, however something
is messing state beyond that.
*)
Vernacstate.System.protect (fun () ->
- typecheck_params_and_fields (kind = Class true) poly udecl ps data) () in
+ typecheck_params_and_fields (kind = Class true) poly udecl ps data) ()
+ in
let template = template, auto_template in
match kind with
| Class def ->
- class_struture ~template ~ubind ~impargs ~cumulative ~params ~univs def records data
+ class_struture ~template ~ubind ~impargs ~cumulative ~params ~univs ~variances
+ def records data
| Inductive_kw | CoInductive | Variant | Record | Structure ->
- regular_structure ~cumulative ~template ~ubind ~impargs ~univs ~params ~finite records data
+ regular_structure ~cumulative ~template ~ubind ~impargs ~univs ~variances ~params ~finite
+ records data
module Internal = struct
type nonrec projection_flags = projection_flags = {
diff --git a/vernac/record.mli b/vernac/record.mli
index ffcae2975e..7a40af048c 100644
--- a/vernac/record.mli
+++ b/vernac/record.mli
@@ -24,7 +24,7 @@ module Ast : sig
end
val definition_structure
- : universe_decl_expr option
+ : cumul_univ_decl_expr option
-> inductive_kind
-> template:bool option
-> cumulative:bool
diff --git a/vernac/vernacentries.ml b/vernac/vernacentries.ml
index 4e52af7959..0f63dfe5ce 100644
--- a/vernac/vernacentries.ml
+++ b/vernac/vernacentries.ml
@@ -674,13 +674,19 @@ let is_polymorphic_inductive_cumulativity =
let polymorphic_cumulative =
let error_poly_context () =
user_err
- Pp.(str "The cumulative and noncumulative attributes can only be used in a polymorphic context.");
+ Pp.(str "The cumulative attribute can only be used in a polymorphic context.");
in
let open Attributes in
let open Notations in
+ (* EJGA: this seems redudant with code in attributes.ml *)
qualify_attribute "universes"
- (bool_attribute ~name:"Polymorphism" ~on:"polymorphic" ~off:"monomorphic"
- ++ bool_attribute ~name:"Cumulativity" ~on:"cumulative" ~off:"noncumulative")
+ (deprecated_bool_attribute
+ ~name:"Polymorphism"
+ ~on:"polymorphic" ~off:"monomorphic"
+ ++
+ deprecated_bool_attribute
+ ~name:"Cumulativity"
+ ~on:"cumulative" ~off:"noncumulative")
>>= function
| Some poly, Some cum ->
(* Case of Polymorphic|Monomorphic Cumulative|NonCumulative Inductive
diff --git a/vernac/vernacexpr.ml b/vernac/vernacexpr.ml
index 6a9a74144f..defb0691c0 100644
--- a/vernac/vernacexpr.ml
+++ b/vernac/vernacexpr.ml
@@ -189,8 +189,9 @@ type inductive_params_expr = local_binder_expr list * local_binder_expr list opt
(** If the option is nonempty the "|" marker was used *)
type inductive_expr =
- ident_decl with_coercion * inductive_params_expr * constr_expr option *
- constructor_list_or_record_decl_expr
+ cumul_ident_decl with_coercion
+ * inductive_params_expr * constr_expr option
+ * constructor_list_or_record_decl_expr
type one_inductive_expr =
lident * inductive_params_expr * constr_expr option * constructor_expr list