aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.common4
-rw-r--r--coqpp/coqpp_main.ml2
-rw-r--r--dev/ci/user-overlays/12218-proux01-numeral-notations-non-inductive.sh18
-rw-r--r--dev/doc/shield-icon.pngbin2512 -> 8582 bytes
-rw-r--r--doc/changelog/01-kernel/12738-fix-sr-cumul-inds.rst5
-rw-r--r--doc/changelog/02-specification-language/13183-using-att.rst6
-rw-r--r--doc/changelog/03-notations/12099-master+constraining-terms-occurring-also-as-pattern-in-notations.rst4
-rw-r--r--doc/changelog/03-notations/12218-numeral-notations-non-inductive.rst19
-rw-r--r--doc/changelog/03-notations/12946-master+fix12908-part1-collision-lonely-notation-printing.rst6
-rw-r--r--doc/changelog/03-notations/13026-master+fix-printing-custom-no-level-8.2.rst7
-rw-r--r--doc/changelog/03-notations/13067-master+fix-display-parentheses-default-coqide.rst5
-rw-r--r--doc/changelog/03-notations/13092-master+fix-13078-no-binder-in-pattern-notation.rst5
-rw-r--r--doc/changelog/04-tactics/12816-master+fix12787-K-redex-injection-anomaly.rst6
-rw-r--r--doc/changelog/04-tactics/12847-master+inversion-works-with-eq-in-type.rst6
-rw-r--r--doc/changelog/05-tactic-language/13232-ltac2-if-then-else.rst5
-rw-r--r--doc/changelog/06-ssreflect/12857-changelog-for-12857.rst8
-rw-r--r--doc/changelog/08-tools/12754-master+fix-coqdoc-index-escaping.rst6
-rw-r--r--doc/changelog/08-tools/12772-fix-details.rst5
-rw-r--r--doc/changelog/08-tools/13063-fix-no-output-sync-make-file.rst6
-rw-r--r--doc/changelog/09-coqide/13145-master+coqide-printing-goal-names-support.rst4
-rw-r--r--doc/changelog/11-infrastructure-and-dependencies/12864-fix-approve-output.rst5
-rw-r--r--doc/changelog/11-infrastructure-and-dependencies/12972-ocaml+4_11.rst4
-rw-r--r--doc/changelog/11-infrastructure-and-dependencies/13011-sphinx-3.rst5
-rw-r--r--doc/sphinx/addendum/micromega.rst2
-rw-r--r--doc/sphinx/addendum/nsatz.rst2
-rw-r--r--doc/sphinx/addendum/omega.rst2
-rw-r--r--doc/sphinx/addendum/ring.rst4
-rw-r--r--doc/sphinx/changes.rst113
-rw-r--r--doc/sphinx/language/core/basic.rst2
-rw-r--r--doc/sphinx/language/core/coinductive.rst4
-rw-r--r--doc/sphinx/language/core/definitions.rst6
-rw-r--r--doc/sphinx/language/core/inductive.rst2
-rw-r--r--doc/sphinx/language/extensions/arguments-command.rst1
-rw-r--r--doc/sphinx/proof-engine/ltac2.rst16
-rw-r--r--doc/sphinx/proof-engine/proof-handling.rst902
-rw-r--r--doc/sphinx/proof-engine/tactics.rst1937
-rw-r--r--doc/sphinx/proof-engine/vernacular-commands.rst10
-rw-r--r--doc/sphinx/proofs/automatic-tactics/auto.rst672
-rw-r--r--doc/sphinx/proofs/automatic-tactics/index.rst10
-rw-r--r--doc/sphinx/proofs/automatic-tactics/logic.rst294
-rw-r--r--doc/sphinx/proofs/writing-proofs/index.rst9
-rw-r--r--doc/sphinx/proofs/writing-proofs/proof-mode.rst1037
-rw-r--r--doc/sphinx/proofs/writing-proofs/rewriting.rst857
-rw-r--r--doc/sphinx/user-extensions/syntax-extensions.rst386
-rw-r--r--doc/stdlib/hidden-files1
-rw-r--r--doc/stdlib/index-list.html.template4
-rw-r--r--doc/tools/docgram/common.edit_mlg20
-rw-r--r--doc/tools/docgram/doc_grammar.ml3
-rw-r--r--doc/tools/docgram/fullGrammar32
-rw-r--r--doc/tools/docgram/orderedGrammar20
-rw-r--r--engine/eConstr.ml3
-rw-r--r--ide/coqide/coq.ml4
-rw-r--r--ide/coqide/coqide_ui.ml1
-rw-r--r--ide/coqide/idetop.ml4
-rw-r--r--ide/coqide/wg_ProofView.ml28
-rw-r--r--interp/constrexpr.ml2
-rw-r--r--interp/constrexpr_ops.ml6
-rw-r--r--interp/constrextern.ml10
-rw-r--r--interp/constrintern.ml227
-rw-r--r--interp/implicit_quantifiers.ml4
-rw-r--r--interp/notation.ml294
-rw-r--r--interp/notation.mli44
-rw-r--r--interp/notation_ops.ml17
-rw-r--r--interp/numTok.mli30
-rw-r--r--interp/smartlocate.ml38
-rw-r--r--interp/smartlocate.mli12
-rw-r--r--interp/syntax_def.ml6
-rw-r--r--interp/syntax_def.mli2
-rw-r--r--kernel/cClosure.ml21
-rw-r--r--kernel/nativelib.ml21
-rw-r--r--kernel/reduction.ml39
-rw-r--r--kernel/vars.ml3
-rw-r--r--lib/control.ml10
-rw-r--r--parsing/cLexer.ml8
-rw-r--r--parsing/cLexer.mli4
-rw-r--r--parsing/g_constr.mlg16
-rw-r--r--plugins/ltac/g_ltac.mlg2
-rw-r--r--plugins/ltac/g_tactic.mlg6
-rw-r--r--plugins/ltac/taccoerce.ml9
-rw-r--r--plugins/ltac/tacentries.ml51
-rw-r--r--plugins/ltac/tacentries.mli3
-rw-r--r--plugins/ltac/tacintern.ml32
-rw-r--r--plugins/ltac/tacintern.mli3
-rw-r--r--plugins/ltac/tacinterp.ml21
-rw-r--r--plugins/ssr/ssrparser.mlg2
-rw-r--r--plugins/ssr/ssrvernac.mlg16
-rw-r--r--plugins/ssr/ssrvernac.mli2
-rw-r--r--plugins/ssrsearch/g_search.mlg4
-rw-r--r--plugins/syntax/dune24
-rw-r--r--plugins/syntax/g_number_string.mlg110
-rw-r--r--plugins/syntax/g_numeral.mlg51
-rw-r--r--plugins/syntax/g_string.mlg25
-rw-r--r--plugins/syntax/int63_syntax.ml3
-rw-r--r--plugins/syntax/number.ml505
-rw-r--r--plugins/syntax/number.mli31
-rw-r--r--plugins/syntax/number_string_notation_plugin.mlpack3
-rw-r--r--plugins/syntax/numeral.ml217
-rw-r--r--plugins/syntax/numeral.mli19
-rw-r--r--plugins/syntax/numeral_notation_plugin.mlpack2
-rw-r--r--plugins/syntax/r_syntax.ml214
-rw-r--r--plugins/syntax/r_syntax.mli9
-rw-r--r--plugins/syntax/r_syntax_plugin.mlpack1
-rw-r--r--plugins/syntax/string_notation.ml27
-rw-r--r--plugins/syntax/string_notation.mli4
-rw-r--r--plugins/syntax/string_notation_plugin.mlpack2
-rw-r--r--pretyping/glob_ops.ml1
-rw-r--r--pretyping/unification.ml13
-rw-r--r--printing/ppconstr.ml17
-rw-r--r--printing/printer.ml2
-rw-r--r--printing/printer.mli3
-rw-r--r--stm/stm.ml5
-rw-r--r--test-suite/bugs/closed/bug_13078.v10
-rw-r--r--test-suite/bugs/closed/bug_13131.v6
-rw-r--r--test-suite/bugs/closed/bug_13162.v7
-rw-r--r--test-suite/bugs/closed/bug_13178.v3
-rw-r--r--test-suite/bugs/closed/bug_13276.v9
-rw-r--r--test-suite/bugs/opened/bug_3395.v232
-rw-r--r--test-suite/output/ErrorLocation_13241_1.out3
-rw-r--r--test-suite/output/ErrorLocation_13241_1.v5
-rw-r--r--test-suite/output/ErrorLocation_13241_2.out3
-rw-r--r--test-suite/output/ErrorLocation_13241_2.v5
-rw-r--r--test-suite/output/Notations4.out54
-rw-r--r--test-suite/output/Notations4.v105
-rw-r--r--test-suite/output/NumberNotations.out291
-rw-r--r--test-suite/output/NumberNotations.v579
-rw-r--r--test-suite/output/QArithSyntax.out90
-rw-r--r--test-suite/output/QArithSyntax.v34
-rw-r--r--test-suite/output/RealSyntax.out101
-rw-r--r--test-suite/output/RealSyntax.v44
-rw-r--r--test-suite/output/Search.out104
-rw-r--r--test-suite/output/SearchHead.out6
-rw-r--r--test-suite/output/SearchPattern.out8
-rw-r--r--test-suite/output/Search_bug13298.out1
-rw-r--r--test-suite/output/Search_bug13298.v3
-rw-r--r--test-suite/output/StringSyntax.out22
-rw-r--r--test-suite/output/StringSyntax.v65
-rw-r--r--test-suite/output/ZSyntax.v2
-rw-r--r--test-suite/output/bug_12159.v6
-rw-r--r--test-suite/output/bug_13004.out4
-rw-r--r--test-suite/output/bug_13238.out8
-rw-r--r--test-suite/output/prim_array.out9
-rw-r--r--test-suite/output/prim_array.v10
-rw-r--r--test-suite/success/NumberNotationsNoLocal.v (renamed from test-suite/success/NumeralNotationsNoLocal.v)2
-rw-r--r--test-suite/success/definition_using.v68
-rw-r--r--test-suite/success/sprop_uip.v27
-rw-r--r--theories/Init/Byte.v2
-rw-r--r--theories/Init/Decimal.v6
-rw-r--r--theories/Init/Hexadecimal.v38
-rw-r--r--theories/Init/Nat.v20
-rw-r--r--theories/Init/Number.v45
-rw-r--r--theories/Init/Numeral.v67
-rw-r--r--theories/Init/Prelude.v15
-rw-r--r--theories/NArith/BinNatDef.v16
-rw-r--r--theories/Numbers/AltBinNotations.v2
-rw-r--r--theories/Numbers/DecimalFacts.v607
-rw-r--r--theories/Numbers/DecimalN.v4
-rw-r--r--theories/Numbers/DecimalNat.v4
-rw-r--r--theories/Numbers/DecimalQ.v894
-rw-r--r--theories/Numbers/DecimalR.v312
-rw-r--r--theories/Numbers/DecimalZ.v27
-rw-r--r--theories/Numbers/HexadecimalFacts.v627
-rw-r--r--theories/Numbers/HexadecimalN.v4
-rw-r--r--theories/Numbers/HexadecimalNat.v4
-rw-r--r--theories/Numbers/HexadecimalQ.v880
-rw-r--r--theories/Numbers/HexadecimalR.v302
-rw-r--r--theories/Numbers/HexadecimalZ.v27
-rw-r--r--theories/PArith/BinPosDef.v16
-rw-r--r--theories/QArith/QArith_base.v285
-rw-r--r--theories/QArith/Qreals.v2
-rw-r--r--theories/Reals/Rdefinitions.v167
-rw-r--r--theories/Reals/Rregisternames.v4
-rw-r--r--theories/ZArith/BinIntDef.v14
-rw-r--r--theories/dune4
-rw-r--r--user-contrib/Ltac2/g_ltac2.mlg2
-rw-r--r--user-contrib/Ltac2/tac2expr.mli1
-rw-r--r--user-contrib/Ltac2/tac2intern.ml20
-rw-r--r--vernac/attributes.ml8
-rw-r--r--vernac/attributes.mli1
-rw-r--r--vernac/comDefinition.ml18
-rw-r--r--vernac/comDefinition.mli2
-rw-r--r--vernac/comFixpoint.ml23
-rw-r--r--vernac/comFixpoint.mli4
-rw-r--r--vernac/comProgramFixpoint.ml30
-rw-r--r--vernac/comProgramFixpoint.mli2
-rw-r--r--vernac/declare.ml58
-rw-r--r--vernac/declare.mli8
-rw-r--r--vernac/egramcoq.ml4
-rw-r--r--vernac/g_vernac.mlg3
-rw-r--r--vernac/metasyntax.ml29
-rw-r--r--vernac/proof_using.ml26
-rw-r--r--vernac/proof_using.mli5
-rw-r--r--vernac/search.ml20
-rw-r--r--vernac/vernacentries.ml101
194 files changed, 9464 insertions, 6005 deletions
diff --git a/.gitignore b/.gitignore
index bdd692420f..aab1d1ede7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -155,6 +155,7 @@ kernel/byterun/coq_jumptbl.h
kernel/genOpcodeFiles.exe
kernel/vmopcodes.ml
kernel/uint63.ml
+kernel/float64.ml
ide/coqide/default.bindings
ide/coqide/default_bindings_src.exe
ide/coqide/index_urls.txt
diff --git a/Makefile.common b/Makefile.common
index a482b9b963..caf1821ce5 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -149,11 +149,9 @@ CCCMO:=plugins/cc/cc_plugin.cmo
BTAUTOCMO:=plugins/btauto/btauto_plugin.cmo
RTAUTOCMO:=plugins/rtauto/rtauto_plugin.cmo
SYNTAXCMO:=$(addprefix plugins/syntax/, \
- r_syntax_plugin.cmo \
int63_syntax_plugin.cmo \
float_syntax_plugin.cmo \
- numeral_notation_plugin.cmo \
- string_notation_plugin.cmo)
+ number_string_notation_plugin.cmo)
DERIVECMO:=plugins/derive/derive_plugin.cmo
LTACCMO:=plugins/ltac/ltac_plugin.cmo plugins/ltac/tauto_plugin.cmo
SSRMATCHINGCMO:=plugins/ssrmatching/ssrmatching_plugin.cmo
diff --git a/coqpp/coqpp_main.ml b/coqpp/coqpp_main.ml
index 83929bd030..8affe58824 100644
--- a/coqpp/coqpp_main.ml
+++ b/coqpp/coqpp_main.ml
@@ -454,7 +454,7 @@ struct
let terminal s =
let p =
- if s <> "" && s.[0] >= '0' && s.[0] <= '9' then "CLexer.terminal_numeral"
+ if s <> "" && s.[0] >= '0' && s.[0] <= '9' then "CLexer.terminal_number"
else "CLexer.terminal" in
let c = Printf.sprintf "Pcoq.Symbol.token (%s \"%s\")" p s in
SymbQuote c
diff --git a/dev/ci/user-overlays/12218-proux01-numeral-notations-non-inductive.sh b/dev/ci/user-overlays/12218-proux01-numeral-notations-non-inductive.sh
new file mode 100644
index 0000000000..d9b49ad0d1
--- /dev/null
+++ b/dev/ci/user-overlays/12218-proux01-numeral-notations-non-inductive.sh
@@ -0,0 +1,18 @@
+if [ "$CI_PULL_REQUEST" = "12218" ] || [ "$CI_BRANCH" = "numeral-notations-non-inductive" ]; then
+
+ stdlib2_CI_REF=numeral-notations-non-inductive
+ stdlib2_CI_GITURL=https://github.com/proux01/stdlib2
+
+ hott_CI_REF=numeral-notations-non-inductive
+ hott_CI_GITURL=https://github.com/proux01/HoTT
+
+ paramcoq_CI_REF=numeral-notations-non-inductive
+ paramcoq_CI_GITURL=https://github.com/proux01/paramcoq
+
+ quickchick_CI_REF=numeral-notations-non-inductive
+ quickchick_CI_GITURL=https://github.com/proux01/QuickChick
+
+ metacoq_CI_REF=numeral-notations-non-inductive
+ metacoq_CI_GITURL=https://github.com/proux01/metacoq
+
+fi
diff --git a/dev/doc/shield-icon.png b/dev/doc/shield-icon.png
index 629e51a819..f4a5b6ff5e 100644
--- a/dev/doc/shield-icon.png
+++ b/dev/doc/shield-icon.png
Binary files differ
diff --git a/doc/changelog/01-kernel/12738-fix-sr-cumul-inds.rst b/doc/changelog/01-kernel/12738-fix-sr-cumul-inds.rst
deleted file mode 100644
index 1bf62de3fd..0000000000
--- a/doc/changelog/01-kernel/12738-fix-sr-cumul-inds.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-- **Fixed:** Incompleteness of conversion checking on problems
- involving :ref:`eta-expansion` and :ref:`cumulative universe
- polymorphic inductive types <cumulative>` (`#12738
- <https://github.com/coq/coq/pull/12738>`_, fixes `#7015
- <https://github.com/coq/coq/issues/7015>`_, by Gaëtan Gilbert).
diff --git a/doc/changelog/02-specification-language/13183-using-att.rst b/doc/changelog/02-specification-language/13183-using-att.rst
new file mode 100644
index 0000000000..c380d932ed
--- /dev/null
+++ b/doc/changelog/02-specification-language/13183-using-att.rst
@@ -0,0 +1,6 @@
+- **Added:**
+ Definition and (Co)Fixpoint now support the :attr:`using` attribute.
+ It has the same effect as :cmd:`Proof using`, which is only available in
+ interactive mode.
+ (`#13183 <https://github.com/coq/coq/pull/13183>`_,
+ by Enrico Tassi).
diff --git a/doc/changelog/03-notations/12099-master+constraining-terms-occurring-also-as-pattern-in-notations.rst b/doc/changelog/03-notations/12099-master+constraining-terms-occurring-also-as-pattern-in-notations.rst
new file mode 100644
index 0000000000..e9b02aed6d
--- /dev/null
+++ b/doc/changelog/03-notations/12099-master+constraining-terms-occurring-also-as-pattern-in-notations.rst
@@ -0,0 +1,4 @@
+- **Changed:**
+ Improved support for notations/abbreviations with mixed terms and patterns (such as the forcing modality)
+ (`#12099 <https://github.com/coq/coq/pull/12099>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/12218-numeral-notations-non-inductive.rst b/doc/changelog/03-notations/12218-numeral-notations-non-inductive.rst
new file mode 100644
index 0000000000..5ea37e7494
--- /dev/null
+++ b/doc/changelog/03-notations/12218-numeral-notations-non-inductive.rst
@@ -0,0 +1,19 @@
+- **Deprecated**
+ ``Numeral.v`` is deprecated, please use ``Number.v`` instead.
+- **Changed**
+ Rational and real constants are parsed differently.
+ The exponent is now encoded separately from the fractional part
+ using ``Z.pow_pos``. This way, parsing large exponents can no longer
+ blow up and constants are printed in a form closer to the one they
+ were parsed (i.e., ``102e-2`` is reprinted as such and not ``1.02``).
+- **Removed**
+ OCaml parser and printer for real constants have been removed.
+ Real constants are now handled with proven Coq code.
+- **Added:**
+ :ref:`Number Notation <number-notations>` and :ref:`String Notation
+ <string-notations>` commands now
+ support parameterized inductive and non inductive types
+ (`#12218 <https://github.com/coq/coq/pull/12218>`_,
+ fixes `#12035 <https://github.com/coq/coq/issues/12035>`_,
+ by Pierre Roux, review by Jason Gross and Jim Fehrle for the
+ reference manual).
diff --git a/doc/changelog/03-notations/12946-master+fix12908-part1-collision-lonely-notation-printing.rst b/doc/changelog/03-notations/12946-master+fix12908-part1-collision-lonely-notation-printing.rst
deleted file mode 100644
index 95a9093272..0000000000
--- a/doc/changelog/03-notations/12946-master+fix12908-part1-collision-lonely-notation-printing.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-- **Fixed:**
- Undetected collision between a lonely notation and a notation in
- scope at printing time
- (`#12946 <https://github.com/coq/coq/pull/12946>`_,
- fixes the first part of `#12908 <https://github.com/coq/coq/issues/12908>`_,
- by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/13026-master+fix-printing-custom-no-level-8.2.rst b/doc/changelog/03-notations/13026-master+fix-printing-custom-no-level-8.2.rst
deleted file mode 100644
index 42b62eed75..0000000000
--- a/doc/changelog/03-notations/13026-master+fix-printing-custom-no-level-8.2.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-- **Fixed:**
- Fixing printing of notations in custom entries with
- variables not mentioning an explicit level
- (`#13026 <https://github.com/coq/coq/pull/13026>`_,
- fixes `#12775 <https://github.com/coq/coq/issues/12775>`_
- and `#13018 <https://github.com/coq/coq/issues/13018>`_,
- by Hugo Herbelin).
diff --git a/doc/changelog/03-notations/13067-master+fix-display-parentheses-default-coqide.rst b/doc/changelog/03-notations/13067-master+fix-display-parentheses-default-coqide.rst
deleted file mode 100644
index 50aa4a9052..0000000000
--- a/doc/changelog/03-notations/13067-master+fix-display-parentheses-default-coqide.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-- **Fixed:**
- Repairing option :g:`Display parentheses` in CoqIDE
- (`#12794 <https://github.com/coq/coq/pull/12794>`_ and `#13067 <https://github.com/coq/coq/pull/13067>`_,
- fixes `#12793 <https://github.com/coq/coq/issues/12793>`_,
- by Jean-Christophe Léchenet and Hugo Herbelin).
diff --git a/doc/changelog/03-notations/13092-master+fix-13078-no-binder-in-pattern-notation.rst b/doc/changelog/03-notations/13092-master+fix-13078-no-binder-in-pattern-notation.rst
new file mode 100644
index 0000000000..fb12c91729
--- /dev/null
+++ b/doc/changelog/03-notations/13092-master+fix-13078-no-binder-in-pattern-notation.rst
@@ -0,0 +1,5 @@
+- **Fixed:**
+ Preventing notations for constructors to involve binders
+ (`#13092 <https://github.com/coq/coq/pull/13092>`_,
+ fixes `#13078 <https://github.com/coq/coq/issues/13078>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/04-tactics/12816-master+fix12787-K-redex-injection-anomaly.rst b/doc/changelog/04-tactics/12816-master+fix12787-K-redex-injection-anomaly.rst
deleted file mode 100644
index 289d17167d..0000000000
--- a/doc/changelog/04-tactics/12816-master+fix12787-K-redex-injection-anomaly.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-- **Fixed:**
- Anomaly with :tacn:`injection` involving artificial
- dependencies disappearing by reduction
- (`#12816 <https://github.com/coq/coq/pull/12816>`_,
- fixes `#12787 <https://github.com/coq/coq/issues/12787>`_,
- by Hugo Herbelin).
diff --git a/doc/changelog/04-tactics/12847-master+inversion-works-with-eq-in-type.rst b/doc/changelog/04-tactics/12847-master+inversion-works-with-eq-in-type.rst
deleted file mode 100644
index b444a2f436..0000000000
--- a/doc/changelog/04-tactics/12847-master+inversion-works-with-eq-in-type.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-- **Added:**
- :tacn:`replace` and :tacn:`inversion` support registration of a
- :g:`core.identity`-like equality in :g:`Type`, such as HoTT's :g:`path`
- (`#12847 <https://github.com/coq/coq/pull/12847>`_,
- partially fixes `#12846 <https://github.com/coq/coq/issues/12846>`_,
- by Hugo Herbelin).
diff --git a/doc/changelog/05-tactic-language/13232-ltac2-if-then-else.rst b/doc/changelog/05-tactic-language/13232-ltac2-if-then-else.rst
new file mode 100644
index 0000000000..d105561a23
--- /dev/null
+++ b/doc/changelog/05-tactic-language/13232-ltac2-if-then-else.rst
@@ -0,0 +1,5 @@
+- **Added:**
+ An if-then-else syntax to Ltac2
+ (`#13232 <https://github.com/coq/coq/pull/13232>`_,
+ fixes `#10110 <https://github.com/coq/coq/issues/10110>`_,
+ by Pierre-Marie Pédrot).
diff --git a/doc/changelog/06-ssreflect/12857-changelog-for-12857.rst b/doc/changelog/06-ssreflect/12857-changelog-for-12857.rst
deleted file mode 100644
index 4350fd0238..0000000000
--- a/doc/changelog/06-ssreflect/12857-changelog-for-12857.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-- **Fixed:**
- Regression in error reporting after :tacn:`case <case (ssreflect)>`.
- A generic error message "Could not fill dependent hole in apply" was
- reported for any error following :tacn:`case <case (ssreflect)>` or
- :tacn:`elim <elim (ssreflect)>`
- (`#12857 <https://github.com/coq/coq/pull/12857>`_,
- fixes `#12837 <https://github.com/coq/coq/issues/12837>`_,
- by Enrico Tassi).
diff --git a/doc/changelog/08-tools/12754-master+fix-coqdoc-index-escaping.rst b/doc/changelog/08-tools/12754-master+fix-coqdoc-index-escaping.rst
deleted file mode 100644
index a05829b720..0000000000
--- a/doc/changelog/08-tools/12754-master+fix-coqdoc-index-escaping.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-- **Fixed:**
- Special symbols now escaped in the index produced by coqdoc,
- avoiding collision with the syntax of the output format
- (`#12754 <https://github.com/coq/coq/pull/12754>`_,
- fixes `#12752 <https://github.com/coq/coq/issues/12752>`_,
- by Hugo Herbelin).
diff --git a/doc/changelog/08-tools/12772-fix-details.rst b/doc/changelog/08-tools/12772-fix-details.rst
deleted file mode 100644
index 67ee061285..0000000000
--- a/doc/changelog/08-tools/12772-fix-details.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-- **Fixed:**
- The `details` environment added in the 8.12 release can now be used
- as advertised in the reference manual
- (`#12772 <https://github.com/coq/coq/pull/12772>`_,
- by Thomas Letan).
diff --git a/doc/changelog/08-tools/13063-fix-no-output-sync-make-file.rst b/doc/changelog/08-tools/13063-fix-no-output-sync-make-file.rst
deleted file mode 100644
index 75b1e26248..0000000000
--- a/doc/changelog/08-tools/13063-fix-no-output-sync-make-file.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-- **Fixed:**
- Targets such as ``print-pretty-timed`` in ``coq_makefile``-made
- ``Makefile``\s no longer error in rare cases where ``--output-sync`` is not
- passed to make and the timing output gets interleaved in just the wrong way
- (`#13063 <https://github.com/coq/coq/pull/13063>`_, fixes `#13062
- <https://github.com/coq/coq/issues/13062>`_, by Jason Gross).
diff --git a/doc/changelog/09-coqide/13145-master+coqide-printing-goal-names-support.rst b/doc/changelog/09-coqide/13145-master+coqide-printing-goal-names-support.rst
new file mode 100644
index 0000000000..f7446cc5aa
--- /dev/null
+++ b/doc/changelog/09-coqide/13145-master+coqide-printing-goal-names-support.rst
@@ -0,0 +1,4 @@
+- **Added:**
+ Support for flag :flag:`Printing Goal Names` in View menu
+ (`#13145 <https://github.com/coq/coq/pull/13145>`_,
+ by Hugo Herbelin).
diff --git a/doc/changelog/11-infrastructure-and-dependencies/12864-fix-approve-output.rst b/doc/changelog/11-infrastructure-and-dependencies/12864-fix-approve-output.rst
deleted file mode 100644
index c754826e62..0000000000
--- a/doc/changelog/11-infrastructure-and-dependencies/12864-fix-approve-output.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-- **Fixed:**
- ``make approve-output`` in the test-suite now correctly handles
- ``output-coqtop`` and ``output-coqchk`` tests (`#12864
- <https://github.com/coq/coq/pull/12864>`_, fixes `#12863
- <https://github.com/coq/coq/issues/12863>`_, by Jason Gross).
diff --git a/doc/changelog/11-infrastructure-and-dependencies/12972-ocaml+4_11.rst b/doc/changelog/11-infrastructure-and-dependencies/12972-ocaml+4_11.rst
deleted file mode 100644
index 855aa360f1..0000000000
--- a/doc/changelog/11-infrastructure-and-dependencies/12972-ocaml+4_11.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-- **Added:**
- Coq is now tested against OCaml 4.11.1
- (`#12972 <https://github.com/coq/coq/pull/12972>`_,
- by Emilio Jesus Gallego Arias).
diff --git a/doc/changelog/11-infrastructure-and-dependencies/13011-sphinx-3.rst b/doc/changelog/11-infrastructure-and-dependencies/13011-sphinx-3.rst
deleted file mode 100644
index d17a2dff6b..0000000000
--- a/doc/changelog/11-infrastructure-and-dependencies/13011-sphinx-3.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-- **Fixed:**
- The reference manual can now build with Sphinx 3
- (`#13011 <https://github.com/coq/coq/pull/13011>`_,
- fixes `#12332 <https://github.com/coq/coq/issues/12332>`_,
- by Théo Zimmermann and Jim Fehrle).
diff --git a/doc/sphinx/addendum/micromega.rst b/doc/sphinx/addendum/micromega.rst
index 0942a82d6f..2c7b637a42 100644
--- a/doc/sphinx/addendum/micromega.rst
+++ b/doc/sphinx/addendum/micromega.rst
@@ -1,6 +1,6 @@
.. _micromega:
-Micromega: tactics for solving arithmetic goals over ordered rings
+Micromega: solvers for arithmetic goals over ordered rings
==================================================================
:Authors: Frédéric Besson and Evgeny Makarov
diff --git a/doc/sphinx/addendum/nsatz.rst b/doc/sphinx/addendum/nsatz.rst
index 85e0cb9536..7a2be3dcef 100644
--- a/doc/sphinx/addendum/nsatz.rst
+++ b/doc/sphinx/addendum/nsatz.rst
@@ -1,6 +1,6 @@
.. _nsatz_chapter:
-Nsatz: tactics for proving equalities in integral domains
+Nsatz: a solver for equalities in integral domains
===========================================================
:Author: Loïc Pottier
diff --git a/doc/sphinx/addendum/omega.rst b/doc/sphinx/addendum/omega.rst
index 35f087d47d..5c08bc44df 100644
--- a/doc/sphinx/addendum/omega.rst
+++ b/doc/sphinx/addendum/omega.rst
@@ -1,6 +1,6 @@
.. _omega_chapter:
-Omega: a solver for quantifier-free problems in Presburger Arithmetic
+Omega: a (deprecated) solver for arithmetic
=====================================================================
:Author: Pierre Crégut
diff --git a/doc/sphinx/addendum/ring.rst b/doc/sphinx/addendum/ring.rst
index da1a393b4a..027db9f47a 100644
--- a/doc/sphinx/addendum/ring.rst
+++ b/doc/sphinx/addendum/ring.rst
@@ -10,8 +10,8 @@
.. _theringandfieldtacticfamilies:
-The ring and field tactic families
-====================================
+ring and field: solvers for polynomial and rational equations
+=============================================================
:Author: Bruno Barras, Benjamin Grégoire, Assia Mahboubi, Laurent Théry [#f1]_
diff --git a/doc/sphinx/changes.rst b/doc/sphinx/changes.rst
index 5bc229954f..79f00a4a5a 100644
--- a/doc/sphinx/changes.rst
+++ b/doc/sphinx/changes.rst
@@ -1141,9 +1141,6 @@ Infrastructure and dependencies
Changes in 8.12.0
~~~~~~~~~~~~~~~~~~~~~
-.. contents::
- :local:
-
**Notations**
- **Added:**
@@ -1216,6 +1213,116 @@ Changes in 8.12.0
modified in the meantime (`#12583 <https://github.com/coq/coq/pull/12583>`_,
fixes `#12582 <https://github.com/coq/coq/issues/12582>`_, by Jason Gross).
+Changes in 8.12.1
+~~~~~~~~~~~~~~~~~~~~~
+
+**Kernel**
+
+- **Fixed:** Incompleteness of conversion checking on problems
+ involving :ref:`eta-expansion` and :ref:`cumulative universe
+ polymorphic inductive types <cumulative>` (`#12738
+ <https://github.com/coq/coq/pull/12738>`_, fixes `#7015
+ <https://github.com/coq/coq/issues/7015>`_, by Gaëtan Gilbert).
+
+**Notations**
+
+- **Fixed:**
+ Undetected collision between a lonely notation and a notation in
+ scope at printing time
+ (`#12946 <https://github.com/coq/coq/pull/12946>`_,
+ fixes the first part of `#12908 <https://github.com/coq/coq/issues/12908>`_,
+ by Hugo Herbelin).
+- **Fixed:**
+ Printing of notations in custom entries with
+ variables not mentioning an explicit level
+ (`#13026 <https://github.com/coq/coq/pull/13026>`_,
+ fixes `#12775 <https://github.com/coq/coq/issues/12775>`_
+ and `#13018 <https://github.com/coq/coq/issues/13018>`_,
+ by Hugo Herbelin).
+
+**Tactics**
+
+- **Added:**
+ :tacn:`replace` and :tacn:`inversion` support registration of a
+ :g:`core.identity`\-like equality in :g:`Type`, such as HoTT's :g:`path`
+ (`#12847 <https://github.com/coq/coq/pull/12847>`_,
+ partially fixes `#12846 <https://github.com/coq/coq/issues/12846>`_,
+ by Hugo Herbelin).
+- **Fixed:**
+ Anomaly with :tacn:`injection` involving artificial
+ dependencies disappearing by reduction
+ (`#12816 <https://github.com/coq/coq/pull/12816>`_,
+ fixes `#12787 <https://github.com/coq/coq/issues/12787>`_,
+ by Hugo Herbelin).
+
+**Tactic language**
+
+- **Fixed:**
+ Miscellaneous issues with locating tactic errors
+ (`#13247 <https://github.com/coq/coq/pull/13247>`_,
+ fixes `#12773 <https://github.com/coq/coq/issues/12773>`_
+ and `#12992 <https://github.com/coq/coq/issues/12992>`_,
+ by Hugo Herbelin).
+
+**SSReflect**
+
+- **Fixed:**
+ Regression in error reporting after :tacn:`case <case (ssreflect)>`.
+ A generic error message "Could not fill dependent hole in apply" was
+ reported for any error following :tacn:`case <case (ssreflect)>` or
+ :tacn:`elim <elim (ssreflect)>`
+ (`#12857 <https://github.com/coq/coq/pull/12857>`_,
+ fixes `#12837 <https://github.com/coq/coq/issues/12837>`_,
+ by Enrico Tassi).
+
+**Commands and options**
+
+- **Fixed:**
+ Failures of :cmd:`Search` in the presence of primitive projections
+ (`#13301 <https://github.com/coq/coq/pull/13301>`_,
+ fixes `#13298 <https://github.com/coq/coq/issues/13298>`_,
+ by Hugo Herbelin).
+
+**Tools**
+
+- **Fixed:**
+ Special symbols now escaped in the index produced by coqdoc,
+ avoiding collision with the syntax of the output format
+ (`#12754 <https://github.com/coq/coq/pull/12754>`_,
+ fixes `#12752 <https://github.com/coq/coq/issues/12752>`_,
+ by Hugo Herbelin).
+- **Fixed:**
+ The `details` environment added in the 8.12 release can now be used
+ as advertised in the reference manual
+ (`#12772 <https://github.com/coq/coq/pull/12772>`_,
+ by Thomas Letan).
+- **Fixed:**
+ Targets such as ``print-pretty-timed`` in ``coq_makefile``\-made
+ ``Makefile``\s no longer error in rare cases where ``--output-sync`` is not
+ passed to make and the timing output gets interleaved in just the wrong way
+ (`#13063 <https://github.com/coq/coq/pull/13063>`_, fixes `#13062
+ <https://github.com/coq/coq/issues/13062>`_, by Jason Gross).
+
+**CoqIDE**
+
+- **Fixed:**
+ View menu "Display parentheses"
+ (`#12794 <https://github.com/coq/coq/pull/12794>`_ and `#13067 <https://github.com/coq/coq/pull/13067>`_,
+ fixes `#12793 <https://github.com/coq/coq/issues/12793>`_,
+ by Jean-Christophe Léchenet and Hugo Herbelin).
+
+**Infrastructure and dependencies**
+
+- **Added:**
+ Coq is now tested against OCaml 4.11.1
+ (`#12972 <https://github.com/coq/coq/pull/12972>`_,
+ by Emilio Jesus Gallego Arias).
+- **Fixed:**
+ The reference manual can now build with Sphinx 3
+ (`#13011 <https://github.com/coq/coq/pull/13011>`_,
+ fixes `#12332 <https://github.com/coq/coq/issues/12332>`_,
+ by Théo Zimmermann and Jim Fehrle).
+
Version 8.11
------------
diff --git a/doc/sphinx/language/core/basic.rst b/doc/sphinx/language/core/basic.rst
index 29a2b40162..dfa2aaf8ff 100644
--- a/doc/sphinx/language/core/basic.rst
+++ b/doc/sphinx/language/core/basic.rst
@@ -113,7 +113,7 @@ Identifiers
Numbers
Numbers are sequences of digits with an optional fractional part
- and exponent, optionally preceded by a minus sign. Hexadecimal numerals
+ and exponent, optionally preceded by a minus sign. Hexadecimal numbers
start with ``0x`` or ``0X``. :n:`@bigint` are integers;
numbers without fractional nor exponent parts. :n:`@bignat` are non-negative
integers. Underscores embedded in the digits are ignored, for example
diff --git a/doc/sphinx/language/core/coinductive.rst b/doc/sphinx/language/core/coinductive.rst
index 0520afd600..2e5dff42ac 100644
--- a/doc/sphinx/language/core/coinductive.rst
+++ b/doc/sphinx/language/core/coinductive.rst
@@ -28,8 +28,8 @@ More information on co-inductive definitions can be found in
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(noncumulative)`, :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 8d67a3cf40..1681eee6e7 100644
--- a/doc/sphinx/language/core/definitions.rst
+++ b/doc/sphinx/language/core/definitions.rst
@@ -87,8 +87,8 @@ 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`) and
- :attr:`canonical` attributes.
+ :attr:`universes(monomorphic)`, :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.
This can be used to define a term incrementally, in particular by relying on the :tacn:`refine` tactic.
@@ -159,6 +159,8 @@ Chapter :ref:`Tactics`. The basic assertion command is:
correct at some time of the interactive development of a proof, use the
command :cmd:`Guarded`.
+ This command accepts the :attr:`using` attribute.
+
.. exn:: The term @term has type @type which should be Set, Prop or Type.
:undocumented:
diff --git a/doc/sphinx/language/core/inductive.rst b/doc/sphinx/language/core/inductive.rst
index ba0ec28f8b..1642482bb1 100644
--- a/doc/sphinx/language/core/inductive.rst
+++ b/doc/sphinx/language/core/inductive.rst
@@ -416,6 +416,8 @@ constructions.
In this case, the proof should be terminated with :cmd:`Defined` in order to define a constant
for which the computational behavior is relevant. See :ref:`proof-editing-mode`.
+ This command accepts the :attr:`using` attribute.
+
.. note::
+ Some fixpoints may have several arguments that fit as decreasing
diff --git a/doc/sphinx/language/extensions/arguments-command.rst b/doc/sphinx/language/extensions/arguments-command.rst
index 29877e1b32..f8c0e23696 100644
--- a/doc/sphinx/language/extensions/arguments-command.rst
+++ b/doc/sphinx/language/extensions/arguments-command.rst
@@ -86,6 +86,7 @@ Setting properties of a function's arguments
the parameter name used in the function definition). Unless `rename` is specified,
the list of :n:`@name`\s must be a prefix of the formal parameters, including all implicit
arguments. `_` can be used to skip over a formal parameter.
+ The construct :n:`@name {? % @scope }` declares :n:`@name` as non-implicit if `clear implicits` is specified or at least one other name is declared implicit in the same list of :n:`@name`\s.
:token:`scope` can be either a scope name or its delimiting key. See :ref:`binding_to_scope`.
`clear implicits`
diff --git a/doc/sphinx/proof-engine/ltac2.rst b/doc/sphinx/proof-engine/ltac2.rst
index 64fc1133f0..41f376c43d 100644
--- a/doc/sphinx/proof-engine/ltac2.rst
+++ b/doc/sphinx/proof-engine/ltac2.rst
@@ -38,7 +38,6 @@ Current limitations include:
- Printing functions are limited and awkward to use. Only a few data types are
printable.
- Deep pattern matching and matching on tuples don't work.
- - If statements on Ltac2 boolean values
- A convenient way to build terms with casts through the low-level API. Because the
cast type is opaque, building terms with casts currently requires an awkward construction like the
following, which also incurs extra overhead to repeat typechecking for each
@@ -345,12 +344,10 @@ Ltac2 Definitions
.. coqtop:: all
- Ltac2 mutable rec f b := match b with true => 0 | _ => f true end.
- Ltac2 Set f := fun b =>
- match b with true => 1 | _ => f true end.
+ Ltac2 mutable rec f b := if b then 0 else f true.
+ Ltac2 Set f := fun b => if b then 1 else f true.
Ltac2 Eval (f false).
- Ltac2 Set f as oldf := fun b =>
- match b with true => 2 | _ => oldf false end.
+ Ltac2 Set f as oldf := fun b => if b then 2 else oldf false.
Ltac2 Eval (f false).
In the definition, the `f` in the body is resolved statically
@@ -1149,6 +1146,13 @@ Match on values
| @tac2pat1 , {*, @tac2pat1 }
| @tac2pat1
+.. tacn:: if @ltac2_expr5__test then @ltac2_expr5__then else @ltac2_expr5__else
+ :name: if-then-else (Ltac2)
+
+ Equivalent to a :tacn:`match <match (Ltac2)>` on a boolean value. If the
+ :n:`@ltac2_expr5__test` evaluates to true, :n:`@ltac2_expr5__then`
+ is evaluated. Otherwise :n:`@ltac2_expr5__else` is evaluated.
+
.. note::
For now, deep pattern matching is not implemented.
diff --git a/doc/sphinx/proof-engine/proof-handling.rst b/doc/sphinx/proof-engine/proof-handling.rst
index b09d6146d8..7f5aacbfdb 100644
--- a/doc/sphinx/proof-engine/proof-handling.rst
+++ b/doc/sphinx/proof-engine/proof-handling.rst
@@ -1,901 +1,5 @@
-.. _proofhandling:
+:orphan:
--------------------
- Proof handling
--------------------
+.. raw:: html
-In |Coq|’s proof editing mode all top-level commands documented in
-Chapter :ref:`vernacularcommands` remain available and the user has access to specialized
-commands dealing with proof development pragmas documented in this
-section. They can also use some other specialized commands called
-*tactics*. They are the very tools allowing the user to deal with
-logical reasoning. They are documented in Chapter :ref:`tactics`.
-
-|Coq| user interfaces usually have a way of marking whether the user has
-switched to proof editing mode. For instance, in coqtop the prompt ``Coq <``   is changed into
-:n:`@ident <`   where :token:`ident` is the declared name of the theorem currently edited.
-
-At each stage of a proof development, one has a list of goals to
-prove. Initially, the list consists only in the theorem itself. After
-having applied some tactics, the list of goals contains the subgoals
-generated by the tactics.
-
-To each subgoal is associated a number of hypotheses called the *local context*
-of the goal. Initially, the local context contains the local variables and
-hypotheses of the current section (see Section :ref:`gallina-assumptions`) and
-the local variables and hypotheses of the theorem statement. It is enriched by
-the use of certain tactics (see e.g. :tacn:`intro`).
-
-When a proof is completed, the message ``Proof completed`` is displayed.
-One can then register this proof as a defined constant in the
-environment. Because there exists a correspondence between proofs and
-terms of λ-calculus, known as the *Curry-Howard isomorphism*
-:cite:`How80,Bar81,Gir89,H89`, |Coq| stores proofs as terms of |Cic|. Those
-terms are called *proof terms*.
-
-
-.. exn:: No focused proof.
-
- |Coq| raises this error message when one attempts to use a proof editing command
- out of the proof editing mode.
-
-.. _proof-editing-mode:
-
-Entering and leaving proof editing mode
----------------------------------------
-
-The proof editing mode is entered by asserting a statement, which typically is
-the assertion of a theorem using an assertion command like :cmd:`Theorem`. The
-list of assertion commands is given in :ref:`Assertions`. The command
-:cmd:`Goal` can also be used.
-
-.. cmd:: Goal @type
-
- This is intended for quick assertion of statements, without knowing in
- advance which name to give to the assertion, typically for quick
- testing of the provability of a statement. If the proof of the
- statement is eventually completed and validated, the statement is then
- bound to the name ``Unnamed_thm`` (or a variant of this name not already
- used for another statement).
-
-.. cmd:: Qed
-
- This command is available in interactive editing proof mode when the
- proof is completed. Then :cmd:`Qed` extracts a proof term from the proof
- script, switches back to |Coq| top-level and attaches the extracted
- proof term to the declared name of the original goal. The name is
- added to the environment as an opaque constant.
-
- .. exn:: Attempt to save an incomplete proof.
- :undocumented:
-
- .. note::
-
- Sometimes an error occurs when building the proof term, because
- tactics do not enforce completely the term construction
- constraints.
-
- The user should also be aware of the fact that since the
- proof term is completely rechecked at this point, one may have to wait
- a while when the proof is large. In some exceptional cases one may
- even incur a memory overflow.
-
-.. cmd:: Save @ident
- :name: Save
-
- Saves a completed proof with the name :token:`ident`, which
- overrides any name provided by the :cmd:`Theorem` command or
- its variants.
-
-.. cmd:: Defined {? @ident }
-
- Similar to :cmd:`Qed` and :cmd:`Save`, except the proof is made *transparent*, which means
- that its content can be explicitly used for type checking and that it can be
- unfolded in conversion tactics (see :ref:`performingcomputations`,
- :cmd:`Opaque`, :cmd:`Transparent`). If :token:`ident` is specified,
- the proof is defined with the given name, which overrides any name
- provided by the :cmd:`Theorem` command or its variants.
-
-.. cmd:: Admitted
-
- This command is available in interactive editing mode to give up
- the current proof and declare the initial goal as an axiom.
-
-.. cmd:: Abort {? {| All | @ident } }
-
- Cancels the current proof development, switching back to
- the previous proof development, or to the |Coq| toplevel if no other
- proof was being edited.
-
- :n:`@ident`
- Aborts editing the proof named :n:`@ident` for use when you have
- nested proofs. See also :flag:`Nested Proofs Allowed`.
-
- :n:`All`
- Aborts all current proofs.
-
- .. exn:: No focused proof (No proof-editing in progress).
- :undocumented:
-
-.. cmd:: Proof @term
- :name: Proof `term`
-
- This command applies in proof editing mode. It is equivalent to
- :n:`exact @term. Qed.`
- That is, you have to give the full proof in one gulp, as a
- proof term (see Section :ref:`applyingtheorems`).
-
- .. warning::
-
- Use of this command is discouraged. In particular, it
- doesn't work in Proof General because it must
- immediately follow the command that opened proof mode, but
- Proof General inserts :cmd:`Unset` :flag:`Silent` before it (see
- `Proof General issue #498
- <https://github.com/ProofGeneral/PG/issues/498>`_).
-
-.. cmd:: Proof
-
- Is a no-op which is useful to delimit the sequence of tactic commands
- which start a proof, after a :cmd:`Theorem` command. It is a good practice to
- use :cmd:`Proof` as an opening parenthesis, closed in the script with a
- closing :cmd:`Qed`.
-
- .. seealso:: :cmd:`Proof with`
-
-.. cmd:: Proof using @section_var_expr {? with @ltac_expr }
-
- .. insertprodn section_var_expr starred_ident_ref
-
- .. prodn::
- section_var_expr ::= {* @starred_ident_ref }
- | {? - } @section_var_expr50
- section_var_expr50 ::= @section_var_expr0 - @section_var_expr0
- | @section_var_expr0 + @section_var_expr0
- | @section_var_expr0
- section_var_expr0 ::= @starred_ident_ref
- | ( @section_var_expr ) {? * }
- starred_ident_ref ::= @ident {? * }
- | Type {? * }
- | All
-
- Opens proof editing mode, declaring the set of
- section variables (see :ref:`gallina-assumptions`) used by the proof.
- At :cmd:`Qed` time, the
- system verifies that the set of section variables used in
- the proof is a subset of the declared one.
-
- The set of declared variables is closed under type dependency. For
- example, if ``T`` is a variable and ``a`` is a variable of type
- ``T``, then the commands ``Proof using a`` and ``Proof using T a``
- are equivalent.
-
- The set of declared variables always includes the variables used by
- the statement. In other words ``Proof using e`` is equivalent to
- ``Proof using Type + e`` for any declaration expression ``e``.
-
- :n:`- @section_var_expr50`
- Use all section variables except those specified by :n:`@section_var_expr50`
-
- :n:`@section_var_expr0 + @section_var_expr0`
- Use section variables from the union of both collections.
- See :ref:`nameaset` to see how to form a named collection.
-
- :n:`@section_var_expr0 - @section_var_expr0`
- Use section variables which are in the first collection but not in the
- second one.
-
- :n:`{? * }`
- Use the transitive closure of the specified collection.
-
- :n:`Type`
- Use only section variables occurring in the statement. Specifying :n:`*`
- uses the forward transitive closure of all the section variables occurring
- in the statement. For example, if the variable ``H`` has type ``p < 5`` then
- ``H`` is in ``p*`` since ``p`` occurs in the type of ``H``.
-
- :n:`All`
- Use all section variables.
-
- .. seealso:: :ref:`tactics-implicit-automation`
-
-Proof using options
-```````````````````
-
-The following options modify the behavior of ``Proof using``.
-
-
-.. opt:: Default Proof Using "@section_var_expr"
- :name: Default Proof Using
-
- Use :n:`@section_var_expr` as the default ``Proof using`` value. E.g. ``Set Default
- Proof Using "a b"`` will complete all ``Proof`` commands not followed by a
- ``using`` part with ``using a b``.
-
-
-.. flag:: Suggest Proof Using
-
- When :cmd:`Qed` is performed, suggest a ``using`` annotation if the user did not
- provide one.
-
-.. _`nameaset`:
-
-Name a set of section hypotheses for ``Proof using``
-````````````````````````````````````````````````````
-
-.. cmd:: Collection @ident := @section_var_expr
-
- This can be used to name a set of section
- hypotheses, with the purpose of making ``Proof using`` annotations more
- compact.
-
- .. example::
-
- Define the collection named ``Some`` containing ``x``, ``y`` and ``z``::
-
- Collection Some := x y z.
-
- Define the collection named ``Fewer`` containing only ``x`` and ``y``::
-
- Collection Fewer := Some - z
-
- Define the collection named ``Many`` containing the set union or set
- difference of ``Fewer`` and ``Some``::
-
- Collection Many := Fewer + Some
- Collection Many := Fewer - Some
-
- Define the collection named ``Many`` containing the set difference of
- ``Fewer`` and the unnamed collection ``x y``::
-
- Collection Many := Fewer - (x y)
-
-
-
-.. cmd:: Existential @natural {? : @type } := @term
-
- This command instantiates an existential variable. :token:`natural` is an index in
- the list of uninstantiated existential variables displayed by :cmd:`Show Existentials`.
-
- This command is intended to be used to instantiate existential
- variables when the proof is completed but some uninstantiated
- existential variables remain. To instantiate existential variables
- during proof edition, you should use the tactic :tacn:`instantiate`.
-
-.. cmd:: Grab Existential Variables
-
- This command can be run when a proof has no more goal to be solved but
- has remaining uninstantiated existential variables. It takes every
- uninstantiated existential variable and turns it into a goal.
-
-Proof modes
-```````````
-
-When entering proof mode through commands such as :cmd:`Goal` and :cmd:`Proof`,
-|Coq| picks by default the |Ltac| mode. Nonetheless, there exist other proof modes
-shipped in the standard |Coq| installation, and furthermore some plugins define
-their own proof modes. The default proof mode used when opening a proof can
-be changed using the following option.
-
-.. opt:: Default Proof Mode @string
-
- Select the proof mode to use when starting a proof. Depending on the proof
- mode, various syntactic constructs are allowed when writing an interactive
- proof. All proof modes support vernacular commands; the proof mode determines
- which tactic language and set of tactic definitions are available. The
- possible option values are:
-
- `"Classic"`
- Activates the |Ltac| language and the tactics with the syntax documented
- in this manual.
- Some tactics are not available until the associated plugin is loaded,
- such as `SSR` or `micromega`.
- This proof mode is set when the :term:`prelude` is loaded.
-
- `"Noedit"`
- No tactic
- language is activated at all. This is the default when the :term:`prelude`
- is not loaded, e.g. through the `-noinit` option for `coqc`.
-
- `"Ltac2"`
- Activates the Ltac2 language and the Ltac2-specific variants of the documented
- tactics.
- This value is only available after :cmd:`Requiring <Require>` Ltac2.
- :cmd:`Importing <Import>` Ltac2 sets this mode.
-
- Some external plugins also define their own proof mode, which can be
- activated with this command.
-
-Navigation in the proof tree
---------------------------------
-
-.. cmd:: Undo {? {? To } @natural }
-
- Cancels the effect of the last :token:`natural` commands or tactics.
- The :n:`To @natural` form goes back to the specified state number.
- If :token:`natural` is not specified, the command goes back one command or tactic.
-
-.. cmd:: Restart
-
- Restores the proof editing process to the original goal.
-
- .. exn:: No focused proof to restart.
- :undocumented:
-
-.. cmd:: Focus {? @natural }
-
- Focuses the attention on the first subgoal to prove or, if :token:`natural` is
- specified, the :token:`natural`\-th. The
- printing of the other subgoals is suspended until the focused subgoal
- is solved or unfocused.
-
- .. deprecated:: 8.8
-
- Prefer the use of bullets or focusing brackets with a goal selector (see below).
-
-.. cmd:: Unfocus
-
- This command restores to focus the goal that were suspended by the
- last :cmd:`Focus` command.
-
- .. deprecated:: 8.8
-
-.. cmd:: Unfocused
-
- Succeeds if the proof is fully unfocused, fails if there are some
- goals out of focus.
-
-.. _curly-braces:
-
-.. index:: {
- }
-
-.. todo: :name: "{"; "}" doesn't work, nor does :name: left curly bracket; right curly bracket,
- hence the verbose names
-
-.. tacn:: {? {| @natural | [ @ident ] } : } %{
- %}
-
- .. todo
- See https://github.com/coq/coq/issues/12004 and
- https://github.com/coq/coq/issues/12825.
-
- ``{`` (without a terminating period) focuses on the first
- goal. The subproof can only be
- unfocused when it has been fully solved (*i.e.*, when there is no
- focused goal left). Unfocusing is then handled by ``}`` (again, without a
- terminating period). See also an example in the next section.
-
- Note that when a focused goal is proved a message is displayed
- together with a suggestion about the right bullet or ``}`` to unfocus it
- or focus the next one.
-
- :n:`@natural:`
- Focuses on the :token:`natural`\-th subgoal to prove.
-
- :n:`[ @ident ]: %{`
- Focuses on the named goal :token:`ident`.
-
- .. note::
-
- Goals are just existential variables and existential variables do not
- get a name by default. You can give a name to a goal by using :n:`refine ?[@ident]`.
- You may also wrap this in an Ltac-definition like:
-
- .. coqtop:: in
-
- Ltac name_goal name := refine ?[name].
-
- .. seealso:: :ref:`existential-variables`
-
- .. example::
-
- This first example uses the Ltac definition above, and the named goals
- only serve for documentation.
-
- .. coqtop:: all
-
- Goal forall n, n + 0 = n.
- Proof.
- induction n; [ name_goal base | name_goal step ].
- [base]: {
-
- .. coqtop:: all
-
- reflexivity.
-
- .. coqtop:: in
-
- }
-
- .. coqtop:: all
-
- [step]: {
-
- .. coqtop:: all
-
- simpl.
- f_equal.
- assumption.
- }
- Qed.
-
- This can also be a way of focusing on a shelved goal, for instance:
-
- .. coqtop:: all
-
- Goal exists n : nat, n = n.
- eexists ?[x].
- reflexivity.
- [x]: exact 0.
- Qed.
-
- .. exn:: This proof is focused, but cannot be unfocused this way.
-
- You are trying to use ``}`` but the current subproof has not been fully solved.
-
- .. exn:: No such goal (@natural).
- :undocumented:
-
- .. exn:: No such goal (@ident).
- :undocumented:
-
- .. exn:: Brackets do not support multi-goal selectors.
-
- Brackets are used to focus on a single goal given either by its position
- or by its name if it has one.
-
- .. seealso:: The error messages for bullets below.
-
-.. _bullets:
-
-Bullets
-```````
-
-Alternatively, proofs can be structured with bullets instead of ``{`` and ``}``. The
-use of a bullet ``b`` for the first time focuses on the first goal ``g``, the
-same bullet cannot be used again until the proof of ``g`` is completed,
-then it is mandatory to focus the next goal with ``b``. The consequence is
-that ``g`` and all goals present when ``g`` was focused are focused with the
-same bullet ``b``. See the example below.
-
-Different bullets can be used to nest levels. The scope of bullet does
-not go beyond enclosing ``{`` and ``}``, so bullets can be reused as further
-nesting levels provided they are delimited by these. Bullets are made of
-repeated ``-``, ``+`` or ``*`` symbols:
-
-.. prodn:: bullet ::= {| {+ - } | {+ + } | {+ * } }
-
-Note again that when a focused goal is proved a message is displayed
-together with a suggestion about the right bullet or ``}`` to unfocus it
-or focus the next one.
-
-.. note::
-
- In Proof General (``Emacs`` interface to |Coq|), you must use
- bullets with the priority ordering shown above to have a correct
- indentation. For example ``-`` must be the outer bullet and ``**`` the inner
- one in the example below.
-
-The following example script illustrates all these features:
-
-.. example::
-
- .. coqtop:: all
-
- Goal (((True /\ True) /\ True) /\ True) /\ True.
- Proof.
- split.
- - split.
- + split.
- ** { split.
- - trivial.
- - trivial.
- }
- ** trivial.
- + trivial.
- - assert True.
- { trivial. }
- assumption.
- Qed.
-
-.. exn:: Wrong bullet @bullet__1: Current bullet @bullet__2 is not finished.
-
- Before using bullet :n:`@bullet__1` again, you should first finish proving
- the current focused goal.
- Note that :n:`@bullet__1` and :n:`@bullet__2` may be the same.
-
-.. exn:: Wrong bullet @bullet__1: Bullet @bullet__2 is mandatory here.
-
- You must put :n:`@bullet__2` to focus on the next goal. No other bullet is
- allowed here.
-
-.. exn:: No such goal. Focus next goal with bullet @bullet.
-
- You tried to apply a tactic but no goals were under focus.
- Using :n:`@bullet` is mandatory here.
-
-.. FIXME: the :noindex: below works around a Sphinx issue.
- (https://github.com/sphinx-doc/sphinx/issues/4979)
- It should be removed once that issue is fixed.
-
-.. exn:: No such goal. Try unfocusing with %}.
- :noindex:
-
- You just finished a goal focused by ``{``, you must unfocus it with ``}``.
-
-Mandatory Bullets
-`````````````````
-
-Using :opt:`Default Goal Selector` with the ``!`` selector forces
-tactic scripts to keep focus to exactly one goal (e.g. using bullets)
-or use explicit goal selectors.
-
-Set Bullet Behavior
-```````````````````
-.. opt:: Bullet Behavior {| "None" | "Strict Subproofs" }
- :name: Bullet Behavior
-
- This option controls the bullet behavior and can take two possible values:
-
- - "None": this makes bullets inactive.
- - "Strict Subproofs": this makes bullets active (this is the default behavior).
-
-.. _requestinginformation:
-
-Requesting information
-----------------------
-
-
-.. cmd:: Show {? {| @ident | @natural } }
-
- Displays the current goals.
-
- :n:`@natural`
- Display only the :token:`natural`\-th subgoal.
-
- :n:`@ident`
- Displays the named goal :token:`ident`. This is useful in
- particular to display a shelved goal but only works if the
- corresponding existential variable has been named by the user
- (see :ref:`existential-variables`) as in the following example.
-
- .. example::
-
- .. coqtop:: all abort
-
- Goal exists n, n = 0.
- eexists ?[n].
- Show n.
-
- .. exn:: No focused proof.
- :undocumented:
-
- .. exn:: No such goal.
- :undocumented:
-
-.. cmd:: Show Proof {? Diffs {? removed } }
-
- Displays the proof term generated by the tactics
- that have been applied so far. If the proof is incomplete, the term
- will contain holes, which correspond to subterms which are still to be
- constructed. Each hole is an existential variable, which appears as a
- question mark followed by an identifier.
-
- Specifying “Diffs” highlights the difference between the
- current and previous proof step. By default, the command shows the
- output once with additions highlighted. Including “removed” shows
- the output twice: once showing removals and once showing additions.
- It does not examine the :opt:`Diffs` option. See :ref:`showing_proof_diffs`.
-
-.. cmd:: Show Conjectures
-
- Prints the names of all the
- theorems that are currently being proved. As it is possible to start
- proving a previous lemma during the proof of a theorem, there may
- be multiple names.
-
-.. cmd:: Show Intro
-
- If the current goal begins by at least one product,
- prints the name of the first product as it would be
- generated by an anonymous :tacn:`intro`. The aim of this command is to ease
- the writing of more robust scripts. For example, with an appropriate
- Proof General macro, it is possible to transform any anonymous :tacn:`intro`
- into a qualified one such as ``intro y13``. In the case of a non-product
- goal, it prints nothing.
-
-.. cmd:: Show Intros
-
- Similar to the previous command.
- Simulates the naming process of :tacn:`intros`.
-
-.. cmd:: Show Existentials
-
- Displays all open goals / existential variables in the current proof
- along with the type and the context of each variable.
-
-.. cmd:: Show Match @qualid
-
- Displays a template of the Gallina :token:`match<term_match>`
- construct with a branch for each constructor of the type
- :token:`qualid`. This is used internally by
- `company-coq <https://github.com/cpitclaudel/company-coq>`_.
-
- .. example::
-
- .. coqtop:: all
-
- Show Match nat.
-
- .. exn:: Unknown inductive type.
- :undocumented:
-
-.. cmd:: Show Universes
-
- Displays the set of all universe constraints and
- its normalized form at the current stage of the proof, useful for
- debugging universe inconsistencies.
-
-.. cmd:: Show Goal @natural at @natural
-
- Available in coqtop. Displays a goal at a
- proof state using the goal ID number and the proof state ID number.
- It is primarily for use by tools such as Prooftree that need to fetch
- goal history in this way. Prooftree is a tool for visualizing a proof
- as a tree that runs in Proof General.
-
-.. cmd:: Guarded
-
- Some tactics (e.g. :tacn:`refine`) allow to build proofs using
- fixpoint or co-fixpoint constructions. Due to the incremental nature
- of interactive proof construction, the check of the termination (or
- guardedness) of the recursive calls in the fixpoint or cofixpoint
- constructions is postponed to the time of the completion of the proof.
-
- The command :cmd:`Guarded` allows checking if the guard condition for
- fixpoint and cofixpoint is violated at some time of the construction
- of the proof without having to wait the completion of the proof.
-
-.. _showing_diffs:
-
-Showing differences between proof steps
----------------------------------------
-
-|Coq| can automatically highlight the differences between successive proof steps
-and between values in some error messages. |Coq| can also highlight differences
-in the proof term.
-For example, the following screenshots of |CoqIDE| and coqtop show the application
-of the same :tacn:`intros` tactic. The tactic creates two new hypotheses, highlighted in green.
-The conclusion is entirely in pale green because although it’s changed, no tokens were added
-to it. The second screenshot uses the "removed" option, so it shows the conclusion a
-second time with the old text, with deletions marked in red. Also, since the hypotheses are
-new, no line of old text is shown for them.
-
-.. comment screenshot produced with:
- Inductive ev : nat -> Prop :=
- | ev_0 : ev 0
- | ev_SS : forall n : nat, ev n -> ev (S (S n)).
-
- Fixpoint double (n:nat) :=
- match n with
- | O => O
- | S n' => S (S (double n'))
- end.
-
- Goal forall n, ev n -> exists k, n = double k.
- intros n E.
-
-..
-
- .. image:: ../_static/diffs-coqide-on.png
- :alt: |CoqIDE| with Set Diffs on
-
-..
-
- .. image:: ../_static/diffs-coqide-removed.png
- :alt: |CoqIDE| with Set Diffs removed
-
-..
-
- .. image:: ../_static/diffs-coqtop-on3.png
- :alt: coqtop with Set Diffs on
-
-This image shows an error message with diff highlighting in |CoqIDE|:
-
-..
-
- .. image:: ../_static/diffs-error-message.png
- :alt: |CoqIDE| error message with diffs
-
-How to enable diffs
-```````````````````
-
-.. opt:: Diffs {| "on" | "off" | "removed" }
- :name: Diffs
-
- The “on” setting highlights added tokens in green, while the “removed” setting
- additionally reprints items with removed tokens in red. Unchanged tokens in
- modified items are shown with pale green or red. Diffs in error messages
- use red and green for the compared values; they appear regardless of the setting.
- (Colors are user-configurable.)
-
-For coqtop, showing diffs can be enabled when starting coqtop with the
-``-diffs on|off|removed`` command-line option or by setting the :opt:`Diffs` option
-within |Coq|. You will need to provide the ``-color on|auto`` command-line option when
-you start coqtop in either case.
-
-Colors for coqtop can be configured by setting the ``COQ_COLORS`` environment
-variable. See section :ref:`customization-by-environment-variables`. Diffs
-use the tags ``diff.added``, ``diff.added.bg``, ``diff.removed`` and ``diff.removed.bg``.
-
-In |CoqIDE|, diffs should be enabled from the ``View`` menu. Don’t use the ``Set Diffs``
-command in |CoqIDE|. You can change the background colors shown for diffs from the
-``Edit | Preferences | Tags`` panel by changing the settings for the ``diff.added``,
-``diff.added.bg``, ``diff.removed`` and ``diff.removed.bg`` tags. This panel also
-lets you control other attributes of the highlights, such as the foreground
-color, bold, italic, underline and strikeout.
-
-Proof General can also display |Coq|-generated proof diffs automatically.
-Please see the PG documentation section
-"`Showing Proof Diffs" <https://proofgeneral.github.io/doc/master/userman/Coq-Proof-General#Showing-Proof-Diffs>`_)
-for details.
-
-How diffs are calculated
-````````````````````````
-
-Diffs are calculated as follows:
-
-1. Select the old proof state to compare to, which is the proof state before
- the last tactic that changed the proof. Changes that only affect the view
- of the proof, such as ``all: swap 1 2``, are ignored.
-
-2. For each goal in the new proof state, determine what old goal to compare
- it to—the one it is derived from or is the same as. Match the hypotheses by
- name (order is ignored), handling compacted items specially.
-
-3. For each hypothesis and conclusion (the “items”) in each goal, pass
- them as strings to the lexer to break them into tokens. Then apply the
- Myers diff algorithm :cite:`Myers` on the tokens and add appropriate highlighting.
-
-Notes:
-
-* Aside from the highlights, output for the "on" option should be identical
- to the undiffed output.
-* Goals completed in the last proof step will not be shown even with the
- "removed" setting.
-
-.. comment The following screenshots show diffs working with multiple goals and with compacted
- hypotheses. In the first one, notice that the goal ``P 1`` is not highlighted at
- all after the split because it has not changed.
-
- .. todo: Use this script and remove the screenshots when COQ_COLORS
- works for coqtop in sphinx
- .. coqtop:: none
-
- Set Diffs "on".
- Parameter P : nat -> Prop.
- Goal P 1 /\ P 2 /\ P 3.
-
- .. coqtop:: out
-
- split.
-
- .. coqtop:: all abort
-
- 2: split.
-
- ..
-
- .. coqtop:: none
-
- Set Diffs "on".
- Goal forall n m : nat, n + m = m + n.
- Set Diffs "on".
-
- .. coqtop:: out
-
- intros n.
-
- .. coqtop:: all abort
-
- intros m.
-
-This screen shot shows the result of applying a :tacn:`split` tactic that replaces one goal
-with 2 goals. Notice that the goal ``P 1`` is not highlighted at all after
-the split because it has not changed.
-
-..
-
- .. image:: ../_static/diffs-coqide-multigoal.png
- :alt: coqide with Set Diffs on with multiple goals
-
-Diffs may appear like this after applying a :tacn:`intro` tactic that results
-in a compacted hypotheses:
-
-..
-
- .. image:: ../_static/diffs-coqide-compacted.png
- :alt: coqide with Set Diffs on with compacted hypotheses
-
-.. _showing_proof_diffs:
-
-"Show Proof" differences
-````````````````````````
-
-To show differences in the proof term:
-
-- In coqtop and Proof General, use the :cmd:`Show Proof` `Diffs` command.
-
-- In |CoqIDE|, position the cursor on or just after a tactic to compare the proof term
- after the tactic with the proof term before the tactic, then select
- `View / Show Proof` from the menu or enter the associated key binding.
- Differences will be shown applying the current `Show Diffs` setting
- from the `View` menu. If the current setting is `Don't show diffs`, diffs
- will not be shown.
-
- Output with the "added and removed" option looks like this:
-
- ..
-
- .. image:: ../_static/diffs-show-proof.png
- :alt: coqide with Set Diffs on with compacted hypotheses
-
-Controlling the effect of proof editing commands
-------------------------------------------------
-
-
-.. opt:: Hyps Limit @natural
- :name: Hyps Limit
-
- This option controls the maximum number of hypotheses displayed in goals
- after the application of a tactic. All the hypotheses remain usable
- in the proof development.
- When unset, it goes back to the default mode which is to print all
- available hypotheses.
-
-
-.. flag:: Nested Proofs Allowed
-
- When turned on (it is off by default), this flag enables support for nested
- proofs: a new assertion command can be inserted before the current proof is
- finished, in which case |Coq| will temporarily switch to the proof of this
- *nested lemma*. When the proof of the nested lemma is finished (with :cmd:`Qed`
- or :cmd:`Defined`), its statement will be made available (as if it had been
- proved before starting the previous proof) and |Coq| will switch back to the
- proof of the previous assertion.
-
-.. flag:: Printing Goal Names
-
- When turned on, the name of the goal is printed in interactive
- proof mode, which can be useful in cases of cross references
- between goals.
-
-Controlling memory usage
-------------------------
-
-.. cmd:: Print Debug GC
-
- Prints heap usage statistics, which are values from the `stat` type of the `Gc` module
- described
- `here <https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html#TYPEstat>`_
- in the |OCaml| documentation.
- The `live_words`, `heap_words` and `top_heap_words` values give the basic information.
- Words are 8 bytes or 4 bytes, respectively, for 64- and 32-bit executables.
-
-When experiencing high memory usage the following commands can be used
-to force |Coq| to optimize some of its internal data structures.
-
-.. cmd:: Optimize Proof
-
- Shrink the data structure used to represent the current proof.
-
-
-.. cmd:: Optimize Heap
-
- Perform a heap compaction. This is generally an expensive operation.
- See: `|OCaml| Gc.compact <http://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html#VALcompact>`_
- There is also an analogous tactic :tacn:`optimize_heap`.
-
-Memory usage parameters can be set through the :ref:`OCAMLRUNPARAM <OCAMLRUNPARAM>`
-environment variable.
+ <meta http-equiv="refresh" content="0;URL=../proofs/writing-proofs/proof-mode.html">
diff --git a/doc/sphinx/proof-engine/tactics.rst b/doc/sphinx/proof-engine/tactics.rst
index fe9a31e220..c665026500 100644
--- a/doc/sphinx/proof-engine/tactics.rst
+++ b/doc/sphinx/proof-engine/tactics.rst
@@ -2663,1760 +2663,6 @@ and an explanation of the underlying technique.
simultaneously proved are respectively :g:`forall binder ... binder, type`
The identifiers :n:`@ident` are the names of the coinduction hypotheses.
-.. _rewritingexpressions:
-
-Rewriting expressions
----------------------
-
-These tactics use the equality :g:`eq:forall A:Type, A->A->Prop` defined in
-file ``Logic.v`` (see :ref:`coq-library-logic`). The notation for :g:`eq T t u` is
-simply :g:`t=u` dropping the implicit type of :g:`t` and :g:`u`.
-
-.. tacn:: rewrite @term
- :name: rewrite
-
- This tactic applies to any goal. The type of :token:`term` must have the form
-
- ``forall (x``:sub:`1` ``:A``:sub:`1` ``) ... (x``:sub:`n` ``:A``:sub:`n` ``), eq term``:sub:`1` ``term``:sub:`2` ``.``
-
- where :g:`eq` is the Leibniz equality or a registered setoid equality.
-
- Then :n:`rewrite @term` finds the first subterm matching `term`\ :sub:`1` in the goal,
- resulting in instances `term`:sub:`1`' and `term`:sub:`2`' and then
- replaces every occurrence of `term`:subscript:`1`' by `term`:subscript:`2`'.
- Hence, some of the variables :g:`x`\ :sub:`i` are solved by unification,
- and some of the types :g:`A`\ :sub:`1`:g:`, ..., A`\ :sub:`n` become new
- subgoals.
-
- .. exn:: The @term provided does not end with an equation.
- :undocumented:
-
- .. exn:: Tactic generated a subgoal identical to the original goal. This happens if @term does not occur in the goal.
- :undocumented:
-
- .. tacv:: rewrite -> @term
-
- Is equivalent to :n:`rewrite @term`
-
- .. tacv:: rewrite <- @term
-
- Uses the equality :n:`@term`:sub:`1` :n:`= @term` :sub:`2` from right to left
-
- .. tacv:: rewrite @term in @goal_occurrences
-
- Analogous to :n:`rewrite @term` but rewriting is done following
- the clause :token:`goal_occurrences`. For instance:
-
- + :n:`rewrite H in H'` will rewrite `H` in the hypothesis
- ``H'`` instead of the current goal.
- + :n:`rewrite H in H' at 1, H'' at - 2 |- *` means
- :n:`rewrite H; rewrite H in H' at 1; rewrite H in H'' at - 2.`
- In particular a failure will happen if any of these three simpler tactics
- fails.
- + :n:`rewrite H in * |-` will do :n:`rewrite H in H'` for all hypotheses
- :g:`H'` different from :g:`H`.
- A success will happen as soon as at least one of these simpler tactics succeeds.
- + :n:`rewrite H in *` is a combination of :n:`rewrite H` and :n:`rewrite H in * |-`
- that succeeds if at least one of these two tactics succeeds.
-
- Orientation :g:`->` or :g:`<-` can be inserted before the :token:`term` to rewrite.
-
- .. tacv:: rewrite @term at @occurrences
-
- Rewrite only the given :token:`occurrences` of :token:`term`. Occurrences are
- specified from left to right as for pattern (:tacn:`pattern`). The rewrite is
- always performed using setoid rewriting, even for Leibniz’s equality, so one
- has to ``Import Setoid`` to use this variant.
-
- .. tacv:: rewrite @term by @tactic
-
- Use tactic to completely solve the side-conditions arising from the
- :tacn:`rewrite`.
-
- .. tacv:: rewrite {+, @orientation @term} {? in @ident }
-
- Is equivalent to the `n` successive tactics :n:`{+; rewrite @term}`, each one
- working on the first subgoal generated by the previous one. An :production:`orientation`
- ``->`` or ``<-`` can be inserted before each :token:`term` to rewrite. One
- unique clause can be added at the end after the keyword in; it will then
- affect all rewrite operations.
-
- In all forms of rewrite described above, a :token:`term` to rewrite can be
- immediately prefixed by one of the following modifiers:
-
- + `?` : the tactic :n:`rewrite ?@term` performs the rewrite of :token:`term` as many
- times as possible (perhaps zero time). This form never fails.
- + :n:`@natural?` : works similarly, except that it will do at most :token:`natural` rewrites.
- + `!` : works as `?`, except that at least one rewrite should succeed, otherwise
- the tactic fails.
- + :n:`@natural!` (or simply :n:`@natural`) : precisely :token:`natural` rewrites of :token:`term` will be done,
- leading to failure if these :token:`natural` rewrites are not possible.
-
- .. tacv:: erewrite @term
- :name: erewrite
-
- This tactic works as :n:`rewrite @term` but turning
- unresolved bindings into existential variables, if any, instead of
- failing. It has the same variants as :tacn:`rewrite` has.
-
- .. flag:: Keyed Unification
-
- Makes higher-order unification used by :tacn:`rewrite` rely on a set of keys to drive
- unification. The subterms, considered as rewriting candidates, must start with
- the same key as the left- or right-hand side of the lemma given to rewrite, and the arguments
- are then unified up to full reduction.
-
-.. tacn:: replace @term with @term’
- :name: replace
-
- This tactic applies to any goal. It replaces all free occurrences of :n:`@term`
- in the current goal with :n:`@term’` and generates an equality :n:`@term = @term’`
- as a subgoal. This equality is automatically solved if it occurs among
- the assumptions, or if its symmetric form occurs. It is equivalent to
- :n:`cut @term = @term’; [intro H`:sub:`n` :n:`; rewrite <- H`:sub:`n` :n:`; clear H`:sub:`n`:n:`|| assumption || symmetry; try assumption]`.
-
- .. exn:: Terms do not have convertible types.
- :undocumented:
-
- .. tacv:: replace @term with @term’ by @tactic
-
- This acts as :n:`replace @term with @term’` but applies :token:`tactic` to solve the generated
- subgoal :n:`@term = @term’`.
-
- .. tacv:: replace @term
-
- Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
- the form :n:`@term = @term’` or :n:`@term’ = @term`.
-
- .. tacv:: replace -> @term
-
- Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
- the form :n:`@term = @term’`
-
- .. tacv:: replace <- @term
-
- Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
- the form :n:`@term’ = @term`
-
- .. tacv:: replace @term {? with @term} in @goal_occurrences {? by @tactic}
- replace -> @term in @goal_occurrences
- replace <- @term in @goal_occurrences
-
- Acts as before but the replacements take place in the specified clauses
- (:token:`goal_occurrences`) (see :ref:`performingcomputations`) and not
- only in the conclusion of the goal. The clause argument must not contain
- any ``type of`` nor ``value of``.
-
-.. tacn:: subst @ident
- :name: subst
-
- This tactic applies to a goal that has :n:`@ident` in its context and (at
- least) one hypothesis, say :g:`H`, of type :n:`@ident = t` or :n:`t = @ident`
- with :n:`@ident` not occurring in :g:`t`. Then it replaces :n:`@ident` by
- :g:`t` everywhere in the goal (in the hypotheses and in the conclusion) and
- clears :n:`@ident` and :g:`H` from the context.
-
- If :n:`@ident` is a local definition of the form :n:`@ident := t`, it is also
- unfolded and cleared.
-
- If :n:`@ident` is a section variable it is expected to have no
- indirect occurrences in the goal, i.e. that no global declarations
- implicitly depending on the section variable must be present in the
- goal.
-
- .. note::
- + When several hypotheses have the form :n:`@ident = t` or :n:`t = @ident`, the
- first one is used.
-
- + If :g:`H` is itself dependent in the goal, it is replaced by the proof of
- reflexivity of equality.
-
- .. tacv:: subst {+ @ident}
-
- This is equivalent to :n:`subst @ident`:sub:`1`:n:`; ...; subst @ident`:sub:`n`.
-
- .. tacv:: subst
-
- This applies :tacn:`subst` repeatedly from top to bottom to all hypotheses of the
- context for which an equality of the form :n:`@ident = t` or :n:`t = @ident`
- or :n:`@ident := t` exists, with :n:`@ident` not occurring in
- ``t`` and :n:`@ident` not a section variable with indirect
- dependencies in the goal.
-
- .. flag:: Regular Subst Tactic
-
- This flag controls the behavior of :tacn:`subst`. When it is
- activated (it is by default), :tacn:`subst` also deals with the following corner cases:
-
- + A context with ordered hypotheses :n:`@ident`:sub:`1` :n:`= @ident`:sub:`2`
- and :n:`@ident`:sub:`1` :n:`= t`, or :n:`t′ = @ident`:sub:`1`` with `t′` not
- a variable, and no other hypotheses of the form :n:`@ident`:sub:`2` :n:`= u`
- or :n:`u = @ident`:sub:`2`; without the flag, a second call to
- subst would be necessary to replace :n:`@ident`:sub:`2` by `t` or
- `t′` respectively.
- + The presence of a recursive equation which without the flag would
- be a cause of failure of :tacn:`subst`.
- + A context with cyclic dependencies as with hypotheses :n:`@ident`:sub:`1` :n:`= f @ident`:sub:`2`
- and :n:`@ident`:sub:`2` :n:`= g @ident`:sub:`1` which without the
- flag would be a cause of failure of :tacn:`subst`.
-
- Additionally, it prevents a local definition such as :n:`@ident := t` to be
- unfolded which otherwise it would exceptionally unfold in configurations
- containing hypotheses of the form :n:`@ident = u`, or :n:`u′ = @ident`
- with `u′` not a variable. Finally, it preserves the initial order of
- hypotheses, which without the flag it may break.
- default.
-
- .. exn:: Cannot find any non-recursive equality over :n:`@ident`.
- :undocumented:
-
- .. exn:: Section variable :n:`@ident` occurs implicitly in global declaration :n:`@qualid` present in hypothesis :n:`@ident`.
- Section variable :n:`@ident` occurs implicitly in global declaration :n:`@qualid` present in the conclusion.
-
- Raised when the variable is a section variable with indirect
- dependencies in the goal.
-
-
-.. tacn:: stepl @term
- :name: stepl
-
- This tactic is for chaining rewriting steps. It assumes a goal of the
- form :n:`R @term @term` where ``R`` is a binary relation and relies on a
- database of lemmas of the form :g:`forall x y z, R x y -> eq x z -> R z y`
- where `eq` is typically a setoid equality. The application of :n:`stepl @term`
- then replaces the goal by :n:`R @term @term` and adds a new goal stating
- :n:`eq @term @term`.
-
- .. cmd:: Declare Left Step @term
-
- Adds :n:`@term` to the database used by :tacn:`stepl`.
-
- This tactic is especially useful for parametric setoids which are not accepted
- as regular setoids for :tacn:`rewrite` and :tacn:`setoid_replace` (see
- :ref:`Generalizedrewriting`).
-
- .. tacv:: stepl @term by @tactic
-
- This applies :n:`stepl @term` then applies :token:`tactic` to the second goal.
-
- .. tacv:: stepr @term by @tactic
- :name: stepr
-
- This behaves as :tacn:`stepl` but on the right-hand-side of the binary
- relation. Lemmas are expected to be of the form
- :g:`forall x y z, R x y -> eq y z -> R x z`.
-
- .. cmd:: Declare Right Step @term
-
- Adds :n:`@term` to the database used by :tacn:`stepr`.
-
-
-.. tacn:: change @term
- :name: change
-
- This tactic applies to any goal. It implements the rule ``Conv`` given in
- :ref:`subtyping-rules`. :g:`change U` replaces the current goal `T`
- with `U` providing that `U` is well-formed and that `T` and `U` are
- convertible.
-
- .. exn:: Not convertible.
- :undocumented:
-
- .. tacv:: change @term with @term’
-
- This replaces the occurrences of :n:`@term` by :n:`@term’` in the current goal.
- The term :n:`@term` and :n:`@term’` must be convertible.
-
- .. tacv:: change @term at {+ @natural} with @term’
-
- This replaces the occurrences numbered :n:`{+ @natural}` of :n:`@term` by :n:`@term’`
- in the current goal. The terms :n:`@term` and :n:`@term’` must be convertible.
-
- .. exn:: Too few occurrences.
- :undocumented:
-
- .. tacv:: change @term {? {? at {+ @natural}} with @term} in @ident
-
- This applies the :tacn:`change` tactic not to the goal but to the hypothesis :n:`@ident`.
-
- .. tacv:: now_show @term
-
- This is a synonym of :n:`change @term`. It can be used to
- make some proof steps explicit when refactoring a proof script
- to make it readable.
-
- .. seealso:: :ref:`Performing computations <performingcomputations>`
-
-.. _performingcomputations:
-
-Performing computations
----------------------------
-
-.. insertprodn red_expr pattern_occ
-
-.. prodn::
- red_expr ::= red
- | hnf
- | simpl {? @delta_flag } {? @ref_or_pattern_occ }
- | cbv {? @strategy_flag }
- | cbn {? @strategy_flag }
- | lazy {? @strategy_flag }
- | compute {? @delta_flag }
- | vm_compute {? @ref_or_pattern_occ }
- | native_compute {? @ref_or_pattern_occ }
- | unfold {+, @unfold_occ }
- | fold {+ @one_term }
- | pattern {+, @pattern_occ }
- | @ident
- delta_flag ::= {? - } [ {+ @reference } ]
- strategy_flag ::= {+ @red_flag }
- | @delta_flag
- red_flag ::= beta
- | iota
- | match
- | fix
- | cofix
- | zeta
- | delta {? @delta_flag }
- ref_or_pattern_occ ::= @reference {? at @occs_nums }
- | @one_term {? at @occs_nums }
- occs_nums ::= {+ {| @natural | @ident } }
- | - {| @natural | @ident } {* @int_or_var }
- int_or_var ::= @integer
- | @ident
- unfold_occ ::= @reference {? at @occs_nums }
- pattern_occ ::= @one_term {? at @occs_nums }
-
-This set of tactics implements different specialized usages of the
-tactic :tacn:`change`.
-
-All conversion tactics (including :tacn:`change`) can be parameterized by the
-parts of the goal where the conversion can occur. This is done using
-*goal clauses* which consists in a list of hypotheses and, optionally,
-of a reference to the conclusion of the goal. For defined hypothesis
-it is possible to specify if the conversion should occur on the type
-part, the body part or both (default).
-
-Goal clauses are written after a conversion tactic (tactics :tacn:`set`,
-:tacn:`rewrite`, :tacn:`replace` and :tacn:`autorewrite` also use goal
-clauses) and are introduced by the keyword `in`. If no goal clause is
-provided, the default is to perform the conversion only in the
-conclusion.
-
-The syntax and description of the various goal clauses is the
-following:
-
-+ :n:`in {+ @ident} |-` only in hypotheses :n:`{+ @ident}`
-+ :n:`in {+ @ident} |- *` in hypotheses :n:`{+ @ident}` and in the
- conclusion
-+ :n:`in * |-` in every hypothesis
-+ :n:`in *` (equivalent to in :n:`* |- *`) everywhere
-+ :n:`in (type of @ident) (value of @ident) ... |-` in type part of
- :n:`@ident`, in the value part of :n:`@ident`, etc.
-
-For backward compatibility, the notation :n:`in {+ @ident}` performs
-the conversion in hypotheses :n:`{+ @ident}`.
-
-.. tacn:: cbv {? @strategy_flag }
- lazy {? @strategy_flag }
- :name: cbv; lazy
-
- These parameterized reduction tactics apply to any goal and perform
- the normalization of the goal according to the specified flags. In
- correspondence with the kinds of reduction considered in |Coq| namely
- :math:`\beta` (reduction of functional application), :math:`\delta`
- (unfolding of transparent constants, see :ref:`vernac-controlling-the-reduction-strategies`),
- :math:`\iota` (reduction of
- pattern matching over a constructed term, and unfolding of :g:`fix` and
- :g:`cofix` expressions) and :math:`\zeta` (contraction of local definitions), the
- flags are either ``beta``, ``delta``, ``match``, ``fix``, ``cofix``,
- ``iota`` or ``zeta``. The ``iota`` flag is a shorthand for ``match``, ``fix``
- and ``cofix``. The ``delta`` flag itself can be refined into
- :n:`delta [ {+ @qualid} ]` or :n:`delta - [ {+ @qualid} ]`, restricting in the first
- case the constants to unfold to the constants listed, and restricting in the
- second case the constant to unfold to all but the ones explicitly mentioned.
- Notice that the ``delta`` flag does not apply to variables bound by a let-in
- construction inside the :n:`@term` itself (use here the ``zeta`` flag). In
- any cases, opaque constants are not unfolded (see :ref:`vernac-controlling-the-reduction-strategies`).
-
- Normalization according to the flags is done by first evaluating the
- head of the expression into a *weak-head* normal form, i.e. until the
- evaluation is blocked by a variable (or an opaque constant, or an
- axiom), as e.g. in :g:`x u1 ... un` , or :g:`match x with ... end`, or
- :g:`(fix f x {struct x} := ...) x`, or is a constructed form (a
- :math:`\lambda`-expression, a constructor, a cofixpoint, an inductive type, a
- product type, a sort), or is a redex that the flags prevent to reduce. Once a
- weak-head normal form is obtained, subterms are recursively reduced using the
- same strategy.
-
- Reduction to weak-head normal form can be done using two strategies:
- *lazy* (``lazy`` tactic), or *call-by-value* (``cbv`` tactic). The lazy
- strategy is a call-by-need strategy, with sharing of reductions: the
- arguments of a function call are weakly evaluated only when necessary,
- and if an argument is used several times then it is weakly computed
- only once. This reduction is efficient for reducing expressions with
- dead code. For instance, the proofs of a proposition :g:`exists x. P(x)`
- reduce to a pair of a witness :g:`t`, and a proof that :g:`t` satisfies the
- predicate :g:`P`. Most of the time, :g:`t` may be computed without computing
- the proof of :g:`P(t)`, thanks to the lazy strategy.
-
- The call-by-value strategy is the one used in ML languages: the
- arguments of a function call are systematically weakly evaluated
- first. Despite the lazy strategy always performs fewer reductions than
- the call-by-value strategy, the latter is generally more efficient for
- evaluating purely computational expressions (i.e. with little dead code).
-
-.. tacv:: compute
- cbv
- :name: compute; _
-
- These are synonyms for ``cbv beta delta iota zeta``.
-
-.. tacv:: lazy
-
- This is a synonym for ``lazy beta delta iota zeta``.
-
-.. tacv:: compute [ {+ @qualid} ]
- cbv [ {+ @qualid} ]
-
- These are synonyms of :n:`cbv beta delta {+ @qualid} iota zeta`.
-
-.. tacv:: compute - [ {+ @qualid} ]
- cbv - [ {+ @qualid} ]
-
- These are synonyms of :n:`cbv beta delta -{+ @qualid} iota zeta`.
-
-.. tacv:: lazy [ {+ @qualid} ]
- lazy - [ {+ @qualid} ]
-
- These are respectively synonyms of :n:`lazy beta delta {+ @qualid} iota zeta`
- and :n:`lazy beta delta -{+ @qualid} iota zeta`.
-
-.. tacv:: vm_compute
- :name: vm_compute
-
- This tactic evaluates the goal using the optimized call-by-value evaluation
- bytecode-based virtual machine described in :cite:`CompiledStrongReduction`.
- This algorithm is dramatically more efficient than the algorithm used for the
- :tacn:`cbv` tactic, but it cannot be fine-tuned. It is especially interesting for
- full evaluation of algebraic objects. This includes the case of
- reflection-based tactics.
-
-.. tacv:: native_compute
- :name: native_compute
-
- This tactic evaluates the goal by compilation to |OCaml| as described
- in :cite:`FullReduction`. If |Coq| is running in native code, it can be
- typically two to five times faster than :tacn:`vm_compute`. Note however that the
- compilation cost is higher, so it is worth using only for intensive
- computations.
-
- .. flag:: NativeCompute Timing
-
- This flag causes all calls to the native compiler to print
- timing information for the conversion to native code,
- compilation, execution, and reification phases of native
- compilation. Timing is printed in units of seconds of
- wall-clock time.
-
- .. flag:: NativeCompute Profiling
-
- On Linux, if you have the ``perf`` profiler installed, this flag makes
- it possible to profile :tacn:`native_compute` evaluations.
-
- .. opt:: NativeCompute Profile Filename @string
- :name: NativeCompute Profile Filename
-
- This option specifies the profile output; the default is
- ``native_compute_profile.data``. The actual filename used
- will contain extra characters to avoid overwriting an existing file; that
- filename is reported to the user.
- That means you can individually profile multiple uses of
- :tacn:`native_compute` in a script. From the Linux command line, run ``perf report``
- on the profile file to see the results. Consult the ``perf`` documentation
- for more details.
-
-.. flag:: Debug Cbv
-
- This flag makes :tacn:`cbv` (and its derivative :tacn:`compute`) print
- information about the constants it encounters and the unfolding decisions it
- makes.
-
-.. tacn:: red
- :name: red
-
- This tactic applies to a goal that has the form::
-
- forall (x:T1) ... (xk:Tk), T
-
- with :g:`T` :math:`\beta`:math:`\iota`:math:`\zeta`-reducing to :g:`c t`:sub:`1` :g:`... t`:sub:`n` and :g:`c` a
- constant. If :g:`c` is transparent then it replaces :g:`c` with its
- definition (say :g:`t`) and then reduces
- :g:`(t t`:sub:`1` :g:`... t`:sub:`n` :g:`)` according to :math:`\beta`:math:`\iota`:math:`\zeta`-reduction rules.
-
-.. exn:: Not reducible.
- :undocumented:
-
-.. exn:: No head constant to reduce.
- :undocumented:
-
-.. tacn:: hnf
- :name: hnf
-
- This tactic applies to any goal. It replaces the current goal with its
- head normal form according to the :math:`\beta`:math:`\delta`:math:`\iota`:math:`\zeta`-reduction rules, i.e. it
- reduces the head of the goal until it becomes a product or an
- irreducible term. All inner :math:`\beta`:math:`\iota`-redexes are also reduced.
- The behavior of both :tacn:`hnf` can be tuned using the :cmd:`Arguments` command.
-
- Example: The term :g:`fun n : nat => S n + S n` is not reduced by :n:`hnf`.
-
-.. note::
- The :math:`\delta` rule only applies to transparent constants (see :ref:`vernac-controlling-the-reduction-strategies`
- on transparency and opacity).
-
-.. tacn:: cbn
- simpl
- :name: cbn; simpl
-
- These tactics apply to any goal. They try to reduce a term to
- something still readable instead of fully normalizing it. They perform
- a sort of strong normalization with two key differences:
-
- + They unfold a constant if and only if it leads to a :math:`\iota`-reduction,
- i.e. reducing a match or unfolding a fixpoint.
- + While reducing a constant unfolding to (co)fixpoints, the tactics
- use the name of the constant the (co)fixpoint comes from instead of
- the (co)fixpoint definition in recursive calls.
-
- The :tacn:`cbn` tactic is claimed to be a more principled, faster and more
- predictable replacement for :tacn:`simpl`.
-
- The :tacn:`cbn` tactic accepts the same flags as :tacn:`cbv` and
- :tacn:`lazy`. The behavior of both :tacn:`simpl` and :tacn:`cbn`
- can be tuned using the :cmd:`Arguments` command.
-
- .. todo add "See <subsection about controlling the behavior of reduction strategies>"
- to TBA section
-
- Notice that only transparent constants whose name can be reused in the
- recursive calls are possibly unfolded by :tacn:`simpl`. For instance a
- constant defined by :g:`plus' := plus` is possibly unfolded and reused in
- the recursive calls, but a constant such as :g:`succ := plus (S O)` is
- never unfolded. This is the main difference between :tacn:`simpl` and :tacn:`cbn`.
- The tactic :tacn:`cbn` reduces whenever it will be able to reuse it or not:
- :g:`succ t` is reduced to :g:`S t`.
-
-.. tacv:: cbn [ {+ @qualid} ]
- cbn - [ {+ @qualid} ]
-
- These are respectively synonyms of :n:`cbn beta delta [ {+ @qualid} ] iota zeta`
- and :n:`cbn beta delta - [ {+ @qualid} ] iota zeta` (see :tacn:`cbn`).
-
-.. tacv:: simpl @pattern
-
- This applies :tacn:`simpl` only to the subterms matching
- :n:`@pattern` in the current goal.
-
-.. tacv:: simpl @pattern at {+ @natural}
-
- This applies :tacn:`simpl` only to the :n:`{+ @natural}` occurrences of the subterms
- matching :n:`@pattern` in the current goal.
-
- .. exn:: Too few occurrences.
- :undocumented:
-
-.. tacv:: simpl @qualid
- simpl @string
-
- This applies :tacn:`simpl` only to the applicative subterms whose head occurrence
- is the unfoldable constant :n:`@qualid` (the constant can be referred to by
- its notation using :n:`@string` if such a notation exists).
-
-.. tacv:: simpl @qualid at {+ @natural}
- simpl @string at {+ @natural}
-
- This applies :tacn:`simpl` only to the :n:`{+ @natural}` applicative subterms whose
- head occurrence is :n:`@qualid` (or :n:`@string`).
-
-.. flag:: Debug RAKAM
-
- This flag makes :tacn:`cbn` print various debugging information.
- ``RAKAM`` is the Refolding Algebraic Krivine Abstract Machine.
-
-.. tacn:: unfold @qualid
- :name: unfold
-
- This tactic applies to any goal. The argument qualid must denote a
- defined transparent constant or local definition (see
- :ref:`gallina-definitions` and
- :ref:`vernac-controlling-the-reduction-strategies`). The tactic
- :tacn:`unfold` applies the :math:`\delta` rule to each occurrence
- of the constant to which :n:`@qualid` refers in the current goal
- and then replaces it with its :math:`\beta\iota\zeta`-normal form.
- Use the general reduction tactics if you want to avoid this final
- reduction, for instance :n:`cbv delta [@qualid]`.
-
- .. exn:: Cannot coerce @qualid to an evaluable reference.
-
- This error is frequent when trying to unfold something that has
- defined as an inductive type (or constructor) and not as a
- definition.
-
- .. example::
-
- .. coqtop:: abort all fail
-
- Goal 0 <= 1.
- unfold le.
-
- This error can also be raised if you are trying to unfold
- something that has been marked as opaque.
-
- .. example::
-
- .. coqtop:: abort all fail
-
- Opaque Nat.add.
- Goal 1 + 0 = 1.
- unfold Nat.add.
-
- .. tacv:: unfold @qualid in @goal_occurrences
-
- Replaces :n:`@qualid` in hypothesis (or hypotheses) designated
- by :token:`goal_occurrences` with its definition and replaces
- the hypothesis with its :math:`\beta`:math:`\iota` normal form.
-
- .. tacv:: unfold {+, @qualid}
-
- Replaces :n:`{+, @qualid}` with their definitions and replaces
- the current goal with its :math:`\beta`:math:`\iota` normal
- form.
-
- .. tacv:: unfold {+, @qualid at @occurrences }
-
- The list :token:`occurrences` specify the occurrences of
- :n:`@qualid` to be unfolded. Occurrences are located from left
- to right.
-
- .. exn:: Bad occurrence number of @qualid.
- :undocumented:
-
- .. exn:: @qualid does not occur.
- :undocumented:
-
- .. tacv:: unfold @string
-
- If :n:`@string` denotes the discriminating symbol of a notation
- (e.g. "+") or an expression defining a notation (e.g. `"_ +
- _"`), and this notation denotes an application whose head symbol
- is an unfoldable constant, then the tactic unfolds it.
-
- .. tacv:: unfold @string%@ident
-
- This is variant of :n:`unfold @string` where :n:`@string` gets
- its interpretation from the scope bound to the delimiting key
- :token:`ident` instead of its default interpretation (see
- :ref:`Localinterpretationrulesfornotations`).
-
- .. tacv:: unfold {+, {| @qualid | @string{? %@ident } } {? at @occurrences } } {? in @goal_occurrences }
-
- This is the most general form.
-
-.. tacn:: fold @term
- :name: fold
-
- This tactic applies to any goal. The term :n:`@term` is reduced using the
- :tacn:`red` tactic. Every occurrence of the resulting :n:`@term` in the goal is
- then replaced by :n:`@term`. This tactic is particularly useful when a fixpoint
- definition has been wrongfully unfolded, making the goal very hard to read.
- On the other hand, when an unfolded function applied to its argument has been
- reduced, the :tacn:`fold` tactic won't do anything.
-
- .. example::
-
- .. coqtop:: all abort
-
- Goal ~0=0.
- unfold not.
- Fail progress fold not.
- pattern (0 = 0).
- fold not.
-
- .. tacv:: fold {+ @term}
-
- Equivalent to :n:`fold @term ; ... ; fold @term`.
-
-.. tacn:: pattern @term
- :name: pattern
-
- This command applies to any goal. The argument :n:`@term` must be a free
- subterm of the current goal. The command pattern performs :math:`\beta`-expansion
- (the inverse of :math:`\beta`-reduction) of the current goal (say :g:`T`) by
-
- + replacing all occurrences of :n:`@term` in :g:`T` with a fresh variable
- + abstracting this variable
- + applying the abstracted goal to :n:`@term`
-
- For instance, if the current goal :g:`T` is expressible as
- :math:`\varphi`:g:`(t)` where the notation captures all the instances of :g:`t`
- in :math:`\varphi`:g:`(t)`, then :n:`pattern t` transforms it into
- :g:`(fun x:A =>` :math:`\varphi`:g:`(x)) t`. This tactic can be used, for
- instance, when the tactic ``apply`` fails on matching.
-
-.. tacv:: pattern @term at {+ @natural}
-
- Only the occurrences :n:`{+ @natural}` of :n:`@term` are considered for
- :math:`\beta`-expansion. Occurrences are located from left to right.
-
-.. tacv:: pattern @term at - {+ @natural}
-
- All occurrences except the occurrences of indexes :n:`{+ @natural }`
- of :n:`@term` are considered for :math:`\beta`-expansion. Occurrences are located from
- left to right.
-
-.. tacv:: pattern {+, @term}
-
- Starting from a goal :math:`\varphi`:g:`(t`:sub:`1` :g:`... t`:sub:`m`:g:`)`,
- the tactic :n:`pattern t`:sub:`1`:n:`, ..., t`:sub:`m` generates the
- equivalent goal
- :g:`(fun (x`:sub:`1`:g:`:A`:sub:`1`:g:`) ... (x`:sub:`m` :g:`:A`:sub:`m` :g:`) =>`:math:`\varphi`:g:`(x`:sub:`1` :g:`... x`:sub:`m` :g:`)) t`:sub:`1` :g:`... t`:sub:`m`.
- If :g:`t`:sub:`i` occurs in one of the generated types :g:`A`:sub:`j` these
- occurrences will also be considered and possibly abstracted.
-
-.. tacv:: pattern {+, @term at {+ @natural}}
-
- This behaves as above but processing only the occurrences :n:`{+ @natural}` of
- :n:`@term` starting from :n:`@term`.
-
-.. tacv:: pattern {+, @term {? at {? -} {+, @natural}}}
-
- This is the most general syntax that combines the different variants.
-
-.. tacn:: with_strategy @strategy_level_or_var [ {+ @reference } ] @ltac_expr3
- :name: with_strategy
-
- Executes :token:`ltac_expr3`, applying the alternate unfolding
- behavior that the :cmd:`Strategy` command controls, but only for
- :token:`ltac_expr3`. This can be useful for guarding calls to
- reduction in tactic automation to ensure that certain constants are
- never unfolded by tactics like :tacn:`simpl` and :tacn:`cbn` or to
- ensure that unfolding does not fail.
-
- .. example::
-
- .. coqtop:: all reset abort
-
- Opaque id.
- Goal id 10 = 10.
- Fail unfold id.
- with_strategy transparent [id] unfold id.
-
- .. warning::
-
- Use this tactic with care, as effects do not persist past the
- end of the proof script. Notably, this fine-tuning of the
- conversion strategy is not in effect during :cmd:`Qed` nor
- :cmd:`Defined`, so this tactic is most useful either in
- combination with :tacn:`abstract`, which will check the proof
- early while the fine-tuning is still in effect, or to guard
- calls to conversion in tactic automation to ensure that, e.g.,
- :tacn:`unfold` does not fail just because the user made a
- constant :cmd:`Opaque`.
-
- This can be illustrated with the following example involving the
- factorial function.
-
- .. coqtop:: in reset
-
- Fixpoint fact (n : nat) : nat :=
- match n with
- | 0 => 1
- | S n' => n * fact n'
- end.
-
- Suppose now that, for whatever reason, we want in general to
- unfold the :g:`id` function very late during conversion:
-
- .. coqtop:: in
-
- Strategy 1000 [id].
-
- If we try to prove :g:`id (fact n) = fact n` by
- :tacn:`reflexivity`, it will now take time proportional to
- :math:`n!`, because |Coq| will keep unfolding :g:`fact` and
- :g:`*` and :g:`+` before it unfolds :g:`id`, resulting in a full
- computation of :g:`fact n` (in unary, because we are using
- :g:`nat`), which takes time :math:`n!`. We can see this cross
- the relevant threshold at around :math:`n = 9`:
-
- .. coqtop:: all abort
-
- Goal True.
- Time assert (id (fact 8) = fact 8) by reflexivity.
- Time assert (id (fact 9) = fact 9) by reflexivity.
-
- Note that behavior will be the same if you mark :g:`id` as
- :g:`Opaque` because while most reduction tactics refuse to
- unfold :g:`Opaque` constants, conversion treats :g:`Opaque` as
- merely a hint to unfold this constant last.
-
- We can get around this issue by using :tacn:`with_strategy`:
-
- .. coqtop:: all
-
- Goal True.
- Fail Timeout 1 assert (id (fact 100) = fact 100) by reflexivity.
- Time assert (id (fact 100) = fact 100) by with_strategy -1 [id] reflexivity.
-
- However, when we go to close the proof, we will run into
- trouble, because the reduction strategy changes are local to the
- tactic passed to :tacn:`with_strategy`.
-
- .. coqtop:: all abort fail
-
- exact I.
- Timeout 1 Defined.
-
- We can fix this issue by using :tacn:`abstract`:
-
- .. coqtop:: all
-
- Goal True.
- Time assert (id (fact 100) = fact 100) by with_strategy -1 [id] abstract reflexivity.
- exact I.
- Time Defined.
-
- On small examples this sort of behavior doesn't matter, but
- because |Coq| is a super-linear performance domain in so many
- places, unless great care is taken, tactic automation using
- :tacn:`with_strategy` may not be robustly performant when
- scaling the size of the input.
-
- .. warning::
-
- In much the same way this tactic does not play well with
- :cmd:`Qed` and :cmd:`Defined` without using :tacn:`abstract` as
- an intermediary, this tactic does not play well with ``coqchk``,
- even when used with :tacn:`abstract`, due to the inability of
- tactics to persist information about conversion hints in the
- proof term. See `#12200
- <https://github.com/coq/coq/issues/12200>`_ for more details.
-
-Conversion tactics applied to hypotheses
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. tacn:: @tactic in {+, @ident}
-
- Applies :token:`tactic` (any of the conversion tactics listed in this
- section) to the hypotheses :n:`{+ @ident}`.
-
- If :token:`ident` is a local definition, then :token:`ident` can be replaced by
- :n:`type of @ident` to address not the body but the type of the local
- definition.
-
- Example: :n:`unfold not in (type of H1) (type of H3)`.
-
-.. exn:: No such hypothesis: @ident.
- :undocumented:
-
-
-.. _automation:
-
-Automation
-----------
-
-.. tacn:: auto
- :name: auto
-
- This tactic implements a Prolog-like resolution procedure to solve the
- current goal. It first tries to solve the goal using the :tacn:`assumption`
- tactic, then it reduces the goal to an atomic one using :tacn:`intros` and
- introduces the newly generated hypotheses as hints. Then it looks at
- the list of tactics associated to the head symbol of the goal and
- tries to apply one of them (starting from the tactics with lower
- cost). This process is recursively applied to the generated subgoals.
-
- By default, :tacn:`auto` only uses the hypotheses of the current goal and
- the hints of the database named ``core``.
-
- .. warning::
-
- :tacn:`auto` uses a weaker version of :tacn:`apply` that is closer to
- :tacn:`simple apply` so it is expected that sometimes :tacn:`auto` will
- fail even if applying manually one of the hints would succeed.
-
- .. tacv:: auto @natural
-
- Forces the search depth to be :token:`natural`. The maximal search depth
- is 5 by default.
-
- .. tacv:: auto with {+ @ident}
-
- Uses the hint databases :n:`{+ @ident}` in addition to the database ``core``.
-
- .. note::
-
- Use the fake database `nocore` if you want to *not* use the `core`
- database.
-
- .. tacv:: auto with *
-
- Uses all existing hint databases. Using this variant is highly discouraged
- in finished scripts since it is both slower and less robust than the variant
- where the required databases are explicitly listed.
-
- .. seealso::
- :ref:`The Hints Databases for auto and eauto <thehintsdatabasesforautoandeauto>` for the list of
- pre-defined databases and the way to create or extend a database.
-
- .. tacv:: auto using {+ @qualid__i} {? with {+ @ident } }
-
- Uses lemmas :n:`@qualid__i` in addition to hints. If :n:`@qualid` is an
- inductive type, it is the collection of its constructors which are added
- as hints.
-
- .. note::
-
- The hints passed through the `using` clause are used in the same
- way as if they were passed through a hint database. Consequently,
- they use a weaker version of :tacn:`apply` and :n:`auto using @qualid`
- may fail where :n:`apply @qualid` succeeds.
-
- Given that this can be seen as counter-intuitive, it could be useful
- to have an option to use full-blown :tacn:`apply` for lemmas passed
- through the `using` clause. Contributions welcome!
-
- .. tacv:: info_auto
-
- Behaves like :tacn:`auto` but shows the tactics it uses to solve the goal. This
- variant is very useful for getting a better understanding of automation, or
- to know what lemmas/assumptions were used.
-
- .. tacv:: debug auto
- :name: debug auto
-
- Behaves like :tacn:`auto` but shows the tactics it tries to solve the goal,
- including failing paths.
-
- .. tacv:: {? info_}auto {? @natural} {? using {+ @qualid}} {? with {+ @ident}}
-
- This is the most general form, combining the various options.
-
-.. tacv:: trivial
- :name: trivial
-
- This tactic is a restriction of :tacn:`auto` that is not recursive
- and tries only hints that cost `0`. Typically it solves trivial
- equalities like :g:`X=X`.
-
- .. tacv:: trivial with {+ @ident}
- trivial with *
- trivial using {+ @qualid}
- debug trivial
- info_trivial
- {? info_}trivial {? using {+ @qualid}} {? with {+ @ident}}
- :name: _; _; _; debug trivial; info_trivial; _
- :undocumented:
-
-.. note::
- :tacn:`auto` and :tacn:`trivial` either solve completely the goal or
- else succeed without changing the goal. Use :g:`solve [ auto ]` and
- :g:`solve [ trivial ]` if you would prefer these tactics to fail when
- they do not manage to solve the goal.
-
-.. flag:: Info Auto
- Debug Auto
- Info Trivial
- Debug Trivial
-
- These flags enable printing of informative or debug information for
- the :tacn:`auto` and :tacn:`trivial` tactics.
-
-.. tacn:: eauto
- :name: eauto
-
- This tactic generalizes :tacn:`auto`. While :tacn:`auto` does not try
- resolution hints which would leave existential variables in the goal,
- :tacn:`eauto` does try them (informally speaking, it internally uses a tactic
- close to :tacn:`simple eapply` instead of a tactic close to :tacn:`simple apply`
- in the case of :tacn:`auto`). As a consequence, :tacn:`eauto`
- can solve such a goal:
-
- .. example::
-
- .. coqtop:: all
-
- Hint Resolve ex_intro : core.
- Goal forall P:nat -> Prop, P 0 -> exists n, P n.
- eauto.
-
- Note that ``ex_intro`` should be declared as a hint.
-
-
- .. tacv:: {? info_}eauto {? @natural} {? using {+ @qualid}} {? with {+ @ident}}
-
- The various options for :tacn:`eauto` are the same as for :tacn:`auto`.
-
- :tacn:`eauto` also obeys the following flags:
-
- .. flag:: Info Eauto
- Debug Eauto
- :undocumented:
-
- .. seealso:: :ref:`The Hints Databases for auto and eauto <thehintsdatabasesforautoandeauto>`
-
-
-.. tacn:: autounfold with {+ @ident}
- :name: autounfold
-
- This tactic unfolds constants that were declared through a :cmd:`Hint Unfold`
- in the given databases.
-
-.. tacv:: autounfold with {+ @ident} in @goal_occurrences
-
- Performs the unfolding in the given clause (:token:`goal_occurrences`).
-
-.. tacv:: autounfold with *
-
- Uses the unfold hints declared in all the hint databases.
-
-.. tacn:: autorewrite with {+ @ident}
- :name: autorewrite
-
- This tactic carries out rewritings according to the rewriting rule
- bases :n:`{+ @ident}`.
-
- Each rewriting rule from the base :n:`@ident` is applied to the main subgoal until
- it fails. Once all the rules have been processed, if the main subgoal has
- progressed (e.g., if it is distinct from the initial main goal) then the rules
- of this base are processed again. If the main subgoal has not progressed then
- the next base is processed. For the bases, the behavior is exactly similar to
- the processing of the rewriting rules.
-
- The rewriting rule bases are built with the :cmd:`Hint Rewrite`
- command.
-
-.. warning::
-
- This tactic may loop if you build non terminating rewriting systems.
-
-.. tacv:: autorewrite with {+ @ident} using @tactic
-
- Performs, in the same way, all the rewritings of the bases :n:`{+ @ident}`
- applying tactic to the main subgoal after each rewriting step.
-
-.. tacv:: autorewrite with {+ @ident} in @qualid
-
- Performs all the rewritings in hypothesis :n:`@qualid`.
-
-.. tacv:: autorewrite with {+ @ident} in @qualid using @tactic
-
- Performs all the rewritings in hypothesis :n:`@qualid` applying :n:`@tactic`
- to the main subgoal after each rewriting step.
-
-.. tacv:: autorewrite with {+ @ident} in @goal_occurrences
-
- Performs all the rewriting in the clause :n:`@goal_occurrences`.
-
-.. seealso::
-
- :ref:`Hint-Rewrite <hintrewrite>` for feeding the database of lemmas used by
- :tacn:`autorewrite` and :tacn:`autorewrite` for examples showing the use of this tactic.
-
-.. tacn:: easy
- :name: easy
-
- This tactic tries to solve the current goal by a number of standard closing steps.
- In particular, it tries to close the current goal using the closing tactics
- :tacn:`trivial`, :tacn:`reflexivity`, :tacn:`symmetry`, :tacn:`contradiction`
- and :tacn:`inversion` of hypothesis.
- If this fails, it tries introducing variables and splitting and-hypotheses,
- using the closing tactics afterwards, and splitting the goal using
- :tacn:`split` and recursing.
-
- This tactic solves goals that belong to many common classes; in particular, many cases of
- unsatisfiable hypotheses, and simple equality goals are usually solved by this tactic.
-
-.. tacv:: now @tactic
- :name: now
-
- Run :n:`@tactic` followed by :tacn:`easy`. This is a notation for :n:`@tactic; easy`.
-
-Controlling automation
---------------------------
-
-.. _thehintsdatabasesforautoandeauto:
-
-The hints databases for auto and eauto
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The hints for :tacn:`auto` and :tacn:`eauto` are stored in databases. Each database
-maps head symbols to a list of hints.
-
-.. cmd:: Print Hint @ident
-
- Use this command
- to display the hints associated to the head symbol :n:`@ident`
- (see :ref:`Print Hint <printhint>`). Each hint has a cost that is a nonnegative
- integer, and an optional pattern. The hints with lower cost are tried first. A
- hint is tried by :tacn:`auto` when the conclusion of the current goal matches its
- pattern or when it has no pattern.
-
-Creating Hint databases
-```````````````````````
-
-One can optionally declare a hint database using the command
-:cmd:`Create HintDb`. If a hint is added to an unknown database, it will be
-automatically created.
-
-.. cmd:: Create HintDb @ident {? discriminated}
-
- This command creates a new database named :n:`@ident`. The database is
- implemented by a Discrimination Tree (DT) that serves as an index of
- all the lemmas. The DT can use transparency information to decide if a
- constant should be indexed or not
- (c.f. :ref:`The hints databases for auto and eauto <thehintsdatabasesforautoandeauto>`),
- making the retrieval more efficient. The legacy implementation (the default one
- for new databases) uses the DT only on goals without existentials (i.e., :tacn:`auto`
- goals), for non-Immediate hints and does not make use of transparency
- hints, putting more work on the unification that is run after
- retrieval (it keeps a list of the lemmas in case the DT is not used).
- The new implementation enabled by the discriminated option makes use
- of DTs in all cases and takes transparency information into account.
- However, the order in which hints are retrieved from the DT may differ
- from the order in which they were inserted, making this implementation
- observationally different from the legacy one.
-
-.. cmd:: Hint @hint_definition : {+ @ident}
-
- The general command to add a hint to some databases :n:`{+ @ident}`.
-
- This command supports the :attr:`local`, :attr:`global` and :attr:`export`
- locality attributes. When no locality is explictly given, the
- command is :attr:`local` inside a section and :attr:`global` otherwise.
-
- + :attr:`local` hints are never visible from other modules, even if they
- require or import the current module. Inside a section, the :attr:`local`
- attribute is useless since hints do not survive anyway to the closure of
- sections.
-
- + :attr:`export` are visible from other modules when they import the current
- module. Requiring it is not enough. This attribute is only effective for
- the :cmd:`Hint Resolve`, :cmd:`Hint Immediate`, :cmd:`Hint Unfold` and
- :cmd:`Hint Extern` variants of the command.
-
- + :attr:`global` hints are made available by merely requiring the current
- module.
-
- The various possible :production:`hint_definition`\s are given below.
-
- .. cmdv:: Hint @hint_definition
-
- No database name is given: the hint is registered in the ``core`` database.
-
- .. deprecated:: 8.10
-
- .. cmdv:: Hint Resolve @qualid {? | {? @natural} {? @pattern}} : @ident
- :name: Hint Resolve
-
- This command adds :n:`simple apply @qualid` to the hint list with the head
- symbol of the type of :n:`@qualid`. The cost of that hint is the number of
- subgoals generated by :n:`simple apply @qualid` or :n:`@natural` if specified. The
- associated :n:`@pattern` is inferred from the conclusion of the type of
- :n:`@qualid` or the given :n:`@pattern` if specified. In case the inferred type
- of :n:`@qualid` does not start with a product the tactic added in the hint list
- is :n:`exact @qualid`. In case this type can however be reduced to a type
- starting with a product, the tactic :n:`simple apply @qualid` is also stored in
- the hints list. If the inferred type of :n:`@qualid` contains a dependent
- quantification on a variable which occurs only in the premisses of the type
- and not in its conclusion, no instance could be inferred for the variable by
- unification with the goal. In this case, the hint is added to the hint list
- of :tacn:`eauto` instead of the hint list of auto and a warning is printed. A
- typical example of a hint that is used only by :tacn:`eauto` is a transitivity
- lemma.
-
- .. exn:: @qualid cannot be used as a hint
-
- The head symbol of the type of :n:`@qualid` is a bound variable
- such that this tactic cannot be associated to a constant.
-
- .. cmdv:: Hint Resolve {+ @qualid} : @ident
-
- Adds each :n:`Hint Resolve @qualid`.
-
- .. cmdv:: Hint Resolve -> @qualid : @ident
-
- Adds the left-to-right implication of an equivalence as a hint (informally
- the hint will be used as :n:`apply <- @qualid`, although as mentioned
- before, the tactic actually used is a restricted version of
- :tacn:`apply`).
-
- .. cmdv:: Hint Resolve <- @qualid
-
- Adds the right-to-left implication of an equivalence as a hint.
-
- .. cmdv:: Hint Immediate @qualid : @ident
- :name: Hint Immediate
-
- This command adds :n:`simple apply @qualid; trivial` to the hint list associated
- with the head symbol of the type of :n:`@ident` in the given database. This
- tactic will fail if all the subgoals generated by :n:`simple apply @qualid` are
- not solved immediately by the :tacn:`trivial` tactic (which only tries tactics
- with cost 0).This command is useful for theorems such as the symmetry of
- equality or :g:`n+1=m+1 -> n=m` that we may like to introduce with a limited
- use in order to avoid useless proof-search. The cost of this tactic (which
- never generates subgoals) is always 1, so that it is not used by :tacn:`trivial`
- itself.
-
- .. exn:: @qualid cannot be used as a hint
- :undocumented:
-
- .. cmdv:: Hint Immediate {+ @qualid} : @ident
-
- Adds each :n:`Hint Immediate @qualid`.
-
- .. cmdv:: Hint Constructors @qualid : @ident
- :name: Hint Constructors
-
- If :token:`qualid` is an inductive type, this command adds all its constructors as
- hints of type ``Resolve``. Then, when the conclusion of current goal has the form
- :n:`(@qualid ...)`, :tacn:`auto` will try to apply each constructor.
-
- .. exn:: @qualid is not an inductive type
- :undocumented:
-
- .. cmdv:: Hint Constructors {+ @qualid} : @ident
-
- Extends the previous command for several inductive types.
-
- .. cmdv:: Hint Unfold @qualid : @ident
- :name: Hint Unfold
-
- This adds the tactic :n:`unfold @qualid` to the hint list that will only be
- used when the head constant of the goal is :token:`qualid`.
- Its cost is 4.
-
- .. cmdv:: Hint Unfold {+ @qualid}
-
- Extends the previous command for several defined constants.
-
- .. cmdv:: Hint Transparent {+ @qualid} : @ident
- Hint Opaque {+ @qualid} : @ident
- :name: Hint Transparent; Hint Opaque
-
- This adds transparency hints to the database, making :n:`@qualid`
- transparent or opaque constants during resolution. This information is used
- during unification of the goal with any lemma in the database and inside the
- discrimination network to relax or constrain it in the case of discriminated
- databases.
-
- .. cmdv:: Hint Variables {| Transparent | Opaque } : @ident
- Hint Constants {| Transparent | Opaque } : @ident
- :name: Hint Variables; Hint Constants
-
- This sets the transparency flag used during unification of
- hints in the database for all constants or all variables,
- overwriting the existing settings of opacity. It is advised
- to use this just after a :cmd:`Create HintDb` command.
-
- .. cmdv:: Hint Extern @natural {? @pattern} => @tactic : @ident
- :name: Hint Extern
-
- This hint type is to extend :tacn:`auto` with tactics other than :tacn:`apply` and
- :tacn:`unfold`. For that, we must specify a cost, an optional :n:`@pattern` and a
- :n:`@tactic` to execute.
-
- .. example::
-
- .. coqtop:: in
-
- Hint Extern 4 (~(_ = _)) => discriminate : core.
-
- Now, when the head of the goal is a disequality, ``auto`` will try
- discriminate if it does not manage to solve the goal with hints with a
- cost less than 4.
-
- One can even use some sub-patterns of the pattern in
- the tactic script. A sub-pattern is a question mark followed by an
- identifier, like ``?X1`` or ``?X2``. Here is an example:
-
- .. example::
-
- .. coqtop:: reset all
-
- Require Import List.
- Hint Extern 5 ({?X1 = ?X2} + {?X1 <> ?X2}) => generalize X1, X2; decide equality : eqdec.
- Goal forall a b:list (nat * nat), {a = b} + {a <> b}.
- Info 1 auto with eqdec.
-
- .. cmdv:: Hint Cut @regexp : @ident
- :name: Hint Cut
-
- .. warning::
-
- These hints currently only apply to typeclass proof search and the
- :tacn:`typeclasses eauto` tactic.
-
- This command can be used to cut the proof-search tree according to a regular
- expression matching paths to be cut. The grammar for regular expressions is
- the following. Beware, there is no operator precedence during parsing, one can
- check with :cmd:`Print HintDb` to verify the current cut expression:
-
- .. prodn::
- regexp ::= @ident (hint or instance identifier)
- | _ (any hint)
- | @regexp | @regexp (disjunction)
- | @regexp @regexp (sequence)
- | @regexp * (Kleene star)
- | emp (empty)
- | eps (epsilon)
- | ( @regexp )
-
- The `emp` regexp does not match any search path while `eps`
- matches the empty path. During proof search, the path of
- successive successful hints on a search branch is recorded, as a
- list of identifiers for the hints (note that :cmd:`Hint Extern`\’s do not have
- an associated identifier).
- Before applying any hint :n:`@ident` the current path `p` extended with
- :n:`@ident` is matched against the current cut expression `c` associated to
- the hint database. If matching succeeds, the hint is *not* applied. The
- semantics of :n:`Hint Cut @regexp` is to set the cut expression
- to :n:`c | regexp`, the initial cut expression being `emp`.
-
- .. cmdv:: Hint Mode @qualid {* {| + | ! | - } } : @ident
- :name: Hint Mode
-
- This sets an optional mode of use of the identifier :n:`@qualid`. When
- proof-search faces a goal that ends in an application of :n:`@qualid` to
- arguments :n:`@term ... @term`, the mode tells if the hints associated to
- :n:`@qualid` can be applied or not. A mode specification is a list of n ``+``,
- ``!`` or ``-`` items that specify if an argument of the identifier is to be
- treated as an input (``+``), if its head only is an input (``!``) or an output
- (``-``) of the identifier. For a mode to match a list of arguments, input
- terms and input heads *must not* contain existential variables or be
- existential variables respectively, while outputs can be any term. Multiple
- modes can be declared for a single identifier, in that case only one mode
- needs to match the arguments for the hints to be applied. The head of a term
- is understood here as the applicative head, or the match or projection
- scrutinee’s head, recursively, casts being ignored. :cmd:`Hint Mode` is
- especially useful for typeclasses, when one does not want to support default
- instances and avoid ambiguity in general. Setting a parameter of a class as an
- input forces proof-search to be driven by that index of the class, with ``!``
- giving more flexibility by allowing existentials to still appear deeper in the
- index but not at its head.
-
- .. note::
-
- + One can use a :cmd:`Hint Extern` with no pattern to do
- pattern matching on hypotheses using ``match goal with``
- inside the tactic.
-
- + If you want to add hints such as :cmd:`Hint Transparent`,
- :cmd:`Hint Cut`, or :cmd:`Hint Mode`, for typeclass
- resolution, do not forget to put them in the
- ``typeclass_instances`` hint database.
-
-
-Hint databases defined in the |Coq| standard library
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Several hint databases are defined in the |Coq| standard library. The
-actual content of a database is the collection of hints declared
-to belong to this database in each of the various modules currently
-loaded. Especially, requiring new modules may extend the database.
-At |Coq| startup, only the core database is nonempty and can be used.
-
-:core: This special database is automatically used by ``auto``, except when
- pseudo-database ``nocore`` is given to ``auto``. The core database
- contains only basic lemmas about negation, conjunction, and so on.
- Most of the hints in this database come from the Init and Logic directories.
-
-:arith: This database contains all lemmas about Peano’s arithmetic proved in the
- directories Init and Arith.
-
-:zarith: contains lemmas about binary signed integers from the
- directories theories/ZArith. The database also contains
- high-cost hints that call :tacn:`lia` on equations and
- inequalities in ``nat`` or ``Z``.
-
-:bool: contains lemmas about booleans, mostly from directory theories/Bool.
-
-:datatypes: is for lemmas about lists, streams and so on that are mainly proved
- in the Lists subdirectory.
-
-:sets: contains lemmas about sets and relations from the directories Sets and
- Relations.
-
-:typeclass_instances: contains all the typeclass instances declared in the
- environment, including those used for ``setoid_rewrite``,
- from the Classes directory.
-
-:fset: internal database for the implementation of the ``FSets`` library.
-
-:ordered_type: lemmas about ordered types (as defined in the legacy ``OrderedType`` module),
- mainly used in the ``FSets`` and ``FMaps`` libraries.
-
-You are advised not to put your own hints in the core database, but
-use one or several databases specific to your development.
-
-.. _removehints:
-
-.. cmd:: Remove Hints {+ @term} : {+ @ident}
-
- This command removes the hints associated to terms :n:`{+ @term}` in databases
- :n:`{+ @ident}`.
-
-.. _printhint:
-
-.. cmd:: Print Hint
-
- This command displays all hints that apply to the current goal. It
- fails if no proof is being edited, while the two variants can be used
- at every moment.
-
-**Variants:**
-
-
-.. cmd:: Print Hint @ident
-
- This command displays only tactics associated with :n:`@ident` in the hints
- list. This is independent of the goal being edited, so this command will not
- fail if no goal is being edited.
-
-.. cmd:: Print Hint *
-
- This command displays all declared hints.
-
-.. cmd:: Print HintDb @ident
-
- This command displays all hints from database :n:`@ident`.
-
-.. _hintrewrite:
-
-.. cmd:: Hint Rewrite {+ @term} : {+ @ident}
-
- This vernacular command adds the terms :n:`{+ @term}` (their types must be
- equalities) in the rewriting bases :n:`{+ @ident}` with the default orientation
- (left to right). Notice that the rewriting bases are distinct from the :tacn:`auto`
- hint bases and that :tacn:`auto` does not take them into account.
-
- This command is synchronous with the section mechanism (see :ref:`section-mechanism`):
- when closing a section, all aliases created by ``Hint Rewrite`` in that
- section are lost. Conversely, when loading a module, all ``Hint Rewrite``
- declarations at the global level of that module are loaded.
-
-**Variants:**
-
-.. cmd:: Hint Rewrite -> {+ @term} : {+ @ident}
-
- This is strictly equivalent to the command above (we only make explicit the
- orientation which otherwise defaults to ->).
-
-.. cmd:: Hint Rewrite <- {+ @term} : {+ @ident}
-
- Adds the rewriting rules :n:`{+ @term}` with a right-to-left orientation in
- the bases :n:`{+ @ident}`.
-
-.. cmd:: Hint Rewrite {? {| -> | <- } } {+ @one_term } {? using @ltac_expr } {? : {* @ident } }
-
- When the rewriting rules :n:`{+ @term}` in :n:`{+ @ident}` will be used, the
- tactic ``tactic`` will be applied to the generated subgoals, the main subgoal
- excluded.
-
-.. cmd:: Print Rewrite HintDb @ident
-
- This command displays all rewrite hints contained in :n:`@ident`.
-
-Hint locality
-~~~~~~~~~~~~~
-
-Hints provided by the ``Hint`` commands are erased when closing a section.
-Conversely, all hints of a module ``A`` that are not defined inside a
-section (and not defined with option ``Local``) become available when the
-module ``A`` is required (using e.g. ``Require A.``).
-
-As of today, hints only have a binary behavior regarding locality, as
-described above: either they disappear at the end of a section scope,
-or they remain global forever. This causes a scalability issue,
-because hints coming from an unrelated part of the code may badly
-influence another development. It can be mitigated to some extent
-thanks to the :cmd:`Remove Hints` command,
-but this is a mere workaround and has some limitations (for instance, external
-hints cannot be removed).
-
-A proper way to fix this issue is to bind the hints to their module scope, as
-for most of the other objects |Coq| uses. Hints should only be made available when
-the module they are defined in is imported, not just required. It is very
-difficult to change the historical behavior, as it would break a lot of scripts.
-We propose a smooth transitional path by providing the :opt:`Loose Hint Behavior`
-option which accepts three flags allowing for a fine-grained handling of
-non-imported hints.
-
-.. opt:: Loose Hint Behavior {| "Lax" | "Warn" | "Strict" }
- :name: Loose Hint Behavior
-
- This option accepts three values, which control the behavior of hints w.r.t.
- :cmd:`Import`:
-
- - "Lax": this is the default, and corresponds to the historical behavior,
- that is, hints defined outside of a section have a global scope.
-
- - "Warn": outputs a warning when a non-imported hint is used. Note that this
- is an over-approximation, because a hint may be triggered by a run that
- will eventually fail and backtrack, resulting in the hint not being
- actually useful for the proof.
-
- - "Strict": changes the behavior of an unloaded hint to a immediate fail
- tactic, allowing to emulate an import-scoped hint mechanism.
-
-.. _tactics-implicit-automation:
-
-Setting implicit automation tactics
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. cmd:: Proof with @tactic
-
- This command may be used to start a proof. It defines a default tactic
- to be used each time a tactic command ``tactic``:sub:`1` is ended by ``...``.
- In this case the tactic command typed by the user is equivalent to
- ``tactic``:sub:`1` ``;tactic``.
-
- .. seealso:: :cmd:`Proof` in :ref:`proof-editing-mode`.
-
-
- .. cmdv:: Proof with @tactic using {+ @ident}
-
- Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode`
-
- .. cmdv:: Proof using {+ @ident} with @tactic
-
- Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode`
-
-.. _decisionprocedures:
-
-Decision procedures
--------------------
-
-.. tacn:: tauto
- :name: tauto
-
- This tactic implements a decision procedure for intuitionistic propositional
- calculus based on the contraction-free sequent calculi LJT* of Roy Dyckhoff
- :cite:`Dyc92`. Note that :tacn:`tauto` succeeds on any instance of an
- intuitionistic tautological proposition. :tacn:`tauto` unfolds negations and
- logical equivalence but does not unfold any other definition.
-
-.. example::
-
- The following goal can be proved by :tacn:`tauto` whereas :tacn:`auto` would
- fail:
-
- .. coqtop:: reset all
-
- Goal forall (x:nat) (P:nat -> Prop), x = 0 \/ P x -> x <> 0 -> P x.
- intros.
- tauto.
-
-Moreover, if it has nothing else to do, :tacn:`tauto` performs introductions.
-Therefore, the use of :tacn:`intros` in the previous proof is unnecessary.
-:tacn:`tauto` can for instance for:
-
-.. example::
-
- .. coqtop:: reset all
-
- Goal forall (A:Prop) (P:nat -> Prop), A \/ (forall x:nat, ~ A -> P x) -> forall x:nat, ~ A -> P x.
- tauto.
-
-.. note::
- In contrast, :tacn:`tauto` cannot solve the following goal
- :g:`Goal forall (A:Prop) (P:nat -> Prop), A \/ (forall x:nat, ~ A -> P x) ->`
- :g:`forall x:nat, ~ ~ (A \/ P x).`
- because :g:`(forall x:nat, ~ A -> P x)` cannot be treated as atomic and
- an instantiation of `x` is necessary.
-
-.. tacv:: dtauto
- :name: dtauto
-
- While :tacn:`tauto` recognizes inductively defined connectives isomorphic to
- the standard connectives ``and``, ``prod``, ``or``, ``sum``, ``False``,
- ``Empty_set``, ``unit``, ``True``, :tacn:`dtauto` also recognizes all inductive
- types with one constructor and no indices, i.e. record-style connectives.
-
-.. tacn:: intuition @tactic
- :name: intuition
-
- The tactic :tacn:`intuition` takes advantage of the search-tree built by the
- decision procedure involved in the tactic :tacn:`tauto`. It uses this
- information to generate a set of subgoals equivalent to the original one (but
- simpler than it) and applies the tactic :n:`@tactic` to them :cite:`Mun94`. If
- this tactic fails on some goals then :tacn:`intuition` fails. In fact,
- :tacn:`tauto` is simply :g:`intuition fail`.
-
- .. example::
-
- For instance, the tactic :g:`intuition auto` applied to the goal::
-
- (forall (x:nat), P x) /\ B -> (forall (y:nat), P y) /\ P O \/ B /\ P O
-
- internally replaces it by the equivalent one::
-
- (forall (x:nat), P x), B |- P O
-
- and then uses :tacn:`auto` which completes the proof.
-
-Originally due to César Muñoz, these tactics (:tacn:`tauto` and
-:tacn:`intuition`) have been completely re-engineered by David Delahaye using
-mainly the tactic language (see :ref:`ltac`). The code is
-now much shorter and a significant increase in performance has been noticed.
-The general behavior with respect to dependent types, unfolding and
-introductions has slightly changed to get clearer semantics. This may lead to
-some incompatibilities.
-
-.. tacv:: intuition
-
- Is equivalent to :g:`intuition auto with *`.
-
-.. tacv:: dintuition
- :name: dintuition
-
- While :tacn:`intuition` recognizes inductively defined connectives
- isomorphic to the standard connectives ``and``, ``prod``, ``or``, ``sum``, ``False``,
- ``Empty_set``, ``unit``, ``True``, :tacn:`dintuition` also recognizes all inductive
- types with one constructor and no indices, i.e. record-style connectives.
-
-.. flag:: Intuition Negation Unfolding
-
- Controls whether :tacn:`intuition` unfolds inner negations which do not need
- to be unfolded. This flag is on by default.
-
-.. tacn:: rtauto
- :name: rtauto
-
- The :tacn:`rtauto` tactic solves propositional tautologies similarly to what
- :tacn:`tauto` does. The main difference is that the proof term is built using a
- reflection scheme applied to a sequent calculus proof of the goal. The search
- procedure is also implemented using a different technique.
-
- Users should be aware that this difference may result in faster proof-search
- but slower proof-checking, and :tacn:`rtauto` might not solve goals that
- :tacn:`tauto` would be able to solve (e.g. goals involving universal
- quantifiers).
-
- Note that this tactic is only available after a ``Require Import Rtauto``.
-
-.. tacn:: firstorder
- :name: firstorder
-
- The tactic :tacn:`firstorder` is an experimental extension of :tacn:`tauto` to
- first- order reasoning, written by Pierre Corbineau. It is not restricted to
- usual logical connectives but instead may reason about any first-order class
- inductive definition.
-
-.. opt:: Firstorder Solver @tactic
- :name: Firstorder Solver
-
- The default tactic used by :tacn:`firstorder` when no rule applies is
- :g:`auto with core`, it can be reset locally or globally using this option.
-
- .. cmd:: Print Firstorder Solver
-
- Prints the default tactic used by :tacn:`firstorder` when no rule applies.
-
-.. tacv:: firstorder @tactic
-
- Tries to solve the goal with :n:`@tactic` when no logical rule may apply.
-
-.. tacv:: firstorder using {+ @qualid}
-
- .. deprecated:: 8.3
-
- Use the syntax below instead (with commas).
-
-.. tacv:: firstorder using {+, @qualid}
-
- Adds lemmas :n:`{+, @qualid}` to the proof-search environment. If :n:`@qualid`
- refers to an inductive type, it is the collection of its constructors which are
- added to the proof-search environment.
-
-.. tacv:: firstorder with {+ @ident}
-
- Adds lemmas from :tacn:`auto` hint bases :n:`{+ @ident}` to the proof-search
- environment.
-
-.. tacv:: firstorder @tactic using {+, @qualid} with {+ @ident}
-
- This combines the effects of the different variants of :tacn:`firstorder`.
-
-.. opt:: Firstorder Depth @natural
- :name: Firstorder Depth
-
- This option controls the proof-search depth bound.
-
-.. tacn:: congruence
- :name: congruence
-
- The tactic :tacn:`congruence`, by Pierre Corbineau, implements the standard
- Nelson and Oppen congruence closure algorithm, which is a decision procedure
- for ground equalities with uninterpreted symbols. It also includes
- constructor theory (see :tacn:`injection` and :tacn:`discriminate`). If the goal
- is a non-quantified equality, congruence tries to prove it with non-quantified
- equalities in the context. Otherwise it tries to infer a discriminable equality
- from those in the context. Alternatively, congruence tries to prove that a
- hypothesis is equal to the goal or to the negation of another hypothesis.
-
- :tacn:`congruence` is also able to take advantage of hypotheses stating
- quantified equalities, but you have to provide a bound for the number of extra
- equalities generated that way. Please note that one of the sides of the
- equality must contain all the quantified variables in order for congruence to
- match against it.
-
-.. example::
-
- .. coqtop:: reset all
-
- Theorem T (A:Type) (f:A -> A) (g: A -> A -> A) a b: a=(f a) -> (g b (f a))=(f (f a)) -> (g a b)=(f (g b a)) -> (g a b)=a.
- intros.
- congruence.
- Qed.
-
- Theorem inj (A:Type) (f:A -> A * A) (a c d: A) : f = pair a -> Some (f c) = Some (f d) -> c=d.
- intros.
- congruence.
- Qed.
-
-.. tacv:: congruence @natural
-
- Tries to add at most :token:`natural` instances of hypotheses stating quantified equalities
- to the problem in order to solve it. A bigger value of :token:`natural` does not make
- success slower, only failure. You might consider adding some lemmas as
- hypotheses using assert in order for :tacn:`congruence` to use them.
-
-.. tacv:: congruence with {+ @term}
- :name: congruence with
-
- Adds :n:`{+ @term}` to the pool of terms used by :tacn:`congruence`. This helps
- in case you have partially applied constructors in your goal.
-
-.. exn:: I don’t know how to handle dependent equality.
-
- The decision procedure managed to find a proof of the goal or of a
- discriminable equality but this proof could not be built in |Coq| because of
- dependently-typed functions.
-
-.. exn:: Goal is solvable by congruence but some arguments are missing. Try congruence with {+ @term}, replacing metavariables by arbitrary terms.
-
- The decision procedure could solve the goal with the provision that additional
- arguments are supplied for some partially applied constructors. Any term of an
- appropriate type will allow the tactic to successfully solve the goal. Those
- additional arguments can be given to congruence by filling in the holes in the
- terms given in the error message, using the :tacn:`congruence with` variant described above.
-
-.. flag:: Congruence Verbose
-
- This flag makes :tacn:`congruence` print debug information.
-
Checking properties of terms
----------------------------
@@ -4647,189 +2893,6 @@ using the ``Require Import`` command.
Use :tacn:`classical_right` to prove the right part of the disjunction with
the assumption that the negation of left part holds.
-.. _tactics-automating:
-
-Automating
-------------
-
-
-.. tacn:: btauto
- :name: btauto
-
- The tactic :tacn:`btauto` implements a reflexive solver for boolean
- tautologies. It solves goals of the form :g:`t = u` where `t` and `u` are
- constructed over the following grammar:
-
- .. prodn::
- btauto_term ::= @ident
- | true
- | false
- | orb @btauto_term @btauto_term
- | andb @btauto_term @btauto_term
- | xorb @btauto_term @btauto_term
- | negb @btauto_term
- | if @btauto_term then @btauto_term else @btauto_term
-
- Whenever the formula supplied is not a tautology, it also provides a
- counter-example.
-
- Internally, it uses a system very similar to the one of the ring
- tactic.
-
- Note that this tactic is only available after a ``Require Import Btauto``.
-
- .. exn:: Cannot recognize a boolean equality.
-
- The goal is not of the form :g:`t = u`. Especially note that :tacn:`btauto`
- doesn't introduce variables into the context on its own.
-
-.. tacv:: field
- field_simplify {* @term}
- field_simplify_eq
-
- The field tactic is built on the same ideas as ring: this is a
- reflexive tactic that solves or simplifies equations in a field
- structure. The main idea is to reduce a field expression (which is an
- extension of ring expressions with the inverse and division
- operations) to a fraction made of two polynomial expressions.
-
- Tactic :n:`field` is used to solve subgoals, whereas :n:`field_simplify {+ @term}`
- replaces the provided terms by their reduced fraction.
- :n:`field_simplify_eq` applies when the conclusion is an equation: it
- simplifies both hand sides and multiplies so as to cancel
- denominators. So it produces an equation without division nor inverse.
-
- All of these 3 tactics may generate a subgoal in order to prove that
- denominators are different from zero.
-
- See :ref:`Theringandfieldtacticfamilies` for more information on the tactic and how to
- declare new field structures. All declared field structures can be
- printed with the Print Fields command.
-
-.. example::
-
- .. coqtop:: reset all
-
- Require Import Reals.
- Goal forall x y:R,
- (x * y > 0)%R ->
- (x * (1 / x + x / (x + y)))%R =
- ((- 1 / y) * y * (- x * (x / (x + y)) - 1))%R.
-
- intros; field.
-
-.. seealso::
-
- File plugins/ring/RealField.v for an example of instantiation,
- theory theories/Reals for many examples of use of field.
-
-Non-logical tactics
-------------------------
-
-
-.. tacn:: cycle @integer
- :name: cycle
-
- Reorders the selected goals so that the first :n:`@integer` goals appear after the
- other selected goals.
- If :n:`@integer` is negative, it puts the last :n:`@integer` goals at the
- beginning of the list.
- The tactic is only useful with a goal selector, most commonly `all:`.
- Note that other selectors reorder goals; `1,3: cycle 1` is not equivalent
- to `all: cycle 1`. See :tacn:`… : … (goal selector)`.
-
-.. example::
-
- .. coqtop:: none reset
-
- Parameter P : nat -> Prop.
-
- .. coqtop:: all abort
-
- Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
- repeat split.
- all: cycle 2.
- all: cycle -3.
-
-.. tacn:: swap @integer @integer
- :name: swap
-
- Exchanges the position of the specified goals.
- Negative values for :n:`@integer` indicate counting goals
- backward from the end of the list of selected goals. Goals are indexed from 1.
- The tactic is only useful with a goal selector, most commonly `all:`.
- Note that other selectors reorder goals; `1,3: swap 1 3` is not equivalent
- to `all: swap 1 3`. See :tacn:`… : … (goal selector)`.
-
-.. example::
-
- .. coqtop:: all abort
-
- Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
- repeat split.
- all: swap 1 3.
- all: swap 1 -1.
-
-.. tacn:: revgoals
- :name: revgoals
-
- Reverses the order of the selected goals. The tactic is only useful with a goal
- selector, most commonly `all :`. Note that other selectors reorder goals;
- `1,3: revgoals` is not equivalent to `all: revgoals`. See :tacn:`… : … (goal selector)`.
-
- .. example::
-
- .. coqtop:: all abort
-
- Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
- repeat split.
- all: revgoals.
-
-.. tacn:: shelve
- :name: shelve
-
- This tactic moves all goals under focus to a shelf. While on the
- shelf, goals will not be focused on. They can be solved by
- unification, or they can be called back into focus with the command
- :cmd:`Unshelve`.
-
- .. tacv:: shelve_unifiable
- :name: shelve_unifiable
-
- Shelves only the goals under focus that are mentioned in other goals.
- Goals that appear in the type of other goals can be solved by unification.
-
- .. example::
-
- .. coqtop:: all abort
-
- Goal exists n, n=0.
- refine (ex_intro _ _ _).
- all: shelve_unifiable.
- reflexivity.
-
-.. cmd:: Unshelve
-
- This command moves all the goals on the shelf (see :tacn:`shelve`)
- from the shelf into focus, by appending them to the end of the current
- list of focused goals.
-
-.. tacn:: unshelve @tactic
- :name: unshelve
-
- Performs :n:`@tactic`, then unshelves existential variables added to the
- shelf by the execution of :n:`@tactic`, prepending them to the current goal.
-
-.. tacn:: give_up
- :name: give_up
-
- This tactic removes the focused goals from the proof. They are not
- solved, and cannot be solved later in the proof. As the goals are not
- solved, the proof cannot be closed.
-
- The ``give_up`` tactic can be used while editing a proof, to choose to
- write the proof script in a non-sequential order.
-
Delaying solving unification constraints
----------------------------------------
diff --git a/doc/sphinx/proof-engine/vernacular-commands.rst b/doc/sphinx/proof-engine/vernacular-commands.rst
index 301559d69d..dd0b12f8ec 100644
--- a/doc/sphinx/proof-engine/vernacular-commands.rst
+++ b/doc/sphinx/proof-engine/vernacular-commands.rst
@@ -990,11 +990,6 @@ described first.
has to check the conversion (see Section :ref:`conversion-rules`) of two distinct
applied constants.
- .. seealso::
-
- Sections :ref:`performingcomputations`, :ref:`tactics-automating`,
- :ref:`proof-editing-mode`
-
.. cmd:: Transparent {+ @reference }
This command accepts the :attr:`global` attribute. By default, the scope
@@ -1015,10 +1010,7 @@ described first.
There is no constant named :n:`@qualid` in the environment.
- .. seealso::
-
- Sections :ref:`performingcomputations`,
- :ref:`tactics-automating`, :ref:`proof-editing-mode`
+.. seealso:: :ref:`performingcomputations` and :ref:`proof-editing-mode`
.. _vernac-strategy:
diff --git a/doc/sphinx/proofs/automatic-tactics/auto.rst b/doc/sphinx/proofs/automatic-tactics/auto.rst
new file mode 100644
index 0000000000..cc8af976d2
--- /dev/null
+++ b/doc/sphinx/proofs/automatic-tactics/auto.rst
@@ -0,0 +1,672 @@
+.. _automation:
+
+=========================
+Programmable proof search
+=========================
+
+.. tacn:: auto
+ :name: auto
+
+ This tactic implements a Prolog-like resolution procedure to solve the
+ current goal. It first tries to solve the goal using the :tacn:`assumption`
+ tactic, then it reduces the goal to an atomic one using :tacn:`intros` and
+ introduces the newly generated hypotheses as hints. Then it looks at
+ the list of tactics associated to the head symbol of the goal and
+ tries to apply one of them (starting from the tactics with lower
+ cost). This process is recursively applied to the generated subgoals.
+
+ By default, :tacn:`auto` only uses the hypotheses of the current goal and
+ the hints of the database named ``core``.
+
+ .. warning::
+
+ :tacn:`auto` uses a weaker version of :tacn:`apply` that is closer to
+ :tacn:`simple apply` so it is expected that sometimes :tacn:`auto` will
+ fail even if applying manually one of the hints would succeed.
+
+ .. tacv:: auto @natural
+
+ Forces the search depth to be :token:`natural`. The maximal search depth
+ is 5 by default.
+
+ .. tacv:: auto with {+ @ident}
+
+ Uses the hint databases :n:`{+ @ident}` in addition to the database ``core``.
+
+ .. note::
+
+ Use the fake database `nocore` if you want to *not* use the `core`
+ database.
+
+ .. tacv:: auto with *
+
+ Uses all existing hint databases. Using this variant is highly discouraged
+ in finished scripts since it is both slower and less robust than the variant
+ where the required databases are explicitly listed.
+
+ .. seealso::
+ :ref:`The Hints Databases for auto and eauto <thehintsdatabasesforautoandeauto>` for the list of
+ pre-defined databases and the way to create or extend a database.
+
+ .. tacv:: auto using {+ @qualid__i} {? with {+ @ident } }
+
+ Uses lemmas :n:`@qualid__i` in addition to hints. If :n:`@qualid` is an
+ inductive type, it is the collection of its constructors which are added
+ as hints.
+
+ .. note::
+
+ The hints passed through the `using` clause are used in the same
+ way as if they were passed through a hint database. Consequently,
+ they use a weaker version of :tacn:`apply` and :n:`auto using @qualid`
+ may fail where :n:`apply @qualid` succeeds.
+
+ Given that this can be seen as counter-intuitive, it could be useful
+ to have an option to use full-blown :tacn:`apply` for lemmas passed
+ through the `using` clause. Contributions welcome!
+
+ .. tacv:: info_auto
+
+ Behaves like :tacn:`auto` but shows the tactics it uses to solve the goal. This
+ variant is very useful for getting a better understanding of automation, or
+ to know what lemmas/assumptions were used.
+
+ .. tacv:: debug auto
+ :name: debug auto
+
+ Behaves like :tacn:`auto` but shows the tactics it tries to solve the goal,
+ including failing paths.
+
+ .. tacv:: {? info_}auto {? @natural} {? using {+ @qualid}} {? with {+ @ident}}
+
+ This is the most general form, combining the various options.
+
+.. tacv:: trivial
+ :name: trivial
+
+ This tactic is a restriction of :tacn:`auto` that is not recursive
+ and tries only hints that cost `0`. Typically it solves trivial
+ equalities like :g:`X=X`.
+
+ .. tacv:: trivial with {+ @ident}
+ trivial with *
+ trivial using {+ @qualid}
+ debug trivial
+ info_trivial
+ {? info_}trivial {? using {+ @qualid}} {? with {+ @ident}}
+ :name: _; _; _; debug trivial; info_trivial; _
+ :undocumented:
+
+.. note::
+ :tacn:`auto` and :tacn:`trivial` either solve completely the goal or
+ else succeed without changing the goal. Use :g:`solve [ auto ]` and
+ :g:`solve [ trivial ]` if you would prefer these tactics to fail when
+ they do not manage to solve the goal.
+
+.. flag:: Info Auto
+ Debug Auto
+ Info Trivial
+ Debug Trivial
+
+ These flags enable printing of informative or debug information for
+ the :tacn:`auto` and :tacn:`trivial` tactics.
+
+.. tacn:: eauto
+ :name: eauto
+
+ This tactic generalizes :tacn:`auto`. While :tacn:`auto` does not try
+ resolution hints which would leave existential variables in the goal,
+ :tacn:`eauto` does try them (informally speaking, it internally uses a tactic
+ close to :tacn:`simple eapply` instead of a tactic close to :tacn:`simple apply`
+ in the case of :tacn:`auto`). As a consequence, :tacn:`eauto`
+ can solve such a goal:
+
+ .. example::
+
+ .. coqtop:: all
+
+ Hint Resolve ex_intro : core.
+ Goal forall P:nat -> Prop, P 0 -> exists n, P n.
+ eauto.
+
+ Note that ``ex_intro`` should be declared as a hint.
+
+
+ .. tacv:: {? info_}eauto {? @natural} {? using {+ @qualid}} {? with {+ @ident}}
+
+ The various options for :tacn:`eauto` are the same as for :tacn:`auto`.
+
+ :tacn:`eauto` also obeys the following flags:
+
+ .. flag:: Info Eauto
+ Debug Eauto
+ :undocumented:
+
+ .. seealso:: :ref:`The Hints Databases for auto and eauto <thehintsdatabasesforautoandeauto>`
+
+
+.. tacn:: autounfold with {+ @ident}
+ :name: autounfold
+
+ This tactic unfolds constants that were declared through a :cmd:`Hint Unfold`
+ in the given databases.
+
+.. tacv:: autounfold with {+ @ident} in @goal_occurrences
+
+ Performs the unfolding in the given clause (:token:`goal_occurrences`).
+
+.. tacv:: autounfold with *
+
+ Uses the unfold hints declared in all the hint databases.
+
+.. tacn:: autorewrite with {+ @ident}
+ :name: autorewrite
+
+ This tactic carries out rewritings according to the rewriting rule
+ bases :n:`{+ @ident}`.
+
+ Each rewriting rule from the base :n:`@ident` is applied to the main subgoal until
+ it fails. Once all the rules have been processed, if the main subgoal has
+ progressed (e.g., if it is distinct from the initial main goal) then the rules
+ of this base are processed again. If the main subgoal has not progressed then
+ the next base is processed. For the bases, the behavior is exactly similar to
+ the processing of the rewriting rules.
+
+ The rewriting rule bases are built with the :cmd:`Hint Rewrite`
+ command.
+
+.. warning::
+
+ This tactic may loop if you build non terminating rewriting systems.
+
+.. tacv:: autorewrite with {+ @ident} using @tactic
+
+ Performs, in the same way, all the rewritings of the bases :n:`{+ @ident}`
+ applying tactic to the main subgoal after each rewriting step.
+
+.. tacv:: autorewrite with {+ @ident} in @qualid
+
+ Performs all the rewritings in hypothesis :n:`@qualid`.
+
+.. tacv:: autorewrite with {+ @ident} in @qualid using @tactic
+
+ Performs all the rewritings in hypothesis :n:`@qualid` applying :n:`@tactic`
+ to the main subgoal after each rewriting step.
+
+.. tacv:: autorewrite with {+ @ident} in @goal_occurrences
+
+ Performs all the rewriting in the clause :n:`@goal_occurrences`.
+
+.. seealso::
+
+ :ref:`Hint-Rewrite <hintrewrite>` for feeding the database of lemmas used by
+ :tacn:`autorewrite` and :tacn:`autorewrite` for examples showing the use of this tactic.
+
+.. tacn:: easy
+ :name: easy
+
+ This tactic tries to solve the current goal by a number of standard closing steps.
+ In particular, it tries to close the current goal using the closing tactics
+ :tacn:`trivial`, :tacn:`reflexivity`, :tacn:`symmetry`, :tacn:`contradiction`
+ and :tacn:`inversion` of hypothesis.
+ If this fails, it tries introducing variables and splitting and-hypotheses,
+ using the closing tactics afterwards, and splitting the goal using
+ :tacn:`split` and recursing.
+
+ This tactic solves goals that belong to many common classes; in particular, many cases of
+ unsatisfiable hypotheses, and simple equality goals are usually solved by this tactic.
+
+.. tacv:: now @tactic
+ :name: now
+
+ Run :n:`@tactic` followed by :tacn:`easy`. This is a notation for :n:`@tactic; easy`.
+
+Controlling automation
+--------------------------
+
+.. _thehintsdatabasesforautoandeauto:
+
+The hints databases for auto and eauto
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The hints for :tacn:`auto` and :tacn:`eauto` are stored in databases. Each database
+maps head symbols to a list of hints.
+
+.. cmd:: Print Hint @ident
+
+ Use this command
+ to display the hints associated to the head symbol :n:`@ident`
+ (see :ref:`Print Hint <printhint>`). Each hint has a cost that is a nonnegative
+ integer, and an optional pattern. The hints with lower cost are tried first. A
+ hint is tried by :tacn:`auto` when the conclusion of the current goal matches its
+ pattern or when it has no pattern.
+
+Creating Hint databases
+```````````````````````
+
+One can optionally declare a hint database using the command
+:cmd:`Create HintDb`. If a hint is added to an unknown database, it will be
+automatically created.
+
+.. cmd:: Create HintDb @ident {? discriminated}
+
+ This command creates a new database named :n:`@ident`. The database is
+ implemented by a Discrimination Tree (DT) that serves as an index of
+ all the lemmas. The DT can use transparency information to decide if a
+ constant should be indexed or not
+ (c.f. :ref:`The hints databases for auto and eauto <thehintsdatabasesforautoandeauto>`),
+ making the retrieval more efficient. The legacy implementation (the default one
+ for new databases) uses the DT only on goals without existentials (i.e., :tacn:`auto`
+ goals), for non-Immediate hints and does not make use of transparency
+ hints, putting more work on the unification that is run after
+ retrieval (it keeps a list of the lemmas in case the DT is not used).
+ The new implementation enabled by the discriminated option makes use
+ of DTs in all cases and takes transparency information into account.
+ However, the order in which hints are retrieved from the DT may differ
+ from the order in which they were inserted, making this implementation
+ observationally different from the legacy one.
+
+.. cmd:: Hint @hint_definition : {+ @ident}
+
+ The general command to add a hint to some databases :n:`{+ @ident}`.
+
+ This command supports the :attr:`local`, :attr:`global` and :attr:`export`
+ locality attributes. When no locality is explictly given, the
+ command is :attr:`local` inside a section and :attr:`global` otherwise.
+
+ + :attr:`local` hints are never visible from other modules, even if they
+ require or import the current module. Inside a section, the :attr:`local`
+ attribute is useless since hints do not survive anyway to the closure of
+ sections.
+
+ + :attr:`export` are visible from other modules when they import the current
+ module. Requiring it is not enough. This attribute is only effective for
+ the :cmd:`Hint Resolve`, :cmd:`Hint Immediate`, :cmd:`Hint Unfold` and
+ :cmd:`Hint Extern` variants of the command.
+
+ + :attr:`global` hints are made available by merely requiring the current
+ module.
+
+ The various possible :production:`hint_definition`\s are given below.
+
+ .. cmdv:: Hint @hint_definition
+
+ No database name is given: the hint is registered in the ``core`` database.
+
+ .. deprecated:: 8.10
+
+ .. cmdv:: Hint Resolve @qualid {? | {? @natural} {? @pattern}} : @ident
+ :name: Hint Resolve
+
+ This command adds :n:`simple apply @qualid` to the hint list with the head
+ symbol of the type of :n:`@qualid`. The cost of that hint is the number of
+ subgoals generated by :n:`simple apply @qualid` or :n:`@natural` if specified. The
+ associated :n:`@pattern` is inferred from the conclusion of the type of
+ :n:`@qualid` or the given :n:`@pattern` if specified. In case the inferred type
+ of :n:`@qualid` does not start with a product the tactic added in the hint list
+ is :n:`exact @qualid`. In case this type can however be reduced to a type
+ starting with a product, the tactic :n:`simple apply @qualid` is also stored in
+ the hints list. If the inferred type of :n:`@qualid` contains a dependent
+ quantification on a variable which occurs only in the premisses of the type
+ and not in its conclusion, no instance could be inferred for the variable by
+ unification with the goal. In this case, the hint is added to the hint list
+ of :tacn:`eauto` instead of the hint list of auto and a warning is printed. A
+ typical example of a hint that is used only by :tacn:`eauto` is a transitivity
+ lemma.
+
+ .. exn:: @qualid cannot be used as a hint
+
+ The head symbol of the type of :n:`@qualid` is a bound variable
+ such that this tactic cannot be associated to a constant.
+
+ .. cmdv:: Hint Resolve {+ @qualid} : @ident
+
+ Adds each :n:`Hint Resolve @qualid`.
+
+ .. cmdv:: Hint Resolve -> @qualid : @ident
+
+ Adds the left-to-right implication of an equivalence as a hint (informally
+ the hint will be used as :n:`apply <- @qualid`, although as mentioned
+ before, the tactic actually used is a restricted version of
+ :tacn:`apply`).
+
+ .. cmdv:: Hint Resolve <- @qualid
+
+ Adds the right-to-left implication of an equivalence as a hint.
+
+ .. cmdv:: Hint Immediate @qualid : @ident
+ :name: Hint Immediate
+
+ This command adds :n:`simple apply @qualid; trivial` to the hint list associated
+ with the head symbol of the type of :n:`@ident` in the given database. This
+ tactic will fail if all the subgoals generated by :n:`simple apply @qualid` are
+ not solved immediately by the :tacn:`trivial` tactic (which only tries tactics
+ with cost 0).This command is useful for theorems such as the symmetry of
+ equality or :g:`n+1=m+1 -> n=m` that we may like to introduce with a limited
+ use in order to avoid useless proof-search. The cost of this tactic (which
+ never generates subgoals) is always 1, so that it is not used by :tacn:`trivial`
+ itself.
+
+ .. exn:: @qualid cannot be used as a hint
+ :undocumented:
+
+ .. cmdv:: Hint Immediate {+ @qualid} : @ident
+
+ Adds each :n:`Hint Immediate @qualid`.
+
+ .. cmdv:: Hint Constructors @qualid : @ident
+ :name: Hint Constructors
+
+ If :token:`qualid` is an inductive type, this command adds all its constructors as
+ hints of type ``Resolve``. Then, when the conclusion of current goal has the form
+ :n:`(@qualid ...)`, :tacn:`auto` will try to apply each constructor.
+
+ .. exn:: @qualid is not an inductive type
+ :undocumented:
+
+ .. cmdv:: Hint Constructors {+ @qualid} : @ident
+
+ Extends the previous command for several inductive types.
+
+ .. cmdv:: Hint Unfold @qualid : @ident
+ :name: Hint Unfold
+
+ This adds the tactic :n:`unfold @qualid` to the hint list that will only be
+ used when the head constant of the goal is :token:`qualid`.
+ Its cost is 4.
+
+ .. cmdv:: Hint Unfold {+ @qualid}
+
+ Extends the previous command for several defined constants.
+
+ .. cmdv:: Hint Transparent {+ @qualid} : @ident
+ Hint Opaque {+ @qualid} : @ident
+ :name: Hint Transparent; Hint Opaque
+
+ This adds transparency hints to the database, making :n:`@qualid`
+ transparent or opaque constants during resolution. This information is used
+ during unification of the goal with any lemma in the database and inside the
+ discrimination network to relax or constrain it in the case of discriminated
+ databases.
+
+ .. cmdv:: Hint Variables {| Transparent | Opaque } : @ident
+ Hint Constants {| Transparent | Opaque } : @ident
+ :name: Hint Variables; Hint Constants
+
+ This sets the transparency flag used during unification of
+ hints in the database for all constants or all variables,
+ overwriting the existing settings of opacity. It is advised
+ to use this just after a :cmd:`Create HintDb` command.
+
+ .. cmdv:: Hint Extern @natural {? @pattern} => @tactic : @ident
+ :name: Hint Extern
+
+ This hint type is to extend :tacn:`auto` with tactics other than :tacn:`apply` and
+ :tacn:`unfold`. For that, we must specify a cost, an optional :n:`@pattern` and a
+ :n:`@tactic` to execute.
+
+ .. example::
+
+ .. coqtop:: in
+
+ Hint Extern 4 (~(_ = _)) => discriminate : core.
+
+ Now, when the head of the goal is a disequality, ``auto`` will try
+ discriminate if it does not manage to solve the goal with hints with a
+ cost less than 4.
+
+ One can even use some sub-patterns of the pattern in
+ the tactic script. A sub-pattern is a question mark followed by an
+ identifier, like ``?X1`` or ``?X2``. Here is an example:
+
+ .. example::
+
+ .. coqtop:: reset all
+
+ Require Import List.
+ Hint Extern 5 ({?X1 = ?X2} + {?X1 <> ?X2}) => generalize X1, X2; decide equality : eqdec.
+ Goal forall a b:list (nat * nat), {a = b} + {a <> b}.
+ Info 1 auto with eqdec.
+
+ .. cmdv:: Hint Cut @regexp : @ident
+ :name: Hint Cut
+
+ .. warning::
+
+ These hints currently only apply to typeclass proof search and the
+ :tacn:`typeclasses eauto` tactic.
+
+ This command can be used to cut the proof-search tree according to a regular
+ expression matching paths to be cut. The grammar for regular expressions is
+ the following. Beware, there is no operator precedence during parsing, one can
+ check with :cmd:`Print HintDb` to verify the current cut expression:
+
+ .. prodn::
+ regexp ::= @ident (hint or instance identifier)
+ | _ (any hint)
+ | @regexp | @regexp (disjunction)
+ | @regexp @regexp (sequence)
+ | @regexp * (Kleene star)
+ | emp (empty)
+ | eps (epsilon)
+ | ( @regexp )
+
+ The `emp` regexp does not match any search path while `eps`
+ matches the empty path. During proof search, the path of
+ successive successful hints on a search branch is recorded, as a
+ list of identifiers for the hints (note that :cmd:`Hint Extern`\’s do not have
+ an associated identifier).
+ Before applying any hint :n:`@ident` the current path `p` extended with
+ :n:`@ident` is matched against the current cut expression `c` associated to
+ the hint database. If matching succeeds, the hint is *not* applied. The
+ semantics of :n:`Hint Cut @regexp` is to set the cut expression
+ to :n:`c | regexp`, the initial cut expression being `emp`.
+
+ .. cmdv:: Hint Mode @qualid {* {| + | ! | - } } : @ident
+ :name: Hint Mode
+
+ This sets an optional mode of use of the identifier :n:`@qualid`. When
+ proof-search faces a goal that ends in an application of :n:`@qualid` to
+ arguments :n:`@term ... @term`, the mode tells if the hints associated to
+ :n:`@qualid` can be applied or not. A mode specification is a list of n ``+``,
+ ``!`` or ``-`` items that specify if an argument of the identifier is to be
+ treated as an input (``+``), if its head only is an input (``!``) or an output
+ (``-``) of the identifier. For a mode to match a list of arguments, input
+ terms and input heads *must not* contain existential variables or be
+ existential variables respectively, while outputs can be any term. Multiple
+ modes can be declared for a single identifier, in that case only one mode
+ needs to match the arguments for the hints to be applied. The head of a term
+ is understood here as the applicative head, or the match or projection
+ scrutinee’s head, recursively, casts being ignored. :cmd:`Hint Mode` is
+ especially useful for typeclasses, when one does not want to support default
+ instances and avoid ambiguity in general. Setting a parameter of a class as an
+ input forces proof-search to be driven by that index of the class, with ``!``
+ giving more flexibility by allowing existentials to still appear deeper in the
+ index but not at its head.
+
+ .. note::
+
+ + One can use a :cmd:`Hint Extern` with no pattern to do
+ pattern matching on hypotheses using ``match goal with``
+ inside the tactic.
+
+ + If you want to add hints such as :cmd:`Hint Transparent`,
+ :cmd:`Hint Cut`, or :cmd:`Hint Mode`, for typeclass
+ resolution, do not forget to put them in the
+ ``typeclass_instances`` hint database.
+
+
+Hint databases defined in the |Coq| standard library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Several hint databases are defined in the |Coq| standard library. The
+actual content of a database is the collection of hints declared
+to belong to this database in each of the various modules currently
+loaded. Especially, requiring new modules may extend the database.
+At |Coq| startup, only the core database is nonempty and can be used.
+
+:core: This special database is automatically used by ``auto``, except when
+ pseudo-database ``nocore`` is given to ``auto``. The core database
+ contains only basic lemmas about negation, conjunction, and so on.
+ Most of the hints in this database come from the Init and Logic directories.
+
+:arith: This database contains all lemmas about Peano’s arithmetic proved in the
+ directories Init and Arith.
+
+:zarith: contains lemmas about binary signed integers from the
+ directories theories/ZArith. The database also contains
+ high-cost hints that call :tacn:`lia` on equations and
+ inequalities in ``nat`` or ``Z``.
+
+:bool: contains lemmas about booleans, mostly from directory theories/Bool.
+
+:datatypes: is for lemmas about lists, streams and so on that are mainly proved
+ in the Lists subdirectory.
+
+:sets: contains lemmas about sets and relations from the directories Sets and
+ Relations.
+
+:typeclass_instances: contains all the typeclass instances declared in the
+ environment, including those used for ``setoid_rewrite``,
+ from the Classes directory.
+
+:fset: internal database for the implementation of the ``FSets`` library.
+
+:ordered_type: lemmas about ordered types (as defined in the legacy ``OrderedType`` module),
+ mainly used in the ``FSets`` and ``FMaps`` libraries.
+
+You are advised not to put your own hints in the core database, but
+use one or several databases specific to your development.
+
+.. _removehints:
+
+.. cmd:: Remove Hints {+ @term} : {+ @ident}
+
+ This command removes the hints associated to terms :n:`{+ @term}` in databases
+ :n:`{+ @ident}`.
+
+.. _printhint:
+
+.. cmd:: Print Hint
+
+ This command displays all hints that apply to the current goal. It
+ fails if no proof is being edited, while the two variants can be used
+ at every moment.
+
+**Variants:**
+
+
+.. cmd:: Print Hint @ident
+
+ This command displays only tactics associated with :n:`@ident` in the hints
+ list. This is independent of the goal being edited, so this command will not
+ fail if no goal is being edited.
+
+.. cmd:: Print Hint *
+
+ This command displays all declared hints.
+
+.. cmd:: Print HintDb @ident
+
+ This command displays all hints from database :n:`@ident`.
+
+.. _hintrewrite:
+
+.. cmd:: Hint Rewrite {+ @term} : {+ @ident}
+
+ This vernacular command adds the terms :n:`{+ @term}` (their types must be
+ equalities) in the rewriting bases :n:`{+ @ident}` with the default orientation
+ (left to right). Notice that the rewriting bases are distinct from the :tacn:`auto`
+ hint bases and that :tacn:`auto` does not take them into account.
+
+ This command is synchronous with the section mechanism (see :ref:`section-mechanism`):
+ when closing a section, all aliases created by ``Hint Rewrite`` in that
+ section are lost. Conversely, when loading a module, all ``Hint Rewrite``
+ declarations at the global level of that module are loaded.
+
+**Variants:**
+
+.. cmd:: Hint Rewrite -> {+ @term} : {+ @ident}
+
+ This is strictly equivalent to the command above (we only make explicit the
+ orientation which otherwise defaults to ->).
+
+.. cmd:: Hint Rewrite <- {+ @term} : {+ @ident}
+
+ Adds the rewriting rules :n:`{+ @term}` with a right-to-left orientation in
+ the bases :n:`{+ @ident}`.
+
+.. cmd:: Hint Rewrite {? {| -> | <- } } {+ @one_term } {? using @ltac_expr } {? : {* @ident } }
+
+ When the rewriting rules :n:`{+ @term}` in :n:`{+ @ident}` will be used, the
+ tactic ``tactic`` will be applied to the generated subgoals, the main subgoal
+ excluded.
+
+.. cmd:: Print Rewrite HintDb @ident
+
+ This command displays all rewrite hints contained in :n:`@ident`.
+
+Hint locality
+~~~~~~~~~~~~~
+
+Hints provided by the ``Hint`` commands are erased when closing a section.
+Conversely, all hints of a module ``A`` that are not defined inside a
+section (and not defined with option ``Local``) become available when the
+module ``A`` is required (using e.g. ``Require A.``).
+
+As of today, hints only have a binary behavior regarding locality, as
+described above: either they disappear at the end of a section scope,
+or they remain global forever. This causes a scalability issue,
+because hints coming from an unrelated part of the code may badly
+influence another development. It can be mitigated to some extent
+thanks to the :cmd:`Remove Hints` command,
+but this is a mere workaround and has some limitations (for instance, external
+hints cannot be removed).
+
+A proper way to fix this issue is to bind the hints to their module scope, as
+for most of the other objects |Coq| uses. Hints should only be made available when
+the module they are defined in is imported, not just required. It is very
+difficult to change the historical behavior, as it would break a lot of scripts.
+We propose a smooth transitional path by providing the :opt:`Loose Hint Behavior`
+option which accepts three flags allowing for a fine-grained handling of
+non-imported hints.
+
+.. opt:: Loose Hint Behavior {| "Lax" | "Warn" | "Strict" }
+ :name: Loose Hint Behavior
+
+ This option accepts three values, which control the behavior of hints w.r.t.
+ :cmd:`Import`:
+
+ - "Lax": this is the default, and corresponds to the historical behavior,
+ that is, hints defined outside of a section have a global scope.
+
+ - "Warn": outputs a warning when a non-imported hint is used. Note that this
+ is an over-approximation, because a hint may be triggered by a run that
+ will eventually fail and backtrack, resulting in the hint not being
+ actually useful for the proof.
+
+ - "Strict": changes the behavior of an unloaded hint to a immediate fail
+ tactic, allowing to emulate an import-scoped hint mechanism.
+
+.. _tactics-implicit-automation:
+
+Setting implicit automation tactics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. cmd:: Proof with @tactic
+
+ This command may be used to start a proof. It defines a default tactic
+ to be used each time a tactic command ``tactic``:sub:`1` is ended by ``...``.
+ In this case the tactic command typed by the user is equivalent to
+ ``tactic``:sub:`1` ``;tactic``.
+
+ .. seealso:: :cmd:`Proof` in :ref:`proof-editing-mode`.
+
+
+ .. cmdv:: Proof with @tactic using {+ @ident}
+
+ Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode`
+
+ .. cmdv:: Proof using {+ @ident} with @tactic
+
+ Combines in a single line ``Proof with`` and ``Proof using``, see :ref:`proof-editing-mode`
diff --git a/doc/sphinx/proofs/automatic-tactics/index.rst b/doc/sphinx/proofs/automatic-tactics/index.rst
index a219770c69..c3712b109d 100644
--- a/doc/sphinx/proofs/automatic-tactics/index.rst
+++ b/doc/sphinx/proofs/automatic-tactics/index.rst
@@ -1,20 +1,22 @@
.. _automatic-tactics:
=====================================================
-Built-in decision procedures and programmable tactics
+Automatic solvers and programmable tactics
=====================================================
Some tactics are largely automated and are able to solve complex
-goals. This chapter presents both some decision procedures that can
-be used to solve some specific categories of goals, and some
-programmable tactics, that the user can instrument to handle some
+goals. This chapter presents both built-in solvers that can
+be used on specific categories of goals and
+programmable tactics that the user can instrument to handle
complex goals in new domains.
.. toctree::
:maxdepth: 1
+ logic
../../addendum/omega
../../addendum/micromega
../../addendum/ring
../../addendum/nsatz
+ auto
../../addendum/generalized-rewriting
diff --git a/doc/sphinx/proofs/automatic-tactics/logic.rst b/doc/sphinx/proofs/automatic-tactics/logic.rst
new file mode 100644
index 0000000000..acf64ae437
--- /dev/null
+++ b/doc/sphinx/proofs/automatic-tactics/logic.rst
@@ -0,0 +1,294 @@
+.. _decisionprocedures:
+
+==============================
+Solvers for logic and equality
+==============================
+
+.. tacn:: tauto
+ :name: tauto
+
+ This tactic implements a decision procedure for intuitionistic propositional
+ calculus based on the contraction-free sequent calculi LJT* of Roy Dyckhoff
+ :cite:`Dyc92`. Note that :tacn:`tauto` succeeds on any instance of an
+ intuitionistic tautological proposition. :tacn:`tauto` unfolds negations and
+ logical equivalence but does not unfold any other definition.
+
+.. example::
+
+ The following goal can be proved by :tacn:`tauto` whereas :tacn:`auto` would
+ fail:
+
+ .. coqtop:: reset all
+
+ Goal forall (x:nat) (P:nat -> Prop), x = 0 \/ P x -> x <> 0 -> P x.
+ intros.
+ tauto.
+
+Moreover, if it has nothing else to do, :tacn:`tauto` performs introductions.
+Therefore, the use of :tacn:`intros` in the previous proof is unnecessary.
+:tacn:`tauto` can for instance for:
+
+.. example::
+
+ .. coqtop:: reset all
+
+ Goal forall (A:Prop) (P:nat -> Prop), A \/ (forall x:nat, ~ A -> P x) -> forall x:nat, ~ A -> P x.
+ tauto.
+
+.. note::
+ In contrast, :tacn:`tauto` cannot solve the following goal
+ :g:`Goal forall (A:Prop) (P:nat -> Prop), A \/ (forall x:nat, ~ A -> P x) ->`
+ :g:`forall x:nat, ~ ~ (A \/ P x).`
+ because :g:`(forall x:nat, ~ A -> P x)` cannot be treated as atomic and
+ an instantiation of `x` is necessary.
+
+.. tacv:: dtauto
+ :name: dtauto
+
+ While :tacn:`tauto` recognizes inductively defined connectives isomorphic to
+ the standard connectives ``and``, ``prod``, ``or``, ``sum``, ``False``,
+ ``Empty_set``, ``unit``, ``True``, :tacn:`dtauto` also recognizes all inductive
+ types with one constructor and no indices, i.e. record-style connectives.
+
+.. tacn:: intuition @tactic
+ :name: intuition
+
+ The tactic :tacn:`intuition` takes advantage of the search-tree built by the
+ decision procedure involved in the tactic :tacn:`tauto`. It uses this
+ information to generate a set of subgoals equivalent to the original one (but
+ simpler than it) and applies the tactic :n:`@tactic` to them :cite:`Mun94`. If
+ this tactic fails on some goals then :tacn:`intuition` fails. In fact,
+ :tacn:`tauto` is simply :g:`intuition fail`.
+
+ .. example::
+
+ For instance, the tactic :g:`intuition auto` applied to the goal::
+
+ (forall (x:nat), P x) /\ B -> (forall (y:nat), P y) /\ P O \/ B /\ P O
+
+ internally replaces it by the equivalent one::
+
+ (forall (x:nat), P x), B |- P O
+
+ and then uses :tacn:`auto` which completes the proof.
+
+Originally due to César Muñoz, these tactics (:tacn:`tauto` and
+:tacn:`intuition`) have been completely re-engineered by David Delahaye using
+mainly the tactic language (see :ref:`ltac`). The code is
+now much shorter and a significant increase in performance has been noticed.
+The general behavior with respect to dependent types, unfolding and
+introductions has slightly changed to get clearer semantics. This may lead to
+some incompatibilities.
+
+.. tacv:: intuition
+
+ Is equivalent to :g:`intuition auto with *`.
+
+.. tacv:: dintuition
+ :name: dintuition
+
+ While :tacn:`intuition` recognizes inductively defined connectives
+ isomorphic to the standard connectives ``and``, ``prod``, ``or``, ``sum``, ``False``,
+ ``Empty_set``, ``unit``, ``True``, :tacn:`dintuition` also recognizes all inductive
+ types with one constructor and no indices, i.e. record-style connectives.
+
+.. flag:: Intuition Negation Unfolding
+
+ Controls whether :tacn:`intuition` unfolds inner negations which do not need
+ to be unfolded. This flag is on by default.
+
+.. tacn:: rtauto
+ :name: rtauto
+
+ The :tacn:`rtauto` tactic solves propositional tautologies similarly to what
+ :tacn:`tauto` does. The main difference is that the proof term is built using a
+ reflection scheme applied to a sequent calculus proof of the goal. The search
+ procedure is also implemented using a different technique.
+
+ Users should be aware that this difference may result in faster proof-search
+ but slower proof-checking, and :tacn:`rtauto` might not solve goals that
+ :tacn:`tauto` would be able to solve (e.g. goals involving universal
+ quantifiers).
+
+ Note that this tactic is only available after a ``Require Import Rtauto``.
+
+.. tacn:: firstorder
+ :name: firstorder
+
+ The tactic :tacn:`firstorder` is an experimental extension of :tacn:`tauto` to
+ first- order reasoning, written by Pierre Corbineau. It is not restricted to
+ usual logical connectives but instead may reason about any first-order class
+ inductive definition.
+
+.. opt:: Firstorder Solver @tactic
+ :name: Firstorder Solver
+
+ The default tactic used by :tacn:`firstorder` when no rule applies is
+ :g:`auto with core`, it can be reset locally or globally using this option.
+
+ .. cmd:: Print Firstorder Solver
+
+ Prints the default tactic used by :tacn:`firstorder` when no rule applies.
+
+.. tacv:: firstorder @tactic
+
+ Tries to solve the goal with :n:`@tactic` when no logical rule may apply.
+
+.. tacv:: firstorder using {+ @qualid}
+
+ .. deprecated:: 8.3
+
+ Use the syntax below instead (with commas).
+
+.. tacv:: firstorder using {+, @qualid}
+
+ Adds lemmas :n:`{+, @qualid}` to the proof-search environment. If :n:`@qualid`
+ refers to an inductive type, it is the collection of its constructors which are
+ added to the proof-search environment.
+
+.. tacv:: firstorder with {+ @ident}
+
+ Adds lemmas from :tacn:`auto` hint bases :n:`{+ @ident}` to the proof-search
+ environment.
+
+.. tacv:: firstorder @tactic using {+, @qualid} with {+ @ident}
+
+ This combines the effects of the different variants of :tacn:`firstorder`.
+
+.. opt:: Firstorder Depth @natural
+ :name: Firstorder Depth
+
+ This option controls the proof-search depth bound.
+
+.. tacn:: congruence
+ :name: congruence
+
+ The tactic :tacn:`congruence`, by Pierre Corbineau, implements the standard
+ Nelson and Oppen congruence closure algorithm, which is a decision procedure
+ for ground equalities with uninterpreted symbols. It also includes
+ constructor theory (see :tacn:`injection` and :tacn:`discriminate`). If the goal
+ is a non-quantified equality, congruence tries to prove it with non-quantified
+ equalities in the context. Otherwise it tries to infer a discriminable equality
+ from those in the context. Alternatively, congruence tries to prove that a
+ hypothesis is equal to the goal or to the negation of another hypothesis.
+
+ :tacn:`congruence` is also able to take advantage of hypotheses stating
+ quantified equalities, but you have to provide a bound for the number of extra
+ equalities generated that way. Please note that one of the sides of the
+ equality must contain all the quantified variables in order for congruence to
+ match against it.
+
+.. example::
+
+ .. coqtop:: reset all
+
+ Theorem T (A:Type) (f:A -> A) (g: A -> A -> A) a b: a=(f a) -> (g b (f a))=(f (f a)) -> (g a b)=(f (g b a)) -> (g a b)=a.
+ intros.
+ congruence.
+ Qed.
+
+ Theorem inj (A:Type) (f:A -> A * A) (a c d: A) : f = pair a -> Some (f c) = Some (f d) -> c=d.
+ intros.
+ congruence.
+ Qed.
+
+.. tacv:: congruence @natural
+
+ Tries to add at most :token:`natural` instances of hypotheses stating quantified equalities
+ to the problem in order to solve it. A bigger value of :token:`natural` does not make
+ success slower, only failure. You might consider adding some lemmas as
+ hypotheses using assert in order for :tacn:`congruence` to use them.
+
+.. tacv:: congruence with {+ @term}
+ :name: congruence with
+
+ Adds :n:`{+ @term}` to the pool of terms used by :tacn:`congruence`. This helps
+ in case you have partially applied constructors in your goal.
+
+.. exn:: I don’t know how to handle dependent equality.
+
+ The decision procedure managed to find a proof of the goal or of a
+ discriminable equality but this proof could not be built in |Coq| because of
+ dependently-typed functions.
+
+.. exn:: Goal is solvable by congruence but some arguments are missing. Try congruence with {+ @term}, replacing metavariables by arbitrary terms.
+
+ The decision procedure could solve the goal with the provision that additional
+ arguments are supplied for some partially applied constructors. Any term of an
+ appropriate type will allow the tactic to successfully solve the goal. Those
+ additional arguments can be given to congruence by filling in the holes in the
+ terms given in the error message, using the :tacn:`congruence with` variant described above.
+
+.. flag:: Congruence Verbose
+
+ This flag makes :tacn:`congruence` print debug information.
+
+.. tacn:: btauto
+ :name: btauto
+
+ The tactic :tacn:`btauto` implements a reflexive solver for boolean
+ tautologies. It solves goals of the form :g:`t = u` where `t` and `u` are
+ constructed over the following grammar:
+
+ .. prodn::
+ btauto_term ::= @ident
+ | true
+ | false
+ | orb @btauto_term @btauto_term
+ | andb @btauto_term @btauto_term
+ | xorb @btauto_term @btauto_term
+ | negb @btauto_term
+ | if @btauto_term then @btauto_term else @btauto_term
+
+ Whenever the formula supplied is not a tautology, it also provides a
+ counter-example.
+
+ Internally, it uses a system very similar to the one of the ring
+ tactic.
+
+ Note that this tactic is only available after a ``Require Import Btauto``.
+
+ .. exn:: Cannot recognize a boolean equality.
+
+ The goal is not of the form :g:`t = u`. Especially note that :tacn:`btauto`
+ doesn't introduce variables into the context on its own.
+
+.. tacv:: field
+ field_simplify {* @term}
+ field_simplify_eq
+
+ The field tactic is built on the same ideas as ring: this is a
+ reflexive tactic that solves or simplifies equations in a field
+ structure. The main idea is to reduce a field expression (which is an
+ extension of ring expressions with the inverse and division
+ operations) to a fraction made of two polynomial expressions.
+
+ Tactic :n:`field` is used to solve subgoals, whereas :n:`field_simplify {+ @term}`
+ replaces the provided terms by their reduced fraction.
+ :n:`field_simplify_eq` applies when the conclusion is an equation: it
+ simplifies both hand sides and multiplies so as to cancel
+ denominators. So it produces an equation without division nor inverse.
+
+ All of these 3 tactics may generate a subgoal in order to prove that
+ denominators are different from zero.
+
+ See :ref:`Theringandfieldtacticfamilies` for more information on the tactic and how to
+ declare new field structures. All declared field structures can be
+ printed with the Print Fields command.
+
+.. example::
+
+ .. coqtop:: reset all
+
+ Require Import Reals.
+ Goal forall x y:R,
+ (x * y > 0)%R ->
+ (x * (1 / x + x / (x + y)))%R =
+ ((- 1 / y) * y * (- x * (x / (x + y)) - 1))%R.
+
+ intros; field.
+
+.. seealso::
+
+ File plugins/ring/RealField.v for an example of instantiation,
+ theory theories/Reals for many examples of use of field.
diff --git a/doc/sphinx/proofs/writing-proofs/index.rst b/doc/sphinx/proofs/writing-proofs/index.rst
index 3f5526dba8..1c7fd050f1 100644
--- a/doc/sphinx/proofs/writing-proofs/index.rst
+++ b/doc/sphinx/proofs/writing-proofs/index.rst
@@ -1,8 +1,8 @@
.. _writing-proofs:
-==============
-Writing proofs
-==============
+===================
+Basic proof writing
+===================
|Coq| is an interactive theorem prover, or proof assistant, which means
that proofs can be constructed interactively through a dialog between
@@ -27,8 +27,9 @@ flavors of tactics, including the SSReflect proof language.
.. toctree::
:maxdepth: 1
- ../../proof-engine/proof-handling
+ proof-mode
../../proof-engine/tactics
+ rewriting
../../proof-engine/ssreflect-proof-language
../../proof-engine/detailed-tactic-examples
../../user-extensions/proof-schemes
diff --git a/doc/sphinx/proofs/writing-proofs/proof-mode.rst b/doc/sphinx/proofs/writing-proofs/proof-mode.rst
new file mode 100644
index 0000000000..b74c9d3a23
--- /dev/null
+++ b/doc/sphinx/proofs/writing-proofs/proof-mode.rst
@@ -0,0 +1,1037 @@
+.. _proofhandling:
+
+-------------------
+ Proof handling
+-------------------
+
+In |Coq|’s proof editing mode all top-level commands documented in
+Chapter :ref:`vernacularcommands` remain available and the user has access to specialized
+commands dealing with proof development pragmas documented in this
+section. They can also use some other specialized commands called
+*tactics*. They are the very tools allowing the user to deal with
+logical reasoning. They are documented in Chapter :ref:`tactics`.
+
+|Coq| user interfaces usually have a way of marking whether the user has
+switched to proof editing mode. For instance, in coqtop the prompt ``Coq <``   is changed into
+:n:`@ident <`   where :token:`ident` is the declared name of the theorem currently edited.
+
+At each stage of a proof development, one has a list of goals to
+prove. Initially, the list consists only in the theorem itself. After
+having applied some tactics, the list of goals contains the subgoals
+generated by the tactics.
+
+To each subgoal is associated a number of hypotheses called the *local context*
+of the goal. Initially, the local context contains the local variables and
+hypotheses of the current section (see Section :ref:`gallina-assumptions`) and
+the local variables and hypotheses of the theorem statement. It is enriched by
+the use of certain tactics (see e.g. :tacn:`intro`).
+
+When a proof is completed, the message ``Proof completed`` is displayed.
+One can then register this proof as a defined constant in the
+environment. Because there exists a correspondence between proofs and
+terms of λ-calculus, known as the *Curry-Howard isomorphism*
+:cite:`How80,Bar81,Gir89,H89`, |Coq| stores proofs as terms of |Cic|. Those
+terms are called *proof terms*.
+
+
+.. exn:: No focused proof.
+
+ |Coq| raises this error message when one attempts to use a proof editing command
+ out of the proof editing mode.
+
+.. _proof-editing-mode:
+
+Entering and leaving proof editing mode
+---------------------------------------
+
+The proof editing mode is entered by asserting a statement, which typically is
+the assertion of a theorem using an assertion command like :cmd:`Theorem`. The
+list of assertion commands is given in :ref:`Assertions`. The command
+:cmd:`Goal` can also be used.
+
+.. cmd:: Goal @type
+
+ This is intended for quick assertion of statements, without knowing in
+ advance which name to give to the assertion, typically for quick
+ testing of the provability of a statement. If the proof of the
+ statement is eventually completed and validated, the statement is then
+ bound to the name ``Unnamed_thm`` (or a variant of this name not already
+ used for another statement).
+
+.. cmd:: Qed
+
+ This command is available in interactive editing proof mode when the
+ proof is completed. Then :cmd:`Qed` extracts a proof term from the proof
+ script, switches back to |Coq| top-level and attaches the extracted
+ proof term to the declared name of the original goal. The name is
+ added to the environment as an opaque constant.
+
+ .. exn:: Attempt to save an incomplete proof.
+ :undocumented:
+
+ .. note::
+
+ Sometimes an error occurs when building the proof term, because
+ tactics do not enforce completely the term construction
+ constraints.
+
+ The user should also be aware of the fact that since the
+ proof term is completely rechecked at this point, one may have to wait
+ a while when the proof is large. In some exceptional cases one may
+ even incur a memory overflow.
+
+.. cmd:: Save @ident
+ :name: Save
+
+ Saves a completed proof with the name :token:`ident`, which
+ overrides any name provided by the :cmd:`Theorem` command or
+ its variants.
+
+.. cmd:: Defined {? @ident }
+
+ Similar to :cmd:`Qed` and :cmd:`Save`, except the proof is made *transparent*, which means
+ that its content can be explicitly used for type checking and that it can be
+ unfolded in conversion tactics (see :ref:`performingcomputations`,
+ :cmd:`Opaque`, :cmd:`Transparent`). If :token:`ident` is specified,
+ the proof is defined with the given name, which overrides any name
+ provided by the :cmd:`Theorem` command or its variants.
+
+.. cmd:: Admitted
+
+ This command is available in interactive editing mode to give up
+ the current proof and declare the initial goal as an axiom.
+
+.. cmd:: Abort {? {| All | @ident } }
+
+ Cancels the current proof development, switching back to
+ the previous proof development, or to the |Coq| toplevel if no other
+ proof was being edited.
+
+ :n:`@ident`
+ Aborts editing the proof named :n:`@ident` for use when you have
+ nested proofs. See also :flag:`Nested Proofs Allowed`.
+
+ :n:`All`
+ Aborts all current proofs.
+
+ .. exn:: No focused proof (No proof-editing in progress).
+ :undocumented:
+
+.. cmd:: Proof @term
+ :name: Proof `term`
+
+ This command applies in proof editing mode. It is equivalent to
+ :n:`exact @term. Qed.`
+ That is, you have to give the full proof in one gulp, as a
+ proof term (see Section :ref:`applyingtheorems`).
+
+ .. warning::
+
+ Use of this command is discouraged. In particular, it
+ doesn't work in Proof General because it must
+ immediately follow the command that opened proof mode, but
+ Proof General inserts :cmd:`Unset` :flag:`Silent` before it (see
+ `Proof General issue #498
+ <https://github.com/ProofGeneral/PG/issues/498>`_).
+
+.. cmd:: Proof
+
+ Is a no-op which is useful to delimit the sequence of tactic commands
+ which start a proof, after a :cmd:`Theorem` command. It is a good practice to
+ use :cmd:`Proof` as an opening parenthesis, closed in the script with a
+ closing :cmd:`Qed`.
+
+ .. seealso:: :cmd:`Proof with`
+
+.. cmd:: Proof using @section_var_expr {? with @ltac_expr }
+
+ .. insertprodn section_var_expr starred_ident_ref
+
+ .. prodn::
+ section_var_expr ::= {* @starred_ident_ref }
+ | {? - } @section_var_expr50
+ section_var_expr50 ::= @section_var_expr0 - @section_var_expr0
+ | @section_var_expr0 + @section_var_expr0
+ | @section_var_expr0
+ section_var_expr0 ::= @starred_ident_ref
+ | ( @section_var_expr ) {? * }
+ starred_ident_ref ::= @ident {? * }
+ | Type {? * }
+ | All
+
+ Opens proof editing mode, declaring the set of
+ section variables (see :ref:`gallina-assumptions`) used by the proof.
+ At :cmd:`Qed` time, the
+ system verifies that the set of section variables used in
+ the proof is a subset of the declared one.
+
+ The set of declared variables is closed under type dependency. For
+ example, if ``T`` is a variable and ``a`` is a variable of type
+ ``T``, then the commands ``Proof using a`` and ``Proof using T a``
+ are equivalent.
+
+ The set of declared variables always includes the variables used by
+ the statement. In other words ``Proof using e`` is equivalent to
+ ``Proof using Type + e`` for any declaration expression ``e``.
+
+ :n:`- @section_var_expr50`
+ Use all section variables except those specified by :n:`@section_var_expr50`
+
+ :n:`@section_var_expr0 + @section_var_expr0`
+ Use section variables from the union of both collections.
+ See :ref:`nameaset` to see how to form a named collection.
+
+ :n:`@section_var_expr0 - @section_var_expr0`
+ Use section variables which are in the first collection but not in the
+ second one.
+
+ :n:`{? * }`
+ Use the transitive closure of the specified collection.
+
+ :n:`Type`
+ Use only section variables occurring in the statement. Specifying :n:`*`
+ uses the forward transitive closure of all the section variables occurring
+ in the statement. For example, if the variable ``H`` has type ``p < 5`` then
+ ``H`` is in ``p*`` since ``p`` occurs in the type of ``H``.
+
+ :n:`All`
+ Use all section variables.
+
+ .. seealso:: :ref:`tactics-implicit-automation`
+
+.. attr:: using
+
+ This attribute can be applied to the :cmd:`Definition`, :cmd:`Example`,
+ :cmd:`Fixpoint` and :cmd:`CoFixpoint` commands as well as to :cmd:`Lemma` and
+ its variants. It takes
+ a :n:`@section_var_expr`, in quotes, as its value. This is equivalent to
+ specifying the same :n:`@section_var_expr` in
+ :cmd:`Proof using`.
+
+ .. example::
+
+ .. coqtop:: all
+
+ Section Test.
+ Variable n : nat.
+ Hypothesis Hn : n <> 0.
+
+ #[using="Hn"]
+ Lemma example : 0 < n.
+
+ .. coqtop:: in
+
+ Abort.
+ End Test.
+
+
+Proof using options
+```````````````````
+
+The following options modify the behavior of ``Proof using``.
+
+
+.. opt:: Default Proof Using "@section_var_expr"
+ :name: Default Proof Using
+
+ Use :n:`@section_var_expr` as the default ``Proof using`` value. E.g. ``Set Default
+ Proof Using "a b"`` will complete all ``Proof`` commands not followed by a
+ ``using`` part with ``using a b``.
+
+
+.. flag:: Suggest Proof Using
+
+ When :cmd:`Qed` is performed, suggest a ``using`` annotation if the user did not
+ provide one.
+
+.. _`nameaset`:
+
+Name a set of section hypotheses for ``Proof using``
+````````````````````````````````````````````````````
+
+.. cmd:: Collection @ident := @section_var_expr
+
+ This can be used to name a set of section
+ hypotheses, with the purpose of making ``Proof using`` annotations more
+ compact.
+
+ .. example::
+
+ Define the collection named ``Some`` containing ``x``, ``y`` and ``z``::
+
+ Collection Some := x y z.
+
+ Define the collection named ``Fewer`` containing only ``x`` and ``y``::
+
+ Collection Fewer := Some - z
+
+ Define the collection named ``Many`` containing the set union or set
+ difference of ``Fewer`` and ``Some``::
+
+ Collection Many := Fewer + Some
+ Collection Many := Fewer - Some
+
+ Define the collection named ``Many`` containing the set difference of
+ ``Fewer`` and the unnamed collection ``x y``::
+
+ Collection Many := Fewer - (x y)
+
+
+
+.. cmd:: Existential @natural {? : @type } := @term
+
+ This command instantiates an existential variable. :token:`natural` is an index in
+ the list of uninstantiated existential variables displayed by :cmd:`Show Existentials`.
+
+ This command is intended to be used to instantiate existential
+ variables when the proof is completed but some uninstantiated
+ existential variables remain. To instantiate existential variables
+ during proof edition, you should use the tactic :tacn:`instantiate`.
+
+.. cmd:: Grab Existential Variables
+
+ This command can be run when a proof has no more goal to be solved but
+ has remaining uninstantiated existential variables. It takes every
+ uninstantiated existential variable and turns it into a goal.
+
+Proof modes
+```````````
+
+When entering proof mode through commands such as :cmd:`Goal` and :cmd:`Proof`,
+|Coq| picks by default the |Ltac| mode. Nonetheless, there exist other proof modes
+shipped in the standard |Coq| installation, and furthermore some plugins define
+their own proof modes. The default proof mode used when opening a proof can
+be changed using the following option.
+
+.. opt:: Default Proof Mode @string
+
+ Select the proof mode to use when starting a proof. Depending on the proof
+ mode, various syntactic constructs are allowed when writing an interactive
+ proof. All proof modes support vernacular commands; the proof mode determines
+ which tactic language and set of tactic definitions are available. The
+ possible option values are:
+
+ `"Classic"`
+ Activates the |Ltac| language and the tactics with the syntax documented
+ in this manual.
+ Some tactics are not available until the associated plugin is loaded,
+ such as `SSR` or `micromega`.
+ This proof mode is set when the :term:`prelude` is loaded.
+
+ `"Noedit"`
+ No tactic
+ language is activated at all. This is the default when the :term:`prelude`
+ is not loaded, e.g. through the `-noinit` option for `coqc`.
+
+ `"Ltac2"`
+ Activates the Ltac2 language and the Ltac2-specific variants of the documented
+ tactics.
+ This value is only available after :cmd:`Requiring <Require>` Ltac2.
+ :cmd:`Importing <Import>` Ltac2 sets this mode.
+
+ Some external plugins also define their own proof mode, which can be
+ activated with this command.
+
+Navigation in the proof tree
+--------------------------------
+
+.. cmd:: Undo {? {? To } @natural }
+
+ Cancels the effect of the last :token:`natural` commands or tactics.
+ The :n:`To @natural` form goes back to the specified state number.
+ If :token:`natural` is not specified, the command goes back one command or tactic.
+
+.. cmd:: Restart
+
+ Restores the proof editing process to the original goal.
+
+ .. exn:: No focused proof to restart.
+ :undocumented:
+
+.. cmd:: Focus {? @natural }
+
+ Focuses the attention on the first subgoal to prove or, if :token:`natural` is
+ specified, the :token:`natural`\-th. The
+ printing of the other subgoals is suspended until the focused subgoal
+ is solved or unfocused.
+
+ .. deprecated:: 8.8
+
+ Prefer the use of bullets or focusing brackets with a goal selector (see below).
+
+.. cmd:: Unfocus
+
+ This command restores to focus the goal that were suspended by the
+ last :cmd:`Focus` command.
+
+ .. deprecated:: 8.8
+
+.. cmd:: Unfocused
+
+ Succeeds if the proof is fully unfocused, fails if there are some
+ goals out of focus.
+
+.. _curly-braces:
+
+.. index:: {
+ }
+
+.. todo: :name: "{"; "}" doesn't work, nor does :name: left curly bracket; right curly bracket,
+ hence the verbose names
+
+.. tacn:: {? {| @natural | [ @ident ] } : } %{
+ %}
+
+ .. todo
+ See https://github.com/coq/coq/issues/12004 and
+ https://github.com/coq/coq/issues/12825.
+
+ ``{`` (without a terminating period) focuses on the first
+ goal. The subproof can only be
+ unfocused when it has been fully solved (*i.e.*, when there is no
+ focused goal left). Unfocusing is then handled by ``}`` (again, without a
+ terminating period). See also an example in the next section.
+
+ Note that when a focused goal is proved a message is displayed
+ together with a suggestion about the right bullet or ``}`` to unfocus it
+ or focus the next one.
+
+ :n:`@natural:`
+ Focuses on the :token:`natural`\-th subgoal to prove.
+
+ :n:`[ @ident ]: %{`
+ Focuses on the named goal :token:`ident`.
+
+ .. note::
+
+ Goals are just existential variables and existential variables do not
+ get a name by default. You can give a name to a goal by using :n:`refine ?[@ident]`.
+ You may also wrap this in an Ltac-definition like:
+
+ .. coqtop:: in
+
+ Ltac name_goal name := refine ?[name].
+
+ .. seealso:: :ref:`existential-variables`
+
+ .. example::
+
+ This first example uses the Ltac definition above, and the named goals
+ only serve for documentation.
+
+ .. coqtop:: all
+
+ Goal forall n, n + 0 = n.
+ Proof.
+ induction n; [ name_goal base | name_goal step ].
+ [base]: {
+
+ .. coqtop:: all
+
+ reflexivity.
+
+ .. coqtop:: in
+
+ }
+
+ .. coqtop:: all
+
+ [step]: {
+
+ .. coqtop:: all
+
+ simpl.
+ f_equal.
+ assumption.
+ }
+ Qed.
+
+ This can also be a way of focusing on a shelved goal, for instance:
+
+ .. coqtop:: all
+
+ Goal exists n : nat, n = n.
+ eexists ?[x].
+ reflexivity.
+ [x]: exact 0.
+ Qed.
+
+ .. exn:: This proof is focused, but cannot be unfocused this way.
+
+ You are trying to use ``}`` but the current subproof has not been fully solved.
+
+ .. exn:: No such goal (@natural).
+ :undocumented:
+
+ .. exn:: No such goal (@ident).
+ :undocumented:
+
+ .. exn:: Brackets do not support multi-goal selectors.
+
+ Brackets are used to focus on a single goal given either by its position
+ or by its name if it has one.
+
+ .. seealso:: The error messages for bullets below.
+
+.. _bullets:
+
+Bullets
+```````
+
+Alternatively, proofs can be structured with bullets instead of ``{`` and ``}``. The
+use of a bullet ``b`` for the first time focuses on the first goal ``g``, the
+same bullet cannot be used again until the proof of ``g`` is completed,
+then it is mandatory to focus the next goal with ``b``. The consequence is
+that ``g`` and all goals present when ``g`` was focused are focused with the
+same bullet ``b``. See the example below.
+
+Different bullets can be used to nest levels. The scope of bullet does
+not go beyond enclosing ``{`` and ``}``, so bullets can be reused as further
+nesting levels provided they are delimited by these. Bullets are made of
+repeated ``-``, ``+`` or ``*`` symbols:
+
+.. prodn:: bullet ::= {| {+ - } | {+ + } | {+ * } }
+
+Note again that when a focused goal is proved a message is displayed
+together with a suggestion about the right bullet or ``}`` to unfocus it
+or focus the next one.
+
+.. note::
+
+ In Proof General (``Emacs`` interface to |Coq|), you must use
+ bullets with the priority ordering shown above to have a correct
+ indentation. For example ``-`` must be the outer bullet and ``**`` the inner
+ one in the example below.
+
+The following example script illustrates all these features:
+
+.. example::
+
+ .. coqtop:: all
+
+ Goal (((True /\ True) /\ True) /\ True) /\ True.
+ Proof.
+ split.
+ - split.
+ + split.
+ ** { split.
+ - trivial.
+ - trivial.
+ }
+ ** trivial.
+ + trivial.
+ - assert True.
+ { trivial. }
+ assumption.
+ Qed.
+
+.. exn:: Wrong bullet @bullet__1: Current bullet @bullet__2 is not finished.
+
+ Before using bullet :n:`@bullet__1` again, you should first finish proving
+ the current focused goal.
+ Note that :n:`@bullet__1` and :n:`@bullet__2` may be the same.
+
+.. exn:: Wrong bullet @bullet__1: Bullet @bullet__2 is mandatory here.
+
+ You must put :n:`@bullet__2` to focus on the next goal. No other bullet is
+ allowed here.
+
+.. exn:: No such goal. Focus next goal with bullet @bullet.
+
+ You tried to apply a tactic but no goals were under focus.
+ Using :n:`@bullet` is mandatory here.
+
+.. FIXME: the :noindex: below works around a Sphinx issue.
+ (https://github.com/sphinx-doc/sphinx/issues/4979)
+ It should be removed once that issue is fixed.
+
+.. exn:: No such goal. Try unfocusing with %}.
+ :noindex:
+
+ You just finished a goal focused by ``{``, you must unfocus it with ``}``.
+
+Mandatory Bullets
+~~~~~~~~~~~~~~~~~
+
+Using :opt:`Default Goal Selector` with the ``!`` selector forces
+tactic scripts to keep focus to exactly one goal (e.g. using bullets)
+or use explicit goal selectors.
+
+Set Bullet Behavior
+~~~~~~~~~~~~~~~~~~~
+
+.. opt:: Bullet Behavior {| "None" | "Strict Subproofs" }
+ :name: Bullet Behavior
+
+ This option controls the bullet behavior and can take two possible values:
+
+ - "None": this makes bullets inactive.
+ - "Strict Subproofs": this makes bullets active (this is the default behavior).
+
+Modifying the order of goals
+````````````````````````````
+
+.. tacn:: cycle @integer
+ :name: cycle
+
+ Reorders the selected goals so that the first :n:`@integer` goals appear after the
+ other selected goals.
+ If :n:`@integer` is negative, it puts the last :n:`@integer` goals at the
+ beginning of the list.
+ The tactic is only useful with a goal selector, most commonly `all:`.
+ Note that other selectors reorder goals; `1,3: cycle 1` is not equivalent
+ to `all: cycle 1`. See :tacn:`… : … (goal selector)`.
+
+.. example::
+
+ .. coqtop:: none reset
+
+ Parameter P : nat -> Prop.
+
+ .. coqtop:: all abort
+
+ Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
+ repeat split.
+ all: cycle 2.
+ all: cycle -3.
+
+.. tacn:: swap @integer @integer
+ :name: swap
+
+ Exchanges the position of the specified goals.
+ Negative values for :n:`@integer` indicate counting goals
+ backward from the end of the list of selected goals. Goals are indexed from 1.
+ The tactic is only useful with a goal selector, most commonly `all:`.
+ Note that other selectors reorder goals; `1,3: swap 1 3` is not equivalent
+ to `all: swap 1 3`. See :tacn:`… : … (goal selector)`.
+
+.. example::
+
+ .. coqtop:: all abort
+
+ Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
+ repeat split.
+ all: swap 1 3.
+ all: swap 1 -1.
+
+.. tacn:: revgoals
+ :name: revgoals
+
+ Reverses the order of the selected goals. The tactic is only useful with a goal
+ selector, most commonly `all :`. Note that other selectors reorder goals;
+ `1,3: revgoals` is not equivalent to `all: revgoals`. See :tacn:`… : … (goal selector)`.
+
+ .. example::
+
+ .. coqtop:: all abort
+
+ Goal P 1 /\ P 2 /\ P 3 /\ P 4 /\ P 5.
+ repeat split.
+ all: revgoals.
+
+Postponing the proof of some goals
+``````````````````````````````````
+
+.. tacn:: shelve
+ :name: shelve
+
+ This tactic moves all goals under focus to a shelf. While on the
+ shelf, goals will not be focused on. They can be solved by
+ unification, or they can be called back into focus with the command
+ :cmd:`Unshelve`.
+
+ .. tacv:: shelve_unifiable
+ :name: shelve_unifiable
+
+ Shelves only the goals under focus that are mentioned in other goals.
+ Goals that appear in the type of other goals can be solved by unification.
+
+ .. example::
+
+ .. coqtop:: all abort
+
+ Goal exists n, n=0.
+ refine (ex_intro _ _ _).
+ all: shelve_unifiable.
+ reflexivity.
+
+.. cmd:: Unshelve
+
+ This command moves all the goals on the shelf (see :tacn:`shelve`)
+ from the shelf into focus, by appending them to the end of the current
+ list of focused goals.
+
+.. tacn:: unshelve @tactic
+ :name: unshelve
+
+ Performs :n:`@tactic`, then unshelves existential variables added to the
+ shelf by the execution of :n:`@tactic`, prepending them to the current goal.
+
+.. tacn:: give_up
+ :name: give_up
+
+ This tactic removes the focused goals from the proof. They are not
+ solved, and cannot be solved later in the proof. As the goals are not
+ solved, the proof cannot be closed.
+
+ The ``give_up`` tactic can be used while editing a proof, to choose to
+ write the proof script in a non-sequential order.
+
+.. _requestinginformation:
+
+Requesting information
+----------------------
+
+
+.. cmd:: Show {? {| @ident | @natural } }
+
+ Displays the current goals.
+
+ :n:`@natural`
+ Display only the :token:`natural`\-th subgoal.
+
+ :n:`@ident`
+ Displays the named goal :token:`ident`. This is useful in
+ particular to display a shelved goal but only works if the
+ corresponding existential variable has been named by the user
+ (see :ref:`existential-variables`) as in the following example.
+
+ .. example::
+
+ .. coqtop:: all abort
+
+ Goal exists n, n = 0.
+ eexists ?[n].
+ Show n.
+
+ .. exn:: No focused proof.
+ :undocumented:
+
+ .. exn:: No such goal.
+ :undocumented:
+
+.. cmd:: Show Proof {? Diffs {? removed } }
+
+ Displays the proof term generated by the tactics
+ that have been applied so far. If the proof is incomplete, the term
+ will contain holes, which correspond to subterms which are still to be
+ constructed. Each hole is an existential variable, which appears as a
+ question mark followed by an identifier.
+
+ Specifying “Diffs” highlights the difference between the
+ current and previous proof step. By default, the command shows the
+ output once with additions highlighted. Including “removed” shows
+ the output twice: once showing removals and once showing additions.
+ It does not examine the :opt:`Diffs` option. See :ref:`showing_proof_diffs`.
+
+.. cmd:: Show Conjectures
+
+ Prints the names of all the
+ theorems that are currently being proved. As it is possible to start
+ proving a previous lemma during the proof of a theorem, there may
+ be multiple names.
+
+.. cmd:: Show Intro
+
+ If the current goal begins by at least one product,
+ prints the name of the first product as it would be
+ generated by an anonymous :tacn:`intro`. The aim of this command is to ease
+ the writing of more robust scripts. For example, with an appropriate
+ Proof General macro, it is possible to transform any anonymous :tacn:`intro`
+ into a qualified one such as ``intro y13``. In the case of a non-product
+ goal, it prints nothing.
+
+.. cmd:: Show Intros
+
+ Similar to the previous command.
+ Simulates the naming process of :tacn:`intros`.
+
+.. cmd:: Show Existentials
+
+ Displays all open goals / existential variables in the current proof
+ along with the type and the context of each variable.
+
+.. cmd:: Show Match @qualid
+
+ Displays a template of the Gallina :token:`match<term_match>`
+ construct with a branch for each constructor of the type
+ :token:`qualid`. This is used internally by
+ `company-coq <https://github.com/cpitclaudel/company-coq>`_.
+
+ .. example::
+
+ .. coqtop:: all
+
+ Show Match nat.
+
+ .. exn:: Unknown inductive type.
+ :undocumented:
+
+.. cmd:: Show Universes
+
+ Displays the set of all universe constraints and
+ its normalized form at the current stage of the proof, useful for
+ debugging universe inconsistencies.
+
+.. cmd:: Show Goal @natural at @natural
+
+ Available in coqtop. Displays a goal at a
+ proof state using the goal ID number and the proof state ID number.
+ It is primarily for use by tools such as Prooftree that need to fetch
+ goal history in this way. Prooftree is a tool for visualizing a proof
+ as a tree that runs in Proof General.
+
+.. cmd:: Guarded
+
+ Some tactics (e.g. :tacn:`refine`) allow to build proofs using
+ fixpoint or co-fixpoint constructions. Due to the incremental nature
+ of interactive proof construction, the check of the termination (or
+ guardedness) of the recursive calls in the fixpoint or cofixpoint
+ constructions is postponed to the time of the completion of the proof.
+
+ The command :cmd:`Guarded` allows checking if the guard condition for
+ fixpoint and cofixpoint is violated at some time of the construction
+ of the proof without having to wait the completion of the proof.
+
+.. _showing_diffs:
+
+Showing differences between proof steps
+---------------------------------------
+
+|Coq| can automatically highlight the differences between successive proof steps
+and between values in some error messages. |Coq| can also highlight differences
+in the proof term.
+For example, the following screenshots of |CoqIDE| and coqtop show the application
+of the same :tacn:`intros` tactic. The tactic creates two new hypotheses, highlighted in green.
+The conclusion is entirely in pale green because although it’s changed, no tokens were added
+to it. The second screenshot uses the "removed" option, so it shows the conclusion a
+second time with the old text, with deletions marked in red. Also, since the hypotheses are
+new, no line of old text is shown for them.
+
+.. comment screenshot produced with:
+ Inductive ev : nat -> Prop :=
+ | ev_0 : ev 0
+ | ev_SS : forall n : nat, ev n -> ev (S (S n)).
+
+ Fixpoint double (n:nat) :=
+ match n with
+ | O => O
+ | S n' => S (S (double n'))
+ end.
+
+ Goal forall n, ev n -> exists k, n = double k.
+ intros n E.
+
+..
+
+ .. image:: ../../_static/diffs-coqide-on.png
+ :alt: |CoqIDE| with Set Diffs on
+
+..
+
+ .. image:: ../../_static/diffs-coqide-removed.png
+ :alt: |CoqIDE| with Set Diffs removed
+
+..
+
+ .. image:: ../../_static/diffs-coqtop-on3.png
+ :alt: coqtop with Set Diffs on
+
+This image shows an error message with diff highlighting in |CoqIDE|:
+
+..
+
+ .. image:: ../../_static/diffs-error-message.png
+ :alt: |CoqIDE| error message with diffs
+
+How to enable diffs
+```````````````````
+
+.. opt:: Diffs {| "on" | "off" | "removed" }
+ :name: Diffs
+
+ The “on” setting highlights added tokens in green, while the “removed” setting
+ additionally reprints items with removed tokens in red. Unchanged tokens in
+ modified items are shown with pale green or red. Diffs in error messages
+ use red and green for the compared values; they appear regardless of the setting.
+ (Colors are user-configurable.)
+
+For coqtop, showing diffs can be enabled when starting coqtop with the
+``-diffs on|off|removed`` command-line option or by setting the :opt:`Diffs` option
+within |Coq|. You will need to provide the ``-color on|auto`` command-line option when
+you start coqtop in either case.
+
+Colors for coqtop can be configured by setting the ``COQ_COLORS`` environment
+variable. See section :ref:`customization-by-environment-variables`. Diffs
+use the tags ``diff.added``, ``diff.added.bg``, ``diff.removed`` and ``diff.removed.bg``.
+
+In |CoqIDE|, diffs should be enabled from the ``View`` menu. Don’t use the ``Set Diffs``
+command in |CoqIDE|. You can change the background colors shown for diffs from the
+``Edit | Preferences | Tags`` panel by changing the settings for the ``diff.added``,
+``diff.added.bg``, ``diff.removed`` and ``diff.removed.bg`` tags. This panel also
+lets you control other attributes of the highlights, such as the foreground
+color, bold, italic, underline and strikeout.
+
+Proof General can also display |Coq|-generated proof diffs automatically.
+Please see the PG documentation section
+"`Showing Proof Diffs" <https://proofgeneral.github.io/doc/master/userman/Coq-Proof-General#Showing-Proof-Diffs>`_)
+for details.
+
+How diffs are calculated
+````````````````````````
+
+Diffs are calculated as follows:
+
+1. Select the old proof state to compare to, which is the proof state before
+ the last tactic that changed the proof. Changes that only affect the view
+ of the proof, such as ``all: swap 1 2``, are ignored.
+
+2. For each goal in the new proof state, determine what old goal to compare
+ it to—the one it is derived from or is the same as. Match the hypotheses by
+ name (order is ignored), handling compacted items specially.
+
+3. For each hypothesis and conclusion (the “items”) in each goal, pass
+ them as strings to the lexer to break them into tokens. Then apply the
+ Myers diff algorithm :cite:`Myers` on the tokens and add appropriate highlighting.
+
+Notes:
+
+* Aside from the highlights, output for the "on" option should be identical
+ to the undiffed output.
+* Goals completed in the last proof step will not be shown even with the
+ "removed" setting.
+
+.. comment The following screenshots show diffs working with multiple goals and with compacted
+ hypotheses. In the first one, notice that the goal ``P 1`` is not highlighted at
+ all after the split because it has not changed.
+
+ .. todo: Use this script and remove the screenshots when COQ_COLORS
+ works for coqtop in sphinx
+ .. coqtop:: none
+
+ Set Diffs "on".
+ Parameter P : nat -> Prop.
+ Goal P 1 /\ P 2 /\ P 3.
+
+ .. coqtop:: out
+
+ split.
+
+ .. coqtop:: all abort
+
+ 2: split.
+
+ ..
+
+ .. coqtop:: none
+
+ Set Diffs "on".
+ Goal forall n m : nat, n + m = m + n.
+ Set Diffs "on".
+
+ .. coqtop:: out
+
+ intros n.
+
+ .. coqtop:: all abort
+
+ intros m.
+
+This screen shot shows the result of applying a :tacn:`split` tactic that replaces one goal
+with 2 goals. Notice that the goal ``P 1`` is not highlighted at all after
+the split because it has not changed.
+
+..
+
+ .. image:: ../../_static/diffs-coqide-multigoal.png
+ :alt: coqide with Set Diffs on with multiple goals
+
+Diffs may appear like this after applying a :tacn:`intro` tactic that results
+in a compacted hypotheses:
+
+..
+
+ .. image:: ../../_static/diffs-coqide-compacted.png
+ :alt: coqide with Set Diffs on with compacted hypotheses
+
+.. _showing_proof_diffs:
+
+"Show Proof" differences
+````````````````````````
+
+To show differences in the proof term:
+
+- In coqtop and Proof General, use the :cmd:`Show Proof` `Diffs` command.
+
+- In |CoqIDE|, position the cursor on or just after a tactic to compare the proof term
+ after the tactic with the proof term before the tactic, then select
+ `View / Show Proof` from the menu or enter the associated key binding.
+ Differences will be shown applying the current `Show Diffs` setting
+ from the `View` menu. If the current setting is `Don't show diffs`, diffs
+ will not be shown.
+
+ Output with the "added and removed" option looks like this:
+
+ ..
+
+ .. image:: ../../_static/diffs-show-proof.png
+ :alt: coqide with Set Diffs on with compacted hypotheses
+
+Controlling the effect of proof editing commands
+------------------------------------------------
+
+
+.. opt:: Hyps Limit @natural
+ :name: Hyps Limit
+
+ This option controls the maximum number of hypotheses displayed in goals
+ after the application of a tactic. All the hypotheses remain usable
+ in the proof development.
+ When unset, it goes back to the default mode which is to print all
+ available hypotheses.
+
+
+.. flag:: Nested Proofs Allowed
+
+ When turned on (it is off by default), this flag enables support for nested
+ proofs: a new assertion command can be inserted before the current proof is
+ finished, in which case |Coq| will temporarily switch to the proof of this
+ *nested lemma*. When the proof of the nested lemma is finished (with :cmd:`Qed`
+ or :cmd:`Defined`), its statement will be made available (as if it had been
+ proved before starting the previous proof) and |Coq| will switch back to the
+ proof of the previous assertion.
+
+.. flag:: Printing Goal Names
+
+ When turned on, the name of the goal is printed in interactive
+ proof mode, which can be useful in cases of cross references
+ between goals.
+
+Controlling memory usage
+------------------------
+
+.. cmd:: Print Debug GC
+
+ Prints heap usage statistics, which are values from the `stat` type of the `Gc` module
+ described
+ `here <https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html#TYPEstat>`_
+ in the |OCaml| documentation.
+ The `live_words`, `heap_words` and `top_heap_words` values give the basic information.
+ Words are 8 bytes or 4 bytes, respectively, for 64- and 32-bit executables.
+
+When experiencing high memory usage the following commands can be used
+to force |Coq| to optimize some of its internal data structures.
+
+.. cmd:: Optimize Proof
+
+ Shrink the data structure used to represent the current proof.
+
+
+.. cmd:: Optimize Heap
+
+ Perform a heap compaction. This is generally an expensive operation.
+ See: `|OCaml| Gc.compact <http://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html#VALcompact>`_
+ There is also an analogous tactic :tacn:`optimize_heap`.
+
+Memory usage parameters can be set through the :ref:`OCAMLRUNPARAM <OCAMLRUNPARAM>`
+environment variable.
diff --git a/doc/sphinx/proofs/writing-proofs/rewriting.rst b/doc/sphinx/proofs/writing-proofs/rewriting.rst
new file mode 100644
index 0000000000..1358aad432
--- /dev/null
+++ b/doc/sphinx/proofs/writing-proofs/rewriting.rst
@@ -0,0 +1,857 @@
+=================================
+Term rewriting and simplification
+=================================
+
+.. _rewritingexpressions:
+
+Rewriting expressions
+---------------------
+
+These tactics use the equality :g:`eq:forall A:Type, A->A->Prop` defined in
+file ``Logic.v`` (see :ref:`coq-library-logic`). The notation for :g:`eq T t u` is
+simply :g:`t=u` dropping the implicit type of :g:`t` and :g:`u`.
+
+.. tacn:: rewrite @term
+ :name: rewrite
+
+ This tactic applies to any goal. The type of :token:`term` must have the form
+
+ ``forall (x``:sub:`1` ``:A``:sub:`1` ``) ... (x``:sub:`n` ``:A``:sub:`n` ``), eq term``:sub:`1` ``term``:sub:`2` ``.``
+
+ where :g:`eq` is the Leibniz equality or a registered setoid equality.
+
+ Then :n:`rewrite @term` finds the first subterm matching `term`\ :sub:`1` in the goal,
+ resulting in instances `term`:sub:`1`' and `term`:sub:`2`' and then
+ replaces every occurrence of `term`:subscript:`1`' by `term`:subscript:`2`'.
+ Hence, some of the variables :g:`x`\ :sub:`i` are solved by unification,
+ and some of the types :g:`A`\ :sub:`1`:g:`, ..., A`\ :sub:`n` become new
+ subgoals.
+
+ .. exn:: The @term provided does not end with an equation.
+ :undocumented:
+
+ .. exn:: Tactic generated a subgoal identical to the original goal. This happens if @term does not occur in the goal.
+ :undocumented:
+
+ .. tacv:: rewrite -> @term
+
+ Is equivalent to :n:`rewrite @term`
+
+ .. tacv:: rewrite <- @term
+
+ Uses the equality :n:`@term`:sub:`1` :n:`= @term` :sub:`2` from right to left
+
+ .. tacv:: rewrite @term in @goal_occurrences
+
+ Analogous to :n:`rewrite @term` but rewriting is done following
+ the clause :token:`goal_occurrences`. For instance:
+
+ + :n:`rewrite H in H'` will rewrite `H` in the hypothesis
+ ``H'`` instead of the current goal.
+ + :n:`rewrite H in H' at 1, H'' at - 2 |- *` means
+ :n:`rewrite H; rewrite H in H' at 1; rewrite H in H'' at - 2.`
+ In particular a failure will happen if any of these three simpler tactics
+ fails.
+ + :n:`rewrite H in * |-` will do :n:`rewrite H in H'` for all hypotheses
+ :g:`H'` different from :g:`H`.
+ A success will happen as soon as at least one of these simpler tactics succeeds.
+ + :n:`rewrite H in *` is a combination of :n:`rewrite H` and :n:`rewrite H in * |-`
+ that succeeds if at least one of these two tactics succeeds.
+
+ Orientation :g:`->` or :g:`<-` can be inserted before the :token:`term` to rewrite.
+
+ .. tacv:: rewrite @term at @occurrences
+
+ Rewrite only the given :token:`occurrences` of :token:`term`. Occurrences are
+ specified from left to right as for pattern (:tacn:`pattern`). The rewrite is
+ always performed using setoid rewriting, even for Leibniz’s equality, so one
+ has to ``Import Setoid`` to use this variant.
+
+ .. tacv:: rewrite @term by @tactic
+
+ Use tactic to completely solve the side-conditions arising from the
+ :tacn:`rewrite`.
+
+ .. tacv:: rewrite {+, @orientation @term} {? in @ident }
+
+ Is equivalent to the `n` successive tactics :n:`{+; rewrite @term}`, each one
+ working on the first subgoal generated by the previous one. An :production:`orientation`
+ ``->`` or ``<-`` can be inserted before each :token:`term` to rewrite. One
+ unique clause can be added at the end after the keyword in; it will then
+ affect all rewrite operations.
+
+ In all forms of rewrite described above, a :token:`term` to rewrite can be
+ immediately prefixed by one of the following modifiers:
+
+ + `?` : the tactic :n:`rewrite ?@term` performs the rewrite of :token:`term` as many
+ times as possible (perhaps zero time). This form never fails.
+ + :n:`@natural?` : works similarly, except that it will do at most :token:`natural` rewrites.
+ + `!` : works as `?`, except that at least one rewrite should succeed, otherwise
+ the tactic fails.
+ + :n:`@natural!` (or simply :n:`@natural`) : precisely :token:`natural` rewrites of :token:`term` will be done,
+ leading to failure if these :token:`natural` rewrites are not possible.
+
+ .. tacv:: erewrite @term
+ :name: erewrite
+
+ This tactic works as :n:`rewrite @term` but turning
+ unresolved bindings into existential variables, if any, instead of
+ failing. It has the same variants as :tacn:`rewrite` has.
+
+ .. flag:: Keyed Unification
+
+ Makes higher-order unification used by :tacn:`rewrite` rely on a set of keys to drive
+ unification. The subterms, considered as rewriting candidates, must start with
+ the same key as the left- or right-hand side of the lemma given to rewrite, and the arguments
+ are then unified up to full reduction.
+
+.. tacn:: replace @term with @term’
+ :name: replace
+
+ This tactic applies to any goal. It replaces all free occurrences of :n:`@term`
+ in the current goal with :n:`@term’` and generates an equality :n:`@term = @term’`
+ as a subgoal. This equality is automatically solved if it occurs among
+ the assumptions, or if its symmetric form occurs. It is equivalent to
+ :n:`cut @term = @term’; [intro H`:sub:`n` :n:`; rewrite <- H`:sub:`n` :n:`; clear H`:sub:`n`:n:`|| assumption || symmetry; try assumption]`.
+
+ .. exn:: Terms do not have convertible types.
+ :undocumented:
+
+ .. tacv:: replace @term with @term’ by @tactic
+
+ This acts as :n:`replace @term with @term’` but applies :token:`tactic` to solve the generated
+ subgoal :n:`@term = @term’`.
+
+ .. tacv:: replace @term
+
+ Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
+ the form :n:`@term = @term’` or :n:`@term’ = @term`.
+
+ .. tacv:: replace -> @term
+
+ Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
+ the form :n:`@term = @term’`
+
+ .. tacv:: replace <- @term
+
+ Replaces :n:`@term` with :n:`@term’` using the first assumption whose type has
+ the form :n:`@term’ = @term`
+
+ .. tacv:: replace @term {? with @term} in @goal_occurrences {? by @tactic}
+ replace -> @term in @goal_occurrences
+ replace <- @term in @goal_occurrences
+
+ Acts as before but the replacements take place in the specified clauses
+ (:token:`goal_occurrences`) (see :ref:`performingcomputations`) and not
+ only in the conclusion of the goal. The clause argument must not contain
+ any ``type of`` nor ``value of``.
+
+.. tacn:: subst @ident
+ :name: subst
+
+ This tactic applies to a goal that has :n:`@ident` in its context and (at
+ least) one hypothesis, say :g:`H`, of type :n:`@ident = t` or :n:`t = @ident`
+ with :n:`@ident` not occurring in :g:`t`. Then it replaces :n:`@ident` by
+ :g:`t` everywhere in the goal (in the hypotheses and in the conclusion) and
+ clears :n:`@ident` and :g:`H` from the context.
+
+ If :n:`@ident` is a local definition of the form :n:`@ident := t`, it is also
+ unfolded and cleared.
+
+ If :n:`@ident` is a section variable it is expected to have no
+ indirect occurrences in the goal, i.e. that no global declarations
+ implicitly depending on the section variable must be present in the
+ goal.
+
+ .. note::
+ + When several hypotheses have the form :n:`@ident = t` or :n:`t = @ident`, the
+ first one is used.
+
+ + If :g:`H` is itself dependent in the goal, it is replaced by the proof of
+ reflexivity of equality.
+
+ .. tacv:: subst {+ @ident}
+
+ This is equivalent to :n:`subst @ident`:sub:`1`:n:`; ...; subst @ident`:sub:`n`.
+
+ .. tacv:: subst
+
+ This applies :tacn:`subst` repeatedly from top to bottom to all hypotheses of the
+ context for which an equality of the form :n:`@ident = t` or :n:`t = @ident`
+ or :n:`@ident := t` exists, with :n:`@ident` not occurring in
+ ``t`` and :n:`@ident` not a section variable with indirect
+ dependencies in the goal.
+
+ .. flag:: Regular Subst Tactic
+
+ This flag controls the behavior of :tacn:`subst`. When it is
+ activated (it is by default), :tacn:`subst` also deals with the following corner cases:
+
+ + A context with ordered hypotheses :n:`@ident`:sub:`1` :n:`= @ident`:sub:`2`
+ and :n:`@ident`:sub:`1` :n:`= t`, or :n:`t′ = @ident`:sub:`1`` with `t′` not
+ a variable, and no other hypotheses of the form :n:`@ident`:sub:`2` :n:`= u`
+ or :n:`u = @ident`:sub:`2`; without the flag, a second call to
+ subst would be necessary to replace :n:`@ident`:sub:`2` by `t` or
+ `t′` respectively.
+ + The presence of a recursive equation which without the flag would
+ be a cause of failure of :tacn:`subst`.
+ + A context with cyclic dependencies as with hypotheses :n:`@ident`:sub:`1` :n:`= f @ident`:sub:`2`
+ and :n:`@ident`:sub:`2` :n:`= g @ident`:sub:`1` which without the
+ flag would be a cause of failure of :tacn:`subst`.
+
+ Additionally, it prevents a local definition such as :n:`@ident := t` to be
+ unfolded which otherwise it would exceptionally unfold in configurations
+ containing hypotheses of the form :n:`@ident = u`, or :n:`u′ = @ident`
+ with `u′` not a variable. Finally, it preserves the initial order of
+ hypotheses, which without the flag it may break.
+ default.
+
+ .. exn:: Cannot find any non-recursive equality over :n:`@ident`.
+ :undocumented:
+
+ .. exn:: Section variable :n:`@ident` occurs implicitly in global declaration :n:`@qualid` present in hypothesis :n:`@ident`.
+ Section variable :n:`@ident` occurs implicitly in global declaration :n:`@qualid` present in the conclusion.
+
+ Raised when the variable is a section variable with indirect
+ dependencies in the goal.
+
+
+.. tacn:: stepl @term
+ :name: stepl
+
+ This tactic is for chaining rewriting steps. It assumes a goal of the
+ form :n:`R @term @term` where ``R`` is a binary relation and relies on a
+ database of lemmas of the form :g:`forall x y z, R x y -> eq x z -> R z y`
+ where `eq` is typically a setoid equality. The application of :n:`stepl @term`
+ then replaces the goal by :n:`R @term @term` and adds a new goal stating
+ :n:`eq @term @term`.
+
+ .. cmd:: Declare Left Step @term
+
+ Adds :n:`@term` to the database used by :tacn:`stepl`.
+
+ This tactic is especially useful for parametric setoids which are not accepted
+ as regular setoids for :tacn:`rewrite` and :tacn:`setoid_replace` (see
+ :ref:`Generalizedrewriting`).
+
+ .. tacv:: stepl @term by @tactic
+
+ This applies :n:`stepl @term` then applies :token:`tactic` to the second goal.
+
+ .. tacv:: stepr @term by @tactic
+ :name: stepr
+
+ This behaves as :tacn:`stepl` but on the right-hand-side of the binary
+ relation. Lemmas are expected to be of the form
+ :g:`forall x y z, R x y -> eq y z -> R x z`.
+
+ .. cmd:: Declare Right Step @term
+
+ Adds :n:`@term` to the database used by :tacn:`stepr`.
+
+
+.. tacn:: change @term
+ :name: change
+
+ This tactic applies to any goal. It implements the rule ``Conv`` given in
+ :ref:`subtyping-rules`. :g:`change U` replaces the current goal `T`
+ with `U` providing that `U` is well-formed and that `T` and `U` are
+ convertible.
+
+ .. exn:: Not convertible.
+ :undocumented:
+
+ .. tacv:: change @term with @term’
+
+ This replaces the occurrences of :n:`@term` by :n:`@term’` in the current goal.
+ The term :n:`@term` and :n:`@term’` must be convertible.
+
+ .. tacv:: change @term at {+ @natural} with @term’
+
+ This replaces the occurrences numbered :n:`{+ @natural}` of :n:`@term` by :n:`@term’`
+ in the current goal. The terms :n:`@term` and :n:`@term’` must be convertible.
+
+ .. exn:: Too few occurrences.
+ :undocumented:
+
+ .. tacv:: change @term {? {? at {+ @natural}} with @term} in @ident
+
+ This applies the :tacn:`change` tactic not to the goal but to the hypothesis :n:`@ident`.
+
+ .. tacv:: now_show @term
+
+ This is a synonym of :n:`change @term`. It can be used to
+ make some proof steps explicit when refactoring a proof script
+ to make it readable.
+
+ .. seealso:: :ref:`Performing computations <performingcomputations>`
+
+.. _performingcomputations:
+
+Performing computations
+---------------------------
+
+.. insertprodn red_expr pattern_occ
+
+.. prodn::
+ red_expr ::= red
+ | hnf
+ | simpl {? @delta_flag } {? @ref_or_pattern_occ }
+ | cbv {? @strategy_flag }
+ | cbn {? @strategy_flag }
+ | lazy {? @strategy_flag }
+ | compute {? @delta_flag }
+ | vm_compute {? @ref_or_pattern_occ }
+ | native_compute {? @ref_or_pattern_occ }
+ | unfold {+, @unfold_occ }
+ | fold {+ @one_term }
+ | pattern {+, @pattern_occ }
+ | @ident
+ delta_flag ::= {? - } [ {+ @reference } ]
+ strategy_flag ::= {+ @red_flag }
+ | @delta_flag
+ red_flag ::= beta
+ | iota
+ | match
+ | fix
+ | cofix
+ | zeta
+ | delta {? @delta_flag }
+ ref_or_pattern_occ ::= @reference {? at @occs_nums }
+ | @one_term {? at @occs_nums }
+ occs_nums ::= {+ {| @natural | @ident } }
+ | - {| @natural | @ident } {* @int_or_var }
+ int_or_var ::= @integer
+ | @ident
+ unfold_occ ::= @reference {? at @occs_nums }
+ pattern_occ ::= @one_term {? at @occs_nums }
+
+This set of tactics implements different specialized usages of the
+tactic :tacn:`change`.
+
+All conversion tactics (including :tacn:`change`) can be parameterized by the
+parts of the goal where the conversion can occur. This is done using
+*goal clauses* which consists in a list of hypotheses and, optionally,
+of a reference to the conclusion of the goal. For defined hypothesis
+it is possible to specify if the conversion should occur on the type
+part, the body part or both (default).
+
+Goal clauses are written after a conversion tactic (tactics :tacn:`set`,
+:tacn:`rewrite`, :tacn:`replace` and :tacn:`autorewrite` also use goal
+clauses) and are introduced by the keyword `in`. If no goal clause is
+provided, the default is to perform the conversion only in the
+conclusion.
+
+The syntax and description of the various goal clauses is the
+following:
+
++ :n:`in {+ @ident} |-` only in hypotheses :n:`{+ @ident}`
++ :n:`in {+ @ident} |- *` in hypotheses :n:`{+ @ident}` and in the
+ conclusion
++ :n:`in * |-` in every hypothesis
++ :n:`in *` (equivalent to in :n:`* |- *`) everywhere
++ :n:`in (type of @ident) (value of @ident) ... |-` in type part of
+ :n:`@ident`, in the value part of :n:`@ident`, etc.
+
+For backward compatibility, the notation :n:`in {+ @ident}` performs
+the conversion in hypotheses :n:`{+ @ident}`.
+
+.. tacn:: cbv {? @strategy_flag }
+ lazy {? @strategy_flag }
+ :name: cbv; lazy
+
+ These parameterized reduction tactics apply to any goal and perform
+ the normalization of the goal according to the specified flags. In
+ correspondence with the kinds of reduction considered in |Coq| namely
+ :math:`\beta` (reduction of functional application), :math:`\delta`
+ (unfolding of transparent constants, see :ref:`vernac-controlling-the-reduction-strategies`),
+ :math:`\iota` (reduction of
+ pattern matching over a constructed term, and unfolding of :g:`fix` and
+ :g:`cofix` expressions) and :math:`\zeta` (contraction of local definitions), the
+ flags are either ``beta``, ``delta``, ``match``, ``fix``, ``cofix``,
+ ``iota`` or ``zeta``. The ``iota`` flag is a shorthand for ``match``, ``fix``
+ and ``cofix``. The ``delta`` flag itself can be refined into
+ :n:`delta [ {+ @qualid} ]` or :n:`delta - [ {+ @qualid} ]`, restricting in the first
+ case the constants to unfold to the constants listed, and restricting in the
+ second case the constant to unfold to all but the ones explicitly mentioned.
+ Notice that the ``delta`` flag does not apply to variables bound by a let-in
+ construction inside the :n:`@term` itself (use here the ``zeta`` flag). In
+ any cases, opaque constants are not unfolded (see :ref:`vernac-controlling-the-reduction-strategies`).
+
+ Normalization according to the flags is done by first evaluating the
+ head of the expression into a *weak-head* normal form, i.e. until the
+ evaluation is blocked by a variable (or an opaque constant, or an
+ axiom), as e.g. in :g:`x u1 ... un` , or :g:`match x with ... end`, or
+ :g:`(fix f x {struct x} := ...) x`, or is a constructed form (a
+ :math:`\lambda`-expression, a constructor, a cofixpoint, an inductive type, a
+ product type, a sort), or is a redex that the flags prevent to reduce. Once a
+ weak-head normal form is obtained, subterms are recursively reduced using the
+ same strategy.
+
+ Reduction to weak-head normal form can be done using two strategies:
+ *lazy* (``lazy`` tactic), or *call-by-value* (``cbv`` tactic). The lazy
+ strategy is a call-by-need strategy, with sharing of reductions: the
+ arguments of a function call are weakly evaluated only when necessary,
+ and if an argument is used several times then it is weakly computed
+ only once. This reduction is efficient for reducing expressions with
+ dead code. For instance, the proofs of a proposition :g:`exists x. P(x)`
+ reduce to a pair of a witness :g:`t`, and a proof that :g:`t` satisfies the
+ predicate :g:`P`. Most of the time, :g:`t` may be computed without computing
+ the proof of :g:`P(t)`, thanks to the lazy strategy.
+
+ The call-by-value strategy is the one used in ML languages: the
+ arguments of a function call are systematically weakly evaluated
+ first. Despite the lazy strategy always performs fewer reductions than
+ the call-by-value strategy, the latter is generally more efficient for
+ evaluating purely computational expressions (i.e. with little dead code).
+
+.. tacv:: compute
+ cbv
+ :name: compute; _
+
+ These are synonyms for ``cbv beta delta iota zeta``.
+
+.. tacv:: lazy
+
+ This is a synonym for ``lazy beta delta iota zeta``.
+
+.. tacv:: compute [ {+ @qualid} ]
+ cbv [ {+ @qualid} ]
+
+ These are synonyms of :n:`cbv beta delta {+ @qualid} iota zeta`.
+
+.. tacv:: compute - [ {+ @qualid} ]
+ cbv - [ {+ @qualid} ]
+
+ These are synonyms of :n:`cbv beta delta -{+ @qualid} iota zeta`.
+
+.. tacv:: lazy [ {+ @qualid} ]
+ lazy - [ {+ @qualid} ]
+
+ These are respectively synonyms of :n:`lazy beta delta {+ @qualid} iota zeta`
+ and :n:`lazy beta delta -{+ @qualid} iota zeta`.
+
+.. tacv:: vm_compute
+ :name: vm_compute
+
+ This tactic evaluates the goal using the optimized call-by-value evaluation
+ bytecode-based virtual machine described in :cite:`CompiledStrongReduction`.
+ This algorithm is dramatically more efficient than the algorithm used for the
+ :tacn:`cbv` tactic, but it cannot be fine-tuned. It is especially interesting for
+ full evaluation of algebraic objects. This includes the case of
+ reflection-based tactics.
+
+.. tacv:: native_compute
+ :name: native_compute
+
+ This tactic evaluates the goal by compilation to |OCaml| as described
+ in :cite:`FullReduction`. If |Coq| is running in native code, it can be
+ typically two to five times faster than :tacn:`vm_compute`. Note however that the
+ compilation cost is higher, so it is worth using only for intensive
+ computations.
+
+ .. flag:: NativeCompute Timing
+
+ This flag causes all calls to the native compiler to print
+ timing information for the conversion to native code,
+ compilation, execution, and reification phases of native
+ compilation. Timing is printed in units of seconds of
+ wall-clock time.
+
+ .. flag:: NativeCompute Profiling
+
+ On Linux, if you have the ``perf`` profiler installed, this flag makes
+ it possible to profile :tacn:`native_compute` evaluations.
+
+ .. opt:: NativeCompute Profile Filename @string
+ :name: NativeCompute Profile Filename
+
+ This option specifies the profile output; the default is
+ ``native_compute_profile.data``. The actual filename used
+ will contain extra characters to avoid overwriting an existing file; that
+ filename is reported to the user.
+ That means you can individually profile multiple uses of
+ :tacn:`native_compute` in a script. From the Linux command line, run ``perf report``
+ on the profile file to see the results. Consult the ``perf`` documentation
+ for more details.
+
+.. flag:: Debug Cbv
+
+ This flag makes :tacn:`cbv` (and its derivative :tacn:`compute`) print
+ information about the constants it encounters and the unfolding decisions it
+ makes.
+
+.. tacn:: red
+ :name: red
+
+ This tactic applies to a goal that has the form::
+
+ forall (x:T1) ... (xk:Tk), T
+
+ with :g:`T` :math:`\beta`:math:`\iota`:math:`\zeta`-reducing to :g:`c t`:sub:`1` :g:`... t`:sub:`n` and :g:`c` a
+ constant. If :g:`c` is transparent then it replaces :g:`c` with its
+ definition (say :g:`t`) and then reduces
+ :g:`(t t`:sub:`1` :g:`... t`:sub:`n` :g:`)` according to :math:`\beta`:math:`\iota`:math:`\zeta`-reduction rules.
+
+.. exn:: Not reducible.
+ :undocumented:
+
+.. exn:: No head constant to reduce.
+ :undocumented:
+
+.. tacn:: hnf
+ :name: hnf
+
+ This tactic applies to any goal. It replaces the current goal with its
+ head normal form according to the :math:`\beta`:math:`\delta`:math:`\iota`:math:`\zeta`-reduction rules, i.e. it
+ reduces the head of the goal until it becomes a product or an
+ irreducible term. All inner :math:`\beta`:math:`\iota`-redexes are also reduced.
+ The behavior of both :tacn:`hnf` can be tuned using the :cmd:`Arguments` command.
+
+ Example: The term :g:`fun n : nat => S n + S n` is not reduced by :n:`hnf`.
+
+.. note::
+ The :math:`\delta` rule only applies to transparent constants (see :ref:`vernac-controlling-the-reduction-strategies`
+ on transparency and opacity).
+
+.. tacn:: cbn
+ simpl
+ :name: cbn; simpl
+
+ These tactics apply to any goal. They try to reduce a term to
+ something still readable instead of fully normalizing it. They perform
+ a sort of strong normalization with two key differences:
+
+ + They unfold a constant if and only if it leads to a :math:`\iota`-reduction,
+ i.e. reducing a match or unfolding a fixpoint.
+ + While reducing a constant unfolding to (co)fixpoints, the tactics
+ use the name of the constant the (co)fixpoint comes from instead of
+ the (co)fixpoint definition in recursive calls.
+
+ The :tacn:`cbn` tactic is claimed to be a more principled, faster and more
+ predictable replacement for :tacn:`simpl`.
+
+ The :tacn:`cbn` tactic accepts the same flags as :tacn:`cbv` and
+ :tacn:`lazy`. The behavior of both :tacn:`simpl` and :tacn:`cbn`
+ can be tuned using the :cmd:`Arguments` command.
+
+ .. todo add "See <subsection about controlling the behavior of reduction strategies>"
+ to TBA section
+
+ Notice that only transparent constants whose name can be reused in the
+ recursive calls are possibly unfolded by :tacn:`simpl`. For instance a
+ constant defined by :g:`plus' := plus` is possibly unfolded and reused in
+ the recursive calls, but a constant such as :g:`succ := plus (S O)` is
+ never unfolded. This is the main difference between :tacn:`simpl` and :tacn:`cbn`.
+ The tactic :tacn:`cbn` reduces whenever it will be able to reuse it or not:
+ :g:`succ t` is reduced to :g:`S t`.
+
+.. tacv:: cbn [ {+ @qualid} ]
+ cbn - [ {+ @qualid} ]
+
+ These are respectively synonyms of :n:`cbn beta delta [ {+ @qualid} ] iota zeta`
+ and :n:`cbn beta delta - [ {+ @qualid} ] iota zeta` (see :tacn:`cbn`).
+
+.. tacv:: simpl @pattern
+
+ This applies :tacn:`simpl` only to the subterms matching
+ :n:`@pattern` in the current goal.
+
+.. tacv:: simpl @pattern at {+ @natural}
+
+ This applies :tacn:`simpl` only to the :n:`{+ @natural}` occurrences of the subterms
+ matching :n:`@pattern` in the current goal.
+
+ .. exn:: Too few occurrences.
+ :undocumented:
+
+.. tacv:: simpl @qualid
+ simpl @string
+
+ This applies :tacn:`simpl` only to the applicative subterms whose head occurrence
+ is the unfoldable constant :n:`@qualid` (the constant can be referred to by
+ its notation using :n:`@string` if such a notation exists).
+
+.. tacv:: simpl @qualid at {+ @natural}
+ simpl @string at {+ @natural}
+
+ This applies :tacn:`simpl` only to the :n:`{+ @natural}` applicative subterms whose
+ head occurrence is :n:`@qualid` (or :n:`@string`).
+
+.. flag:: Debug RAKAM
+
+ This flag makes :tacn:`cbn` print various debugging information.
+ ``RAKAM`` is the Refolding Algebraic Krivine Abstract Machine.
+
+.. tacn:: unfold @qualid
+ :name: unfold
+
+ This tactic applies to any goal. The argument qualid must denote a
+ defined transparent constant or local definition (see
+ :ref:`gallina-definitions` and
+ :ref:`vernac-controlling-the-reduction-strategies`). The tactic
+ :tacn:`unfold` applies the :math:`\delta` rule to each occurrence
+ of the constant to which :n:`@qualid` refers in the current goal
+ and then replaces it with its :math:`\beta\iota\zeta`-normal form.
+ Use the general reduction tactics if you want to avoid this final
+ reduction, for instance :n:`cbv delta [@qualid]`.
+
+ .. exn:: Cannot coerce @qualid to an evaluable reference.
+
+ This error is frequent when trying to unfold something that has
+ defined as an inductive type (or constructor) and not as a
+ definition.
+
+ .. example::
+
+ .. coqtop:: abort all fail
+
+ Goal 0 <= 1.
+ unfold le.
+
+ This error can also be raised if you are trying to unfold
+ something that has been marked as opaque.
+
+ .. example::
+
+ .. coqtop:: abort all fail
+
+ Opaque Nat.add.
+ Goal 1 + 0 = 1.
+ unfold Nat.add.
+
+ .. tacv:: unfold @qualid in @goal_occurrences
+
+ Replaces :n:`@qualid` in hypothesis (or hypotheses) designated
+ by :token:`goal_occurrences` with its definition and replaces
+ the hypothesis with its :math:`\beta`:math:`\iota` normal form.
+
+ .. tacv:: unfold {+, @qualid}
+
+ Replaces :n:`{+, @qualid}` with their definitions and replaces
+ the current goal with its :math:`\beta`:math:`\iota` normal
+ form.
+
+ .. tacv:: unfold {+, @qualid at @occurrences }
+
+ The list :token:`occurrences` specify the occurrences of
+ :n:`@qualid` to be unfolded. Occurrences are located from left
+ to right.
+
+ .. exn:: Bad occurrence number of @qualid.
+ :undocumented:
+
+ .. exn:: @qualid does not occur.
+ :undocumented:
+
+ .. tacv:: unfold @string
+
+ If :n:`@string` denotes the discriminating symbol of a notation
+ (e.g. "+") or an expression defining a notation (e.g. `"_ +
+ _"`), and this notation denotes an application whose head symbol
+ is an unfoldable constant, then the tactic unfolds it.
+
+ .. tacv:: unfold @string%@ident
+
+ This is variant of :n:`unfold @string` where :n:`@string` gets
+ its interpretation from the scope bound to the delimiting key
+ :token:`ident` instead of its default interpretation (see
+ :ref:`Localinterpretationrulesfornotations`).
+
+ .. tacv:: unfold {+, {| @qualid | @string{? %@ident } } {? at @occurrences } } {? in @goal_occurrences }
+
+ This is the most general form.
+
+.. tacn:: fold @term
+ :name: fold
+
+ This tactic applies to any goal. The term :n:`@term` is reduced using the
+ :tacn:`red` tactic. Every occurrence of the resulting :n:`@term` in the goal is
+ then replaced by :n:`@term`. This tactic is particularly useful when a fixpoint
+ definition has been wrongfully unfolded, making the goal very hard to read.
+ On the other hand, when an unfolded function applied to its argument has been
+ reduced, the :tacn:`fold` tactic won't do anything.
+
+ .. example::
+
+ .. coqtop:: all abort
+
+ Goal ~0=0.
+ unfold not.
+ Fail progress fold not.
+ pattern (0 = 0).
+ fold not.
+
+ .. tacv:: fold {+ @term}
+
+ Equivalent to :n:`fold @term ; ... ; fold @term`.
+
+.. tacn:: pattern @term
+ :name: pattern
+
+ This command applies to any goal. The argument :n:`@term` must be a free
+ subterm of the current goal. The command pattern performs :math:`\beta`-expansion
+ (the inverse of :math:`\beta`-reduction) of the current goal (say :g:`T`) by
+
+ + replacing all occurrences of :n:`@term` in :g:`T` with a fresh variable
+ + abstracting this variable
+ + applying the abstracted goal to :n:`@term`
+
+ For instance, if the current goal :g:`T` is expressible as
+ :math:`\varphi`:g:`(t)` where the notation captures all the instances of :g:`t`
+ in :math:`\varphi`:g:`(t)`, then :n:`pattern t` transforms it into
+ :g:`(fun x:A =>` :math:`\varphi`:g:`(x)) t`. This tactic can be used, for
+ instance, when the tactic ``apply`` fails on matching.
+
+.. tacv:: pattern @term at {+ @natural}
+
+ Only the occurrences :n:`{+ @natural}` of :n:`@term` are considered for
+ :math:`\beta`-expansion. Occurrences are located from left to right.
+
+.. tacv:: pattern @term at - {+ @natural}
+
+ All occurrences except the occurrences of indexes :n:`{+ @natural }`
+ of :n:`@term` are considered for :math:`\beta`-expansion. Occurrences are located from
+ left to right.
+
+.. tacv:: pattern {+, @term}
+
+ Starting from a goal :math:`\varphi`:g:`(t`:sub:`1` :g:`... t`:sub:`m`:g:`)`,
+ the tactic :n:`pattern t`:sub:`1`:n:`, ..., t`:sub:`m` generates the
+ equivalent goal
+ :g:`(fun (x`:sub:`1`:g:`:A`:sub:`1`:g:`) ... (x`:sub:`m` :g:`:A`:sub:`m` :g:`) =>`:math:`\varphi`:g:`(x`:sub:`1` :g:`... x`:sub:`m` :g:`)) t`:sub:`1` :g:`... t`:sub:`m`.
+ If :g:`t`:sub:`i` occurs in one of the generated types :g:`A`:sub:`j` these
+ occurrences will also be considered and possibly abstracted.
+
+.. tacv:: pattern {+, @term at {+ @natural}}
+
+ This behaves as above but processing only the occurrences :n:`{+ @natural}` of
+ :n:`@term` starting from :n:`@term`.
+
+.. tacv:: pattern {+, @term {? at {? -} {+, @natural}}}
+
+ This is the most general syntax that combines the different variants.
+
+.. tacn:: with_strategy @strategy_level_or_var [ {+ @reference } ] @ltac_expr3
+ :name: with_strategy
+
+ Executes :token:`ltac_expr3`, applying the alternate unfolding
+ behavior that the :cmd:`Strategy` command controls, but only for
+ :token:`ltac_expr3`. This can be useful for guarding calls to
+ reduction in tactic automation to ensure that certain constants are
+ never unfolded by tactics like :tacn:`simpl` and :tacn:`cbn` or to
+ ensure that unfolding does not fail.
+
+ .. example::
+
+ .. coqtop:: all reset abort
+
+ Opaque id.
+ Goal id 10 = 10.
+ Fail unfold id.
+ with_strategy transparent [id] unfold id.
+
+ .. warning::
+
+ Use this tactic with care, as effects do not persist past the
+ end of the proof script. Notably, this fine-tuning of the
+ conversion strategy is not in effect during :cmd:`Qed` nor
+ :cmd:`Defined`, so this tactic is most useful either in
+ combination with :tacn:`abstract`, which will check the proof
+ early while the fine-tuning is still in effect, or to guard
+ calls to conversion in tactic automation to ensure that, e.g.,
+ :tacn:`unfold` does not fail just because the user made a
+ constant :cmd:`Opaque`.
+
+ This can be illustrated with the following example involving the
+ factorial function.
+
+ .. coqtop:: in reset
+
+ Fixpoint fact (n : nat) : nat :=
+ match n with
+ | 0 => 1
+ | S n' => n * fact n'
+ end.
+
+ Suppose now that, for whatever reason, we want in general to
+ unfold the :g:`id` function very late during conversion:
+
+ .. coqtop:: in
+
+ Strategy 1000 [id].
+
+ If we try to prove :g:`id (fact n) = fact n` by
+ :tacn:`reflexivity`, it will now take time proportional to
+ :math:`n!`, because |Coq| will keep unfolding :g:`fact` and
+ :g:`*` and :g:`+` before it unfolds :g:`id`, resulting in a full
+ computation of :g:`fact n` (in unary, because we are using
+ :g:`nat`), which takes time :math:`n!`. We can see this cross
+ the relevant threshold at around :math:`n = 9`:
+
+ .. coqtop:: all abort
+
+ Goal True.
+ Time assert (id (fact 8) = fact 8) by reflexivity.
+ Time assert (id (fact 9) = fact 9) by reflexivity.
+
+ Note that behavior will be the same if you mark :g:`id` as
+ :g:`Opaque` because while most reduction tactics refuse to
+ unfold :g:`Opaque` constants, conversion treats :g:`Opaque` as
+ merely a hint to unfold this constant last.
+
+ We can get around this issue by using :tacn:`with_strategy`:
+
+ .. coqtop:: all
+
+ Goal True.
+ Fail Timeout 1 assert (id (fact 100) = fact 100) by reflexivity.
+ Time assert (id (fact 100) = fact 100) by with_strategy -1 [id] reflexivity.
+
+ However, when we go to close the proof, we will run into
+ trouble, because the reduction strategy changes are local to the
+ tactic passed to :tacn:`with_strategy`.
+
+ .. coqtop:: all abort fail
+
+ exact I.
+ Timeout 1 Defined.
+
+ We can fix this issue by using :tacn:`abstract`:
+
+ .. coqtop:: all
+
+ Goal True.
+ Time assert (id (fact 100) = fact 100) by with_strategy -1 [id] abstract reflexivity.
+ exact I.
+ Time Defined.
+
+ On small examples this sort of behavior doesn't matter, but
+ because |Coq| is a super-linear performance domain in so many
+ places, unless great care is taken, tactic automation using
+ :tacn:`with_strategy` may not be robustly performant when
+ scaling the size of the input.
+
+ .. warning::
+
+ In much the same way this tactic does not play well with
+ :cmd:`Qed` and :cmd:`Defined` without using :tacn:`abstract` as
+ an intermediary, this tactic does not play well with ``coqchk``,
+ even when used with :tacn:`abstract`, due to the inability of
+ tactics to persist information about conversion hints in the
+ proof term. See `#12200
+ <https://github.com/coq/coq/issues/12200>`_ for more details.
+
+Conversion tactics applied to hypotheses
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. tacn:: @tactic in {+, @ident}
+
+ Applies :token:`tactic` (any of the conversion tactics listed in this
+ section) to the hypotheses :n:`{+ @ident}`.
+
+ If :token:`ident` is a local definition, then :token:`ident` can be replaced by
+ :n:`type of @ident` to address not the body but the type of the local
+ definition.
+
+ Example: :n:`unfold not in (type of H1) (type of H3)`.
diff --git a/doc/sphinx/user-extensions/syntax-extensions.rst b/doc/sphinx/user-extensions/syntax-extensions.rst
index 06018304ab..9d1fcc160d 100644
--- a/doc/sphinx/user-extensions/syntax-extensions.rst
+++ b/doc/sphinx/user-extensions/syntax-extensions.rst
@@ -1386,7 +1386,7 @@ Scopes` or :cmd:`Print Scope`.
``char_scope``
This scope includes interpretation for all strings of the form ``"c"``
where :g:`c` is an ASCII character, or of the form ``"nnn"`` where nnn is
- a three-digits number (possibly with leading 0's), or of the form
+ a three-digit number (possibly with leading 0s), or of the form
``""""``. Their respective denotations are the ASCII code of :g:`c`, the
decimal ASCII code ``nnn``, or the ascii code of the character ``"`` (i.e.
the ASCII code 34), all of them being represented in the type :g:`ascii`.
@@ -1553,16 +1553,18 @@ numbers (see :ref:`datatypes`).
Number notations
~~~~~~~~~~~~~~~~
-.. cmd:: Number Notation @qualid__type @qualid__parse @qualid__print : @scope_name {? @numeral_modifier }
+.. cmd:: Number Notation @qualid__type @qualid__parse @qualid__print {? ( {+, @number_modifier } ) } : @scope_name
:name: Number Notation
- .. insertprodn numeral_modifier numeral_modifier
+ .. insertprodn number_modifier number_string_via
.. prodn::
- numeral_modifier ::= ( warning after @bignat )
- | ( abstract after @bignat )
+ number_modifier ::= warning after @bignat
+ | abstract after @bignat
+ | @number_string_via
+ number_string_via ::= via @qualid mapping [ {+, {| @qualid => @qualid | [ @qualid ] => @qualid } } ]
- This command allows the user to customize the way numeral literals
+ This command allows the user to customize the way number literals
are parsed and printed.
:n:`@qualid__type`
@@ -1571,32 +1573,32 @@ Number notations
parsing and printing functions, respectively. The parsing function
:n:`@qualid__parse` should have one of the following types:
- * :n:`Numeral.int -> @qualid__type`
- * :n:`Numeral.int -> option @qualid__type`
- * :n:`Numeral.uint -> @qualid__type`
- * :n:`Numeral.uint -> option @qualid__type`
+ * :n:`Number.int -> @qualid__type`
+ * :n:`Number.int -> option @qualid__type`
+ * :n:`Number.uint -> @qualid__type`
+ * :n:`Number.uint -> option @qualid__type`
* :n:`Z -> @qualid__type`
* :n:`Z -> option @qualid__type`
- * :n:`Numeral.numeral -> @qualid__type`
- * :n:`Numeral.numeral -> option @qualid__type`
+ * :n:`Number.number -> @qualid__type`
+ * :n:`Number.number -> option @qualid__type`
And the printing function :n:`@qualid__print` should have one of the
following types:
- * :n:`@qualid__type -> Numeral.int`
- * :n:`@qualid__type -> option Numeral.int`
- * :n:`@qualid__type -> Numeral.uint`
- * :n:`@qualid__type -> option Numeral.uint`
+ * :n:`@qualid__type -> Number.int`
+ * :n:`@qualid__type -> option Number.int`
+ * :n:`@qualid__type -> Number.uint`
+ * :n:`@qualid__type -> option Number.uint`
* :n:`@qualid__type -> Z`
* :n:`@qualid__type -> option Z`
- * :n:`@qualid__type -> Numeral.numeral`
- * :n:`@qualid__type -> option Numeral.numeral`
+ * :n:`@qualid__type -> Number.number`
+ * :n:`@qualid__type -> option Number.number`
.. deprecated:: 8.12
- Numeral notations on :g:`Decimal.uint`, :g:`Decimal.int` and
- :g:`Decimal.decimal` are replaced respectively by numeral
- notations on :g:`Numeral.uint`, :g:`Numeral.int` and
- :g:`Numeral.numeral`.
+ Number notations on :g:`Decimal.uint`, :g:`Decimal.int` and
+ :g:`Decimal.decimal` are replaced respectively by number
+ notations on :g:`Number.uint`, :g:`Number.int` and
+ :g:`Number.number`.
When parsing, the application of the parsing function
:n:`@qualid__parse` to the number will be fully reduced, and universes
@@ -1606,7 +1608,44 @@ Number notations
function application, constructors, inductive type families,
sorts, and primitive integers) will be considered for printing.
- :n:`( warning after @bignat )`
+ .. _number-string-via:
+
+ :n:`via @qualid__ind mapping [ {+, @qualid__constant => @qualid__constructor } ]`
+ When using this option, :n:`@qualid__type` no
+ longer needs to be an inductive type and is instead mapped to the
+ inductive type :n:`@qualid__ind` according to the provided
+ list of pairs, whose first component :n:`@qualid__constant` is a
+ constant of type :n:`@qualid__type`
+ (or a function of type :n:`{* _ -> } @qualid__type`) and the second a
+ constructor of type :n:`@qualid__ind`. The type
+ :n:`@qualid__type` is then replaced by :n:`@qualid__ind` in the
+ above parser and printer types.
+
+ When :n:`@qualid__constant` is surrounded by square brackets,
+ all the implicit arguments of :n:`@qualid__constant` (whether maximally inserted or not) are ignored
+ when translating to :n:`@qualid__constructor` (i.e., before
+ applying :n:`@qualid__print`) and replaced with implicit
+ argument holes :g:`_` when translating from
+ :n:`@qualid__constructor` to :n:`@qualid__constant` (after
+ :n:`@qualid__parse`). See below for an :ref:`example <example-number-notation-implicit-args>`.
+
+ .. note::
+ The implicit status of the arguments is considered
+ only at notation declaration time, any further
+ modification of this status has no impact
+ on the previously declared notations.
+
+ .. note::
+ In case of multiple implicit options (for instance
+ :g:`Arguments eq_refl {A}%type_scope {x}, [_] _`), an
+ argument is considered implicit when it is implicit in any of the
+ options.
+
+ .. note::
+ To use a :token:`sort` as the target type :n:`@qualid__type`, use an :ref:`abbreviation <Abbreviations>`
+ as in the :ref:`example below <example-number-notation-non-inductive>`.
+
+ :n:`warning after @bignat`
displays a warning message about a possible stack
overflow when calling :n:`@qualid__parse` to parse a literal larger than :n:`@bignat`.
@@ -1616,11 +1655,11 @@ Number notations
with :n:`(warning after @bignat)`, this warning is emitted when
parsing a number greater than or equal to :token:`bignat`.
- :n:`( abstract after @bignat )`
+ :n:`abstract after @bignat`
returns :n:`(@qualid__parse m)` when parsing a literal
:n:`m` that's greater than :n:`@bignat` rather than reducing it to a normal form.
Here :g:`m` will be a
- :g:`Numeral.int`, :g:`Numeral.uint`, :g:`Z` or :g:`Numeral.numeral`, depending on the
+ :g:`Number.int`, :g:`Number.uint`, :g:`Z` or :g:`Number.number`, depending on the
type of the parsing function :n:`@qualid__parse`. This allows for a
more compact representation of literals in types such as :g:`nat`,
and limits parse failures due to stack overflow. Note that a
@@ -1642,76 +1681,94 @@ Number notations
As noted above, the :n:`(abstract after @natural)` directive has no
effect when :n:`@qualid__parse` lands in an :g:`option` type.
+ .. exn:: 'via' and 'abstract' cannot be used together.
+
+ With the :n:`abstract after` option, the parser function
+ :n:`@qualid__parse` does not reduce large numbers to a normal form,
+ which prevents doing the translation given in the :n:`mapping` list.
+
.. exn:: Cannot interpret this number as a value of type @type
- The numeral notation registered for :token:`type` does not support
+ The number notation registered for :token:`type` does not support
the given number. This error is given when the interpretation
function returns :g:`None`, or if the interpretation is registered
only for integers or non-negative integers, and the given number
has a fractional or exponent part or is negative.
- .. exn:: @qualid__parse should go from Numeral.int to @type or (option @type). Instead of Numeral.int, the types Numeral.uint or Z or Int63.int or Numeral.numeral could be used (you may need to require BinNums or Numeral or Int63 first).
+ .. exn:: @qualid__parse should go from Number.int to @type or (option @type). Instead of Number.int, the types Number.uint or Z or Int63.int or Number.number could be used (you may need to require BinNums or Number or Int63 first).
The parsing function given to the :cmd:`Number Notation`
vernacular is not of the right type.
- .. exn:: @qualid__print should go from @type to Numeral.int or (option Numeral.int). Instead of Numeral.int, the types Numeral.uint or Z or Int63.int or Numeral.numeral could be used (you may need to require BinNums or Numeral or Int63 first).
+ .. exn:: @qualid__print should go from @type to Number.int or (option Number.int). Instead of Number.int, the types Number.uint or Z or Int63.int or Number.number could be used (you may need to require BinNums or Number or Int63 first).
The printing function given to the :cmd:`Number Notation`
vernacular is not of the right type.
- .. exn:: Unexpected term @term while parsing a numeral notation.
+ .. exn:: Unexpected term @term while parsing a number notation.
Parsing functions must always return ground terms, made up of
- applications of constructors, inductive types, and primitive
+ function application, constructors, inductive type families, sorts and primitive
integers. Parsing functions may not return terms containing
axioms, bare (co)fixpoints, lambdas, etc.
- .. exn:: Unexpected non-option term @term while parsing a numeral notation.
+ .. exn:: Unexpected non-option term @term while parsing a number notation.
Parsing functions expected to return an :g:`option` must always
return a concrete :g:`Some` or :g:`None` when applied to a
concrete number expressed as a (hexa)decimal. They may not return
opaque constants.
+ .. exn:: Multiple 'via' options.
+
+ At most one :g:`via` option can be given.
+
+ .. exn:: Multiple 'warning after' or 'abstract after' options.
+
+ At most one :g:`warning after` or :g:`abstract after` option can be given.
+
.. _string-notations:
String notations
~~~~~~~~~~~~~~~~
-.. cmd:: String Notation @qualid @qualid__parse @qualid__print : @scope_name
+.. cmd:: String Notation @qualid__type @qualid__parse @qualid__print {? ( @number_string_via ) } : @scope_name
:name: String Notation
Allows the user to customize how strings are parsed and printed.
- The token :n:`@qualid` should be the name of an inductive type,
- while :n:`@qualid__parse` and :n:`@qualid__print` should be the names of the
- parsing and printing functions, respectively. The parsing function
- :n:`@qualid__parse` should have one of the following types:
+ :n:`@qualid__type`
+ the name of an inductive type,
+ while :n:`@qualid__parse` and :n:`@qualid__print` should be the names of the
+ parsing and printing functions, respectively. The parsing function
+ :n:`@qualid__parse` should have one of the following types:
- * :n:`Byte.byte -> @qualid`
- * :n:`Byte.byte -> option @qualid`
- * :n:`list Byte.byte -> @qualid`
- * :n:`list Byte.byte -> option @qualid`
+ * :n:`Byte.byte -> @qualid__type`
+ * :n:`Byte.byte -> option @qualid__type`
+ * :n:`list Byte.byte -> @qualid__type`
+ * :n:`list Byte.byte -> option @qualid__type`
- The printing function :n:`@qualid__print` should have one of the
- following types:
+ The printing function :n:`@qualid__print` should have one of the
+ following types:
- * :n:`@qualid -> Byte.byte`
- * :n:`@qualid -> option Byte.byte`
- * :n:`@qualid -> list Byte.byte`
- * :n:`@qualid -> option (list Byte.byte)`
+ * :n:`@qualid__type -> Byte.byte`
+ * :n:`@qualid__type -> option Byte.byte`
+ * :n:`@qualid__type -> list Byte.byte`
+ * :n:`@qualid__type -> option (list Byte.byte)`
- When parsing, the application of the parsing function
- :n:`@qualid__parse` to the string will be fully reduced, and universes
- of the resulting term will be refreshed.
+ When parsing, the application of the parsing function
+ :n:`@qualid__parse` to the string will be fully reduced, and universes
+ of the resulting term will be refreshed.
- Note that only fully-reduced ground terms (terms containing only
- function application, constructors, inductive type families,
- sorts, and primitive integers) will be considered for printing.
+ Note that only fully-reduced ground terms (terms containing only
+ function application, constructors, inductive type families,
+ sorts, and primitive integers) will be considered for printing.
- .. exn:: Cannot interpret this string as a value of type @type
+ :n:`via @qualid__ind mapping [ {+, @qualid__constant => @qualid__constructor } ]`
+ works as for :ref:`number notations above <number-string-via>`.
+
+ .. exn:: Cannot interpret this string as a value of type @type
The string notation registered for :token:`type` does not support
the given string. This error is given when the interpretation
@@ -1730,7 +1787,7 @@ String notations
.. exn:: Unexpected term @term while parsing a string notation.
Parsing functions must always return ground terms, made up of
- applications of constructors, inductive types, and primitive
+ function application, constructors, inductive type families, sorts and primitive
integers. Parsing functions may not return terms containing
axioms, bare (co)fixpoints, lambdas, etc.
@@ -1741,16 +1798,37 @@ String notations
concrete string expressed as a decimal. They may not return
opaque constants.
-The following errors apply to both string and numeral notations:
+.. note::
+ Number or string notations for parameterized inductive types can be
+ added by declaring an :ref:`abbreviation <Abbreviations>` for the
+ inductive which instantiates all parameters. See :ref:`example below <example-string-notation-parameterized-inductive>`.
+
+The following errors apply to both string and number notations:
.. exn:: @type is not an inductive type.
- String and numeral notations can only be declared for inductive types with no
- arguments.
+ String and number notations can only be declared for inductive types.
+ Declare string or numeral notations for non-inductive types using :n:`@number_string_via`.
+
+ .. exn:: @qualid was already mapped to @qualid and cannot be remapped to @qualid
+
+ Duplicates are not allowed in the :n:`mapping` list.
+
+ .. exn:: Missing mapping for constructor @qualid
+
+ A mapping should be provided for :n:`@qualid` in the :n:`mapping` list.
+
+ .. warn:: @type was already mapped to @type, mapping it also to @type might yield ill typed terms when using the notation.
+
+ Two pairs in the :n:`mapping` list associate types that might be incompatible.
+
+ .. warn:: Type of @qualid seems incompatible with the type of @qualid. Expected type is: @type instead of @type. This might yield ill typed terms when using the notation.
+
+ A mapping given in the :n:`mapping` list associates a constant with a seemingly incompatible constructor.
.. exn:: Cannot interpret in @scope_name because @qualid could not be found in the current environment.
- The inductive type used to register the string or numeral notation is no
+ The inductive type used to register the string or number notation is no
longer available in the environment. Most likely, this is because
the notation was declared inside a functor for an
inductive type inside the functor. This use case is not currently
@@ -1779,6 +1857,198 @@ The following errors apply to both string and numeral notations:
.. todo note on "single qualified identifiers" https://github.com/coq/coq/pull/11718#discussion_r415076703
+.. example:: Number Notation for radix 3
+
+ The following example parses and prints natural numbers
+ whose digits are :g:`0`, :g:`1` or :g:`2` as terms of the following
+ inductive type encoding radix 3 numbers.
+
+ .. coqtop:: in reset
+
+ Inductive radix3 : Set :=
+ | x0 : radix3
+ | x3 : radix3 -> radix3
+ | x3p1 : radix3 -> radix3
+ | x3p2 : radix3 -> radix3.
+
+ We first define a parsing function
+
+ .. coqtop:: in
+
+ Definition of_uint_dec (u : Decimal.uint) : option radix3 :=
+ let fix f u := match u with
+ | Decimal.Nil => Some x0
+ | Decimal.D0 u => match f u with Some u => Some (x3 u) | None => None end
+ | Decimal.D1 u => match f u with Some u => Some (x3p1 u) | None => None end
+ | Decimal.D2 u => match f u with Some u => Some (x3p2 u) | None => None end
+ | _ => None end in
+ f (Decimal.rev u).
+ Definition of_uint (u : Number.uint) : option radix3 :=
+ match u with Number.UIntDecimal u => of_uint_dec u | Number.UIntHexadecimal _ => None end.
+
+ and a printing function
+
+ .. coqtop:: in
+
+ Definition to_uint_dec (x : radix3) : Decimal.uint :=
+ let fix f x := match x with
+ | x0 => Decimal.Nil
+ | x3 x => Decimal.D0 (f x)
+ | x3p1 x => Decimal.D1 (f x)
+ | x3p2 x => Decimal.D2 (f x) end in
+ Decimal.rev (f x).
+ Definition to_uint (x : radix3) : Number.uint := Number.UIntDecimal (to_uint_dec x).
+
+ before declaring the notation
+
+ .. coqtop:: in
+
+ Declare Scope radix3_scope.
+ Open Scope radix3_scope.
+ Number Notation radix3 of_uint to_uint : radix3_scope.
+
+ We can check the printer
+
+ .. coqtop:: all
+
+ Check x3p2 (x3p1 x0).
+
+ and the parser
+
+ .. coqtop:: all
+
+ Set Printing All.
+ Check 120.
+
+ Digits other than :g:`0`, :g:`1` and :g:`2` are rejected.
+
+ .. coqtop:: all fail
+
+ Check 3.
+
+.. _example-number-notation-non-inductive:
+
+.. example:: Number Notation for a non inductive type
+
+ The following example encodes the terms in the form :g:`sum unit ( ... (sum unit unit) ... )`
+ as the number of units in the term. For instance :g:`sum unit (sum unit unit)`
+ is encoded as :g:`3` while :g:`unit` is :g:`1` and :g:`0` stands for :g:`Empty_set`.
+ The inductive :g:`I` will be used as :n:`@qualid__ind`.
+
+ .. coqtop:: in reset
+
+ Inductive I := Iempty : I | Iunit : I | Isum : I -> I -> I.
+
+ We then define :n:`@qualid__parse` and :n:`@qualid__print`
+
+ .. coqtop:: in
+
+ Definition of_uint (x : Number.uint) : I :=
+ let fix f n := match n with
+ | O => Iempty | S O => Iunit
+ | S n => Isum Iunit (f n) end in
+ f (Nat.of_num_uint x).
+
+ Definition to_uint (x : I) : Number.uint :=
+ let fix f i := match i with
+ | Iempty => O | Iunit => 1
+ | Isum i1 i2 => f i1 + f i2 end in
+ Nat.to_num_uint (f x).
+
+ Inductive sum (A : Set) (B : Set) : Set := pair : A -> B -> sum A B.
+
+ the number notation itself
+
+ .. coqtop:: in
+
+ Notation nSet := Set (only parsing).
+ Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum]) : type_scope.
+
+ and check the printer
+
+ .. coqtop:: all
+
+ Local Open Scope type_scope.
+ Check sum unit (sum unit unit).
+
+ and the parser
+
+ .. coqtop:: all
+
+ Set Printing All.
+ Check 3.
+
+.. _example-number-notation-implicit-args:
+
+.. example:: Number Notation with implicit arguments
+
+ The following example parses and prints natural numbers between
+ :g:`0` and :g:`n-1` as terms of type :g:`Fin.t n`.
+
+ .. coqtop:: all reset
+
+ Require Import Vector.
+ Print Fin.t.
+
+ Note the implicit arguments of :g:`Fin.F1` and :g:`Fin.FS`,
+ which won't appear in the corresponding inductive type.
+
+ .. coqtop:: in
+
+ Inductive I := I1 : I | IS : I -> I.
+
+ Definition of_uint (x : Number.uint) : I :=
+ let fix f n := match n with O => I1 | S n => IS (f n) end in
+ f (Nat.of_num_uint x).
+
+ Definition to_uint (x : I) : Number.uint :=
+ let fix f i := match i with I1 => O | IS n => S (f n) end in
+ Nat.to_num_uint (f x).
+
+ Declare Scope fin_scope.
+ Delimit Scope fin_scope with fin.
+ Local Open Scope fin_scope.
+ Number Notation Fin.t of_uint to_uint (via I
+ mapping [[Fin.F1] => I1, [Fin.FS] => IS]) : fin_scope.
+
+ Now :g:`2` is parsed as :g:`Fin.FS (Fin.FS Fin.F1)`, that is
+ :g:`@Fin.FS _ (@Fin.FS _ (@Fin.F1 _))`.
+
+ .. coqtop:: all
+
+ Check 2.
+
+ which can be of type :g:`Fin.t 3` (numbers :g:`0`, :g:`1` and :g:`2`)
+
+ .. coqtop:: all
+
+ Check 2 : Fin.t 3.
+
+ but cannot be of type :g:`Fin.t 2` (only :g:`0` and :g:`1`)
+
+ .. coqtop:: all fail
+
+ Check 2 : Fin.t 2.
+
+.. _example-string-notation-parameterized-inductive:
+
+.. example:: String Notation with a parameterized inductive type
+
+ The parameter :g:`Byte.byte` for the parameterized inductive type
+ :g:`list` is given through an :ref:`abbreviation <Abbreviations>`.
+
+ .. coqtop:: in reset
+
+ Notation string := (list Byte.byte) (only parsing).
+ Definition id_string := @id string.
+
+ String Notation string id_string id_string : list_scope.
+
+ .. coqtop:: all
+
+ Check "abc"%list.
+
.. _TacticNotation:
Tactic Notations
diff --git a/doc/stdlib/hidden-files b/doc/stdlib/hidden-files
index 4d2972ef8f..e4f0967794 100644
--- a/doc/stdlib/hidden-files
+++ b/doc/stdlib/hidden-files
@@ -1,3 +1,4 @@
+theories/Init/Numeral.v
theories/btauto/Algebra.v
theories/btauto/Btauto.v
theories/btauto/Reflect.v
diff --git a/doc/stdlib/index-list.html.template b/doc/stdlib/index-list.html.template
index 7c1328916b..b08d7e9d2c 100644
--- a/doc/stdlib/index-list.html.template
+++ b/doc/stdlib/index-list.html.template
@@ -22,7 +22,7 @@ through the <tt>Require Import</tt> command.</p>
theories/Init/Nat.v
theories/Init/Decimal.v
theories/Init/Hexadecimal.v
- theories/Init/Numeral.v
+ theories/Init/Number.v
theories/Init/Peano.v
theories/Init/Specif.v
theories/Init/Tactics.v
@@ -238,6 +238,7 @@ through the <tt>Require Import</tt> command.</p>
theories/Numbers/DecimalN.v
theories/Numbers/DecimalZ.v
theories/Numbers/DecimalQ.v
+ theories/Numbers/DecimalR.v
theories/Numbers/DecimalString.v
theories/Numbers/HexadecimalFacts.v
theories/Numbers/HexadecimalNat.v
@@ -245,6 +246,7 @@ through the <tt>Require Import</tt> command.</p>
theories/Numbers/HexadecimalN.v
theories/Numbers/HexadecimalZ.v
theories/Numbers/HexadecimalQ.v
+ theories/Numbers/HexadecimalR.v
theories/Numbers/HexadecimalString.v
</dd>
diff --git a/doc/tools/docgram/common.edit_mlg b/doc/tools/docgram/common.edit_mlg
index f6a684bbd7..97d479b238 100644
--- a/doc/tools/docgram/common.edit_mlg
+++ b/doc/tools/docgram/common.edit_mlg
@@ -1285,12 +1285,12 @@ command: [
| WITH "Declare" "Scope" scope_name
(* odd that these are in command while other notation-related ones are in syntax *)
-| REPLACE "Numeral" "Notation" reference reference reference ":" ident numeral_modifier
-| WITH "Numeral" "Notation" reference reference reference ":" scope_name numeral_modifier
-| REPLACE "Number" "Notation" reference reference reference ":" ident numeral_modifier
-| WITH "Number" "Notation" reference reference reference ":" scope_name numeral_modifier
-| REPLACE "String" "Notation" reference reference reference ":" ident
-| WITH "String" "Notation" reference reference reference ":" scope_name
+| REPLACE "Number" "Notation" reference reference reference OPT number_options ":" ident
+| WITH "Number" "Notation" reference reference reference OPT number_options ":" scope_name
+| REPLACE "Numeral" "Notation" reference reference reference ":" ident deprecated_number_modifier
+| WITH "Numeral" "Notation" reference reference reference ":" scope_name deprecated_number_modifier
+| REPLACE "String" "Notation" reference reference reference OPT string_option ":" ident
+| WITH "String" "Notation" reference reference reference OPT string_option ":" scope_name
| DELETE "Ltac2" ltac2_entry (* was split up *)
| DELETE "Add" "Zify" "InjTyp" constr (* micromega plugin *)
@@ -1358,10 +1358,6 @@ explicit_subentry: [
| DELETE "constr" (* covered by another prod *)
]
-numeral_modifier: [
-| OPTINREF
-]
-
binder_tactic: [
| REPLACE "let" [ "rec" | ] LIST1 let_clause SEP "with" "in" ltac_expr5
| WITH "let" OPT "rec" let_clause LIST0 ( "with" let_clause ) "in" ltac_expr5
@@ -2198,6 +2194,7 @@ ltac2_expr5: [
| REPLACE "let" OPT "rec" LIST1 ltac2_let_clause SEP "with" "in" ltac2_expr6 (* Ltac2 plugin *)
| WITH "let" OPT "rec" ltac2_let_clause LIST0 ( "with" ltac2_let_clause ) "in" ltac2_expr6 TAG Ltac2
| MOVETO simple_tactic "match" ltac2_expr5 "with" OPT ltac2_branches "end" (* Ltac2 plugin *)
+| MOVETO simple_tactic "if" ltac2_expr5 "then" ltac2_expr5 "else" ltac2_expr5 (* Ltac2 plugin *)
| DELETE simple_tactic
]
@@ -2464,6 +2461,9 @@ SPLICE: [
| constr_with_bindings
| simple_binding
| ssexpr35 (* strange in mlg, ssexpr50 is after this *)
+| number_string_mapping
+| number_options
+| string_option
] (* end SPLICE *)
RENAME: [
diff --git a/doc/tools/docgram/doc_grammar.ml b/doc/tools/docgram/doc_grammar.ml
index b7f1e18d2b..92bcd51528 100644
--- a/doc/tools/docgram/doc_grammar.ml
+++ b/doc/tools/docgram/doc_grammar.ml
@@ -538,12 +538,11 @@ let autoloaded_mlgs = [ (* in the order they are loaded by Coq *)
"plugins/ltac/g_eqdecide.mlg";
"plugins/ltac/g_tactic.mlg";
"plugins/ltac/g_ltac.mlg";
- "plugins/syntax/g_string.mlg";
"plugins/btauto/g_btauto.mlg";
"plugins/rtauto/g_rtauto.mlg";
"plugins/cc/g_congruence.mlg";
"plugins/firstorder/g_ground.mlg";
- "plugins/syntax/g_numeral.mlg";
+ "plugins/syntax/g_number_string.mlg";
]
diff --git a/doc/tools/docgram/fullGrammar b/doc/tools/docgram/fullGrammar
index c764cb6f37..20ac8f8bf3 100644
--- a/doc/tools/docgram/fullGrammar
+++ b/doc/tools/docgram/fullGrammar
@@ -686,9 +686,9 @@ command: [
| "Print" "Rings" (* ring plugin *)
| "Add" "Field" ident ":" constr OPT field_mods (* ring plugin *)
| "Print" "Fields" (* ring plugin *)
-| "Number" "Notation" reference reference reference ":" ident numeral_modifier
-| "Numeral" "Notation" reference reference reference ":" ident numeral_modifier
-| "String" "Notation" reference reference reference ":" ident
+| "Number" "Notation" reference reference reference OPT number_options ":" ident
+| "Numeral" "Notation" reference reference reference ":" ident deprecated_number_modifier
+| "String" "Notation" reference reference reference OPT string_option ":" ident
| "Ltac2" ltac2_entry (* Ltac2 plugin *)
| "Ltac2" "Eval" ltac2_expr6 (* Ltac2 plugin *)
| "Print" "Ltac2" reference (* Ltac2 plugin *)
@@ -2549,12 +2549,35 @@ field_mods: [
| "(" LIST1 field_mod SEP "," ")" (* ring plugin *)
]
-numeral_modifier: [
+deprecated_number_modifier: [
|
| "(" "warning" "after" bignat ")"
| "(" "abstract" "after" bignat ")"
]
+number_string_mapping: [
+| reference "=>" reference
+| "[" reference "]" "=>" reference
+]
+
+number_string_via: [
+| "via" reference "mapping" "[" LIST1 number_string_mapping SEP "," "]"
+]
+
+number_modifier: [
+| "warning" "after" bignat
+| "abstract" "after" bignat
+| number_string_via
+]
+
+number_options: [
+| "(" LIST1 number_modifier SEP "," ")"
+]
+
+string_option: [
+| "(" number_string_via ")"
+]
+
tac2pat1: [
| Prim.qualid LIST1 tac2pat0 (* Ltac2 plugin *)
| Prim.qualid (* Ltac2 plugin *)
@@ -2586,6 +2609,7 @@ ltac2_expr5: [
| "fun" LIST1 G_LTAC2_input_fun "=>" ltac2_expr6 (* Ltac2 plugin *)
| "let" rec_flag LIST1 G_LTAC2_let_clause SEP "with" "in" ltac2_expr6 (* Ltac2 plugin *)
| "match" ltac2_expr5 "with" G_LTAC2_branches "end" (* Ltac2 plugin *)
+| "if" ltac2_expr5 "then" ltac2_expr5 "else" ltac2_expr5 (* Ltac2 plugin *)
| ltac2_expr4 (* Ltac2 plugin *)
]
diff --git a/doc/tools/docgram/orderedGrammar b/doc/tools/docgram/orderedGrammar
index 12a7bc684d..75c0ca1453 100644
--- a/doc/tools/docgram/orderedGrammar
+++ b/doc/tools/docgram/orderedGrammar
@@ -884,8 +884,6 @@ command: [
| "Print" "Rings" (* ring plugin *)
| "Add" "Field" ident ":" one_term OPT ( "(" LIST1 field_mod SEP "," ")" ) (* ring plugin *)
| "Print" "Fields" (* ring plugin *)
-| "Number" "Notation" qualid qualid qualid ":" scope_name OPT numeral_modifier
-| "Numeral" "Notation" qualid qualid qualid ":" scope_name OPT numeral_modifier
| "Hint" "Cut" "[" hints_path "]" OPT ( ":" LIST1 ident )
| "Typeclasses" "Transparent" LIST1 qualid
| "Typeclasses" "Opaque" LIST1 qualid
@@ -910,7 +908,9 @@ command: [
| "Derive" "Dependent" "Inversion_clear" ident "with" one_term "Sort" sort_family
| "Declare" "Left" "Step" one_term
| "Declare" "Right" "Step" one_term
-| "String" "Notation" qualid qualid qualid ":" scope_name
+| "Number" "Notation" qualid qualid qualid OPT ( "(" LIST1 number_modifier SEP "," ")" ) ":" scope_name
+| "Numeral" "Notation" qualid qualid qualid ":" scope_name deprecated_number_modifier
+| "String" "Notation" qualid qualid qualid OPT ( "(" number_string_via ")" ) ":" scope_name
| "SubClass" ident_decl def_body
| thm_token ident_decl LIST0 binder ":" type LIST0 [ "with" ident_decl LIST0 binder ":" type ]
| assumption_token OPT ( "Inline" OPT ( "(" natural ")" ) ) [ LIST1 ( "(" assumpt ")" ) | assumpt ]
@@ -1269,11 +1269,22 @@ field_mod: [
| "completeness" one_term (* ring plugin *)
]
-numeral_modifier: [
+deprecated_number_modifier: [
+|
| "(" "warning" "after" bignat ")"
| "(" "abstract" "after" bignat ")"
]
+number_modifier: [
+| "warning" "after" bignat
+| "abstract" "after" bignat
+| number_string_via
+]
+
+number_string_via: [
+| "via" qualid "mapping" "[" LIST1 [ qualid "=>" qualid | "[" qualid "]" "=>" qualid ] SEP "," "]"
+]
+
hints_path: [
| "(" hints_path ")"
| hints_path "*"
@@ -1640,6 +1651,7 @@ simple_tactic: [
| "ring" OPT ( "[" LIST1 one_term "]" )
| "ring_simplify" OPT ( "[" LIST1 one_term "]" ) LIST1 one_term OPT ( "in" ident )
| "match" ltac2_expr5 "with" OPT ltac2_branches "end"
+| "if" ltac2_expr5 "then" ltac2_expr5 "else" ltac2_expr5
| qualid LIST1 tactic_arg
]
diff --git a/engine/eConstr.ml b/engine/eConstr.ml
index 374cb72753..bb2873b486 100644
--- a/engine/eConstr.ml
+++ b/engine/eConstr.ml
@@ -563,6 +563,9 @@ let universes_of_constr sigma c =
| Array (u,_,_,_) ->
let s = LSet.fold LSet.add (Instance.levels (EInstance.kind sigma u)) s in
fold sigma aux s c
+ | Case (_,_,CaseInvert {univs;args=_},_,_) ->
+ let s = LSet.fold LSet.add (Instance.levels (EInstance.kind sigma univs)) s in
+ fold sigma aux s c
| _ -> fold sigma aux s c
in aux LSet.empty c
diff --git a/ide/coqide/coq.ml b/ide/coqide/coq.ml
index 1167b8199e..b8228df2aa 100644
--- a/ide/coqide/coq.ml
+++ b/ide/coqide/coq.ml
@@ -550,6 +550,7 @@ struct
let existential = BoolOpt ["Printing"; "Existential"; "Instances"]
let universes = BoolOpt ["Printing"; "Universes"]
let unfocused = BoolOpt ["Printing"; "Unfocused"]
+ let goal_names = BoolOpt ["Printing"; "Goal"; "Names"]
let diff = StringOpt ["Diffs"]
type 'a descr = { opts : 'a t list; init : 'a; label : string }
@@ -568,7 +569,8 @@ struct
{ opts = [universes]; init = false; label = "Display _universe levels" };
{ opts = [all_basic;existential;universes]; init = false;
label = "Display all _low-level contents" };
- { opts = [unfocused]; init = false; label = "Display _unfocused goals" }
+ { opts = [unfocused]; init = false; label = "Display _unfocused goals" };
+ { opts = [goal_names]; init = false; label = "Display _goal names" }
]
let diff_item = { opts = [diff]; init = "off"; label = "Display _proof diffs" }
diff --git a/ide/coqide/coqide_ui.ml b/ide/coqide/coqide_ui.ml
index 6540fc6fca..badfabf07e 100644
--- a/ide/coqide/coqide_ui.ml
+++ b/ide/coqide/coqide_ui.ml
@@ -85,6 +85,7 @@ let init () =
\n <menuitem action='Display universe levels' />\
\n <menuitem action='Display all low-level contents' />\
\n <menuitem action='Display unfocused goals' />\
+\n <menuitem action='Display goal names' />\
\n <separator/>\
\n <menuitem action='Unset diff' />\
\n <menuitem action='Set diff' />\
diff --git a/ide/coqide/idetop.ml b/ide/coqide/idetop.ml
index ddfa3a80bd..602acefa7c 100644
--- a/ide/coqide/idetop.ml
+++ b/ide/coqide/idetop.ml
@@ -195,7 +195,7 @@ let concl_next_tac =
let process_goal sigma g =
let env = Goal.V82.env sigma g in
let min_env = Environ.reset_context env in
- let id = Goal.uid g in
+ let id = if Printer.print_goal_names () then Names.Id.to_string (Termops.evar_suggested_name g sigma) else "" in
let ccl =
pr_letype_env ~goal_concl_style:true env sigma (Goal.V82.concl sigma g)
in
@@ -206,7 +206,7 @@ let process_goal sigma g =
let (_env, hyps) =
Context.Compacted.fold process_hyp
(Termops.compact_named_context (Environ.named_context env)) ~init:(min_env,[]) in
- { Interface.goal_hyp = List.rev hyps; Interface.goal_ccl = ccl; Interface.goal_id = id; }
+ { Interface.goal_hyp = List.rev hyps; Interface.goal_ccl = ccl; Interface.goal_id = id }
let process_goal_diffs diff_goal_map oldp nsigma ng =
let open Evd in
diff --git a/ide/coqide/wg_ProofView.ml b/ide/coqide/wg_ProofView.ml
index 1de63953af..8e451c9917 100644
--- a/ide/coqide/wg_ProofView.ml
+++ b/ide/coqide/wg_ProofView.ml
@@ -52,7 +52,7 @@ let hook_tag_cb tag menu_content sel_cb hover_cb =
let mode_tactic sel_cb (proof : #GText.view_skel) goals ~unfoc_goals hints = match goals with
| [] -> assert false
- | { Interface.goal_hyp = hyps; Interface.goal_ccl = cur_goal; } :: rem_goals ->
+ | { Interface.goal_hyp = hyps; Interface.goal_ccl = cur_goal; Interface.goal_id = cur_id } :: rem_goals ->
let on_hover sel_start sel_stop =
proof#buffer#remove_tag
~start:proof#buffer#start_iter
@@ -68,11 +68,11 @@ let mode_tactic sel_cb (proof : #GText.view_skel) goals ~unfoc_goals hints = mat
let head_str = Printf.sprintf
"%d subgoal%s\n" goals_cnt (if 1 < goals_cnt then "s" else "")
in
- let goal_str ?(shownum=false) index total =
- if shownum then Printf.sprintf
- "______________________________________(%d/%d)\n" index total
- else Printf.sprintf
- "______________________________________\n"
+ let goal_str ?(shownum=false) index total id =
+ let annot =
+ if CString.is_empty id then if shownum then Printf.sprintf "(%d/%d)" index total else ""
+ else Printf.sprintf "(?%s)" id in
+ Printf.sprintf "______________________________________%s\n" annot
in
(* Insert current goal and its hypotheses *)
let hyps_hints, goal_hints = match hints with
@@ -103,13 +103,13 @@ let mode_tactic sel_cb (proof : #GText.view_skel) goals ~unfoc_goals hints = mat
[tag]
else []
in
- proof#buffer#insert (goal_str ~shownum:true 1 goals_cnt);
+ proof#buffer#insert (goal_str ~shownum:true 1 goals_cnt cur_id);
insert_xml ~tags:[Tags.Proof.goal] proof#buffer (Richpp.richpp_of_pp width cur_goal);
proof#buffer#insert "\n"
in
(* Insert remaining goals (no hypotheses) *)
- let fold_goal ?(shownum=false) i _ { Interface.goal_ccl = g } =
- proof#buffer#insert (goal_str ~shownum i goals_cnt);
+ let fold_goal ?(shownum=false) i _ { Interface.goal_ccl = g; Interface.goal_id = id } =
+ proof#buffer#insert (goal_str ~shownum i goals_cnt id);
insert_xml proof#buffer (Richpp.richpp_of_pp width g);
proof#buffer#insert "\n"
in
@@ -178,12 +178,16 @@ let display mode (view : #GText.view_skel) goals hints evars =
| _, _, _, _ ->
(* No foreground proofs, but still unfocused ones *)
let total = List.length bg in
- let goal_str index = Printf.sprintf
- "______________________________________(%d/%d)\n" index total
+ let goal_str index id =
+ let annot =
+ if CString.is_empty id then Printf.sprintf "(%d/%d)" index total
+ else Printf.sprintf "(?%s)" id in
+ Printf.sprintf
+ "______________________________________%s\n" annot
in
view#buffer#insert "This subproof is complete, but there are some unfocused goals:\n\n";
let iter i goal =
- let () = view#buffer#insert (goal_str (succ i)) in
+ let () = view#buffer#insert (goal_str (succ i) goal.Interface.goal_id) in
insert_xml view#buffer (Richpp.richpp_of_pp width goal.Interface.goal_ccl);
view#buffer#insert "\n"
in
diff --git a/interp/constrexpr.ml b/interp/constrexpr.ml
index d14d156ffc..235310660b 100644
--- a/interp/constrexpr.ml
+++ b/interp/constrexpr.ml
@@ -58,7 +58,7 @@ type abstraction_kind = AbsLambda | AbsPi
type proj_flag = int option (** [Some n] = proj of the n-th visible argument *)
type prim_token =
- | Numeral of NumTok.Signed.t
+ | Number of NumTok.Signed.t
| String of string
type instance_expr = Glob_term.glob_level list
diff --git a/interp/constrexpr_ops.ml b/interp/constrexpr_ops.ml
index 7075d082ee..8cc63c5d03 100644
--- a/interp/constrexpr_ops.ml
+++ b/interp/constrexpr_ops.ml
@@ -44,13 +44,13 @@ let names_of_local_binders bl =
(**********************************************************************)
(* Functions on constr_expr *)
-(* Note: redundant Numeral representations, such as -0 and +0 (and others),
+(* Note: redundant Number representations, such as -0 and +0 (and others),
are considered different here. *)
let prim_token_eq t1 t2 = match t1, t2 with
-| Numeral n1, Numeral n2 -> NumTok.Signed.equal n1 n2
+| Number n1, Number n2 -> NumTok.Signed.equal n1 n2
| String s1, String s2 -> String.equal s1 s2
-| (Numeral _ | String _), _ -> false
+| (Number _ | String _), _ -> false
let explicitation_eq ex1 ex2 = match ex1, ex2 with
| ExplByPos (i1, id1), ExplByPos (i2, id2) ->
diff --git a/interp/constrextern.ml b/interp/constrextern.ml
index 7bf1c58148..d1bec16a3f 100644
--- a/interp/constrextern.ml
+++ b/interp/constrextern.ml
@@ -357,18 +357,18 @@ let destPatPrim = function { CAst.v = CPatPrim t } -> Some t | _ -> None
let make_notation_gen loc ntn mknot mkprim destprim l bl =
match snd ntn,List.map destprim l with
(* Special case to avoid writing "- 3" for e.g. (Z.opp 3) *)
- | "- _", [Some (Numeral p)] when not (NumTok.Signed.is_zero p) ->
+ | "- _", [Some (Number p)] when not (NumTok.Signed.is_zero p) ->
assert (bl=[]);
mknot (loc,ntn,([mknot (loc,(InConstrEntry,"( _ )"),l,[])]),[])
| _ ->
match decompose_notation_key ntn, l with
| (InConstrEntry,[Terminal "-"; Terminal x]), [] ->
begin match NumTok.Unsigned.parse_string x with
- | Some n -> mkprim (loc, Numeral (NumTok.SMinus,n))
+ | Some n -> mkprim (loc, Number (NumTok.SMinus,n))
| None -> mknot (loc,ntn,l,bl) end
| (InConstrEntry,[Terminal x]), [] ->
begin match NumTok.Unsigned.parse_string x with
- | Some n -> mkprim (loc, Numeral (NumTok.SPlus,n))
+ | Some n -> mkprim (loc, Number (NumTok.SPlus,n))
| None -> mknot (loc,ntn,l,bl) end
| _ -> mknot (loc,ntn,l,bl)
@@ -915,7 +915,7 @@ let extern_float f scopes =
let hex = !Flags.raw_print || not (get_printing_float ()) in
if hex then Float64.to_hex_string f else Float64.to_string f in
let n = NumTok.Signed.of_string s in
- extern_prim_token_delimiter_if_required (Numeral n)
+ extern_prim_token_delimiter_if_required (Number n)
"float" "float_scope" scopes
(**********************************************************************)
@@ -1097,7 +1097,7 @@ let rec extern inctx ?impargs scopes vars r =
| GInt i ->
extern_prim_token_delimiter_if_required
- (Numeral (NumTok.Signed.of_int_string (Uint63.to_string i)))
+ (Number (NumTok.Signed.of_int_string (Uint63.to_string i)))
"int63" "int63_scope" (snd scopes)
| GFloat f -> extern_float f (snd scopes)
diff --git a/interp/constrintern.ml b/interp/constrintern.ml
index 959b61a3d7..409e46864e 100644
--- a/interp/constrintern.ml
+++ b/interp/constrintern.ml
@@ -263,6 +263,13 @@ type intern_env = {
binder_block_names: (abstraction_kind option (* None = unknown *) * Id.Set.t) option;
}
+type pattern_intern_env = {
+ pat_scopes: Notation_term.subscopes;
+ (* ids = Some means accept local variables; this is useful for
+ terms as patterns parsed as pattersn in notations *)
+ pat_ids: Id.Set.t option;
+}
+
(**********************************************************************)
(* Remembering the parsing scope of variables in notations *)
@@ -317,6 +324,9 @@ let reset_tmp_scope env = {env with tmp_scope = None}
let set_env_scopes env (scopt,subscopes) =
{env with tmp_scope = scopt; scopes = subscopes @ env.scopes}
+let env_for_pattern env =
+ {pat_scopes = (env.tmp_scope, env.scopes); pat_ids = Some env.ids}
+
let mkGProd ?loc (na,bk,t) body = DAst.make ?loc @@ GProd (na, bk, t, body)
let mkGLambda ?loc (na,bk,t) body = DAst.make ?loc @@ GLambda (na, bk, t, body)
@@ -420,6 +430,40 @@ let binder_status_fun = {
slide = on_snd slide_binders;
}
+(* [test_kind_strict] rules out pattern which refers to global other
+ than constructors or variables; It is used in instances of notations *)
+
+let test_kind_pattern_in_notation ?loc = function
+ | GlobRef.ConstructRef _ -> ()
+ (* We do not accept non constructors to be used as variables in
+ patterns *)
+ | GlobRef.ConstRef _ ->
+ user_err ?loc (str "Found a constant while a pattern was expected.")
+ | GlobRef.IndRef _ ->
+ user_err ?loc (str "Found an inductive type while a pattern was expected.")
+ | GlobRef.VarRef _ ->
+ (* we accept a section variable name to be used as pattern variable *)
+ raise Not_found
+
+let test_kind_ident_in_notation ?loc = function
+ | GlobRef.ConstructRef _ ->
+ user_err ?loc (str "Found a constructor while a variable name was expected.")
+ | GlobRef.ConstRef _ ->
+ user_err ?loc (str "Found a constant while a variable name was expected.")
+ | GlobRef.IndRef _ ->
+ user_err ?loc (str "Found an inductive type while a variable name was expected.")
+ | GlobRef.VarRef _ ->
+ (* we accept a section variable name to be used as pattern variable *)
+ raise Not_found
+
+(* [test_kind_tolerant] allow global reference names to be used as pattern variables *)
+
+let test_kind_tolerant ?loc = function
+ | GlobRef.ConstructRef _ -> ()
+ | GlobRef.ConstRef _ | GlobRef.IndRef _ | GlobRef.VarRef _ ->
+ (* A non-constructor global reference in a pattern is seen as a variable *)
+ raise Not_found
+
(**)
let locate_if_hole ?loc na c = match DAst.get c with
@@ -539,9 +583,9 @@ let intern_letin_binder intern ntnvars env (({loc;v=na} as locna),def,ty) =
(push_name_env ntnvars impls env locna,
(na,Explicit,term,ty))
-let intern_cases_pattern_as_binder ?loc ntnvars env p =
+let intern_cases_pattern_as_binder ?loc test_kind ntnvars env p =
let il,disjpat =
- let (il, subst_disjpat) = !intern_cases_pattern_fwd ntnvars (None,env.scopes) p in
+ let (il, subst_disjpat) = !intern_cases_pattern_fwd test_kind ntnvars (env_for_pattern (reset_tmp_scope env)) p in
let substl,disjpat = List.split subst_disjpat in
if not (List.for_all (fun subst -> Id.Map.equal Id.equal subst Id.Map.empty) substl) then
user_err ?loc (str "Unsupported nested \"as\" clause.");
@@ -568,7 +612,7 @@ let intern_local_binder_aux intern ntnvars (env,bl) = function
| Some ty -> ty
| None -> CAst.make ?loc @@ CHole(None,IntroAnonymous,None)
in
- let env, ((disjpat,il),id),na = intern_cases_pattern_as_binder ?loc ntnvars env p in
+ let env, ((disjpat,il),id),na = intern_cases_pattern_as_binder ?loc test_kind_tolerant ntnvars env p in
let bk = Default Explicit in
let _, bl' = intern_assumption intern ntnvars env [na] bk tyc in
let {v=(_,bk,t)} = List.hd bl' in
@@ -661,27 +705,21 @@ let is_patvar_store store pat =
| PatVar na -> ignore(store na); true
| _ -> false
-let out_patvar pat =
- match pat.v with
+let out_patvar = CAst.map_with_loc (fun ?loc -> function
| CPatAtom (Some qid) when qualid_is_ident qid ->
Name (qualid_basename qid)
| CPatAtom None -> Anonymous
- | _ -> assert false
-
-let term_of_name = function
- | Name id -> DAst.make (GVar id)
- | Anonymous ->
- let st = Evar_kinds.Define (not (Program.get_proofs_transparency ())) in
- DAst.make (GHole (Evar_kinds.QuestionMark { Evar_kinds.default_question_mark with Evar_kinds.qm_obligation=st }, IntroAnonymous, None))
+ | _ -> assert false)
let traverse_binder intern_pat ntnvars (terms,_,binders,_ as subst) avoid (renaming,env) = function
| Anonymous -> (renaming,env), None, Anonymous
| Name id ->
let store,get = set_temporary_memory () in
+ let test_kind = test_kind_tolerant in
try
(* We instantiate binder name with patterns which may be parsed as terms *)
let pat = coerce_to_cases_pattern_expr (fst (Id.Map.find id terms)) in
- let env,((disjpat,ids),id),na = intern_pat ntnvars env pat in
+ let env,((disjpat,ids),id),na = intern_pat test_kind ntnvars env pat in
let pat, na = match disjpat with
| [pat] when is_patvar_store store pat -> let na = get () in None, na
| _ -> Some ((List.map (fun x -> x.v) ids,disjpat),id), na.v in
@@ -694,11 +732,11 @@ let traverse_binder intern_pat ntnvars (terms,_,binders,_ as subst) avoid (renam
if onlyident then
(* Do not try to interpret a variable as a constructor *)
let na = out_patvar pat in
- let env = push_name_env ntnvars [] env (make ?loc:pat.loc na) in
- (renaming,env), None, na
+ let env = push_name_env ntnvars [] env na in
+ (renaming,env), None, na.v
else
(* Interpret as a pattern *)
- let env,((disjpat,ids),id),na = intern_pat ntnvars env pat in
+ let env,((disjpat,ids),id),na = intern_pat test_kind ntnvars env pat in
let pat, na =
match disjpat with
| [pat] when is_patvar_store store pat -> let na = get () in None, na
@@ -829,22 +867,22 @@ let instantiate_notation_constr loc intern intern_pat ntnvars subst infos c =
let arg = match arg with
| None -> None
| Some arg ->
- let mk_env id (c, (tmp_scope, subscopes)) map =
- let nenv = {env with tmp_scope; scopes = subscopes @ env.scopes} in
+ let mk_env id (c, scopes) map =
+ let nenv = set_env_scopes env scopes in
try
let gc = intern nenv c in
Id.Map.add id (gc, None) map
with Nametab.GlobalizationError _ -> map
in
- let mk_env' (c, (onlyident,(tmp_scope,subscopes))) =
- let nenv = {env with tmp_scope; scopes = subscopes @ env.scopes} in
- if onlyident then
- let na = out_patvar c in term_of_name na, None
- else
- let _,((disjpat,_),_),_ = intern_pat ntnvars nenv c in
- match disjpat with
- | [pat] -> (glob_constr_of_cases_pattern (Global.env()) pat, None)
- | _ -> error_cannot_coerce_disjunctive_pattern_term ?loc:c.loc ()
+ let mk_env' (c, (onlyident,scopes)) =
+ let nenv = set_env_scopes env scopes in
+ let test_kind =
+ if onlyident then test_kind_ident_in_notation
+ else test_kind_pattern_in_notation in
+ let _,((disjpat,_),_),_ = intern_pat test_kind ntnvars nenv c in
+ match disjpat with
+ | [pat] -> (glob_constr_of_cases_pattern (Global.env()) pat, None)
+ | _ -> error_cannot_coerce_disjunctive_pattern_term ?loc:c.loc ()
in
let terms = Id.Map.fold mk_env terms Id.Map.empty in
let binders = Id.Map.map mk_env' binders in
@@ -890,20 +928,19 @@ let instantiate_notation_constr loc intern intern_pat ntnvars subst infos c =
(* subst remembers the delimiters stack in the interpretation *)
(* of the notations *)
try
- let (a,(scopt,subscopes)) = Id.Map.find id terms in
- intern {env with tmp_scope = scopt;
- scopes = subscopes @ env.scopes} a
+ let (a,scopes) = Id.Map.find id terms in
+ intern (set_env_scopes env scopes) a
with Not_found ->
try
let pat,(onlyident,scopes) = Id.Map.find id binders in
- let env = set_env_scopes env scopes in
- if onlyident then
- term_of_name (out_patvar pat)
- else
- let env,((disjpat,ids),id),na = intern_pat ntnvars env pat in
- match disjpat with
- | [pat] -> glob_constr_of_cases_pattern (Global.env()) pat
- | _ -> user_err Pp.(str "Cannot turn a disjunctive pattern into a term.")
+ let nenv = set_env_scopes env scopes in
+ let test_kind =
+ if onlyident then test_kind_ident_in_notation
+ else test_kind_pattern_in_notation in
+ let env,((disjpat,ids),id),na = intern_pat test_kind ntnvars nenv pat in
+ match disjpat with
+ | [pat] -> glob_constr_of_cases_pattern (Global.env()) pat
+ | _ -> user_err Pp.(str "Cannot turn a disjunctive pattern into a term.")
with Not_found ->
try
match binderopt with
@@ -1570,11 +1607,11 @@ let rec subst_pat_iterator y t = DAst.(map (function
| RCPatOr pl -> RCPatOr (List.map (subst_pat_iterator y t) pl)))
let is_non_zero c = match c with
-| { CAst.v = CPrim (Numeral p) } -> not (NumTok.Signed.is_zero p)
+| { CAst.v = CPrim (Number p) } -> not (NumTok.Signed.is_zero p)
| _ -> false
let is_non_zero_pat c = match c with
-| { CAst.v = CPatPrim (Numeral p) } -> not (NumTok.Signed.is_zero p)
+| { CAst.v = CPatPrim (Number p) } -> not (NumTok.Signed.is_zero p)
| _ -> false
let get_asymmetric_patterns = Goptions.declare_bool_option_and_ref
@@ -1582,19 +1619,14 @@ let get_asymmetric_patterns = Goptions.declare_bool_option_and_ref
~key:["Asymmetric";"Patterns"]
~value:false
-let drop_notations_pattern looked_for genv =
+let drop_notations_pattern (test_kind_top,test_kind_inner) genv env pat =
(* At toplevel, Constructors and Inductives are accepted, in recursive calls
only constructor are allowed *)
- let ensure_kind top loc g =
- try
- if top then looked_for g else
- match g with GlobRef.ConstructRef _ -> () | _ -> raise Not_found
+ let ensure_kind test_kind ?loc g =
+ try test_kind ?loc g
with Not_found ->
error_invalid_pattern_notation ?loc ()
in
- let test_kind top =
- if top then looked_for else function GlobRef.ConstructRef _ -> () | _ -> raise Not_found
- in
(* [rcp_of_glob] : from [glob_constr] to [raw_cases_pattern_expr] *)
let rec rcp_of_glob scopes x = DAst.(map (function
| GVar id -> RCPatAtom (Some (CAst.make ?loc:x.loc id,scopes))
@@ -1611,47 +1643,49 @@ let drop_notations_pattern looked_for genv =
end
| _ -> CErrors.anomaly Pp.(str "Invalid return pattern from Notation.interp_prim_token_cases_pattern_expr."))) x
in
- let rec drop_syndef top scopes qid pats =
+ let rec drop_syndef test_kind ?loc scopes qid pats =
try
+ if qualid_is_ident qid && Option.cata (Id.Set.mem (qualid_basename qid)) false env.pat_ids then
+ raise Not_found;
match Nametab.locate_extended qid with
| SynDef sp ->
let filter (vars,a) =
try match a with
| NRef g ->
(* Convention: do not deactivate implicit arguments and scopes for further arguments *)
- test_kind top g;
+ test_kind ?loc g;
let () = assert (List.is_empty vars) in
let (_,argscs) = find_remaining_scopes [] pats g in
Some (g, [], List.map2 (in_pat_sc scopes) argscs pats)
| NApp (NRef g,[]) -> (* special case: Syndef for @Cstr deactivates implicit arguments *)
- test_kind top g;
+ test_kind ?loc g;
let () = assert (List.is_empty vars) in
let (_,argscs) = find_remaining_scopes [] pats g in
Some (g, List.map2 (in_pat_sc scopes) argscs pats, [])
| NApp (NRef g,args) ->
(* Convention: do not deactivate implicit arguments and scopes for further arguments *)
- test_kind top g;
+ test_kind ?loc g;
let nvars = List.length vars in
if List.length pats < nvars then error_not_enough_arguments ?loc:qid.loc;
let pats1,pats2 = List.chop nvars pats in
let subst = split_by_type_pat vars (pats1,[]) in
- let idspl1 = List.map (in_not false qid.loc scopes subst []) args in
+ let idspl1 = List.map (in_not test_kind_inner qid.loc scopes subst []) args in
let (_,argscs) = find_remaining_scopes pats1 pats2 g in
Some (g, idspl1, List.map2 (in_pat_sc scopes) argscs pats2)
| _ -> raise Not_found
with Not_found -> None in
Syntax_def.search_filtered_syntactic_definition filter sp
| TrueGlobal g ->
- test_kind top g;
+ test_kind ?loc g;
Dumpglob.add_glob ?loc:qid.loc g;
let (_,argscs) = find_remaining_scopes [] pats g in
Some (g,[],List.map2 (in_pat_sc scopes) argscs pats)
with Not_found -> None
- and in_pat top scopes pt =
+ and in_pat test_kind scopes pt =
let open CAst in
let loc = pt.loc in
match pt.v with
- | CPatAlias (p, id) -> DAst.make ?loc @@ RCPatAlias (in_pat top scopes p, id)
+ | CPatAlias (p, id) -> DAst.make ?loc @@ RCPatAlias (in_pat test_kind scopes p, id)
| CPatRecord l ->
let sorted_fields =
sort_fields ~complete:false loc l (fun _idx fieldname constructor -> CAst.make ?loc @@ CPatAtom None) in
@@ -1668,7 +1702,7 @@ let drop_notations_pattern looked_for genv =
end
| CPatCstr (head, None, pl) ->
begin
- match drop_syndef top scopes head pl with
+ match drop_syndef test_kind ?loc scopes head pl with
| Some (a,b,c) -> DAst.make ?loc @@ RCPatCstr(a, b, c)
| None -> Loc.raise ?loc (InternalizationError (NotAConstructor head))
end
@@ -1682,37 +1716,37 @@ let drop_notations_pattern looked_for genv =
in
if expl_pl == [] then
(* Convention: (@r) deactivates all further implicit arguments and scopes *)
- DAst.make ?loc @@ RCPatCstr (g, List.map (in_pat false scopes) pl, [])
+ DAst.make ?loc @@ RCPatCstr (g, List.map (in_pat test_kind_inner scopes) pl, [])
else
(* Convention: (@r expl_pl) deactivates implicit arguments in expl_pl and in pl *)
(* but not scopes in expl_pl *)
let (argscs1,_) = find_remaining_scopes expl_pl pl g in
- DAst.make ?loc @@ RCPatCstr (g, List.map2 (in_pat_sc scopes) argscs1 expl_pl @ List.map (in_pat false scopes) pl, [])
+ DAst.make ?loc @@ RCPatCstr (g, List.map2 (in_pat_sc scopes) argscs1 expl_pl @ List.map (in_pat test_kind_inner scopes) pl, [])
| CPatNotation (_,(InConstrEntry,"- _"),([a],[]),[]) when is_non_zero_pat a ->
- let p = match a.CAst.v with CPatPrim (Numeral (_, p)) -> p | _ -> assert false in
- let pat, _df = Notation.interp_prim_token_cases_pattern_expr ?loc (ensure_kind false loc) (Numeral (SMinus,p)) scopes in
+ let p = match a.CAst.v with CPatPrim (Number (_, p)) -> p | _ -> assert false in
+ let pat, _df = Notation.interp_prim_token_cases_pattern_expr ?loc (ensure_kind test_kind_inner) (Number (SMinus,p)) scopes in
rcp_of_glob scopes pat
| CPatNotation (_,(InConstrEntry,"( _ )"),([a],[]),[]) ->
- in_pat top scopes a
+ in_pat test_kind scopes a
| CPatNotation (_,ntn,fullargs,extrargs) ->
let ntn,(terms,termlists) = contract_curly_brackets_pat ntn fullargs in
let ((ids',c),df) = Notation.interp_notation ?loc ntn scopes in
- let (terms,termlists) = split_by_type_pat ?loc ids' (terms,termlists) in
+ let subst = split_by_type_pat ?loc ids' (terms,termlists) in
Dumpglob.dump_notation_location (patntn_loc ?loc fullargs ntn) ntn df;
- in_not top loc scopes (terms,termlists) extrargs c
+ in_not test_kind loc scopes subst extrargs c
| CPatDelimiters (key, e) ->
- in_pat top (None,find_delimiters_scope ?loc key::snd scopes) e
+ in_pat test_kind (None,find_delimiters_scope ?loc key::snd scopes) e
| CPatPrim p ->
- let pat, _df = Notation.interp_prim_token_cases_pattern_expr ?loc (test_kind false) p scopes in
+ let pat, _df = Notation.interp_prim_token_cases_pattern_expr ?loc test_kind_inner p scopes in
rcp_of_glob scopes pat
| CPatAtom (Some id) ->
begin
- match drop_syndef top scopes id [] with
+ match drop_syndef test_kind ?loc scopes id [] with
| Some (a,b,c) -> DAst.make ?loc @@ RCPatCstr (a, b, c)
| None -> DAst.make ?loc @@ RCPatAtom (Some ((make ?loc @@ find_pattern_variable id),scopes))
end
| CPatAtom None -> DAst.make ?loc @@ RCPatAtom None
- | CPatOr pl -> DAst.make ?loc @@ RCPatOr (List.map (in_pat top scopes) pl)
+ | CPatOr pl -> DAst.make ?loc @@ RCPatOr (List.map (in_pat test_kind scopes) pl)
| CPatCast (_,_) ->
(* We raise an error if the pattern contains a cast, due to
current restrictions on casts in patterns. Cast in patterns
@@ -1725,8 +1759,8 @@ let drop_notations_pattern looked_for genv =
This check is here and not in the parser because it would require
duplicating the levels of the [pattern] rule. *)
CErrors.user_err ?loc (Pp.strbrk "Casts are not supported in this pattern.")
- and in_pat_sc scopes x = in_pat false (x,snd scopes)
- and in_not top loc scopes (subst,substlist as fullsubst) args = function
+ and in_pat_sc scopes x = in_pat test_kind_inner (x,snd scopes)
+ and in_not (test_kind:?loc:Loc.t->'a->'b) loc scopes (subst,substlist as fullsubst) args = function
| NVar id ->
let () = assert (List.is_empty args) in
begin
@@ -1734,21 +1768,21 @@ let drop_notations_pattern looked_for genv =
(* of the notations *)
try
let (a,(scopt,subscopes)) = Id.Map.find id subst in
- in_pat top (scopt,subscopes@snd scopes) a
+ in_pat test_kind (scopt,subscopes@snd scopes) a
with Not_found ->
if Id.equal id ldots_var then DAst.make ?loc @@ RCPatAtom (Some ((make ?loc id),scopes)) else
anomaly (str "Unbound pattern notation variable: " ++ Id.print id ++ str ".")
end
| NRef g ->
- ensure_kind top loc g;
+ ensure_kind test_kind ?loc g;
let (_,argscs) = find_remaining_scopes [] args g in
DAst.make ?loc @@ RCPatCstr (g, [], List.map2 (in_pat_sc scopes) argscs args)
| NApp (NRef g,pl) ->
- ensure_kind top loc g;
+ ensure_kind test_kind ?loc g;
let (argscs1,argscs2) = find_remaining_scopes pl args g in
- let pl = List.map2 (fun x -> in_not false loc (x,snd scopes) fullsubst []) argscs1 pl in
+ let pl = List.map2 (fun x -> in_not test_kind_inner loc (x,snd scopes) fullsubst []) argscs1 pl in
let pl = add_local_defs_and_check_length loc genv g pl args in
- let args = List.map2 (fun x -> in_pat false (x,snd scopes)) argscs2 args in
+ let args = List.map2 (fun x -> in_pat test_kind_inner (x,snd scopes)) argscs2 args in
let pat =
if List.length pl = 0 then
(* Convention: if notation is @f, encoded as NApp(Nref g,[]), then
@@ -1763,10 +1797,10 @@ let drop_notations_pattern looked_for genv =
(try
(* All elements of the list are in scopes (scopt,subscopes) *)
let (l,(scopt,subscopes)) = Id.Map.find x substlist in
- let termin = in_not top loc scopes fullsubst [] terminator in
+ let termin = in_not test_kind_inner loc scopes fullsubst [] terminator in
List.fold_right (fun a t ->
let nsubst = Id.Map.add y (a, (scopt, subscopes)) subst in
- let u = in_not false loc scopes (nsubst, substlist) [] iter in
+ let u = in_not test_kind_inner loc scopes (nsubst, substlist) [] iter in
subst_pat_iterator ldots_var t u)
(if revert then List.rev l else l) termin
with Not_found ->
@@ -1775,7 +1809,7 @@ let drop_notations_pattern looked_for genv =
let () = assert (List.is_empty args) in
DAst.make ?loc @@ RCPatAtom None
| t -> error_invalid_pattern_notation ?loc ()
- in in_pat true
+ in in_pat test_kind_top env.pat_scopes pat
let rec intern_pat genv ntnvars aliases pat =
let intern_cstr_with_all_args loc c with_letin idslpl1 pl2 =
@@ -1816,19 +1850,30 @@ let rec intern_pat genv ntnvars aliases pat =
check_or_pat_variables loc ids (List.tl idsl);
(ids,List.flatten pl')
-let intern_cases_pattern genv ntnvars scopes aliases pat =
+let intern_cases_pattern test_kind genv ntnvars env aliases pat =
intern_pat genv ntnvars aliases
- (drop_notations_pattern (function GlobRef.ConstructRef _ -> () | _ -> raise Not_found) genv scopes pat)
+ (drop_notations_pattern (test_kind,test_kind) genv env pat)
let _ =
intern_cases_pattern_fwd :=
- fun ntnvars scopes p -> intern_cases_pattern (Global.env ()) ntnvars scopes empty_alias p
-
-let intern_ind_pattern genv ntnvars scopes pat =
+ fun test_kind ntnvars env p ->
+ intern_cases_pattern test_kind (Global.env ()) ntnvars env empty_alias p
+
+let intern_ind_pattern genv ntnvars env pat =
+ let test_kind_top ?loc = function
+ | GlobRef.IndRef _ -> ()
+ | GlobRef.ConstructRef _ | GlobRef.ConstRef _ | GlobRef.VarRef _ ->
+ (* A non-inductive global reference at top is an error *)
+ error_invalid_pattern_notation ?loc () in
+ let test_kind_inner ?loc = function
+ | GlobRef.ConstructRef _ -> ()
+ | GlobRef.IndRef _ | GlobRef.ConstRef _ | GlobRef.VarRef _ ->
+ (* A non-constructor global reference deep in a pattern is seen as a variable *)
+ raise Not_found in
let no_not =
try
- drop_notations_pattern (function (GlobRef.IndRef _ | GlobRef.ConstructRef _) -> () | _ -> raise Not_found) genv scopes pat
- with InternalizationError(NotAConstructor _) as exn ->
+ drop_notations_pattern (test_kind_top,test_kind_inner) genv env pat
+ with InternalizationError (NotAConstructor _) as exn ->
let _, info = Exninfo.capture exn in
error_bad_inductive_type ~info ()
in
@@ -2006,8 +2051,8 @@ let internalize globalenv env pattern_mode (_, ntnvars as lvar) c =
GLetIn (na.CAst.v, inc1, int,
intern_restart_binders (push_name_env ntnvars (impls_term_list 1 inc1) env na) c2)
| CNotation (_,(InConstrEntry,"- _"), ([a],[],[],[])) when is_non_zero a ->
- let p = match a.CAst.v with CPrim (Numeral (_, p)) -> p | _ -> assert false in
- intern env (CAst.make ?loc @@ CPrim (Numeral (SMinus,p)))
+ let p = match a.CAst.v with CPrim (Number (_, p)) -> p | _ -> assert false in
+ intern env (CAst.make ?loc @@ CPrim (Number (SMinus,p)))
| CNotation (_,(InConstrEntry,"( _ )"),([a],[],[],[])) -> intern env a
| CNotation (_,ntn,args) ->
let c = intern_notation intern env ntnvars loc ntn args in
@@ -2221,7 +2266,8 @@ let internalize globalenv env pattern_mode (_, ntnvars as lvar) c =
(* Expands a multiple pattern into a disjunction of multiple patterns *)
and intern_multiple_pattern env n pl =
- let idsl_pll = List.map (intern_cases_pattern globalenv ntnvars (None,env.scopes) empty_alias) pl in
+ let env = { pat_ids = None; pat_scopes = (None,env.scopes) } in
+ let idsl_pll = List.map (intern_cases_pattern test_kind_tolerant globalenv ntnvars env empty_alias) pl in
let loc = loc_of_multiple_pattern pl in
check_number_of_pattern loc n pl;
product_of_cases_patterns empty_alias idsl_pll
@@ -2262,7 +2308,7 @@ let internalize globalenv env pattern_mode (_, ntnvars as lvar) c =
let match_td,typ = match t with
| Some t ->
let with_letin,(ind,ind_ids,alias_subst,l) =
- intern_ind_pattern globalenv ntnvars (None,env.scopes) t in
+ intern_ind_pattern globalenv ntnvars (env_for_pattern (set_type_scope env)) t in
let (mib,mip) = Inductive.lookup_mind_specif globalenv ind in
let nparams = (List.length (mib.Declarations.mind_params_ctxt)) in
(* for "in Vect n", we answer (["n","n"],[(loc,"n")])
@@ -2403,7 +2449,8 @@ let intern_gen kind env sigma
let intern_constr env sigma c = intern_gen WithoutTypeConstraint env sigma c
let intern_type env sigma c = intern_gen IsType env sigma c
let intern_pattern globalenv patt =
- intern_cases_pattern globalenv Id.Map.empty (None,[]) empty_alias patt
+ let env = {pat_ids = None; pat_scopes = (None, [])} in
+ intern_cases_pattern test_kind_tolerant globalenv Id.Map.empty env empty_alias patt
(*********************************************************************)
(* Functions to parse and interpret constructions *)
diff --git a/interp/implicit_quantifiers.ml b/interp/implicit_quantifiers.ml
index 2853eef5c5..ee07fb6ed1 100644
--- a/interp/implicit_quantifiers.ml
+++ b/interp/implicit_quantifiers.ml
@@ -114,8 +114,8 @@ let generalizable_vars_of_glob_constr ?(bound=Id.Set.empty) ?(allowed=Id.Set.emp
ungeneralizable loc id) vars;
vars
-let rec make_fresh ids env x =
- if is_freevar ids env x then x else make_fresh ids env (Nameops.increment_subscript x)
+let make_fresh ids env x =
+ Namegen.next_ident_away_from x (fun x -> not (is_freevar ids env x))
let next_name_away_from na avoid =
match na with
diff --git a/interp/notation.ml b/interp/notation.ml
index 269e20c16e..8d05fab63c 100644
--- a/interp/notation.ml
+++ b/interp/notation.ml
@@ -32,7 +32,7 @@ open NumTok
fail if a number has no interpretation in the scope (e.g. there is
no interpretation for negative numbers in [nat]); interpreters both for
terms and patterns can be set; these interpreters are in permanent table
- [numeral_interpreter_tab]
+ [number_interpreter_tab]
- a set of ML printers for expressions denoting numbers parsable in
this scope
- a set of interpretations for infix (more generally distfix) notations
@@ -341,22 +341,27 @@ type notation_rule = interp_rule * interpretation * notation_applicative_status
let notation_rule_eq (rule1,pat1,s1 as x1) (rule2,pat2,s2 as x2) =
x1 == x2 || (rule1 = rule2 && interpretation_eq pat1 pat2 && s1 = s2)
+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 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 (notation_rule_eq interp) old with Not_found -> old in
+ let old = try List.remove_first (also_cases_notation_rule_eq interp) old with Not_found -> old in
KeyMap.add key (interp :: old) map
let keymap_remove key interp map =
let old = try KeyMap.find key map with Not_found -> [] in
- KeyMap.add key (List.remove_first (notation_rule_eq interp) old) map
+ KeyMap.add key (List.remove_first (also_cases_notation_rule_eq interp) old) map
let keymap_find key map =
try KeyMap.find key map
with Not_found -> []
(* Scopes table : interpretation -> scope_name *)
-let notations_key_table = ref (KeyMap.empty : notation_rule list KeyMap.t)
+(* Boolean = for cases pattern also *)
+let notations_key_table = ref (KeyMap.empty : (bool * notation_rule) list KeyMap.t)
let glob_prim_constr_key c = match DAst.get c with
| GRef (ref, _) -> Some (canonical_gr ref)
@@ -446,13 +451,13 @@ module InnerPrimToken = struct
let do_interp ?loc interp primtok =
match primtok, interp with
- | Numeral n, RawNumInterp interp -> interp ?loc n
- | Numeral n, BigNumInterp interp ->
+ | Number n, RawNumInterp interp -> interp ?loc n
+ | Number n, BigNumInterp interp ->
(match NumTok.Signed.to_bigint n with
| Some n -> interp ?loc n
| None -> raise Not_found)
| String s, StringInterp interp -> interp ?loc s
- | (Numeral _ | String _),
+ | (Number _ | String _),
(RawNumInterp _ | BigNumInterp _ | StringInterp _) -> raise Not_found
type uninterpreter =
@@ -466,16 +471,16 @@ module InnerPrimToken = struct
| StringUninterp f, StringUninterp f' -> f == f'
| _ -> false
- let mkNumeral n =
- Numeral (NumTok.Signed.of_bigint CDec n)
+ let mkNumber n =
+ Number (NumTok.Signed.of_bigint CDec n)
let mkString = function
| None -> None
| Some s -> if Unicode.is_utf8 s then Some (String s) else None
let do_uninterp uninterp g = match uninterp with
- | RawNumUninterp u -> Option.map (fun (s,n) -> Numeral (s,n)) (u g)
- | BigNumUninterp u -> Option.map mkNumeral (u g)
+ | RawNumUninterp u -> Option.map (fun (s,n) -> Number (s,n)) (u g)
+ | BigNumUninterp u -> Option.map mkNumber (u g)
| StringUninterp u -> mkString (u g)
end
@@ -495,7 +500,7 @@ let prim_token_uninterpreters =
(Hashtbl.create 7 : (prim_token_uid, InnerPrimToken.uninterpreter) Hashtbl.t)
(*******************************************************)
-(* Numeral notation interpretation *)
+(* Number notation interpretation *)
type prim_token_notation_error =
| UnexpectedTerm of Constr.t
| UnexpectedNonOptionTerm of Constr.t
@@ -519,21 +524,21 @@ type z_pos_ty =
{ z_ty : Names.inductive;
pos_ty : Names.inductive }
-type numeral_ty =
+type number_ty =
{ int : int_ty;
decimal : Names.inductive;
hexadecimal : Names.inductive;
- numeral : Names.inductive }
+ number : Names.inductive }
type target_kind =
- | Int of int_ty (* Coq.Init.Numeral.int + uint *)
- | UInt of int_ty (* Coq.Init.Numeral.uint *)
+ | Int of int_ty (* Coq.Init.Number.int + uint *)
+ | UInt of int_ty (* Coq.Init.Number.uint *)
| Z of z_pos_ty (* Coq.Numbers.BinNums.Z and positive *)
| Int63 (* Coq.Numbers.Cyclic.Int63.Int63.int *)
- | Numeral of numeral_ty (* Coq.Init.Numeral.numeral + uint + int *)
+ | Number of number_ty (* Coq.Init.Number.number + uint + int *)
| DecimalInt of int_ty (* Coq.Init.Decimal.int + uint (deprecated) *)
| DecimalUInt of int_ty (* Coq.Init.Decimal.uint (deprecated) *)
- | Decimal of numeral_ty (* Coq.Init.Decimal.Decimal + uint + int (deprecated) *)
+ | Decimal of number_ty (* Coq.Init.Decimal.Decimal + uint + int (deprecated) *)
type string_target_kind =
| ListByte
@@ -542,19 +547,36 @@ type string_target_kind =
type option_kind = Option | Direct
type 'target conversion_kind = 'target * option_kind
+(** A postprocessing translation [to_post] can be done after execution
+ of the [to_ty] interpreter. The reverse translation is performed
+ before the [of_ty] uninterpreter.
+
+ [to_post] is an array of [n] lists [l_i] of tuples [(f, t,
+ args)]. When the head symbol of the translated term matches one of
+ the [f] in the list [l_0] it is replaced by [t] and its arguments
+ are translated acording to [args] where [ToPostCopy] means that the
+ argument is kept unchanged and [ToPostAs k] means that the
+ argument is recursively translated according to [l_k].
+ [ToPostHole] introduces an additional implicit argument hole
+ (in the reverse translation, the corresponding argument is removed).
+ [ToPostCheck r] behaves as [ToPostCopy] except in the reverse
+ translation which fails if the copied term is not [r].
+ When [n] is null, no translation is performed. *)
+type to_post_arg = ToPostCopy | ToPostAs of int | ToPostHole | ToPostCheck of GlobRef.t
type ('target, 'warning) prim_token_notation_obj =
{ to_kind : 'target conversion_kind;
to_ty : GlobRef.t;
+ to_post : ((GlobRef.t * GlobRef.t * to_post_arg list) list) array;
of_kind : 'target conversion_kind;
of_ty : GlobRef.t;
ty_name : Libnames.qualid; (* for warnings / error messages *)
warning : 'warning }
-type numeral_notation_obj = (target_kind, numnot_option) prim_token_notation_obj
+type number_notation_obj = (target_kind, numnot_option) prim_token_notation_obj
type string_notation_obj = (string_target_kind, unit) prim_token_notation_obj
module PrimTokenNotation = struct
-(** * Code shared between Numeral notation and String notation *)
+(** * Code shared between Number notation and String notation *)
(** Reduction
The constr [c] below isn't necessarily well-typed, since we
@@ -588,22 +610,69 @@ exception NotAValidPrimToken
to [constr] for the subset that concerns us.
Note that if you update [constr_of_glob], you should update the
- corresponding numeral notation *and* string notation doc in
+ corresponding number notation *and* string notation doc in
doc/sphinx/user-extensions/syntax-extensions.rst that describes
what it means for a term to be ground / to be able to be
considered for parsing. *)
-let rec constr_of_glob env sigma g = match DAst.get g with
- | Glob_term.GRef (GlobRef.ConstructRef c, _) ->
- let sigma,c = Evd.fresh_constructor_instance env sigma c in
- sigma,mkConstructU c
- | Glob_term.GRef (GlobRef.IndRef c, _) ->
- let sigma,c = Evd.fresh_inductive_instance env sigma c in
- sigma,mkIndU c
+let constr_of_globref allow_constant env sigma = function
+ | GlobRef.ConstructRef c ->
+ let sigma,c = Evd.fresh_constructor_instance env sigma c in
+ sigma,mkConstructU c
+ | GlobRef.IndRef c ->
+ let sigma,c = Evd.fresh_inductive_instance env sigma c in
+ sigma,mkIndU c
+ | GlobRef.ConstRef c when allow_constant ->
+ let sigma,c = Evd.fresh_constant_instance env sigma c in
+ sigma,mkConstU c
+ | _ -> raise NotAValidPrimToken
+
+let rec constr_of_glob allow_constant to_post post env sigma g = match DAst.get g with
+ | Glob_term.GRef (r, _) ->
+ let o = List.find_opt (fun (_,r',_) -> GlobRef.equal r r') post in
+ begin match o with
+ | None -> constr_of_globref allow_constant env sigma r
+ | Some (r, _, a) ->
+ (* [g] is not a GApp so check that [post]
+ does not expect any actual argument
+ (i.e., [a] contains only ToPostHole since they mean "ignore arg") *)
+ if List.exists ((<>) ToPostHole) a then raise NotAValidPrimToken;
+ constr_of_globref true env sigma r
+ end
| Glob_term.GApp (gc, gcl) ->
- let sigma,c = constr_of_glob env sigma gc in
- let sigma,cl = List.fold_left_map (constr_of_glob env) sigma gcl in
- sigma,mkApp (c, Array.of_list cl)
+ let o = match DAst.get gc with
+ | Glob_term.GRef (r, _) -> List.find_opt (fun (_,r',_) -> GlobRef.equal r r') post
+ | _ -> None in
+ begin match o with
+ | None ->
+ let sigma,c = constr_of_glob allow_constant to_post post env sigma gc in
+ let sigma,cl = List.fold_left_map (constr_of_glob allow_constant to_post post env) sigma gcl in
+ sigma,mkApp (c, Array.of_list cl)
+ | Some (r, _, a) ->
+ let sigma,c = constr_of_globref true env sigma r in
+ let rec aux sigma a gcl = match a, gcl with
+ | [], [] -> sigma,[]
+ | ToPostCopy :: a, gc :: gcl ->
+ let sigma,c = constr_of_glob allow_constant [||] [] env sigma gc in
+ let sigma,cl = aux sigma a gcl in
+ sigma, c :: cl
+ | ToPostCheck r :: a, gc :: gcl ->
+ let () = match DAst.get gc with
+ | Glob_term.GRef (r', _) when GlobRef.equal r r' -> ()
+ | _ -> raise NotAValidPrimToken in
+ let sigma,c = constr_of_glob true [||] [] env sigma gc in
+ let sigma,cl = aux sigma a gcl in
+ sigma, c :: cl
+ | ToPostAs i :: a, gc :: gcl ->
+ let sigma,c = constr_of_glob allow_constant to_post to_post.(i) env sigma gc in
+ let sigma,cl = aux sigma a gcl in
+ sigma, c :: cl
+ | ToPostHole :: post, _ :: gcl -> aux sigma post gcl
+ | [], _ :: _ | _ :: _, [] -> raise NotAValidPrimToken
+ in
+ let sigma,cl = aux sigma a gcl in
+ sigma,mkApp (c, Array.of_list cl)
+ end
| Glob_term.GInt i -> sigma, mkInt i
| Glob_term.GSort gs ->
let sigma,c = Evd.fresh_sort_in_family sigma (Glob_ops.glob_sort_family gs) in
@@ -611,6 +680,10 @@ let rec constr_of_glob env sigma g = match DAst.get g with
| _ ->
raise NotAValidPrimToken
+let constr_of_glob to_post env sigma (Glob_term.AnyGlobConstr g) =
+ let post = match to_post with [||] -> [] | _ -> to_post.(0) in
+ constr_of_glob false to_post post env sigma g
+
let rec glob_of_constr token_kind ?loc env sigma c = match Constr.kind c with
| App (c, ca) ->
let c = glob_of_constr token_kind ?loc env sigma c in
@@ -632,9 +705,38 @@ let no_such_prim_token uninterpreted_token_kind ?loc ty =
(str ("Cannot interpret this "^uninterpreted_token_kind^" as a value of type ") ++
pr_qualid ty)
-let interp_option uninterpreted_token_kind token_kind ty ?loc env sigma c =
+let rec postprocess token_kind ?loc ty to_post post g =
+ let g', gl = match DAst.get g with Glob_term.GApp (g, gl) -> g, gl | _ -> g, [] in
+ let o =
+ match DAst.get g' with
+ | Glob_term.GRef (r, None) ->
+ List.find_opt (fun (r',_,_) -> GlobRef.equal r r') post
+ | _ -> None in
+ match o with None -> g | Some (_, r, a) ->
+ let rec f n a gl = match a, gl with
+ | [], [] -> []
+ | ToPostHole :: a, gl ->
+ let e = Evar_kinds.ImplicitArg (r, (n, None), true) in
+ let h = DAst.make ?loc (Glob_term.GHole (e, Namegen.IntroAnonymous, None)) in
+ h :: f (n+1) a gl
+ | (ToPostCopy | ToPostCheck _) :: a, g :: gl -> g :: f (n+1) a gl
+ | ToPostAs c :: a, g :: gl ->
+ postprocess token_kind ?loc ty to_post to_post.(c) g :: f (n+1) a gl
+ | [], _::_ | _::_, [] ->
+ no_such_prim_token token_kind ?loc ty
+ in
+ let gl = f 1 a gl in
+ let g = DAst.make ?loc (Glob_term.GRef (r, None)) in
+ DAst.make ?loc (Glob_term.GApp (g, gl))
+
+let glob_of_constr token_kind ty ?loc env sigma to_post c =
+ let g = glob_of_constr token_kind ?loc env sigma c in
+ match to_post with [||] -> g | _ ->
+ postprocess token_kind ?loc ty to_post to_post.(0) g
+
+let interp_option uninterpreted_token_kind token_kind ty ?loc env sigma to_post c =
match Constr.kind c with
- | App (_Some, [| _; c |]) -> glob_of_constr token_kind ?loc env sigma c
+ | App (_Some, [| _; c |]) -> glob_of_constr token_kind ty ?loc env sigma to_post c
| App (_None, [| _ |]) -> no_such_prim_token uninterpreted_token_kind ?loc ty
| x -> Loc.raise ?loc (PrimTokenNotationError(token_kind,env,sigma,UnexpectedNonOptionTerm c))
@@ -643,13 +745,13 @@ let uninterp_option c =
| App (_Some, [| _; x |]) -> x
| _ -> raise NotAValidPrimToken
-let uninterp to_raw o (Glob_term.AnyGlobConstr n) =
+let uninterp to_raw o n =
let env = Global.env () in
let sigma = Evd.from_env env in
let sigma,of_ty = Evd.fresh_global env sigma o.of_ty in
let of_ty = EConstr.Unsafe.to_constr of_ty in
try
- let sigma,n = constr_of_glob env sigma n in
+ let sigma,n = constr_of_glob o.to_post env sigma n in
let c = eval_constr_app env sigma of_ty n in
let c = if snd o.of_kind == Direct then c else uninterp_option c in
Some (to_raw (fst o.of_kind, c))
@@ -670,8 +772,8 @@ let rec int63_of_pos_bigint i =
(Uint63.mul (Uint63.of_int 2) (int63_of_pos_bigint quo))
else Uint63.mul (Uint63.of_int 2) (int63_of_pos_bigint quo)
-module Numeral = struct
-(** * Numeral notation *)
+module Numbers = struct
+(** * Number notation *)
open PrimTokenNotation
let warn_large_num =
@@ -727,7 +829,7 @@ let coqint_of_rawnum inds c (sign,n) =
let pos_neg = match sign with SPlus -> 1 | SMinus -> 2 in
mkApp (mkConstruct (ind, pos_neg), [|uint|])
-let coqnumeral_of_rawnum inds c n =
+let coqnumber_of_rawnum inds c n =
let ind = match c with CDec -> inds.decimal | CHex -> inds.hexadecimal in
let i, f, e = NumTok.Signed.to_int_frac_and_exponent n in
let i = coqint_of_rawnum inds.int c i in
@@ -739,19 +841,19 @@ let coqnumeral_of_rawnum inds c n =
mkApp (mkConstruct (ind, 2), [|i; f; e|]) (* (D|Hexad)ecimalExp *)
let mkDecHex ind c n = match c with
- | CDec -> mkApp (mkConstruct (ind, 1), [|n|]) (* (UInt|Int|)Dec *)
- | CHex -> mkApp (mkConstruct (ind, 2), [|n|]) (* (UInt|Int|)Hex *)
+ | CDec -> mkApp (mkConstruct (ind, 1), [|n|]) (* (UInt|Int|)Decimal *)
+ | CHex -> mkApp (mkConstruct (ind, 2), [|n|]) (* (UInt|Int|)Hexadecimal *)
exception NonDecimal
-let decimal_coqnumeral_of_rawnum inds n =
+let decimal_coqnumber_of_rawnum inds n =
if NumTok.Signed.classify n <> CDec then raise NonDecimal;
- coqnumeral_of_rawnum inds CDec n
+ coqnumber_of_rawnum inds CDec n
-let coqnumeral_of_rawnum inds n =
+let coqnumber_of_rawnum inds n =
let c = NumTok.Signed.classify n in
- let n = coqnumeral_of_rawnum inds c n in
- mkDecHex inds.numeral c n
+ let n = coqnumber_of_rawnum inds c n in
+ mkDecHex inds.number c n
let decimal_coquint_of_rawnum inds n =
if NumTok.UnsignedNat.classify n <> CDec then raise NonDecimal;
@@ -801,7 +903,7 @@ let rawnum_of_coqint cl c =
| _ -> raise NotAValidPrimToken)
| _ -> raise NotAValidPrimToken
-let rawnum_of_coqnumeral cl c =
+let rawnum_of_coqnumber cl c =
let of_ife i f e =
let n = rawnum_of_coqint cl i in
let f = try Some (rawnum_of_coquint cl f) with NotAValidPrimToken -> None in
@@ -815,17 +917,17 @@ let rawnum_of_coqnumeral cl c =
let destDecHex c = match Constr.kind c with
| App (c,[|c'|]) ->
(match Constr.kind c with
- | Construct ((_,1), _) (* (UInt|Int|)Dec *) -> CDec, c'
- | Construct ((_,2), _) (* (UInt|Int|)Hex *) -> CHex, c'
+ | Construct ((_,1), _) (* (UInt|Int|)Decimal *) -> CDec, c'
+ | Construct ((_,2), _) (* (UInt|Int|)Hexadecimal *) -> CHex, c'
| _ -> raise NotAValidPrimToken)
| _ -> raise NotAValidPrimToken
-let decimal_rawnum_of_coqnumeral c =
- rawnum_of_coqnumeral CDec c
+let decimal_rawnum_of_coqnumber c =
+ rawnum_of_coqnumber CDec c
-let rawnum_of_coqnumeral c =
+let rawnum_of_coqnumber c =
let cl, c = destDecHex c in
- rawnum_of_coqnumeral cl c
+ rawnum_of_coqnumber cl c
let decimal_rawnum_of_coquint c =
rawnum_of_coquint CDec c
@@ -947,9 +1049,9 @@ let interp o ?loc n =
interp_int63 ?loc (NumTok.SignedNat.to_bigint n)
| (Int _ | UInt _ | DecimalInt _ | DecimalUInt _ | Z _ | Int63), _ ->
no_such_prim_token "number" ?loc o.ty_name
- | Numeral numeral_ty, _ -> coqnumeral_of_rawnum numeral_ty n
- | Decimal numeral_ty, _ ->
- (try decimal_coqnumeral_of_rawnum numeral_ty n
+ | Number number_ty, _ -> coqnumber_of_rawnum number_ty n
+ | Decimal number_ty, _ ->
+ (try decimal_coqnumber_of_rawnum number_ty n
with NonDecimal -> no_such_prim_token "number" ?loc o.ty_name)
in
let env = Global.env () in
@@ -959,12 +1061,13 @@ let interp o ?loc n =
match o.warning, snd o.to_kind with
| Abstract threshold, Direct when NumTok.Signed.is_bigger_int_than n threshold ->
warn_abstract_large_num (o.ty_name,o.to_ty);
- glob_of_constr "numeral" ?loc env sigma (mkApp (to_ty,[|c|]))
+ assert (Array.length o.to_post = 0);
+ glob_of_constr "number" o.ty_name ?loc env sigma o.to_post (mkApp (to_ty,[|c|]))
| _ ->
let res = eval_constr_app env sigma to_ty c in
match snd o.to_kind with
- | Direct -> glob_of_constr "numeral" ?loc env sigma res
- | Option -> interp_option "number" "numeral" o.ty_name ?loc env sigma res
+ | Direct -> glob_of_constr "number" o.ty_name ?loc env sigma o.to_post res
+ | Option -> interp_option "number" "number" o.ty_name ?loc env sigma o.to_post res
let uninterp o n =
PrimTokenNotation.uninterp
@@ -973,10 +1076,10 @@ let uninterp o n =
| (UInt _, c) -> NumTok.Signed.of_nat (rawnum_of_coquint c)
| (Z _, c) -> NumTok.Signed.of_bigint CDec (bigint_of_z c)
| (Int63, c) -> NumTok.Signed.of_bigint CDec (bigint_of_int63 c)
- | (Numeral _, c) -> rawnum_of_coqnumeral c
+ | (Number _, c) -> rawnum_of_coqnumber c
| (DecimalInt _, c) -> NumTok.Signed.of_int (decimal_rawnum_of_coqint c)
| (DecimalUInt _, c) -> NumTok.Signed.of_nat (decimal_rawnum_of_coquint c)
- | (Decimal _, c) -> decimal_rawnum_of_coqnumeral c
+ | (Decimal _, c) -> decimal_rawnum_of_coqnumber c
end o n
end
@@ -1009,11 +1112,12 @@ let coqbyte_of_string ?loc byte s =
let p =
if Int.equal (String.length s) 1 then int_of_char s.[0]
else
- if Int.equal (String.length s) 3 && is_digit s.[0] && is_digit s.[1] && is_digit s.[2]
- then int_of_string s
- else
+ let n =
+ if Int.equal (String.length s) 3 && is_digit s.[0] && is_digit s.[1] && is_digit s.[2]
+ then int_of_string s else 256 in
+ if n < 256 then n else
user_err ?loc ~hdr:"coqbyte_of_string"
- (str "Expects a single character or a three-digits ascii code.") in
+ (str "Expects a single character or a three-digit ASCII code.") in
coqbyte_of_char_code byte p
let coqbyte_of_char byte c = coqbyte_of_char_code byte (Char.code c)
@@ -1068,8 +1172,8 @@ let interp o ?loc n =
let to_ty = EConstr.Unsafe.to_constr to_ty in
let res = eval_constr_app env sigma to_ty c in
match snd o.to_kind with
- | Direct -> glob_of_constr "string" ?loc env sigma res
- | Option -> interp_option "string" "string" o.ty_name ?loc env sigma res
+ | Direct -> glob_of_constr "string" o.ty_name ?loc env sigma o.to_post res
+ | Option -> interp_option "string" "string" o.ty_name ?loc env sigma o.to_post res
let uninterp o n =
PrimTokenNotation.uninterp
@@ -1081,21 +1185,21 @@ end
(* A [prim_token_infos], which is synchronized with the document
state, either contains a unique id pointing to an unsynchronized
- prim token function, or a numeral notation object describing how to
+ prim token function, or a number notation object describing how to
interpret and uninterpret. We provide [prim_token_infos] because
we expect plugins to provide their own interpretation functions,
- rather than going through numeral notations, which are available as
+ rather than going through number notations, which are available as
a vernacular. *)
type prim_token_interp_info =
Uid of prim_token_uid
- | NumeralNotation of numeral_notation_obj
+ | NumberNotation of number_notation_obj
| StringNotation of string_notation_obj
type prim_token_infos = {
pt_local : bool; (** Is this interpretation local? *)
pt_scope : scope_name; (** Concerned scope *)
- pt_interp_info : prim_token_interp_info; (** Unique id "pointing" to (un)interp functions, OR a numeral notation object describing (un)interp functions *)
+ pt_interp_info : prim_token_interp_info; (** Unique id "pointing" to (un)interp functions, OR a number notation object describing (un)interp functions *)
pt_required : required_module; (** Module that should be loaded first *)
pt_refs : GlobRef.t list; (** Entry points during uninterpretation *)
pt_in_match : bool (** Is this prim token legal in match patterns ? *)
@@ -1119,7 +1223,7 @@ let hashtbl_check_and_set allow_overwrite uid f h eq =
| _ ->
user_err ~hdr:"prim_token_interpreter"
(str "Unique identifier " ++ str uid ++
- str " already used to register a numeral or string (un)interpreter.")
+ str " already used to register a number or string (un)interpreter.")
let register_gen_interpretation allow_overwrite uid (interp, uninterp) =
hashtbl_check_and_set
@@ -1147,7 +1251,6 @@ let cache_prim_token_interpretation (_,infos) =
String.Map.add sc (infos.pt_required,ptii) !prim_token_interp_infos;
let add_uninterp r =
let l = try GlobRef.Map.find r !prim_token_uninterp_infos with Not_found -> [] in
- let l = List.remove_assoc_f String.equal sc l in
prim_token_uninterp_infos :=
GlobRef.Map.add r ((sc,(ptii,infos.pt_in_match)) :: l)
!prim_token_uninterp_infos in
@@ -1220,7 +1323,7 @@ let check_required_module ?loc sc (sp,d) =
(str "Cannot interpret in " ++ str sc ++ str " without requiring first module " ++
str (List.last d) ++ str ".")
-(* Look if some notation or numeral printer in [scope] can be used in
+(* Look if some notation or number printer in [scope] can be used in
the scope stack [scopes], and if yes, using delimiters or not *)
let find_with_delimiters = function
@@ -1237,7 +1340,7 @@ let rec find_without_delimiters find (ntn_scope,ntn) = function
| NotationInScope scope' when String.equal scope scope' ->
Some (None,None)
| _ ->
- (* If the most recently open scope has a notation/numeral printer
+ (* If the most recently open scope has a notation/number printer
but not the expected one then we need delimiters *)
if find scope then
find_with_delimiters ntn_scope
@@ -1333,13 +1436,13 @@ let check_printing_override (scopt,ntn) data parsingdata printingdata =
exists) printingdata in
parsing_update, exists
-let remove_uninterpretation rule (metas,c as pat) =
+let remove_uninterpretation rule also_in_cases_pattern (metas,c as pat) =
let (key,n) = notation_constr_key c in
- notations_key_table := keymap_remove key (rule,pat,n) !notations_key_table
+ notations_key_table := keymap_remove key (also_in_cases_pattern,(rule,pat,n)) !notations_key_table
-let declare_uninterpretation rule (metas,c as pat) =
+let declare_uninterpretation ?(also_in_cases_pattern=true) rule (metas,c as pat) =
let (key,n) = notation_constr_key c in
- notations_key_table := keymap_add key (rule,pat,n) !notations_key_table
+ notations_key_table := keymap_add key (also_in_cases_pattern,(rule,pat,n)) !notations_key_table
let update_notation_data (scopt,ntn) use data table =
let (parsingdata,printingdata) =
@@ -1375,8 +1478,8 @@ let find_notation ntn sc =
| _ -> raise Not_found
let notation_of_prim_token = function
- | Constrexpr.Numeral (SPlus,n) -> InConstrEntry, NumTok.Unsigned.sprint n
- | Constrexpr.Numeral (SMinus,n) -> InConstrEntry, "- "^NumTok.Unsigned.sprint n
+ | Constrexpr.Number (SPlus,n) -> InConstrEntry, NumTok.Unsigned.sprint n
+ | Constrexpr.Number (SMinus,n) -> InConstrEntry, "- "^NumTok.Unsigned.sprint n
| String _ -> raise Not_found
let find_prim_token check_allowed ?loc p sc =
@@ -1394,7 +1497,7 @@ let find_prim_token check_allowed ?loc p sc =
check_required_module ?loc sc spdir;
let interp = match info with
| Uid uid -> Hashtbl.find prim_token_interpreters uid
- | NumeralNotation o -> InnerPrimToken.RawNumInterp (Numeral.interp o)
+ | NumberNotation o -> InnerPrimToken.RawNumInterp (Numbers.interp o)
| StringNotation o -> InnerPrimToken.StringInterp (Strings.interp o)
in
let pat = InnerPrimToken.do_interp ?loc interp p in
@@ -1411,8 +1514,8 @@ let interp_prim_token_gen ?loc g p local_scopes =
let _, info = Exninfo.capture exn in
user_err ?loc ~info ~hdr:"interp_prim_token"
((match p with
- | Numeral _ ->
- str "No interpretation for numeral " ++ pr_notation (notation_of_prim_token p)
+ | Number _ ->
+ str "No interpretation for number " ++ pr_notation (notation_of_prim_token p)
| String s -> str "No interpretation for string " ++ qs s) ++ str ".")
let interp_prim_token ?loc =
@@ -1448,14 +1551,17 @@ let interp_notation ?loc ntn local_scopes =
(str "Unknown interpretation for notation " ++ pr_notation ntn ++ str ".")
let uninterp_notations c =
- List.map_append (fun key -> keymap_find key !notations_key_table)
+ List.map_append (fun key -> List.map snd (keymap_find key !notations_key_table))
(glob_constr_keys c)
+let filter_also_for_pattern =
+ List.map_filter (function (true,x) -> Some x | _ -> None)
+
let uninterp_cases_pattern_notations c =
- keymap_find (cases_pattern_key c) !notations_key_table
+ filter_also_for_pattern (keymap_find (cases_pattern_key c) !notations_key_table)
let uninterp_ind_pattern_notations ind =
- keymap_find (RefKey (canonical_gr (GlobRef.IndRef ind))) !notations_key_table
+ filter_also_for_pattern (keymap_find (RefKey (canonical_gr (GlobRef.IndRef ind))) !notations_key_table)
let has_active_parsing_rule_in_scope ntn sc =
try
@@ -1615,7 +1721,7 @@ type entry_coercion_kind =
| IsEntryGlobal of string * int
| IsEntryIdent of string * int
-let declare_notation (scopt,ntn) pat df ~use coe deprecation =
+let declare_notation (scopt,ntn) pat df ~use ~also_in_cases_pattern coe deprecation =
(* Register the interpretation *)
let scope = match scopt with NotationInScope s -> s | LastLonelyNotation -> default_scope in
let sc = find_scope scope in
@@ -1630,10 +1736,10 @@ let declare_notation (scopt,ntn) pat df ~use coe deprecation =
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)) pat
+ | Some pat -> remove_uninterpretation (NotationRule (scopt,ntn)) also_in_cases_pattern pat
| None -> ()
end;
- if not exists && use <> OnlyParsing then declare_uninterpretation (NotationRule (scopt,ntn)) pat;
+ if not exists && 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
| LastLonelyNotation -> scope_stack := LonelyNotationItem ntn :: !scope_stack
@@ -1659,14 +1765,14 @@ let availability_of_prim_token n printer_scope local_scopes =
let uid = snd (String.Map.find scope !prim_token_interp_infos) in
let open InnerPrimToken in
match n, uid with
- | Constrexpr.Numeral _, NumeralNotation _ -> true
- | _, NumeralNotation _ -> false
+ | Constrexpr.Number _, NumberNotation _ -> true
+ | _, NumberNotation _ -> false
| String _, StringNotation _ -> true
| _, StringNotation _ -> false
| _, Uid uid ->
let interp = Hashtbl.find prim_token_interpreters uid in
match n, interp with
- | Constrexpr.Numeral _, (RawNumInterp _ | BigNumInterp _) -> true
+ | Constrexpr.Number _, (RawNumInterp _ | BigNumInterp _) -> true
| String _, StringInterp _ -> true
| _ -> false
with Not_found -> false
@@ -1681,7 +1787,7 @@ let rec find_uninterpretation need_delim def find = function
def
| OpenScopeItem scope :: scopes ->
(try find need_delim scope
- with Not_found -> find_uninterpretation need_delim def find scopes) (* TODO: here we should also update the need_delim list with all regular notations in scope [scope] that could shadow a numeral notation *)
+ with Not_found -> find_uninterpretation need_delim def find scopes) (* TODO: here we should also update the need_delim list with all regular notations in scope [scope] that could shadow a number notation *)
| LonelyNotationItem ntn::scopes ->
find_uninterpretation (ntn::need_delim) def find scopes
@@ -1693,7 +1799,7 @@ let uninterp_prim_token c local_scopes =
try
let uninterp = match info with
| Uid uid -> Hashtbl.find prim_token_uninterpreters uid
- | NumeralNotation o -> InnerPrimToken.RawNumUninterp (Numeral.uninterp o)
+ | NumberNotation o -> InnerPrimToken.RawNumUninterp (Numbers.uninterp o)
| StringNotation o -> InnerPrimToken.StringUninterp (Strings.uninterp o)
in
match InnerPrimToken.do_uninterp uninterp (AnyGlobConstr c) with
diff --git a/interp/notation.mli b/interp/notation.mli
index d744ff41d9..b8939ff87b 100644
--- a/interp/notation.mli
+++ b/interp/notation.mli
@@ -74,7 +74,7 @@ val find_delimiters_scope : ?loc:Loc.t -> delimiters -> scope_name
(** {6 Declare and uses back and forth an interpretation of primitive token } *)
-(** A numeral interpreter is the pair of an interpreter for **(hexa)decimal**
+(** A number interpreter is the pair of an interpreter for **(hexa)decimal**
numbers in terms and an optional interpreter in pattern, if
non integer or negative numbers are not supported, the interpreter
must fail with an appropriate error message *)
@@ -84,7 +84,7 @@ type required_module = full_path * string list
type rawnum = NumTok.Signed.t
(** The unique id string below will be used to refer to a particular
- registered interpreter/uninterpreter of numeral or string notation.
+ registered interpreter/uninterpreter of number or string notation.
Using the same uid for different (un)interpreters will fail.
If at most one interpretation of prim token is used per scope,
then the scope name could be used as unique id. *)
@@ -106,7 +106,7 @@ val register_bignumeral_interpretation :
val register_string_interpretation :
?allow_overwrite:bool -> prim_token_uid -> string prim_token_interpretation -> unit
-(** * Numeral notation *)
+(** * Number notation *)
type prim_token_notation_error =
| UnexpectedTerm of Constr.t
@@ -131,21 +131,21 @@ type z_pos_ty =
{ z_ty : Names.inductive;
pos_ty : Names.inductive }
-type numeral_ty =
+type number_ty =
{ int : int_ty;
decimal : Names.inductive;
hexadecimal : Names.inductive;
- numeral : Names.inductive }
+ number : Names.inductive }
type target_kind =
- | Int of int_ty (* Coq.Init.Numeral.int + uint *)
- | UInt of int_ty (* Coq.Init.Numeral.uint *)
+ | Int of int_ty (* Coq.Init.Number.int + uint *)
+ | UInt of int_ty (* Coq.Init.Number.uint *)
| Z of z_pos_ty (* Coq.Numbers.BinNums.Z and positive *)
| Int63 (* Coq.Numbers.Cyclic.Int63.Int63.int *)
- | Numeral of numeral_ty (* Coq.Init.Numeral.numeral + uint + int *)
+ | Number of number_ty (* Coq.Init.Number.number + uint + int *)
| DecimalInt of int_ty (* Coq.Init.Decimal.int + uint (deprecated) *)
| DecimalUInt of int_ty (* Coq.Init.Decimal.uint (deprecated) *)
- | Decimal of numeral_ty (* Coq.Init.Decimal.Decimal + uint + int (deprecated) *)
+ | Decimal of number_ty (* Coq.Init.Decimal.Decimal + uint + int (deprecated) *)
type string_target_kind =
| ListByte
@@ -154,26 +154,43 @@ type string_target_kind =
type option_kind = Option | Direct
type 'target conversion_kind = 'target * option_kind
+(** A postprocessing translation [to_post] can be done after execution
+ of the [to_ty] interpreter. The reverse translation is performed
+ before the [of_ty] uninterpreter.
+
+ [to_post] is an array of [n] lists [l_i] of tuples [(f, t,
+ args)]. When the head symbol of the translated term matches one of
+ the [f] in the list [l_0] it is replaced by [t] and its arguments
+ are translated acording to [args] where [ToPostCopy] means that the
+ argument is kept unchanged and [ToPostAs k] means that the
+ argument is recursively translated according to [l_k].
+ [ToPostHole] introduces an additional implicit argument hole
+ (in the reverse translation, the corresponding argument is removed).
+ [ToPostCheck r] behaves as [ToPostCopy] except in the reverse
+ translation which fails if the copied term is not [r].
+ When [n] is null, no translation is performed. *)
+type to_post_arg = ToPostCopy | ToPostAs of int | ToPostHole | ToPostCheck of GlobRef.t
type ('target, 'warning) prim_token_notation_obj =
{ to_kind : 'target conversion_kind;
to_ty : GlobRef.t;
+ to_post : ((GlobRef.t * GlobRef.t * to_post_arg list) list) array;
of_kind : 'target conversion_kind;
of_ty : GlobRef.t;
ty_name : Libnames.qualid; (* for warnings / error messages *)
warning : 'warning }
-type numeral_notation_obj = (target_kind, numnot_option) prim_token_notation_obj
+type number_notation_obj = (target_kind, numnot_option) prim_token_notation_obj
type string_notation_obj = (string_target_kind, unit) prim_token_notation_obj
type prim_token_interp_info =
Uid of prim_token_uid
- | NumeralNotation of numeral_notation_obj
+ | NumberNotation of number_notation_obj
| StringNotation of string_notation_obj
type prim_token_infos = {
pt_local : bool; (** Is this interpretation local? *)
pt_scope : scope_name; (** Concerned scope *)
- pt_interp_info : prim_token_interp_info; (** Unique id "pointing" to (un)interp functions, OR a numeral notation object describing (un)interp functions *)
+ pt_interp_info : prim_token_interp_info; (** Unique id "pointing" to (un)interp functions, OR a number notation object describing (un)interp functions *)
pt_required : required_module; (** Module that should be loaded first *)
pt_refs : GlobRef.t list; (** Entry points during uninterpretation *)
pt_in_match : bool (** Is this prim token legal in match patterns ? *)
@@ -234,7 +251,7 @@ type notation_use =
| OnlyParsing
| ParsingAndPrinting
-val declare_uninterpretation : interp_rule -> interpretation -> unit
+val declare_uninterpretation : ?also_in_cases_pattern:bool -> interp_rule -> interpretation -> unit
type entry_coercion_kind =
| IsEntryCoercion of notation_entry_level
@@ -243,6 +260,7 @@ type entry_coercion_kind =
val declare_notation : notation_with_optional_scope * notation ->
interpretation -> notation_location -> use:notation_use ->
+ also_in_cases_pattern:bool ->
entry_coercion_kind option ->
Deprecation.t option -> unit
diff --git a/interp/notation_ops.ml b/interp/notation_ops.ml
index fe874cd01d..2e3fa0aa0e 100644
--- a/interp/notation_ops.ml
+++ b/interp/notation_ops.ml
@@ -941,7 +941,7 @@ let bind_term_as_binding_env alp (terms,termlists,binders,binderlists as sigma)
try
(* If already bound to a term, unify the binder and the term *)
match DAst.get (Id.List.assoc var terms) with
- | GVar id' ->
+ | GVar id' | GRef (GlobRef.VarRef id',None) ->
(if not (Id.equal id id') then (fst alp,(id,id')::snd alp) else alp),
sigma
| t ->
@@ -1147,16 +1147,22 @@ let does_not_come_from_already_eta_expanded_var glob =
(* checked). *)
match DAst.get glob with GVar _ -> false | _ -> true
+let is_var_term = function
+ (* The kind of expressions allowed to be both a term and a binding variable *)
+ | GVar _ -> true
+ | GRef (GlobRef.VarRef _,None) -> true
+ | _ -> false
+
let rec match_ inner u alp metas sigma a1 a2 =
let open CAst in
let loc = a1.loc in
match DAst.get a1, a2 with
(* Matching notation variable *)
| r1, NVar id2 when is_term_meta id2 metas -> bind_term_env alp sigma id2 a1
- | GVar _, NVar id2 when is_onlybinding_pattern_like_meta true id2 metas -> bind_binding_as_term_env alp sigma id2 a1
+ | r1, NVar id2 when is_var_term r1 && is_onlybinding_pattern_like_meta true id2 metas -> bind_binding_as_term_env alp sigma id2 a1
| r1, NVar id2 when is_onlybinding_pattern_like_meta false id2 metas -> bind_binding_as_term_env alp sigma id2 a1
- | GVar _, NVar id2 when is_onlybinding_strict_meta id2 metas -> raise No_match
- | GVar _, NVar id2 when is_onlybinding_meta id2 metas -> bind_binding_as_term_env alp sigma id2 a1
+ | r1, NVar id2 when is_var_term r1 && is_onlybinding_strict_meta id2 metas -> raise No_match
+ | r1, NVar id2 when is_var_term r1 && is_onlybinding_meta id2 metas -> bind_binding_as_term_env alp sigma id2 a1
| r1, NVar id2 when is_bindinglist_meta id2 metas -> bind_term_env alp sigma id2 a1
(* Matching recursive notations for terms *)
@@ -1436,9 +1442,8 @@ let reorder_canonically_substitution terms termlists metas =
List.fold_right (fun (x,(scl,typ)) (terms',termlists') ->
match typ with
| NtnTypeConstr -> ((Id.List.assoc x terms, scl)::terms',termlists')
- | NtnTypeBinder _ -> assert false
| NtnTypeConstrList -> (terms',(Id.List.assoc x termlists,scl)::termlists')
- | NtnTypeBinderList -> assert false)
+ | NtnTypeBinder _ | NtnTypeBinderList -> anomaly (str "Unexpected binder in pattern notation."))
metas ([],[])
let match_notation_constr_cases_pattern c (metas,pat) =
diff --git a/interp/numTok.mli b/interp/numTok.mli
index bcfe663dd2..386a25f042 100644
--- a/interp/numTok.mli
+++ b/interp/numTok.mli
@@ -8,20 +8,20 @@
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
-(** Numerals in different forms: signed or unsigned, possibly with
+(** Numbers in different forms: signed or unsigned, possibly with
fractional part and exponent.
- Numerals are represented using raw strings of (hexa)decimal
+ Numbers are represented using raw strings of (hexa)decimal
literals and a separate sign flag.
Note that this representation is not unique, due to possible
multiple leading or trailing zeros, and -0 = +0, for instances.
- The reason to keep the numeral exactly as it was parsed is that
- specific notations can be declared for specific numerals
+ The reason to keep the number exactly as it was parsed is that
+ specific notations can be declared for specific numbers
(e.g. [Notation "0" := False], or [Notation "00" := (nil,nil)], or
[Notation "2e1" := ...]). Those notations override the generic
- interpretation as numeral. So, one has to record the form of the
- numeral which exactly matches the notation. *)
+ interpretation as number. So, one has to record the form of the
+ number which exactly matches the notation. *)
type sign = SPlus | SMinus
@@ -44,7 +44,7 @@ sig
val sprint : t -> string
val print : t -> Pp.t
- (** [sprint] and [print] returns the numeral as it was parsed, for printing *)
+ (** [sprint] and [print] returns the number as it was parsed, for printing *)
val classify : t -> num_class
@@ -69,7 +69,7 @@ sig
val to_bigint : t -> Z.t
end
-(** {6 Unsigned decimal numerals } *)
+(** {6 Unsigned decimal numbers } *)
module Unsigned :
sig
@@ -80,12 +80,12 @@ sig
val sprint : t -> string
val print : t -> Pp.t
- (** [sprint] and [print] returns the numeral as it was parsed, for printing *)
+ (** [sprint] and [print] returns the number as it was parsed, for printing *)
val parse : char Stream.t -> t
- (** Parse a positive Coq numeral.
+ (** Parse a positive Coq number.
Precondition: the first char on the stream is already known to be a digit (\[0-9\]).
- Precondition: at least two extra chars after the numeral to parse.
+ Precondition: at least two extra chars after the number to parse.
The recognized syntax is:
- integer part: \[0-9\]\[0-9_\]*
@@ -97,13 +97,13 @@ sig
- exponent part: empty or \[pP\]\[+-\]?\[0-9\]\[0-9_\]* *)
val parse_string : string -> t option
- (** Parse the string as a non negative Coq numeral, if possible *)
+ (** Parse the string as a non negative Coq number, if possible *)
val classify : t -> num_class
end
-(** {6 Signed decimal numerals } *)
+(** {6 Signed decimal numbers } *)
module Signed :
sig
@@ -117,10 +117,10 @@ sig
val sprint : t -> string
val print : t -> Pp.t
- (** [sprint] and [print] returns the numeral as it was parsed, for printing *)
+ (** [sprint] and [print] returns the number as it was parsed, for printing *)
val parse_string : string -> t option
- (** Parse the string as a signed Coq numeral, if possible *)
+ (** Parse the string as a signed Coq number, if possible *)
val of_int_string : string -> t
(** Convert from a string in the syntax of OCaml's int/int64 *)
diff --git a/interp/smartlocate.ml b/interp/smartlocate.ml
index 33d8aa6064..46baa00c74 100644
--- a/interp/smartlocate.ml
+++ b/interp/smartlocate.ml
@@ -50,6 +50,16 @@ let locate_global_with_alias ?(head=false) qid =
user_err ?loc:qid.CAst.loc (pr_qualid qid ++
str " is bound to a notation that does not denote a reference.")
+let global_constant_with_alias qid =
+ try match locate_global_with_alias qid with
+ | Names.GlobRef.ConstRef c -> c
+ | ref ->
+ user_err ?loc:qid.CAst.loc ~hdr:"global_inductive"
+ (pr_qualid qid ++ spc () ++ str "is not a reference to a constant.")
+ with Not_found as exn ->
+ let _, info = Exninfo.capture exn in
+ Nametab.error_global_not_found ~info qid
+
let global_inductive_with_alias qid =
try match locate_global_with_alias qid with
| Names.GlobRef.IndRef ind -> ind
@@ -60,6 +70,16 @@ let global_inductive_with_alias qid =
let _, info = Exninfo.capture exn in
Nametab.error_global_not_found ~info qid
+let global_constructor_with_alias qid =
+ try match locate_global_with_alias qid with
+ | Names.GlobRef.ConstructRef c -> c
+ | ref ->
+ user_err ?loc:qid.CAst.loc ~hdr:"global_inductive"
+ (pr_qualid qid ++ spc () ++ str "is not a constructor of an inductive type.")
+ with Not_found as exn ->
+ let _, info = Exninfo.capture exn in
+ Nametab.error_global_not_found ~info qid
+
let global_with_alias ?head qid =
try locate_global_with_alias ?head qid
with Not_found as exn ->
@@ -72,9 +92,17 @@ let smart_global ?(head = false) = let open Constrexpr in CAst.with_loc_val (fun
| ByNotation (ntn,sc) ->
Notation.interp_notation_as_global_reference ?loc ~head (fun _ -> true) ntn sc)
-let smart_global_inductive = let open Constrexpr in CAst.with_loc_val (fun ?loc -> function
- | AN r ->
- global_inductive_with_alias r
+let smart_global_kind f dest is = let open Constrexpr in CAst.with_loc_val (fun ?loc -> function
+ | AN r -> f r
| ByNotation (ntn,sc) ->
- destIndRef
- (Notation.interp_notation_as_global_reference ?loc ~head:false isIndRef ntn sc))
+ dest
+ (Notation.interp_notation_as_global_reference ?loc ~head:false is ntn sc))
+
+let smart_global_constant =
+ smart_global_kind global_constant_with_alias destConstRef isConstRef
+
+let smart_global_inductive =
+ smart_global_kind global_inductive_with_alias destIndRef isIndRef
+
+let smart_global_constructor =
+ smart_global_kind global_constructor_with_alias destConstructRef isConstructRef
diff --git a/interp/smartlocate.mli b/interp/smartlocate.mli
index 9b24a62086..26f2a4f36d 100644
--- a/interp/smartlocate.mli
+++ b/interp/smartlocate.mli
@@ -28,11 +28,23 @@ val global_of_extended_global : extended_global_reference -> GlobRef.t
a reference. *)
val global_with_alias : ?head:bool -> qualid -> GlobRef.t
+(** The same for constants *)
+val global_constant_with_alias : qualid -> Constant.t
+
(** The same for inductive types *)
val global_inductive_with_alias : qualid -> inductive
+(** The same for constructors of an inductive type *)
+val global_constructor_with_alias : qualid -> constructor
+
(** Locate a reference taking into account notations and "aliases" *)
val smart_global : ?head:bool -> qualid Constrexpr.or_by_notation -> GlobRef.t
+(** The same for constants *)
+val smart_global_constant : qualid Constrexpr.or_by_notation -> Constant.t
+
(** The same for inductive types *)
val smart_global_inductive : qualid Constrexpr.or_by_notation -> inductive
+
+(** The same for constructors of an inductive type *)
+val smart_global_constructor : qualid Constrexpr.or_by_notation -> constructor
diff --git a/interp/syntax_def.ml b/interp/syntax_def.ml
index bd3e234a91..f3ad3546ff 100644
--- a/interp/syntax_def.ml
+++ b/interp/syntax_def.ml
@@ -22,6 +22,7 @@ type syndef =
{ syndef_pattern : interpretation;
syndef_onlyparsing : bool;
syndef_deprecation : Deprecation.t option;
+ syndef_also_in_cases_pattern : bool;
}
let syntax_table =
@@ -52,7 +53,7 @@ let open_syntax_constant i ((sp,kn),(_local,syndef)) =
if not syndef.syndef_onlyparsing then
(* Redeclare it to be used as (short) name in case an other (distfix)
notation was declared in between *)
- Notation.declare_uninterpretation (Notation.SynDefRule kn) pat
+ Notation.declare_uninterpretation ~also_in_cases_pattern:syndef.syndef_also_in_cases_pattern (Notation.SynDefRule kn) pat
end
let cache_syntax_constant d =
@@ -81,11 +82,12 @@ let in_syntax_constant : (bool * syndef) -> obj =
subst_function = subst_syntax_constant;
classify_function = classify_syntax_constant }
-let declare_syntactic_definition ~local deprecation id ~onlyparsing pat =
+let declare_syntactic_definition ~local ?(also_in_cases_pattern=true) deprecation id ~onlyparsing pat =
let syndef =
{ syndef_pattern = pat;
syndef_onlyparsing = onlyparsing;
syndef_deprecation = deprecation;
+ syndef_also_in_cases_pattern = also_in_cases_pattern;
}
in
let _ = add_leaf id (in_syntax_constant (local,syndef)) in ()
diff --git a/interp/syntax_def.mli b/interp/syntax_def.mli
index 66a3132f2a..31f685152c 100644
--- a/interp/syntax_def.mli
+++ b/interp/syntax_def.mli
@@ -13,7 +13,7 @@ open Notation_term
(** Syntactic definitions. *)
-val declare_syntactic_definition : local:bool -> Deprecation.t option -> Id.t ->
+val declare_syntactic_definition : local:bool -> ?also_in_cases_pattern:bool -> Deprecation.t option -> Id.t ->
onlyparsing:bool -> interpretation -> unit
val search_syntactic_definition : ?loc:Loc.t -> KerName.t -> interpretation
diff --git a/kernel/cClosure.ml b/kernel/cClosure.ml
index a23ef8fdca..174125fc57 100644
--- a/kernel/cClosure.ml
+++ b/kernel/cClosure.ml
@@ -1165,7 +1165,7 @@ module FNativeEntries =
let mkFloat env f =
check_float env;
- { mark = mark Norm KnownR; term = FFloat f }
+ { mark = mark Cstr KnownR; term = FFloat f }
let mkBool env b =
check_bool env;
@@ -1328,10 +1328,14 @@ let rec knr info tab m stk =
| FFlex(ConstKey (kn,_u as c)) when red_set info.i_flags (fCONST kn) ->
(match ref_value_cache info tab (ConstKey c) with
| Def v -> kni info tab v stk
- | Primitive op when check_native_args op stk ->
- let rargs, a, nargs, stk = get_native_args1 op c stk in
- kni info tab a (Zprimitive(op,c,rargs,nargs)::stk)
- | Undef _ | OpaqueDef _ | Primitive _ -> (set_norm m; (m,stk)))
+ | Primitive op ->
+ if check_native_args op stk then
+ let rargs, a, nargs, stk = get_native_args1 op c stk in
+ kni info tab a (Zprimitive(op,c,rargs,nargs)::stk)
+ else
+ (* Similarly to fix, partially applied primitives are not Norm! *)
+ (m, stk)
+ | Undef _ | OpaqueDef _ -> (set_norm m; (m,stk)))
| FFlex(VarKey id) when red_set info.i_flags (fVAR id) ->
(match ref_value_cache info tab (VarKey id) with
| Def v -> kni info tab v stk
@@ -1531,7 +1535,12 @@ let whd_stack infos tab m stk = match Mark.red_state m.mark with
knh infos m stk
| Red | Cstr ->
let k = kni infos tab m stk in
- let () = if infos.i_cache.i_share then ignore (fapp_stack k) in (* to unlock Zupdates! *)
+ let () =
+ if infos.i_cache.i_share then
+ (* to unlock Zupdates! *)
+ let (m', stk') = k in
+ if not (m == m' && stk == stk') then ignore (zip m' stk')
+ in
k
let create_clos_infos ?univs ?(evars=fun _ -> None) flgs env =
diff --git a/kernel/nativelib.ml b/kernel/nativelib.ml
index 494282d4e1..c1f14923fa 100644
--- a/kernel/nativelib.ml
+++ b/kernel/nativelib.ml
@@ -25,7 +25,8 @@ let open_header = ["Nativevalues";
let open_header = List.map mk_open open_header
(* Directory where compiled files are stored *)
-let output_dir = ref ".coq-native"
+let dft_output_dir = ".coq-native"
+let output_dir = ref dft_output_dir
(* Extension of generated ml files, stored for debugging purposes *)
let source_ext = ".native"
@@ -92,9 +93,14 @@ let error_native_compiler_failed e =
CErrors.user_err msg
let call_compiler ?profile:(profile=false) ml_filename =
- let load_path = !get_load_paths () in
- let load_path = List.map (fun dn -> dn / !output_dir) load_path in
- let include_dirs = List.flatten (List.map (fun x -> ["-I"; x]) (get_include_dirs () @ load_path)) in
+ (* The below path is computed from Require statements, by uniquizing
+ the paths, see [Library.get_used_load_paths] This is in general
+ hacky and we should do a bit better once we move loadpath to its
+ own library *)
+ let require_load_path = !get_load_paths () in
+ (* We assume that installed files always go in .coq-native for now *)
+ let install_load_path = List.map (fun dn -> dn / dft_output_dir) require_load_path in
+ let include_dirs = List.flatten (List.map (fun x -> ["-I"; x]) (get_include_dirs () @ install_load_path)) in
let f = Filename.chop_extension ml_filename in
let link_filename = f ^ ".cmo" in
let link_filename = Dynlink.adapt_filename link_filename in
@@ -186,5 +192,10 @@ let call_linker ?(fatal=true) env ~prefix f upds =
match upds with Some upds -> update_locations upds | _ -> ()
let link_library env ~prefix ~dirname ~basename =
- let f = dirname / !output_dir / basename in
+ (* We try both [output_dir] and [.coq-native], unfortunately from
+ [Require] we don't know if we are loading a library in the build
+ dir or in the installed layout *)
+ let install_location = dirname / dft_output_dir / basename in
+ let build_location = dirname / !output_dir / basename in
+ let f = if Sys.file_exists build_location then build_location else install_location in
call_linker env ~fatal:false ~prefix f None
diff --git a/kernel/reduction.ml b/kernel/reduction.ml
index 5589ae3483..c891b885c4 100644
--- a/kernel/reduction.ml
+++ b/kernel/reduction.ml
@@ -301,7 +301,7 @@ let unfold_ref_with_args infos tab fl v =
| Primitive op when check_native_args op v ->
let c = match fl with ConstKey c -> c | _ -> assert false in
let rargs, a, nargs, v = get_native_args1 op c v in
- Some (whd_stack infos tab a (Zupdate a::(Zprimitive(op,c,rargs,nargs)::v)))
+ Some (a, (Zupdate a::(Zprimitive(op,c,rargs,nargs)::v)))
| Undef _ | OpaqueDef _ | Primitive _ -> None
type conv_tab = {
@@ -411,23 +411,26 @@ and eqappr cv_pb l2r infos (lft1,st1) (lft2,st2) cuniv =
let cuniv = conv_table_key infos.cnv_inf fl1 fl2 cuniv in
convert_stacks l2r infos lft1 lft2 v1 v2 cuniv
with NotConvertible | Univ.UniverseInconsistency _ ->
- (* else the oracle tells which constant is to be expanded *)
- let oracle = CClosure.oracle_of_infos infos.cnv_inf in
- let (app1,app2) =
- let aux appr1 lft1 fl1 tab1 v1 appr2 lft2 fl2 tab2 v2 =
- match unfold_ref_with_args infos.cnv_inf tab1 fl1 v1 with
- | Some t1 -> ((lft1, t1), appr2)
- | None -> match unfold_ref_with_args infos.cnv_inf tab2 fl2 v2 with
- | Some t2 -> (appr1, (lft2, t2))
- | None -> raise NotConvertible
- in
- if Conv_oracle.oracle_order Univ.out_punivs oracle l2r fl1 fl2 then
- aux appr1 lft1 fl1 infos.lft_tab v1 appr2 lft2 fl2 infos.rgt_tab v2
- else
- let (app2,app1) = aux appr2 lft2 fl2 infos.rgt_tab v2 appr1 lft1 fl1 infos.lft_tab v1 in
- (app1,app2)
- in
- eqappr cv_pb l2r infos app1 app2 cuniv)
+ let r1 = unfold_ref_with_args infos.cnv_inf infos.lft_tab fl1 v1 in
+ let r2 = unfold_ref_with_args infos.cnv_inf infos.rgt_tab fl2 v2 in
+ match r1, r2 with
+ | None, None -> raise NotConvertible
+ | Some t1, Some t2 ->
+ (* else the oracle tells which constant is to be expanded *)
+ let oracle = CClosure.oracle_of_infos infos.cnv_inf in
+ if Conv_oracle.oracle_order Univ.out_punivs oracle l2r fl1 fl2 then
+ eqappr cv_pb l2r infos (lft1, t1) appr2 cuniv
+ else
+ eqappr cv_pb l2r infos appr1 (lft2, t2) cuniv
+ | Some (t1, v1), None ->
+ let all = RedFlags.red_add_transparent all (RedFlags.red_transparent (info_flags infos.cnv_inf)) in
+ let t1 = whd_stack (infos_with_reds infos.cnv_inf all) infos.lft_tab t1 v1 in
+ eqappr cv_pb l2r infos (lft1, t1) appr2 cuniv
+ | None, Some (t2, v2) ->
+ let all = RedFlags.red_add_transparent all (RedFlags.red_transparent (info_flags infos.cnv_inf)) in
+ let t2 = whd_stack (infos_with_reds infos.cnv_inf all) infos.rgt_tab t2 v2 in
+ eqappr cv_pb l2r infos appr1 (lft2, t2) cuniv
+ )
| (FProj (p1,c1), FProj (p2, c2)) ->
(* Projections: prefer unfolding to first-order unification,
diff --git a/kernel/vars.ml b/kernel/vars.ml
index f7e28b0cfe..a446fa413c 100644
--- a/kernel/vars.ml
+++ b/kernel/vars.ml
@@ -348,5 +348,8 @@ let universes_of_constr c =
| Array (u,_,_,_) ->
let s = LSet.fold LSet.add (Instance.levels u) s in
Constr.fold aux s c
+ | Case (_,_,CaseInvert {univs;args=_},_,_) ->
+ let s = LSet.fold LSet.add (Instance.levels univs) s in
+ Constr.fold aux s c
| _ -> Constr.fold aux s c
in aux LSet.empty c
diff --git a/lib/control.ml b/lib/control.ml
index bb42b5727e..95ea3935a7 100644
--- a/lib/control.ml
+++ b/lib/control.ml
@@ -18,10 +18,12 @@ let enable_thread_delay = ref false
let check_for_interrupt () =
if !interrupt then begin interrupt := false; raise Sys.Break end;
- incr steps;
- if !enable_thread_delay && !steps = 1000 then begin
- Thread.delay 0.001;
- steps := 0;
+ if !enable_thread_delay then begin
+ incr steps;
+ if !steps = 1000 then begin
+ Thread.delay 0.001;
+ steps := 0;
+ end
end
(** This function does not work on windows, sigh... *)
diff --git a/parsing/cLexer.ml b/parsing/cLexer.ml
index f485970eec..d8d2f2a2ef 100644
--- a/parsing/cLexer.ml
+++ b/parsing/cLexer.ml
@@ -823,7 +823,7 @@ let token_text : type c. c Tok.p -> string = function
| PKEYWORD t -> "'" ^ t ^ "'"
| PIDENT None -> "identifier"
| PIDENT (Some t) -> "'" ^ t ^ "'"
- | PNUMBER None -> "numeral"
+ | PNUMBER None -> "number"
| PNUMBER (Some n) -> "'" ^ NumTok.Unsigned.sprint n ^ "'"
| PSTRING None -> "string"
| PSTRING (Some s) -> "STRING \"" ^ s ^ "\""
@@ -916,7 +916,7 @@ let terminal s =
if is_ident_not_keyword s then PIDENT (Some s)
else PKEYWORD s
-(* Precondition: the input is a numeral (c.f. [NumTok.t]) *)
-let terminal_numeral s = match NumTok.Unsigned.parse_string s with
+(* Precondition: the input is a number (c.f. [NumTok.t]) *)
+let terminal_number s = match NumTok.Unsigned.parse_string s with
| Some n -> PNUMBER (Some n)
- | None -> failwith "numeral token expected."
+ | None -> failwith "number token expected."
diff --git a/parsing/cLexer.mli b/parsing/cLexer.mli
index ac2c5bcfe2..af4b7ba334 100644
--- a/parsing/cLexer.mli
+++ b/parsing/cLexer.mli
@@ -49,8 +49,8 @@ val check_keyword : string -> unit
(** When string is not an ident, returns a keyword. *)
val terminal : string -> string Tok.p
-(** Precondition: the input is a numeral (c.f. [NumTok.t]) *)
-val terminal_numeral : string -> NumTok.Unsigned.t Tok.p
+(** Precondition: the input is a number (c.f. [NumTok.t]) *)
+val terminal_number : string -> NumTok.Unsigned.t Tok.p
(** The lexer of Coq: *)
diff --git a/parsing/g_constr.mlg b/parsing/g_constr.mlg
index 349e14bba3..67a061175a 100644
--- a/parsing/g_constr.mlg
+++ b/parsing/g_constr.mlg
@@ -173,10 +173,10 @@ GRAMMAR EXTEND Gram
[ c = atomic_constr -> { c }
| c = term_match -> { c }
| "("; c = term LEVEL "200"; ")" ->
- { (* Preserve parentheses around numerals so that constrintern does not
- collapse -(3) into the numeral -3. *)
+ { (* Preserve parentheses around numbers so that constrintern does not
+ collapse -(3) into the number -3. *)
(match c.CAst.v with
- | CPrim (Numeral (NumTok.SPlus,n)) ->
+ | CPrim (Number (NumTok.SPlus,n)) ->
CAst.make ~loc @@ CNotation(None,(InConstrEntry,"( _ )"),([c],[],[],[]))
| _ -> c) }
| "{|"; c = record_declaration; bar_cbrace -> { c }
@@ -258,7 +258,7 @@ GRAMMAR EXTEND Gram
atomic_constr:
[ [ g = global; i = univ_annot -> { CAst.make ~loc @@ CRef (g,i) }
| s = sort -> { CAst.make ~loc @@ CSort s }
- | n = NUMBER-> { CAst.make ~loc @@ CPrim (Numeral (NumTok.SPlus,n)) }
+ | n = NUMBER-> { CAst.make ~loc @@ CPrim (Number (NumTok.SPlus,n)) }
| s = string -> { CAst.make ~loc @@ CPrim (String s) }
| "_" -> { CAst.make ~loc @@ CHole (None, IntroAnonymous, None) }
| "?"; "["; id = identref; "]" -> { CAst.make ~loc @@ CHole (None, IntroIdentifier id.CAst.v, None) }
@@ -362,15 +362,15 @@ GRAMMAR EXTEND Gram
| "{|"; pat = record_patterns; bar_cbrace -> { CAst.make ~loc @@ CPatRecord pat }
| "_" -> { CAst.make ~loc @@ CPatAtom None }
| "("; p = pattern LEVEL "200"; ")" ->
- { (* Preserve parentheses around numerals so that constrintern does not
- collapse -(3) into the numeral -3. *)
+ { (* Preserve parentheses around numbers so that constrintern does not
+ collapse -(3) into the number -3. *)
match p.CAst.v with
- | CPatPrim (Numeral (NumTok.SPlus,n)) ->
+ | CPatPrim (Number (NumTok.SPlus,n)) ->
CAst.make ~loc @@ CPatNotation(None,(InConstrEntry,"( _ )"),([p],[]),[])
| _ -> p }
| "("; p = pattern LEVEL "200"; "|" ; pl = LIST1 pattern LEVEL "200" SEP "|"; ")" ->
{ CAst.make ~loc @@ CPatOr (p::pl) }
- | n = NUMBER-> { CAst.make ~loc @@ CPatPrim (Numeral (NumTok.SPlus,n)) }
+ | n = NUMBER-> { CAst.make ~loc @@ CPatPrim (Number (NumTok.SPlus,n)) }
| s = string -> { CAst.make ~loc @@ CPatPrim (String s) } ] ]
;
fixannot:
diff --git a/plugins/ltac/g_ltac.mlg b/plugins/ltac/g_ltac.mlg
index c38a4dcd90..c54f8ffa78 100644
--- a/plugins/ltac/g_ltac.mlg
+++ b/plugins/ltac/g_ltac.mlg
@@ -466,7 +466,7 @@ END
VERNAC COMMAND EXTEND VernacPrintLtac CLASSIFIED AS QUERY
| [ "Print" "Ltac" reference(r) ] ->
- { Feedback.msg_notice (Tacintern.print_ltac r) }
+ { Feedback.msg_notice (Tacentries.print_ltac r) }
END
VERNAC COMMAND EXTEND VernacLocateLtac CLASSIFIED AS QUERY
diff --git a/plugins/ltac/g_tactic.mlg b/plugins/ltac/g_tactic.mlg
index 97d75261c5..ecfe6c1664 100644
--- a/plugins/ltac/g_tactic.mlg
+++ b/plugins/ltac/g_tactic.mlg
@@ -121,8 +121,8 @@ let destruction_arg_of_constr (c,lbind as clbind) = match lbind with
end
| _ -> ElimOnConstr clbind
-let mkNumeral n =
- Numeral (NumTok.Signed.of_int_string (string_of_int n))
+let mkNumber n =
+ Number (NumTok.Signed.of_int_string (string_of_int n))
let mkTacCase with_evar = function
| [(clear,ElimOnConstr cl),(None,None),None],None ->
@@ -130,7 +130,7 @@ let mkTacCase with_evar = function
(* Reinterpret numbers as a notation for terms *)
| [(clear,ElimOnAnonHyp n),(None,None),None],None ->
TacCase (with_evar,
- (clear,(CAst.make @@ CPrim (mkNumeral n),
+ (clear,(CAst.make @@ CPrim (mkNumber n),
NoBindings)))
(* Reinterpret ident as notations for variables in the context *)
(* because we don't know if they are quantified or not *)
diff --git a/plugins/ltac/taccoerce.ml b/plugins/ltac/taccoerce.ml
index ee28229cb7..4c1fe6417e 100644
--- a/plugins/ltac/taccoerce.ml
+++ b/plugins/ltac/taccoerce.ml
@@ -394,8 +394,13 @@ type appl =
(* Values for interpretation *)
type tacvalue =
- | VFun of appl * Tacexpr.ltac_trace * Loc.t option * Val.t Id.Map.t *
- Name.t list * Tacexpr.glob_tactic_expr
+ | VFun of
+ appl *
+ Tacexpr.ltac_trace *
+ Loc.t option * (* when executing a global Ltac function: the location where this function was called *)
+ Val.t Id.Map.t * (* closure *)
+ Name.t list * (* binders *)
+ Tacexpr.glob_tactic_expr (* body *)
| VRec of Val.t Id.Map.t ref * Tacexpr.glob_tactic_expr
let (wit_tacvalue : (Empty.t, tacvalue, tacvalue) Genarg.genarg_type) =
diff --git a/plugins/ltac/tacentries.ml b/plugins/ltac/tacentries.ml
index a05b36c1b4..29e29044f1 100644
--- a/plugins/ltac/tacentries.ml
+++ b/plugins/ltac/tacentries.ml
@@ -528,16 +528,40 @@ let print_ltacs () =
let locatable_ltac = "Ltac"
+let split_ltac_fun = function
+ | Tacexpr.TacFun (l,t) -> (l,t)
+ | t -> ([],t)
+
+let pr_ltac_fun_arg n = spc () ++ Name.print n
+
+let print_ltac_body qid tac =
+ let filter mp =
+ try Some (Nametab.shortest_qualid_of_module mp)
+ with Not_found -> None
+ in
+ let mods = List.map_filter filter tac.Tacenv.tac_redef in
+ let redefined = match mods with
+ | [] -> mt ()
+ | mods ->
+ let redef = prlist_with_sep fnl pr_qualid mods in
+ fnl () ++ str "Redefined by:" ++ fnl () ++ redef
+ in
+ let l,t = split_ltac_fun tac.Tacenv.tac_body in
+ hv 2 (
+ hov 2 (str "Ltac" ++ spc() ++ pr_qualid qid ++
+ prlist pr_ltac_fun_arg l ++ spc () ++ str ":=")
+ ++ spc() ++ Pptactic.pr_glob_tactic (Global.env ()) t) ++ redefined
+
let () =
let open Prettyp in
- let locate qid = try Some (Tacenv.locate_tactic qid) with Not_found -> None in
- let locate_all = Tacenv.locate_extended_all_tactic in
- let shortest_qualid = Tacenv.shortest_qualid_of_tactic in
- let name kn = str "Ltac" ++ spc () ++ pr_path (Tacenv.path_of_tactic kn) in
- let print kn =
- let qid = qualid_of_path (Tacenv.path_of_tactic kn) in
- Tacintern.print_ltac qid
- in
+ let locate qid = try Some (qid, Tacenv.locate_tactic qid) with Not_found -> None in
+ let locate_all qid = List.map (fun kn -> (qid,kn)) (Tacenv.locate_extended_all_tactic qid) in
+ let shortest_qualid (qid,kn) = Tacenv.shortest_qualid_of_tactic kn in
+ let name (qid,kn) = str "Ltac" ++ spc () ++ pr_path (Tacenv.path_of_tactic kn) in
+ let print (qid,kn) =
+ let entries = Tacenv.ltac_entries () in
+ let tac = KNmap.find kn entries in
+ print_ltac_body qid tac in
let about = name in
register_locatable locatable_ltac {
locate;
@@ -551,6 +575,17 @@ let () =
let print_located_tactic qid =
Feedback.msg_notice (Prettyp.print_located_other locatable_ltac qid)
+let print_ltac id =
+ try
+ let kn = Tacenv.locate_tactic id in
+ let entries = Tacenv.ltac_entries () in
+ let tac = KNmap.find kn entries in
+ print_ltac_body id tac
+ with
+ Not_found ->
+ user_err ~hdr:"print_ltac"
+ (pr_qualid id ++ spc() ++ str "is not a user defined tactic.")
+
(** Grammar *)
let () =
diff --git a/plugins/ltac/tacentries.mli b/plugins/ltac/tacentries.mli
index 6ee3ce091b..fc9ab54eba 100644
--- a/plugins/ltac/tacentries.mli
+++ b/plugins/ltac/tacentries.mli
@@ -69,6 +69,9 @@ val print_ltacs : unit -> unit
val print_located_tactic : Libnames.qualid -> unit
(** Display the absolute name of a tactic. *)
+val print_ltac : Libnames.qualid -> Pp.t
+(** Display the definition of a tactic. *)
+
(** {5 Low-level registering of tactics} *)
type (_, 'a) ml_ty_sig =
diff --git a/plugins/ltac/tacintern.ml b/plugins/ltac/tacintern.ml
index 9c3b05fdf1..47f1d3bf66 100644
--- a/plugins/ltac/tacintern.ml
+++ b/plugins/ltac/tacintern.ml
@@ -769,38 +769,6 @@ let glob_tactic_env l env x =
(intern_pure_tactic { (Genintern.empty_glob_sign env) with ltacvars })
x
-let split_ltac_fun = function
- | TacFun (l,t) -> (l,t)
- | t -> ([],t)
-
-let pr_ltac_fun_arg n = spc () ++ Name.print n
-
-let print_ltac id =
- try
- let kn = Tacenv.locate_tactic id in
- let entries = Tacenv.ltac_entries () in
- let tac = KNmap.find kn entries in
- let filter mp =
- try Some (Nametab.shortest_qualid_of_module mp)
- with Not_found -> None
- in
- let mods = List.map_filter filter tac.Tacenv.tac_redef in
- let redefined = match mods with
- | [] -> mt ()
- | mods ->
- let redef = prlist_with_sep fnl pr_qualid mods in
- fnl () ++ str "Redefined by:" ++ fnl () ++ redef
- in
- let l,t = split_ltac_fun tac.Tacenv.tac_body in
- hv 2 (
- hov 2 (str "Ltac" ++ spc() ++ pr_qualid id ++
- prlist pr_ltac_fun_arg l ++ spc () ++ str ":=")
- ++ spc() ++ Pptactic.pr_glob_tactic (Global.env ()) t) ++ redefined
- with
- Not_found ->
- user_err ~hdr:"print_ltac"
- (pr_qualid id ++ spc() ++ str "is not a user defined tactic.")
-
(** Registering *)
let lift intern = (); fun ist x -> (ist, intern ist x)
diff --git a/plugins/ltac/tacintern.mli b/plugins/ltac/tacintern.mli
index 22ec15566b..f779aa470c 100644
--- a/plugins/ltac/tacintern.mli
+++ b/plugins/ltac/tacintern.mli
@@ -55,9 +55,6 @@ val intern_hyp : glob_sign -> lident -> lident
val intern_genarg : glob_sign -> raw_generic_argument -> glob_generic_argument
-(** printing *)
-val print_ltac : Libnames.qualid -> Pp.t
-
(** Reduction expressions *)
val intern_red_expr : glob_sign -> raw_red_expr -> glob_red_expr
diff --git a/plugins/ltac/tacinterp.ml b/plugins/ltac/tacinterp.ml
index 7728415ddd..3d734d3a66 100644
--- a/plugins/ltac/tacinterp.ml
+++ b/plugins/ltac/tacinterp.ml
@@ -153,11 +153,15 @@ let add_extra_loc loc extra =
match loc with
| None -> extra
| Some loc -> TacStore.set extra f_loc loc
-let add_loc loc ist =
+let extract_loc ist = TacStore.get ist.extra f_loc
+
+let ensure_loc loc ist =
match loc with
| None -> ist
- | Some loc -> { ist with extra = TacStore.set ist.extra f_loc loc }
-let extract_loc ist = TacStore.get ist.extra f_loc
+ | Some loc ->
+ match extract_loc ist with
+ | None -> { ist with extra = TacStore.set ist.extra f_loc loc }
+ | Some _ -> ist
let print_top_val env v = Pptactic.pr_value Pptactic.ltop v
@@ -1175,7 +1179,7 @@ and eval_tactic_ist ist tac : unit Proofview.tactic = match tac with
| TacFirst l -> Tacticals.New.tclFIRST (List.map (interp_tactic ist) l)
| TacSolve l -> Tacticals.New.tclSOLVE (List.map (interp_tactic ist) l)
| TacComplete tac -> Tacticals.New.tclCOMPLETE (interp_tactic ist tac)
- | TacArg {CAst.loc} -> Ftactic.run (val_interp (add_loc loc ist) tac) (fun v -> tactic_of_value ist v)
+ | TacArg {CAst.loc} -> Ftactic.run (val_interp (ensure_loc loc ist) tac) (fun v -> tactic_of_value ist v)
| TacSelect (sel, tac) -> Tacticals.New.tclSELECT sel (interp_tactic ist tac)
(* For extensions *)
| TacAlias {loc; v=(s,l)} ->
@@ -1254,9 +1258,12 @@ and interp_ltac_reference ?loc' mustbetac ist r : Val.t Ftactic.t =
let extra = TacStore.set extra f_trace trace in
let ist = { lfun = Id.Map.empty; poly; extra } in
let appl = GlbAppl[r,[]] in
+ (* We call a global ltac reference: add a loc on its executation only if not
+ already in another global reference *)
+ let ist = ensure_loc loc ist in
Profile_ltac.do_profile "interp_ltac_reference" trace ~count_call:false
- (catch_error_tac_loc (* interp *) loc false trace
- (val_interp ~appl (add_loc (* exec *) loc ist) (Tacenv.interp_ltac r)))
+ (catch_error_tac_loc (* loc for interpretation *) loc false trace
+ (val_interp ~appl ist (Tacenv.interp_ltac r)))
and interp_tacarg ist arg : Val.t Ftactic.t =
match arg with
@@ -1325,7 +1332,7 @@ and interp_app loc ist fv largs : Val.t Ftactic.t =
; extra = TacStore.set ist.extra f_trace []
} in
Profile_ltac.do_profile "interp_app" trace ~count_call:false
- (catch_error_tac_loc loc false trace (val_interp (add_loc loc ist) body)) >>= fun v ->
+ (catch_error_tac_loc loc false trace (val_interp (ensure_loc loc ist) body)) >>= fun v ->
Ftactic.return (name_vfun (push_appl appl largs) v)
end
begin fun (e, info) ->
diff --git a/plugins/ssr/ssrparser.mlg b/plugins/ssr/ssrparser.mlg
index 35fecfb0a5..ccdf5fa68e 100644
--- a/plugins/ssr/ssrparser.mlg
+++ b/plugins/ssr/ssrparser.mlg
@@ -350,7 +350,7 @@ let interp_index ist gl idx =
| Some c ->
let rc = Detyping.detype Detyping.Now false Id.Set.empty (pf_env gl) (project gl) c in
begin match Notation.uninterp_prim_token rc (None, []) with
- | Constrexpr.Numeral n, _ when NumTok.Signed.is_int n ->
+ | Constrexpr.Number n, _ when NumTok.Signed.is_int n ->
int_of_string (NumTok.Signed.to_string n)
| _ -> raise Not_found
end
diff --git a/plugins/ssr/ssrvernac.mlg b/plugins/ssr/ssrvernac.mlg
index a49a5e8b28..99cf197b78 100644
--- a/plugins/ssr/ssrvernac.mlg
+++ b/plugins/ssr/ssrvernac.mlg
@@ -304,21 +304,6 @@ END
{
- let warn_search_moved_enabled = ref true
- let warn_search_moved = CWarnings.create ~name:"ssr-search-moved"
- ~category:"deprecated" ~default:CWarnings.Enabled
- (fun () ->
- (Pp.strbrk
- "In previous versions of Coq, loading SSReflect had the effect of \
- replacing the built-in 'Search' command with an SSReflect version \
- of that command. \
- Coq's own search feature was still available via 'SearchAbout' \
- (but that alias is deprecated). \
- This replacement no longer happens; now 'Search' calls Coq's own search \
- feature even when SSReflect is loaded. \
- If you want to use SSReflect's deprecated Search command \
- instead of the built-in one, please Require the ssrsearch module."))
-
open G_vernac
}
@@ -328,7 +313,6 @@ GRAMMAR EXTEND Gram
query_command:
[ [ IDENT "Search"; s = search_query; l = search_queries; "." ->
{ let (sl,m) = l in
- if !warn_search_moved_enabled then warn_search_moved ();
fun g ->
Vernacexpr.VernacSearch (Vernacexpr.Search (s::sl),g, m) }
] ]
diff --git a/plugins/ssr/ssrvernac.mli b/plugins/ssr/ssrvernac.mli
index 93339313f0..327a2d4660 100644
--- a/plugins/ssr/ssrvernac.mli
+++ b/plugins/ssr/ssrvernac.mli
@@ -9,5 +9,3 @@
(************************************************************************)
(* This file is (C) Copyright 2006-2015 Microsoft Corporation and Inria. *)
-
-val warn_search_moved_enabled : bool ref
diff --git a/plugins/ssrsearch/g_search.mlg b/plugins/ssrsearch/g_search.mlg
index 5e002e09cc..54fdea0860 100644
--- a/plugins/ssrsearch/g_search.mlg
+++ b/plugins/ssrsearch/g_search.mlg
@@ -301,10 +301,6 @@ let ssrdisplaysearch gr env t =
let pr_res = pr_global gr ++ str ":" ++ spc () ++ pr_lconstr_env env Evd.empty t in
Feedback.msg_notice (hov 2 pr_res ++ fnl ())
-(* Remove the warning entirely when this plugin is loaded. *)
-let _ =
- Ssreflect_plugin.Ssrvernac.warn_search_moved_enabled := false
-
let deprecated_search =
CWarnings.create
~name:"deprecated-ssr-search"
diff --git a/plugins/syntax/dune b/plugins/syntax/dune
index b395695c8a..f930fc265a 100644
--- a/plugins/syntax/dune
+++ b/plugins/syntax/dune
@@ -1,22 +1,8 @@
(library
- (name numeral_notation_plugin)
- (public_name coq.plugins.numeral_notation)
- (synopsis "Coq numeral notation plugin")
- (modules g_numeral numeral)
- (libraries coq.vernac))
-
-(library
- (name string_notation_plugin)
- (public_name coq.plugins.string_notation)
- (synopsis "Coq string notation plugin")
- (modules g_string string_notation)
- (libraries coq.vernac))
-
-(library
- (name r_syntax_plugin)
- (public_name coq.plugins.r_syntax)
- (synopsis "Coq syntax plugin: reals")
- (modules r_syntax)
+ (name number_string_notation_plugin)
+ (public_name coq.plugins.number_string_notation)
+ (synopsis "Coq number and string notation plugin")
+ (modules g_number_string string_notation number)
(libraries coq.vernac))
(library
@@ -33,4 +19,4 @@
(modules float_syntax)
(libraries coq.vernac))
-(coq.pp (modules g_numeral g_string))
+(coq.pp (modules g_number_string))
diff --git a/plugins/syntax/g_number_string.mlg b/plugins/syntax/g_number_string.mlg
new file mode 100644
index 0000000000..c8badd238d
--- /dev/null
+++ b/plugins/syntax/g_number_string.mlg
@@ -0,0 +1,110 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+DECLARE PLUGIN "number_string_notation_plugin"
+
+{
+
+open Notation
+open Number
+open String_notation
+open Pp
+open Names
+open Stdarg
+open Pcoq.Prim
+
+let pr_number_after = function
+ | Nop -> mt ()
+ | Warning n -> str "warning after " ++ NumTok.UnsignedNat.print n
+ | Abstract n -> str "abstract after " ++ NumTok.UnsignedNat.print n
+
+let pr_deprecated_number_modifier m = str "(" ++ pr_number_after m ++ str ")"
+
+let warn_deprecated_numeral_notation =
+ CWarnings.create ~name:"numeral-notation" ~category:"deprecated"
+ (fun () ->
+ strbrk "Numeral Notation is deprecated, please use Number Notation instead.")
+
+let pr_number_string_mapping (b, n, n') =
+ if b then
+ str "[" ++ Libnames.pr_qualid n ++ str "]" ++ spc () ++ str "=>" ++ spc ()
+ ++ Libnames.pr_qualid n'
+ else
+ Libnames.pr_qualid n ++ spc () ++ str "=>" ++ spc ()
+ ++ Libnames.pr_qualid n'
+
+let pr_number_string_via (n, l) =
+ str "via " ++ Libnames.pr_qualid n ++ str " mapping ["
+ ++ prlist_with_sep pr_comma pr_number_string_mapping l ++ str "]"
+
+let pr_number_modifier = function
+ | After a -> pr_number_after a
+ | Via nl -> pr_number_string_via nl
+
+let pr_number_options l =
+ str "(" ++ prlist_with_sep pr_comma pr_number_modifier l ++ str ")"
+
+let pr_string_option l =
+ str "(" ++ pr_number_string_via l ++ str ")"
+
+}
+
+VERNAC ARGUMENT EXTEND deprecated_number_modifier
+ PRINTED BY { pr_deprecated_number_modifier }
+| [ ] -> { Nop }
+| [ "(" "warning" "after" bignat(waft) ")" ] -> { Warning (NumTok.UnsignedNat.of_string waft) }
+| [ "(" "abstract" "after" bignat(n) ")" ] -> { Abstract (NumTok.UnsignedNat.of_string n) }
+END
+
+VERNAC ARGUMENT EXTEND number_string_mapping
+ PRINTED BY { pr_number_string_mapping }
+| [ reference(n) "=>" reference(n') ] -> { false, n, n' }
+| [ "[" reference(n) "]" "=>" reference(n') ] -> { true, n, n' }
+END
+
+VERNAC ARGUMENT EXTEND number_string_via
+ PRINTED BY { pr_number_string_via }
+| [ "via" reference(n) "mapping" "[" ne_number_string_mapping_list_sep(l, ",") "]" ] -> { n, l }
+END
+
+VERNAC ARGUMENT EXTEND number_modifier
+ PRINTED BY { pr_number_modifier }
+| [ "warning" "after" bignat(waft) ] -> { After (Warning (NumTok.UnsignedNat.of_string waft)) }
+| [ "abstract" "after" bignat(n) ] -> { After (Abstract (NumTok.UnsignedNat.of_string n)) }
+| [ number_string_via(v) ] -> { Via v }
+END
+
+VERNAC ARGUMENT EXTEND number_options
+ PRINTED BY { pr_number_options }
+| [ "(" ne_number_modifier_list_sep(l, ",") ")" ] -> { l }
+END
+
+VERNAC ARGUMENT EXTEND string_option
+ PRINTED BY { pr_string_option }
+| [ "(" number_string_via(v) ")" ] -> { v }
+END
+
+VERNAC COMMAND EXTEND NumberNotation CLASSIFIED AS SIDEFF
+ | #[ locality = Attributes.locality; ] [ "Number" "Notation" reference(ty) reference(f) reference(g) number_options_opt(nl) ":"
+ ident(sc) ] ->
+
+ { vernac_number_notation (Locality.make_module_locality locality) ty f g (Option.default [] nl) (Id.to_string sc) }
+ | #[ locality = Attributes.locality; ] [ "Numeral" "Notation" reference(ty) reference(f) reference(g) ":"
+ ident(sc) deprecated_number_modifier(o) ] ->
+
+ { warn_deprecated_numeral_notation ();
+ vernac_number_notation (Locality.make_module_locality locality) ty f g [After o] (Id.to_string sc) }
+END
+
+VERNAC COMMAND EXTEND StringNotation CLASSIFIED AS SIDEFF
+ | #[ locality = Attributes.locality; ] [ "String" "Notation" reference(ty) reference(f) reference(g) string_option_opt(o) ":"
+ ident(sc) ] ->
+ { vernac_string_notation (Locality.make_module_locality locality) ty f g o (Id.to_string sc) }
+END
diff --git a/plugins/syntax/g_numeral.mlg b/plugins/syntax/g_numeral.mlg
deleted file mode 100644
index 93d91abea3..0000000000
--- a/plugins/syntax/g_numeral.mlg
+++ /dev/null
@@ -1,51 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-DECLARE PLUGIN "numeral_notation_plugin"
-
-{
-
-open Notation
-open Numeral
-open Pp
-open Names
-open Stdarg
-open Pcoq.Prim
-
-let pr_numnot_option = function
- | Nop -> mt ()
- | Warning n -> str "(warning after " ++ NumTok.UnsignedNat.print n ++ str ")"
- | Abstract n -> str "(abstract after " ++ NumTok.UnsignedNat.print n ++ str ")"
-
-let warn_deprecated_numeral_notation =
- CWarnings.create ~name:"numeral-notation" ~category:"deprecated"
- (fun () ->
- strbrk "Numeral Notation is deprecated, please use Number Notation instead.")
-
-}
-
-VERNAC ARGUMENT EXTEND numeral_modifier
- PRINTED BY { pr_numnot_option }
-| [ ] -> { Nop }
-| [ "(" "warning" "after" bignat(waft) ")" ] -> { Warning (NumTok.UnsignedNat.of_string waft) }
-| [ "(" "abstract" "after" bignat(n) ")" ] -> { Abstract (NumTok.UnsignedNat.of_string n) }
-END
-
-VERNAC COMMAND EXTEND NumeralNotation CLASSIFIED AS SIDEFF
- | #[ locality = Attributes.locality; ] [ "Number" "Notation" reference(ty) reference(f) reference(g) ":"
- ident(sc) numeral_modifier(o) ] ->
-
- { vernac_numeral_notation (Locality.make_module_locality locality) ty f g (Id.to_string sc) o }
- | #[ locality = Attributes.locality; ] [ "Numeral" "Notation" reference(ty) reference(f) reference(g) ":"
- ident(sc) numeral_modifier(o) ] ->
-
- { warn_deprecated_numeral_notation ();
- vernac_numeral_notation (Locality.make_module_locality locality) ty f g (Id.to_string sc) o }
-END
diff --git a/plugins/syntax/g_string.mlg b/plugins/syntax/g_string.mlg
deleted file mode 100644
index 788f9e011d..0000000000
--- a/plugins/syntax/g_string.mlg
+++ /dev/null
@@ -1,25 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-DECLARE PLUGIN "string_notation_plugin"
-
-{
-
-open String_notation
-open Names
-open Stdarg
-
-}
-
-VERNAC COMMAND EXTEND StringNotation CLASSIFIED AS SIDEFF
- | #[ locality = Attributes.locality; ] [ "String" "Notation" reference(ty) reference(f) reference(g) ":"
- ident(sc) ] ->
- { vernac_string_notation (Locality.make_module_locality locality) ty f g (Id.to_string sc) }
-END
diff --git a/plugins/syntax/int63_syntax.ml b/plugins/syntax/int63_syntax.ml
index 5f4db8e800..b14b02f3bb 100644
--- a/plugins/syntax/int63_syntax.ml
+++ b/plugins/syntax/int63_syntax.ml
@@ -43,6 +43,7 @@ let _ =
let id_int63 = Nametab.locate q_id_int63 in
let o = { to_kind = Int63, Direct;
to_ty = id_int63;
+ to_post = [||];
of_kind = Int63, Direct;
of_ty = id_int63;
ty_name = q_int63;
@@ -50,7 +51,7 @@ let _ =
enable_prim_token_interpretation
{ pt_local = false;
pt_scope = int63_scope;
- pt_interp_info = NumeralNotation o;
+ pt_interp_info = NumberNotation o;
pt_required = (int63_path, int63_module);
pt_refs = [];
pt_in_match = false })
diff --git a/plugins/syntax/number.ml b/plugins/syntax/number.ml
new file mode 100644
index 0000000000..89d757a72a
--- /dev/null
+++ b/plugins/syntax/number.ml
@@ -0,0 +1,505 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Pp
+open Util
+open Names
+open Libnames
+open Constrexpr
+open Constrexpr_ops
+open Notation
+
+module CSet = CSet.Make (Constr)
+module CMap = CMap.Make (Constr)
+
+(** * Number notation *)
+
+type number_string_via = qualid * (bool * qualid * qualid) list
+type number_option =
+ | After of numnot_option
+ | Via of number_string_via
+
+let warn_abstract_large_num_no_op =
+ CWarnings.create ~name:"abstract-large-number-no-op" ~category:"numbers"
+ (fun f ->
+ strbrk "The 'abstract after' directive has no effect when " ++
+ strbrk "the parsing function (" ++
+ Nametab.pr_global_env (Termops.vars_of_env (Global.env ())) f ++ strbrk ") targets an " ++
+ strbrk "option type.")
+
+let get_constructors ind =
+ let mib,oib = Global.lookup_inductive ind in
+ let mc = oib.Declarations.mind_consnames in
+ Array.to_list
+ (Array.mapi (fun j c -> GlobRef.ConstructRef (ind, j + 1)) mc)
+
+let qualid_of_ref n =
+ n |> Coqlib.lib_ref |> Nametab.shortest_qualid_of_global Id.Set.empty
+
+let q_option () = qualid_of_ref "core.option.type"
+
+let unsafe_locate_ind q =
+ match Nametab.locate q with
+ | GlobRef.IndRef i -> i
+ | _ -> raise Not_found
+
+let locate_z () =
+ let zn = "num.Z.type" in
+ let pn = "num.pos.type" in
+ if Coqlib.has_ref zn && Coqlib.has_ref pn
+ then
+ let q_z = qualid_of_ref zn in
+ let q_pos = qualid_of_ref pn in
+ Some ({
+ z_ty = unsafe_locate_ind q_z;
+ pos_ty = unsafe_locate_ind q_pos;
+ }, mkRefC q_z)
+ else None
+
+let locate_number () =
+ let dint = "num.int.type" in
+ let duint = "num.uint.type" in
+ let dec = "num.decimal.type" in
+ let hint = "num.hexadecimal_int.type" in
+ let huint = "num.hexadecimal_uint.type" in
+ let hex = "num.hexadecimal.type" in
+ let int = "num.num_int.type" in
+ let uint = "num.num_uint.type" in
+ let num = "num.number.type" in
+ if Coqlib.has_ref dint && Coqlib.has_ref duint && Coqlib.has_ref dec
+ && Coqlib.has_ref hint && Coqlib.has_ref huint && Coqlib.has_ref hex
+ && Coqlib.has_ref int && Coqlib.has_ref uint && Coqlib.has_ref num
+ then
+ let q_dint = qualid_of_ref dint in
+ let q_duint = qualid_of_ref duint in
+ let q_dec = qualid_of_ref dec in
+ let q_hint = qualid_of_ref hint in
+ let q_huint = qualid_of_ref huint in
+ let q_hex = qualid_of_ref hex in
+ let q_int = qualid_of_ref int in
+ let q_uint = qualid_of_ref uint in
+ let q_num = qualid_of_ref num in
+ let int_ty = {
+ dec_int = unsafe_locate_ind q_dint;
+ dec_uint = unsafe_locate_ind q_duint;
+ hex_int = unsafe_locate_ind q_hint;
+ hex_uint = unsafe_locate_ind q_huint;
+ int = unsafe_locate_ind q_int;
+ uint = unsafe_locate_ind q_uint;
+ } in
+ let num_ty = {
+ int = int_ty;
+ decimal = unsafe_locate_ind q_dec;
+ hexadecimal = unsafe_locate_ind q_hex;
+ number = unsafe_locate_ind q_num;
+ } in
+ Some (int_ty, mkRefC q_int, mkRefC q_uint, mkRefC q_dint, mkRefC q_duint,
+ num_ty, mkRefC q_num, mkRefC q_dec)
+ else None
+
+let locate_int63 () =
+ let int63n = "num.int63.type" in
+ if Coqlib.has_ref int63n
+ then
+ let q_int63 = qualid_of_ref int63n in
+ Some (mkRefC q_int63)
+ else None
+
+let has_type env sigma f ty =
+ let c = mkCastC (mkRefC f, Glob_term.CastConv ty) in
+ try let _ = Constrintern.interp_constr env sigma c in true
+ with Pretype_errors.PretypeError _ -> false
+
+let type_error_to f ty =
+ CErrors.user_err
+ (pr_qualid f ++ str " should go from Number.int to " ++
+ pr_qualid ty ++ str " or (option " ++ pr_qualid ty ++ str ")." ++
+ fnl () ++ str "Instead of Number.int, the types Number.uint or Z or Int63.int or Number.number could be used (you may need to require BinNums or Number or Int63 first).")
+
+let type_error_of g ty =
+ CErrors.user_err
+ (pr_qualid g ++ str " should go from " ++ pr_qualid ty ++
+ str " to Number.int or (option Number.int)." ++ fnl () ++
+ str "Instead of Number.int, the types Number.uint or Z or Int63.int or Number.number could be used (you may need to require BinNums or Number or Int63 first).")
+
+let warn_deprecated_decimal =
+ CWarnings.create ~name:"decimal-numeral-notation" ~category:"deprecated"
+ (fun () ->
+ strbrk "Deprecated Number Notation for Decimal.uint, \
+ Decimal.int or Decimal.decimal. Use Number.uint, \
+ Number.int or Number.number respectively.")
+
+let error_params ind =
+ CErrors.user_err
+ (str "Wrong number of parameters for inductive" ++ spc ()
+ ++ Printer.pr_global (GlobRef.IndRef ind) ++ str ".")
+
+let remapping_error ?loc ty ty' ty'' =
+ CErrors.user_err ?loc
+ (Printer.pr_global ty
+ ++ str " was already mapped to" ++ spc () ++ Printer.pr_global ty'
+ ++ str " and cannot be remapped to" ++ spc () ++ Printer.pr_global ty''
+ ++ str ".")
+
+let error_missing c =
+ CErrors.user_err
+ (str "Missing mapping for constructor " ++ Printer.pr_global c ++ str ".")
+
+let pr_constr env sigma c =
+ let c = Constrextern.extern_constr env sigma (EConstr.of_constr c) in
+ Ppconstr.pr_constr_expr env sigma c
+
+let warn_via_remapping =
+ CWarnings.create ~name:"via-type-remapping" ~category:"numbers"
+ (fun (env, sigma, ty, ty', ty'') ->
+ let constr = pr_constr env sigma in
+ constr ty ++ str " was already mapped to" ++ spc () ++ constr ty'
+ ++ str ", mapping it also to" ++ spc () ++ constr ty''
+ ++ str " might yield ill typed terms when using the notation.")
+
+let warn_via_type_mismatch =
+ CWarnings.create ~name:"via-type-mismatch" ~category:"numbers"
+ (fun (env, sigma, g, g', exp, actual) ->
+ let constr = pr_constr env sigma in
+ str "Type of" ++ spc() ++ Printer.pr_global g
+ ++ str " seems incompatible with the type of" ++ spc ()
+ ++ Printer.pr_global g' ++ str "." ++ spc ()
+ ++ str "Expected type is: " ++ constr exp ++ spc ()
+ ++ str "instead of " ++ constr actual ++ str "." ++ spc ()
+ ++ str "This might yield ill typed terms when using the notation.")
+
+let multiple_via_error () =
+ CErrors.user_err (Pp.str "Multiple 'via' options.")
+
+let multiple_after_error () =
+ CErrors.user_err (Pp.str "Multiple 'warning after' or 'abstract after' options.")
+
+let via_abstract_error () =
+ CErrors.user_err (Pp.str "'via' and 'abstract' cannot be used together.")
+
+let locate_global_sort_inductive_or_constant sigma qid =
+ let locate_sort qid =
+ match Nametab.locate_extended qid with
+ | Globnames.TrueGlobal _ -> raise Not_found
+ | Globnames.SynDef kn ->
+ match Syntax_def.search_syntactic_definition kn with
+ | [], Notation_term.NSort r ->
+ let sigma,c = Evd.fresh_sort_in_family sigma (Glob_ops.glob_sort_family r) in
+ sigma,Constr.mkSort c
+ | _ -> raise Not_found in
+ try locate_sort qid
+ with Not_found ->
+ match Smartlocate.global_with_alias qid with
+ | GlobRef.IndRef i -> sigma, Constr.mkInd i
+ | _ -> sigma, Constr.mkConst (Smartlocate.global_constant_with_alias qid)
+
+let locate_global_constructor_inductive_or_constant qid =
+ let g = Smartlocate.global_with_alias qid in
+ match g with
+ | GlobRef.ConstructRef c -> g, Constr.mkConstruct c
+ | GlobRef.IndRef i -> g, Constr.mkInd i
+ | _ -> g, Constr.mkConst (Smartlocate.global_constant_with_alias qid)
+
+(* [get_type env sigma c] retrieves the type of [c] and returns a pair
+ [l, t] such that [c : l_0 -> ... -> l_n -> t]. *)
+let get_type env sigma c =
+ (* inspired from [compute_implicit_names] in "interp/impargs.ml" *)
+ let rec aux env acc t =
+ let t = Reductionops.whd_all env sigma t in
+ match EConstr.kind sigma t with
+ | Constr.Prod (na, a, b) ->
+ let a = Reductionops.whd_all env sigma a in
+ let rel = Context.Rel.Declaration.LocalAssum (na, a) in
+ aux (EConstr.push_rel rel env) ((na, a) :: acc) b
+ | _ -> List.rev acc, t in
+ let t = Retyping.get_type_of env sigma (EConstr.of_constr c) in
+ let l, t = aux env [] t in
+ List.map (fun (na, a) -> na, EConstr.Unsafe.to_constr a) l,
+ EConstr.Unsafe.to_constr t
+
+(* [elaborate_to_post_params env sigma ty_ind params] builds the
+ [to_post] translation (c.f., interp/notation.mli) for the numeral
+ notation to parse/print type [ty_ind]. This translation is the
+ identity ([ToPostCopy]) except that it checks ([ToPostCheck]) that
+ the parameters of the inductive type [ty_ind] match the ones given
+ in [params]. *)
+let elaborate_to_post_params env sigma ty_ind params =
+ let to_post_for_constructor indc =
+ let sigma, c = match indc with
+ | GlobRef.ConstructRef c ->
+ let sigma,c = Evd.fresh_constructor_instance env sigma c in
+ sigma, Constr.mkConstructU c
+ | _ -> assert false in (* c.f. get_constructors *)
+ let args, t = get_type env sigma c in
+ let params_indc = match Constr.kind t with
+ | Constr.App (_, a) -> Array.to_list a | _ -> [] in
+ let sz = List.length args in
+ let a = Array.make sz ToPostCopy in
+ if List.length params <> List.length params_indc then error_params ty_ind;
+ List.iter2 (fun param param_indc ->
+ match param, Constr.kind param_indc with
+ | Some p, Constr.Rel i when i <= sz -> a.(sz - i) <- ToPostCheck p
+ | _ -> ())
+ params params_indc;
+ indc, indc, Array.to_list a in
+ let pt_refs = get_constructors ty_ind in
+ let to_post_0 = List.map to_post_for_constructor pt_refs in
+ let to_post =
+ let only_copy (_, _, args) = List.for_all ((=) ToPostCopy) args in
+ if (List.for_all only_copy to_post_0) then [||] else [|to_post_0|] in
+ to_post, pt_refs
+
+(* [elaborate_to_post_via env sigma ty_name ty_ind l] builds the [to_post]
+ translation (c.f., interp/notation.mli) for the number notation to
+ parse/print type [ty_name] through the inductive [ty_ind] according
+ to the pairs [constant, constructor] in the list [l]. *)
+let elaborate_to_post_via env sigma ty_name ty_ind l =
+ let sigma, ty_name =
+ locate_global_sort_inductive_or_constant sigma ty_name in
+ let ty_ind = Constr.mkInd ty_ind in
+ (* Retrieve constants and constructors mappings and their type.
+ For each constant [cnst] and inductive constructor [indc] in [l], retrieve:
+ * its location: [lcnst] and [lindc]
+ * its GlobRef: [cnst] and [indc]
+ * its type: [tcnst] and [tindc] (decomposed in product by [get_type] above)
+ * [impls] are the implicit arguments of [cnst] *)
+ let l =
+ let read (consider_implicits, cnst, indc) =
+ let lcnst, lindc = cnst.CAst.loc, indc.CAst.loc in
+ let cnst, ccnst = locate_global_constructor_inductive_or_constant cnst in
+ let indc, cindc =
+ let indc = Smartlocate.global_constructor_with_alias indc in
+ GlobRef.ConstructRef indc, Constr.mkConstruct indc in
+ let get_type_wo_params c =
+ (* ignore parameters of inductive types *)
+ let rm_params c = match Constr.kind c with
+ | Constr.App (c, _) when Constr.isInd c -> c
+ | _ -> c in
+ let lc, tc = get_type env sigma c in
+ List.map (fun (n, c) -> n, rm_params c) lc, rm_params tc in
+ let tcnst, tindc = get_type_wo_params ccnst, get_type_wo_params cindc in
+ let impls =
+ if not consider_implicits then [] else
+ Impargs.(select_stronger_impargs (implicits_of_global cnst)) in
+ lcnst, cnst, tcnst, lindc, indc, tindc, impls in
+ List.map read l in
+ let eq_indc indc (_, _, _, _, indc', _, _) = GlobRef.equal indc indc' in
+ (* Collect all inductive types involved.
+ That is [ty_ind] and all final codomains of [tindc] above. *)
+ let inds =
+ List.fold_left (fun s (_, _, _, _, _, tindc, _) -> CSet.add (snd tindc) s)
+ (CSet.singleton ty_ind) l in
+ (* And for each inductive, retrieve its constructors. *)
+ let constructors =
+ CSet.fold (fun ind m ->
+ let inductive, _ = Constr.destInd ind in
+ CMap.add ind (get_constructors inductive) m)
+ inds CMap.empty in
+ (* Error if one [constructor] in some inductive in [inds]
+ doesn't appear exactly once in [l] *)
+ let _ = (* check_for duplicate constructor and error *)
+ List.fold_left (fun already_seen (_, cnst, _, loc, indc, _, _) ->
+ try
+ let cnst' = List.assoc_f GlobRef.equal indc already_seen in
+ remapping_error ?loc indc cnst' cnst
+ with Not_found -> (indc, cnst) :: already_seen)
+ [] l in
+ let () = (* check for missing constructor and error *)
+ CMap.iter (fun _ ->
+ List.iter (fun cstr ->
+ if not (List.exists (eq_indc cstr) l) then error_missing cstr))
+ constructors in
+ (* Perform some checks on types and warn if they look strange.
+ These checks are neither sound nor complete, so we only warn. *)
+ let () =
+ (* associate inductives to types, and check that this mapping is one to one
+ and maps [ty_ind] to [ty_name] *)
+ let ind2ty, ty2ind =
+ let add loc ckey cval m =
+ match CMap.find_opt ckey m with
+ | None -> CMap.add ckey cval m
+ | Some old_cval ->
+ if not (Constr.equal old_cval cval) then
+ warn_via_remapping ?loc (env, sigma, ckey, old_cval, cval);
+ m in
+ List.fold_left
+ (fun (ind2ty, ty2ind) (lcnst, _, (_, tcnst), lindc, _, (_, tindc), _) ->
+ add lcnst tindc tcnst ind2ty, add lindc tcnst tindc ty2ind)
+ CMap.(singleton ty_ind ty_name, singleton ty_name ty_ind) l in
+ (* check that type of constants and constructors mapped in [l]
+ match modulo [ind2ty] *)
+ let rm_impls impls (l, t) =
+ let rec aux impls l = match impls, l with
+ | Some _ :: impls, _ :: b -> aux impls b
+ | None :: impls, (n, a) :: b -> (n, a) :: aux impls b
+ | _ -> l in
+ aux impls l, t in
+ let replace m (l, t) =
+ let apply_m c = try CMap.find c m with Not_found -> c in
+ List.fold_right (fun (na, a) b -> Constr.mkProd (na, (apply_m a), b))
+ l (apply_m t) in
+ List.iter (fun (_, cnst, tcnst, loc, indc, tindc, impls) ->
+ let tcnst = rm_impls impls tcnst in
+ let tcnst' = replace CMap.empty tcnst in
+ if not (Constr.equal tcnst' (replace ind2ty tindc)) then
+ let actual = replace CMap.empty tindc in
+ let expected = replace ty2ind tcnst in
+ warn_via_type_mismatch ?loc (env, sigma, indc, cnst, expected, actual))
+ l in
+ (* Associate an index to each inductive, starting from 0 for [ty_ind]. *)
+ let ind2num, num2ind, nb_ind =
+ CMap.fold (fun ind _ (ind2num, num2ind, i) ->
+ CMap.add ind i ind2num, Int.Map.add i ind num2ind, i + 1)
+ (CMap.remove ty_ind constructors)
+ (CMap.singleton ty_ind 0, Int.Map.singleton 0 ty_ind, 1) in
+ (* Finally elaborate [to_post] *)
+ let to_post =
+ let rec map_prod impls tindc = match impls with
+ | Some _ :: impls -> ToPostHole :: map_prod impls tindc
+ | _ ->
+ match tindc with
+ | [] -> []
+ | (_, a) :: b ->
+ let t = match CMap.find_opt a ind2num with
+ | Some i -> ToPostAs i
+ | None -> ToPostCopy in
+ let impls = match impls with [] -> [] | _ :: t -> t in
+ t :: map_prod impls b in
+ Array.init nb_ind (fun i ->
+ List.map (fun indc ->
+ let _, cnst, _, _, _, tindc, impls = List.find (eq_indc indc) l in
+ indc, cnst, map_prod impls (fst tindc))
+ (CMap.find (Int.Map.find i num2ind) constructors)) in
+ (* and use constants mapped to constructors of [ty_ind] as triggers. *)
+ let pt_refs = List.map (fun (_, cnst, _) -> cnst) (to_post.(0)) in
+ to_post, pt_refs
+
+let locate_global_inductive allow_params qid =
+ let locate_param_inductive qid =
+ match Nametab.locate_extended qid with
+ | Globnames.TrueGlobal _ -> raise Not_found
+ | Globnames.SynDef kn ->
+ match Syntax_def.search_syntactic_definition kn with
+ | [], Notation_term.(NApp (NRef (GlobRef.IndRef i), l)) when allow_params ->
+ i,
+ List.map (function
+ | Notation_term.NRef r -> Some r
+ | Notation_term.NHole _ -> None
+ | _ -> raise Not_found) l
+ | _ -> raise Not_found in
+ try locate_param_inductive qid
+ with Not_found -> Smartlocate.global_inductive_with_alias qid, []
+
+let vernac_number_notation local ty f g opts scope =
+ let rec parse_opts = function
+ | [] -> None, Nop
+ | h :: opts ->
+ let via, opts = parse_opts opts in
+ let via = match h, via with
+ | Via _, Some _ -> multiple_via_error ()
+ | Via v, None -> Some v
+ | _ -> via in
+ let opts = match h, opts with
+ | After _, (Warning _ | Abstract _) -> multiple_after_error ()
+ | After a, Nop -> a
+ | _ -> opts in
+ via, opts in
+ let via, opts = parse_opts opts in
+ (match via, opts with Some _, Abstract _ -> via_abstract_error () | _ -> ());
+ let env = Global.env () in
+ let sigma = Evd.from_env env in
+ let num_ty = locate_number () in
+ let z_pos_ty = locate_z () in
+ let int63_ty = locate_int63 () in
+ let ty_name = ty in
+ let ty, via =
+ match via with None -> ty, via | Some (ty', a) -> ty', Some (ty, a) in
+ let tyc, params = locate_global_inductive (via = None) ty in
+ let to_ty = Smartlocate.global_with_alias f in
+ let of_ty = Smartlocate.global_with_alias g in
+ let cty = mkRefC ty in
+ let app x y = mkAppC (x,[y]) in
+ let arrow x y =
+ mkProdC ([CAst.make Anonymous],Default Glob_term.Explicit, x, y)
+ in
+ let opt r = app (mkRefC (q_option ())) r in
+ (* Check the type of f *)
+ let to_kind =
+ match num_ty with
+ | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma f (arrow cint cty) -> Int int_ty, Direct
+ | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma f (arrow cint (opt cty)) -> Int int_ty, Option
+ | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma f (arrow cuint cty) -> UInt int_ty, Direct
+ | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma f (arrow cuint (opt cty)) -> UInt int_ty, Option
+ | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma f (arrow cnum cty) -> Number num_ty, Direct
+ | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma f (arrow cnum (opt cty)) -> Number num_ty, Option
+ | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma f (arrow cint cty) -> DecimalInt int_ty, Direct
+ | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma f (arrow cint (opt cty)) -> DecimalInt int_ty, Option
+ | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma f (arrow cuint cty) -> DecimalUInt int_ty, Direct
+ | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma f (arrow cuint (opt cty)) -> DecimalUInt int_ty, Option
+ | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma f (arrow cdec cty) -> Decimal num_ty, Direct
+ | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma f (arrow cdec (opt cty)) -> Decimal num_ty, Option
+ | _ ->
+ match z_pos_ty with
+ | Some (z_pos_ty, cZ) when has_type env sigma f (arrow cZ cty) -> Z z_pos_ty, Direct
+ | Some (z_pos_ty, cZ) when has_type env sigma f (arrow cZ (opt cty)) -> Z z_pos_ty, Option
+ | _ ->
+ match int63_ty with
+ | Some cint63 when has_type env sigma f (arrow cint63 cty) -> Int63, Direct
+ | Some cint63 when has_type env sigma f (arrow cint63 (opt cty)) -> Int63, Option
+ | _ -> type_error_to f ty
+ in
+ (* Check the type of g *)
+ let of_kind =
+ match num_ty with
+ | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma g (arrow cty cint) -> Int int_ty, Direct
+ | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma g (arrow cty (opt cint)) -> Int int_ty, Option
+ | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma g (arrow cty cuint) -> UInt int_ty, Direct
+ | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma g (arrow cty (opt cuint)) -> UInt int_ty, Option
+ | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma g (arrow cty cnum) -> Number num_ty, Direct
+ | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma g (arrow cty (opt cnum)) -> Number num_ty, Option
+ | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma g (arrow cty cint) -> DecimalInt int_ty, Direct
+ | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma g (arrow cty (opt cint)) -> DecimalInt int_ty, Option
+ | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma g (arrow cty cuint) -> DecimalUInt int_ty, Direct
+ | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma g (arrow cty (opt cuint)) -> DecimalUInt int_ty, Option
+ | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma g (arrow cty cdec) -> Decimal num_ty, Direct
+ | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma g (arrow cty (opt cdec)) -> Decimal num_ty, Option
+ | _ ->
+ match z_pos_ty with
+ | Some (z_pos_ty, cZ) when has_type env sigma g (arrow cty cZ) -> Z z_pos_ty, Direct
+ | Some (z_pos_ty, cZ) when has_type env sigma g (arrow cty (opt cZ)) -> Z z_pos_ty, Option
+ | _ ->
+ match int63_ty with
+ | Some cint63 when has_type env sigma g (arrow cty cint63) -> Int63, Direct
+ | Some cint63 when has_type env sigma g (arrow cty (opt cint63)) -> Int63, Option
+ | _ -> type_error_of g ty
+ in
+ (match to_kind, of_kind with
+ | ((DecimalInt _ | DecimalUInt _ | Decimal _), _), _
+ | _, ((DecimalInt _ | DecimalUInt _ | Decimal _), _) ->
+ warn_deprecated_decimal ()
+ | _ -> ());
+ let to_post, pt_refs = match via with
+ | None -> elaborate_to_post_params env sigma tyc params
+ | Some (ty, l) -> elaborate_to_post_via env sigma ty tyc l in
+ let o = { to_kind; to_ty; to_post; of_kind; of_ty; ty_name;
+ warning = opts }
+ in
+ (match opts, to_kind with
+ | Abstract _, (_, Option) -> warn_abstract_large_num_no_op o.to_ty
+ | _ -> ());
+ let i =
+ { pt_local = local;
+ pt_scope = scope;
+ pt_interp_info = NumberNotation o;
+ pt_required = Nametab.path_of_global (GlobRef.IndRef tyc),[];
+ pt_refs;
+ pt_in_match = true }
+ in
+ enable_prim_token_interpretation i
diff --git a/plugins/syntax/number.mli b/plugins/syntax/number.mli
new file mode 100644
index 0000000000..d7d28b29ed
--- /dev/null
+++ b/plugins/syntax/number.mli
@@ -0,0 +1,31 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Libnames
+open Vernacexpr
+open Notation
+
+(** * Number notation *)
+
+type number_string_via = qualid * (bool * qualid * qualid) list
+type number_option =
+ | After of numnot_option
+ | Via of number_string_via
+
+val vernac_number_notation : locality_flag ->
+ qualid ->
+ qualid -> qualid ->
+ number_option list ->
+ Notation_term.scope_name -> unit
+
+(** These are also used in string notations *)
+val locate_global_inductive : bool -> Libnames.qualid -> Names.inductive * Names.GlobRef.t option list
+val elaborate_to_post_params : Environ.env -> Evd.evar_map -> Names.inductive -> Names.GlobRef.t option list -> (Names.GlobRef.t * Names.GlobRef.t * Notation.to_post_arg list) list array * Names.GlobRef.t list
+val elaborate_to_post_via : Environ.env -> Evd.evar_map -> Libnames.qualid -> Names.inductive -> (bool * Libnames.qualid * Libnames.qualid) list -> (Names.GlobRef.t * Names.GlobRef.t * Notation.to_post_arg list) list array * Names.GlobRef.t list
diff --git a/plugins/syntax/number_string_notation_plugin.mlpack b/plugins/syntax/number_string_notation_plugin.mlpack
new file mode 100644
index 0000000000..74c32d3a53
--- /dev/null
+++ b/plugins/syntax/number_string_notation_plugin.mlpack
@@ -0,0 +1,3 @@
+Number
+String_notation
+G_number_string
diff --git a/plugins/syntax/numeral.ml b/plugins/syntax/numeral.ml
deleted file mode 100644
index 2db76719b8..0000000000
--- a/plugins/syntax/numeral.ml
+++ /dev/null
@@ -1,217 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-open Pp
-open Util
-open Names
-open Libnames
-open Constrexpr
-open Constrexpr_ops
-open Notation
-
-(** * Numeral notation *)
-
-let warn_abstract_large_num_no_op =
- CWarnings.create ~name:"abstract-large-number-no-op" ~category:"numbers"
- (fun f ->
- strbrk "The 'abstract after' directive has no effect when " ++
- strbrk "the parsing function (" ++
- Nametab.pr_global_env (Termops.vars_of_env (Global.env ())) f ++ strbrk ") targets an " ++
- strbrk "option type.")
-
-let get_constructors ind =
- let mib,oib = Global.lookup_inductive ind in
- let mc = oib.Declarations.mind_consnames in
- Array.to_list
- (Array.mapi (fun j c -> GlobRef.ConstructRef (ind, j + 1)) mc)
-
-let qualid_of_ref n =
- n |> Coqlib.lib_ref |> Nametab.shortest_qualid_of_global Id.Set.empty
-
-let q_option () = qualid_of_ref "core.option.type"
-
-let unsafe_locate_ind q =
- match Nametab.locate q with
- | GlobRef.IndRef i -> i
- | _ -> raise Not_found
-
-let locate_z () =
- let zn = "num.Z.type" in
- let pn = "num.pos.type" in
- if Coqlib.has_ref zn && Coqlib.has_ref pn
- then
- let q_z = qualid_of_ref zn in
- let q_pos = qualid_of_ref pn in
- Some ({
- z_ty = unsafe_locate_ind q_z;
- pos_ty = unsafe_locate_ind q_pos;
- }, mkRefC q_z)
- else None
-
-let locate_numeral () =
- let dint = "num.int.type" in
- let duint = "num.uint.type" in
- let dec = "num.decimal.type" in
- let hint = "num.hexadecimal_int.type" in
- let huint = "num.hexadecimal_uint.type" in
- let hex = "num.hexadecimal.type" in
- let int = "num.num_int.type" in
- let uint = "num.num_uint.type" in
- let num = "num.numeral.type" in
- if Coqlib.has_ref dint && Coqlib.has_ref duint && Coqlib.has_ref dec
- && Coqlib.has_ref hint && Coqlib.has_ref huint && Coqlib.has_ref hex
- && Coqlib.has_ref int && Coqlib.has_ref uint && Coqlib.has_ref num
- then
- let q_dint = qualid_of_ref dint in
- let q_duint = qualid_of_ref duint in
- let q_dec = qualid_of_ref dec in
- let q_hint = qualid_of_ref hint in
- let q_huint = qualid_of_ref huint in
- let q_hex = qualid_of_ref hex in
- let q_int = qualid_of_ref int in
- let q_uint = qualid_of_ref uint in
- let q_num = qualid_of_ref num in
- let int_ty = {
- dec_int = unsafe_locate_ind q_dint;
- dec_uint = unsafe_locate_ind q_duint;
- hex_int = unsafe_locate_ind q_hint;
- hex_uint = unsafe_locate_ind q_huint;
- int = unsafe_locate_ind q_int;
- uint = unsafe_locate_ind q_uint;
- } in
- let num_ty = {
- int = int_ty;
- decimal = unsafe_locate_ind q_dec;
- hexadecimal = unsafe_locate_ind q_hex;
- numeral = unsafe_locate_ind q_num;
- } in
- Some (int_ty, mkRefC q_int, mkRefC q_uint, mkRefC q_dint, mkRefC q_duint,
- num_ty, mkRefC q_num, mkRefC q_dec)
- else None
-
-let locate_int63 () =
- let int63n = "num.int63.type" in
- if Coqlib.has_ref int63n
- then
- let q_int63 = qualid_of_ref int63n in
- Some (mkRefC q_int63)
- else None
-
-let has_type env sigma f ty =
- let c = mkCastC (mkRefC f, Glob_term.CastConv ty) in
- try let _ = Constrintern.interp_constr env sigma c in true
- with Pretype_errors.PretypeError _ -> false
-
-let type_error_to f ty =
- CErrors.user_err
- (pr_qualid f ++ str " should go from Numeral.int to " ++
- pr_qualid ty ++ str " or (option " ++ pr_qualid ty ++ str ")." ++
- fnl () ++ str "Instead of Numeral.int, the types Numeral.uint or Z or Int63.int or Numeral.numeral could be used (you may need to require BinNums or Numeral or Int63 first).")
-
-let type_error_of g ty =
- CErrors.user_err
- (pr_qualid g ++ str " should go from " ++ pr_qualid ty ++
- str " to Numeral.int or (option Numeral.int)." ++ fnl () ++
- str "Instead of Numeral.int, the types Numeral.uint or Z or Int63.int or Numeral.numeral could be used (you may need to require BinNums or Numeral or Int63 first).")
-
-let warn_deprecated_decimal =
- CWarnings.create ~name:"decimal-numeral-notation" ~category:"deprecated"
- (fun () ->
- strbrk "Deprecated Numeral Notation for Decimal.uint, \
- Decimal.int or Decimal.decimal. Use Numeral.uint, \
- Numeral.int or Numeral.numeral respectively.")
-
-let vernac_numeral_notation local ty f g scope opts =
- let env = Global.env () in
- let sigma = Evd.from_env env in
- let num_ty = locate_numeral () in
- let z_pos_ty = locate_z () in
- let int63_ty = locate_int63 () in
- let tyc = Smartlocate.global_inductive_with_alias ty in
- let to_ty = Smartlocate.global_with_alias f in
- let of_ty = Smartlocate.global_with_alias g in
- let cty = mkRefC ty in
- let app x y = mkAppC (x,[y]) in
- let arrow x y =
- mkProdC ([CAst.make Anonymous],Default Glob_term.Explicit, x, y)
- in
- let opt r = app (mkRefC (q_option ())) r in
- let constructors = get_constructors tyc in
- (* Check the type of f *)
- let to_kind =
- match num_ty with
- | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma f (arrow cint cty) -> Int int_ty, Direct
- | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma f (arrow cint (opt cty)) -> Int int_ty, Option
- | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma f (arrow cuint cty) -> UInt int_ty, Direct
- | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma f (arrow cuint (opt cty)) -> UInt int_ty, Option
- | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma f (arrow cnum cty) -> Numeral num_ty, Direct
- | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma f (arrow cnum (opt cty)) -> Numeral num_ty, Option
- | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma f (arrow cint cty) -> DecimalInt int_ty, Direct
- | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma f (arrow cint (opt cty)) -> DecimalInt int_ty, Option
- | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma f (arrow cuint cty) -> DecimalUInt int_ty, Direct
- | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma f (arrow cuint (opt cty)) -> DecimalUInt int_ty, Option
- | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma f (arrow cdec cty) -> Decimal num_ty, Direct
- | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma f (arrow cdec (opt cty)) -> Decimal num_ty, Option
- | _ ->
- match z_pos_ty with
- | Some (z_pos_ty, cZ) when has_type env sigma f (arrow cZ cty) -> Z z_pos_ty, Direct
- | Some (z_pos_ty, cZ) when has_type env sigma f (arrow cZ (opt cty)) -> Z z_pos_ty, Option
- | _ ->
- match int63_ty with
- | Some cint63 when has_type env sigma f (arrow cint63 cty) -> Int63, Direct
- | Some cint63 when has_type env sigma f (arrow cint63 (opt cty)) -> Int63, Option
- | _ -> type_error_to f ty
- in
- (* Check the type of g *)
- let of_kind =
- match num_ty with
- | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma g (arrow cty cint) -> Int int_ty, Direct
- | Some (int_ty, cint, _, _, _, _, _, _) when has_type env sigma g (arrow cty (opt cint)) -> Int int_ty, Option
- | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma g (arrow cty cuint) -> UInt int_ty, Direct
- | Some (int_ty, _, cuint, _, _, _, _, _) when has_type env sigma g (arrow cty (opt cuint)) -> UInt int_ty, Option
- | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma g (arrow cty cnum) -> Numeral num_ty, Direct
- | Some (_, _, _, _, _, num_ty, cnum, _) when has_type env sigma g (arrow cty (opt cnum)) -> Numeral num_ty, Option
- | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma g (arrow cty cint) -> DecimalInt int_ty, Direct
- | Some (int_ty, _, _, cint, _, _, _, _) when has_type env sigma g (arrow cty (opt cint)) -> DecimalInt int_ty, Option
- | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma g (arrow cty cuint) -> DecimalUInt int_ty, Direct
- | Some (int_ty, _, _, _, cuint, _, _, _) when has_type env sigma g (arrow cty (opt cuint)) -> DecimalUInt int_ty, Option
- | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma g (arrow cty cdec) -> Decimal num_ty, Direct
- | Some (_, _, _, _, _, num_ty, _, cdec) when has_type env sigma g (arrow cty (opt cdec)) -> Decimal num_ty, Option
- | _ ->
- match z_pos_ty with
- | Some (z_pos_ty, cZ) when has_type env sigma g (arrow cty cZ) -> Z z_pos_ty, Direct
- | Some (z_pos_ty, cZ) when has_type env sigma g (arrow cty (opt cZ)) -> Z z_pos_ty, Option
- | _ ->
- match int63_ty with
- | Some cint63 when has_type env sigma g (arrow cty cint63) -> Int63, Direct
- | Some cint63 when has_type env sigma g (arrow cty (opt cint63)) -> Int63, Option
- | _ -> type_error_of g ty
- in
- (match to_kind, of_kind with
- | ((DecimalInt _ | DecimalUInt _ | Decimal _), _), _
- | _, ((DecimalInt _ | DecimalUInt _ | Decimal _), _) ->
- warn_deprecated_decimal ()
- | _ -> ());
- let o = { to_kind; to_ty; of_kind; of_ty;
- ty_name = ty;
- warning = opts }
- in
- (match opts, to_kind with
- | Abstract _, (_, Option) -> warn_abstract_large_num_no_op o.to_ty
- | _ -> ());
- let i =
- { pt_local = local;
- pt_scope = scope;
- pt_interp_info = NumeralNotation o;
- pt_required = Nametab.path_of_global (GlobRef.IndRef tyc),[];
- pt_refs = constructors;
- pt_in_match = true }
- in
- enable_prim_token_interpretation i
diff --git a/plugins/syntax/numeral.mli b/plugins/syntax/numeral.mli
deleted file mode 100644
index 99252484b4..0000000000
--- a/plugins/syntax/numeral.mli
+++ /dev/null
@@ -1,19 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-open Libnames
-open Vernacexpr
-open Notation
-
-(** * Numeral notation *)
-
-val vernac_numeral_notation : locality_flag ->
- qualid -> qualid -> qualid ->
- Notation_term.scope_name -> numnot_option -> unit
diff --git a/plugins/syntax/numeral_notation_plugin.mlpack b/plugins/syntax/numeral_notation_plugin.mlpack
deleted file mode 100644
index f4d9cae3ff..0000000000
--- a/plugins/syntax/numeral_notation_plugin.mlpack
+++ /dev/null
@@ -1,2 +0,0 @@
-Numeral
-G_numeral
diff --git a/plugins/syntax/r_syntax.ml b/plugins/syntax/r_syntax.ml
deleted file mode 100644
index d66b9537b4..0000000000
--- a/plugins/syntax/r_syntax.ml
+++ /dev/null
@@ -1,214 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-open Util
-open Names
-open Glob_term
-
-(* Poor's man DECLARE PLUGIN *)
-let __coq_plugin_name = "r_syntax_plugin"
-let () = Mltop.add_known_module __coq_plugin_name
-
-exception Non_closed_number
-
-(**********************************************************************)
-(* Parsing positive via scopes *)
-(**********************************************************************)
-
-let binnums = ["Coq";"Numbers";"BinNums"]
-
-let make_dir l = DirPath.make (List.rev_map Id.of_string l)
-let make_path dir id = Libnames.make_path (make_dir dir) (Id.of_string id)
-
-let is_gr c gr = match DAst.get c with
-| GRef (r, _) -> GlobRef.equal r gr
-| _ -> false
-
-let positive_modpath = MPfile (make_dir binnums)
-
-let positive_kn = MutInd.make2 positive_modpath (Label.make "positive")
-let path_of_xI = ((positive_kn,0),1)
-let path_of_xO = ((positive_kn,0),2)
-let path_of_xH = ((positive_kn,0),3)
-let glob_xI = GlobRef.ConstructRef path_of_xI
-let glob_xO = GlobRef.ConstructRef path_of_xO
-let glob_xH = GlobRef.ConstructRef path_of_xH
-
-let pos_of_bignat ?loc x =
- let ref_xI = DAst.make @@ GRef (glob_xI, None) in
- let ref_xH = DAst.make @@ GRef (glob_xH, None) in
- let ref_xO = DAst.make @@ GRef (glob_xO, None) in
- let rec pos_of x =
- match Z.(div_rem x (of_int 2)) with
- | (q,rem) when rem = Z.zero -> DAst.make @@ GApp (ref_xO,[pos_of q])
- | (q,_) when not Z.(equal q zero) -> DAst.make @@ GApp (ref_xI,[pos_of q])
- | (q,_) -> ref_xH
- in
- pos_of x
-
-(**********************************************************************)
-(* Printing positive via scopes *)
-(**********************************************************************)
-
-let rec bignat_of_pos c = match DAst.get c with
- | GApp (r, [a]) when is_gr r glob_xO -> Z.mul Z.(of_int 2) (bignat_of_pos a)
- | GApp (r, [a]) when is_gr r glob_xI -> Z.add Z.one Z.(mul (of_int 2) (bignat_of_pos a))
- | GRef (a, _) when GlobRef.equal a glob_xH -> Z.one
- | _ -> raise Non_closed_number
-
-(**********************************************************************)
-(* Parsing Z via scopes *)
-(**********************************************************************)
-
-let z_kn = MutInd.make2 positive_modpath (Label.make "Z")
-let path_of_ZERO = ((z_kn,0),1)
-let path_of_POS = ((z_kn,0),2)
-let path_of_NEG = ((z_kn,0),3)
-let glob_ZERO = GlobRef.ConstructRef path_of_ZERO
-let glob_POS = GlobRef.ConstructRef path_of_POS
-let glob_NEG = GlobRef.ConstructRef path_of_NEG
-
-let z_of_int ?loc n =
- if not Z.(equal n zero) then
- let sgn, n =
- if Z.(leq zero n) then glob_POS, n else glob_NEG, Z.neg n in
- DAst.make @@ GApp(DAst.make @@ GRef (sgn,None), [pos_of_bignat ?loc n])
- else
- DAst.make @@ GRef (glob_ZERO, None)
-
-(**********************************************************************)
-(* Printing Z via scopes *)
-(**********************************************************************)
-
-let bigint_of_z c = match DAst.get c with
- | GApp (r,[a]) when is_gr r glob_POS -> bignat_of_pos a
- | GApp (r,[a]) when is_gr r glob_NEG -> Z.neg (bignat_of_pos a)
- | GRef (a, _) when GlobRef.equal a glob_ZERO -> Z.zero
- | _ -> raise Non_closed_number
-
-(**********************************************************************)
-(* Parsing R via scopes *)
-(**********************************************************************)
-
-let rdefinitions = ["Coq";"Reals";"Rdefinitions"]
-let r_modpath = MPfile (make_dir rdefinitions)
-let r_base_modpath = MPdot (r_modpath, Label.make "RbaseSymbolsImpl")
-let r_path = make_path ["Coq";"Reals";"Rdefinitions";"RbaseSymbolsImpl"] "R"
-
-let glob_IZR = GlobRef.ConstRef (Constant.make2 r_modpath @@ Label.make "IZR")
-let glob_Rmult = GlobRef.ConstRef (Constant.make2 r_base_modpath @@ Label.make "Rmult")
-let glob_Rdiv = GlobRef.ConstRef (Constant.make2 r_modpath @@ Label.make "Rdiv")
-
-let binintdef = ["Coq";"ZArith";"BinIntDef"]
-let z_modpath = MPdot (MPfile (make_dir binintdef), Label.make "Z")
-
-let glob_pow_pos = GlobRef.ConstRef (Constant.make2 z_modpath @@ Label.make "pow_pos")
-
-let r_of_rawnum ?loc n =
- let n,e = NumTok.Signed.to_bigint_and_exponent n in
- let e,p = NumTok.(match e with EDec e -> e, 10 | EBin e -> e, 2) in
- let izr z =
- DAst.make @@ GApp (DAst.make @@ GRef(glob_IZR,None), [z]) in
- let rmult r r' =
- DAst.make @@ GApp (DAst.make @@ GRef(glob_Rmult,None), [r; r']) in
- let rdiv r r' =
- DAst.make @@ GApp (DAst.make @@ GRef(glob_Rdiv,None), [r; r']) in
- let pow p e =
- let p = z_of_int ?loc (Z.of_int p) in
- let e = pos_of_bignat e in
- DAst.make @@ GApp (DAst.make @@ GRef(glob_pow_pos,None), [p; e]) in
- let n =
- izr (z_of_int ?loc n) in
- if Int.equal (Z.sign e) 1 then rmult n (izr (pow p e))
- else if Int.equal (Z.sign e) (-1) then rdiv n (izr (pow p (Z.neg e)))
- else n (* e = 0 *)
-
-(**********************************************************************)
-(* Printing R via scopes *)
-(**********************************************************************)
-
-let rawnum_of_r c =
- (* print i * 10^e, precondition: e <> 0 *)
- let numTok_of_int_exp i e =
- (* choose between 123e-2 and 1.23, this is purely heuristic
- and doesn't play any soundness role *)
- let choose_exponent =
- if Int.equal (Z.sign e) 1 then
- true (* don't print 12 * 10^2 as 1200 to distinguish them *)
- else
- let i = Z.to_string i in
- let li = if i.[0] = '-' then String.length i - 1 else String.length i in
- let e = Z.neg e in
- let le = String.length (Z.to_string e) in
- Z.(lt (add (of_int li) (of_int le)) e) in
- (* print 123 * 10^-2 as 123e-2 *)
- let numTok_exponent () =
- NumTok.Signed.of_bigint_and_exponent i (NumTok.EDec e) in
- (* print 123 * 10^-2 as 1.23, precondition e < 0 *)
- let numTok_dot () =
- let s, i =
- if Z.sign i >= 0 then NumTok.SPlus, Z.to_string i
- else NumTok.SMinus, Z.(to_string (neg i)) in
- let ni = String.length i in
- let e = - (Z.to_int e) in
- assert (e > 0);
- let i, f =
- if e < ni then String.sub i 0 (ni - e), String.sub i (ni - e) e
- else "0", String.make (e - ni) '0' ^ i in
- let i = s, NumTok.UnsignedNat.of_string i in
- let f = NumTok.UnsignedNat.of_string f in
- NumTok.Signed.of_int_frac_and_exponent i (Some f) None in
- if choose_exponent then numTok_exponent () else numTok_dot () in
- match DAst.get c with
- | GApp (r, [a]) when is_gr r glob_IZR ->
- let n = bigint_of_z a in
- NumTok.(Signed.of_bigint CDec n)
- | GApp (md, [l; r]) when is_gr md glob_Rmult || is_gr md glob_Rdiv ->
- begin match DAst.get l, DAst.get r with
- | GApp (i, [l]), GApp (i', [r])
- when is_gr i glob_IZR && is_gr i' glob_IZR ->
- begin match DAst.get r with
- | GApp (p, [t; e]) when is_gr p glob_pow_pos ->
- let t = bigint_of_z t in
- if not (Z.(equal t (of_int 10))) then
- raise Non_closed_number
- else
- let i = bigint_of_z l in
- let e = bignat_of_pos e in
- let e = if is_gr md glob_Rdiv then Z.neg e else e in
- numTok_of_int_exp i e
- | _ -> raise Non_closed_number
- end
- | _ -> raise Non_closed_number
- end
- | _ -> raise Non_closed_number
-
-let uninterp_r (AnyGlobConstr p) =
- try
- Some (rawnum_of_r p)
- with Non_closed_number ->
- None
-
-open Notation
-
-let at_declare_ml_module f x =
- Mltop.declare_cache_obj (fun () -> f x) __coq_plugin_name
-
-let r_scope = "R_scope"
-
-let _ =
- register_rawnumeral_interpretation r_scope (r_of_rawnum,uninterp_r);
- at_declare_ml_module enable_prim_token_interpretation
- { pt_local = false;
- pt_scope = r_scope;
- pt_interp_info = Uid r_scope;
- pt_required = (r_path,["Coq";"Reals";"Rdefinitions"]);
- pt_refs = [glob_IZR; glob_Rmult; glob_Rdiv];
- pt_in_match = false }
diff --git a/plugins/syntax/r_syntax.mli b/plugins/syntax/r_syntax.mli
deleted file mode 100644
index b72d544151..0000000000
--- a/plugins/syntax/r_syntax.mli
+++ /dev/null
@@ -1,9 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
diff --git a/plugins/syntax/r_syntax_plugin.mlpack b/plugins/syntax/r_syntax_plugin.mlpack
deleted file mode 100644
index d4ee75ea48..0000000000
--- a/plugins/syntax/r_syntax_plugin.mlpack
+++ /dev/null
@@ -1 +0,0 @@
-R_syntax
diff --git a/plugins/syntax/string_notation.ml b/plugins/syntax/string_notation.ml
index e7ed0d8061..774d59dda3 100644
--- a/plugins/syntax/string_notation.ml
+++ b/plugins/syntax/string_notation.ml
@@ -9,21 +9,15 @@
(************************************************************************)
open Pp
-open Util
open Names
open Libnames
open Constrexpr
open Constrexpr_ops
open Notation
+open Number
(** * String notation *)
-let get_constructors ind =
- let mib,oib = Global.lookup_inductive ind in
- let mc = oib.Declarations.mind_consnames in
- Array.to_list
- (Array.mapi (fun j c -> GlobRef.ConstructRef (ind, j + 1)) mc)
-
let qualid_of_ref n =
n |> Coqlib.lib_ref |> Nametab.shortest_qualid_of_global Id.Set.empty
@@ -46,7 +40,7 @@ let type_error_of g ty =
(pr_qualid g ++ str " should go from " ++ pr_qualid ty ++
str " to Byte.byte or (option Byte.byte) or (list Byte.byte) or (option (list Byte.byte)).")
-let vernac_string_notation local ty f g scope =
+let vernac_string_notation local ty f g via scope =
let env = Global.env () in
let sigma = Evd.from_env env in
let app x y = mkAppC (x,[y]) in
@@ -56,14 +50,16 @@ let vernac_string_notation local ty f g scope =
let coption = cref (q_option ()) in
let opt r = app coption r in
let clist_byte = app clist cbyte in
- let tyc = Smartlocate.global_inductive_with_alias ty in
+ let ty_name = ty in
+ let ty, via =
+ match via with None -> ty, via | Some (ty', a) -> ty', Some (ty, a) in
+ let tyc, params = locate_global_inductive (via = None) ty in
let to_ty = Smartlocate.global_with_alias f in
let of_ty = Smartlocate.global_with_alias g in
let cty = cref ty in
let arrow x y =
mkProdC ([CAst.make Anonymous],Default Glob_term.Explicit, x, y)
in
- let constructors = get_constructors tyc in
(* Check the type of f *)
let to_kind =
if has_type env sigma f (arrow clist_byte cty) then ListByte, Direct
@@ -80,11 +76,10 @@ let vernac_string_notation local ty f g scope =
else if has_type env sigma g (arrow cty (opt cbyte)) then Byte, Option
else type_error_of g ty
in
- let o = { to_kind = to_kind;
- to_ty = to_ty;
- of_kind = of_kind;
- of_ty = of_ty;
- ty_name = ty;
+ let to_post, pt_refs = match via with
+ | None -> elaborate_to_post_params env sigma tyc params
+ | Some (ty, l) -> elaborate_to_post_via env sigma ty tyc l in
+ let o = { to_kind; to_ty; to_post; of_kind; of_ty; ty_name;
warning = () }
in
let i =
@@ -92,7 +87,7 @@ let vernac_string_notation local ty f g scope =
pt_scope = scope;
pt_interp_info = StringNotation o;
pt_required = Nametab.path_of_global (GlobRef.IndRef tyc),[];
- pt_refs = constructors;
+ pt_refs;
pt_in_match = true }
in
enable_prim_token_interpretation i
diff --git a/plugins/syntax/string_notation.mli b/plugins/syntax/string_notation.mli
index 0d99f98d26..f3c7c969c6 100644
--- a/plugins/syntax/string_notation.mli
+++ b/plugins/syntax/string_notation.mli
@@ -14,5 +14,7 @@ open Vernacexpr
(** * String notation *)
val vernac_string_notation : locality_flag ->
- qualid -> qualid -> qualid ->
+ qualid ->
+ qualid -> qualid ->
+ Number.number_string_via option ->
Notation_term.scope_name -> unit
diff --git a/plugins/syntax/string_notation_plugin.mlpack b/plugins/syntax/string_notation_plugin.mlpack
deleted file mode 100644
index 6aa081dab4..0000000000
--- a/plugins/syntax/string_notation_plugin.mlpack
+++ /dev/null
@@ -1,2 +0,0 @@
-String_notation
-G_string
diff --git a/pretyping/glob_ops.ml b/pretyping/glob_ops.ml
index bdf3495479..f42c754ef5 100644
--- a/pretyping/glob_ops.ml
+++ b/pretyping/glob_ops.ml
@@ -523,6 +523,7 @@ let rec cases_pattern_of_glob_constr env na c =
| Anonymous -> PatVar (Name id)
end
| GHole (_,_,_) -> PatVar na
+ | GRef (GlobRef.VarRef id,_) -> PatVar (Name id)
| GRef (GlobRef.ConstructRef cstr,_) -> PatCstr (cstr,[],na)
| GApp (c, l) ->
begin match DAst.get c with
diff --git a/pretyping/unification.ml b/pretyping/unification.ml
index 4d37c0ef60..982814fdfc 100644
--- a/pretyping/unification.ml
+++ b/pretyping/unification.ml
@@ -687,6 +687,17 @@ let eta_constructor_app env sigma f l1 term =
| _ -> assert false)
| _ -> assert false
+(* If the terms are irrelevant, check that they have the same type. *)
+let careful_infer_conv ~pb ~ts env sigma m n =
+ if Retyping.relevance_of_term env sigma m == Sorts.Irrelevant &&
+ Retyping.relevance_of_term env sigma n == Sorts.Irrelevant
+ then
+ let tm = Retyping.get_type_of env sigma m in
+ let tn = Retyping.get_type_of env sigma n in
+ Option.bind (infer_conv ~pb:CONV ~ts env sigma tm tn)
+ (fun sigma -> infer_conv ~pb ~ts env sigma m n)
+ else infer_conv ~pb ~ts env sigma m n
+
let rec unify_0_with_initial_metas (sigma,ms,es as subst : subst0) conv_at_top env cv_pb flags m n =
let rec unirec_rec (curenv,nb as curenvnb) pb opt ((sigma,metasubst,evarsubst) as substn : subst0) curm curn =
let cM = Evarutil.whd_head_evar sigma curm
@@ -1127,7 +1138,7 @@ let rec unify_0_with_initial_metas (sigma,ms,es as subst : subst0) conv_at_top e
None
else
let ans = match flags.modulo_conv_on_closed_terms with
- | Some convflags -> infer_conv ~pb:cv_pb ~ts:convflags env sigma m n
+ | Some convflags -> careful_infer_conv ~pb:cv_pb ~ts:convflags env sigma m n
| _ -> constr_cmp cv_pb env sigma flags m n in
match ans with
| Some sigma -> ans
diff --git a/printing/ppconstr.ml b/printing/ppconstr.ml
index 8da1d636f0..e312c68b7d 100644
--- a/printing/ppconstr.ml
+++ b/printing/ppconstr.ml
@@ -77,8 +77,8 @@ let tag_var = tag Tag.variable
| LevelSome -> true
let prec_of_prim_token = function
- | Numeral (NumTok.SPlus,_) -> lposint
- | Numeral (NumTok.SMinus,_) -> lnegint
+ | Number (NumTok.SPlus,_) -> lposint
+ | Number (NumTok.SMinus,_) -> lnegint
| String _ -> latom
let print_hunks n pr pr_patt pr_binders (terms, termlists, binders, binderlists) unps =
@@ -222,7 +222,7 @@ let tag_var = tag Tag.variable
| t -> str " :" ++ pr_sep_com (fun()->brk(1,4)) (pr ltop) t
let pr_prim_token = function
- | Numeral n -> NumTok.Signed.print n
+ | Number n -> NumTok.Signed.print n
| String s -> qs s
let pr_evar pr id l =
@@ -681,13 +681,10 @@ let tag_var = tag Tag.variable
| CDelimiters (sc,a) ->
return (pr_delimiters sc (pr mt (LevelLe ldelim) a), ldelim)
| CArray(u, t,def,ty) ->
- let pp = ref (str " |"++ spc () ++ pr mt ltop def
- ++ pr_opt_type_spc (pr mt) ty ++ str " |]" ++ pr_universe_instance u) in
- for i = Array.length t - 1 downto 1 do
- pp := str ";" ++ pr mt ltop t.(i) ++ !pp
- done;
- pp := pr mt ltop t.(0) ++ !pp;
- hov 0 (str "[|" ++ !pp), 0
+ hov 0 (str "[| " ++ prvect_with_sep (fun () -> str "; ") (pr mt ltop) t ++
+ (if not (Array.is_empty t) then str " " else mt()) ++
+ str "|" ++ spc() ++ pr mt ltop def ++ pr_opt_type_spc (pr mt) ty ++
+ str " |]" ++ pr_universe_instance u), 0
in
let loc = constr_loc a in
pr_with_comments ?loc
diff --git a/printing/printer.ml b/printing/printer.ml
index be1cc0d64a..ea718526de 100644
--- a/printing/printer.ml
+++ b/printing/printer.ml
@@ -45,6 +45,8 @@ let should_gname =
~key:["Printing";"Goal";"Names"]
~value:false
+let print_goal_names = should_gname (* for export *)
+
(**********************************************************************)
(** Terms *)
diff --git a/printing/printer.mli b/printing/printer.mli
index a25cbebe91..ea388ae57e 100644
--- a/printing/printer.mli
+++ b/printing/printer.mli
@@ -264,3 +264,6 @@ val pr_goal_by_id : proof:Proof.t -> Id.t -> Pp.t
val pr_goal_emacs : proof:Proof.t option -> int -> int -> Pp.t
val pr_typing_flags : Declarations.typing_flags -> Pp.t
+
+(** Tells if flag "Printing Goal Names" is activated *)
+val print_goal_names : unit -> bool
diff --git a/stm/stm.ml b/stm/stm.ml
index 85f889c879..df7e35beb5 100644
--- a/stm/stm.ml
+++ b/stm/stm.ml
@@ -2275,8 +2275,9 @@ let known_state ~doc ?(redefine_qed=false) ~cache id =
), true, true
| `MaybeASync (start, nodes, name, delegate) -> (fun () ->
reach ~cache:true start;
- (* no sections *)
- if CList.is_empty (Environ.named_context (Global.env ()))
+ if CList.is_empty (Environ.named_context (Global.env ())) (* no sections *)
+ || PG_compat.get_pstate () |> (* #[using] attribute *)
+ Option.cata (fun x -> Option.has_some (Declare.Proof.get_used_variables x)) false
then Util.pi1 (aux (`ASync (start, nodes, name, delegate))) ()
else Util.pi1 (aux (`Sync (name, `NoPU_NoHint_NoES))) ()
), not redefine_qed, true
diff --git a/test-suite/bugs/closed/bug_13078.v b/test-suite/bugs/closed/bug_13078.v
new file mode 100644
index 0000000000..ec04408fd1
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13078.v
@@ -0,0 +1,10 @@
+(* Check that rules with patterns are not registered for cases patterns *)
+Module PrintingTest.
+Declare Custom Entry test.
+Notation "& x" := (Some x) (in custom test at level 0, x pattern).
+Check fun x => match x with | None => None | Some tt => Some tt end.
+Notation "& x" := (Some x) (at level 0, x pattern).
+Check fun x => match x with | None => None | Some tt => Some tt end.
+End PrintingTest.
+
+Fail Notation "x &" := (Some x) (at level 0, x pattern).
diff --git a/test-suite/bugs/closed/bug_13131.v b/test-suite/bugs/closed/bug_13131.v
new file mode 100644
index 0000000000..b358ae3ecc
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13131.v
@@ -0,0 +1,6 @@
+Set Mangle Names.
+
+Class A := {}.
+
+Lemma foo `{A} : A.
+Proof. Fail exact H. assumption. Qed.
diff --git a/test-suite/bugs/closed/bug_13162.v b/test-suite/bugs/closed/bug_13162.v
new file mode 100644
index 0000000000..eacc8980a9
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13162.v
@@ -0,0 +1,7 @@
+
+Module Type T. End T.
+Module F (X:T). End F.
+Fail Import F.
+(* Error: Anomaly "Uncaught exception Not_found." *)
+
+Fail Import T.
diff --git a/test-suite/bugs/closed/bug_13178.v b/test-suite/bugs/closed/bug_13178.v
new file mode 100644
index 0000000000..d9c516c362
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13178.v
@@ -0,0 +1,3 @@
+Primitive array := #array_type.
+
+Check [| | 0 |].
diff --git a/test-suite/bugs/closed/bug_13276.v b/test-suite/bugs/closed/bug_13276.v
new file mode 100644
index 0000000000..15ac7e7b36
--- /dev/null
+++ b/test-suite/bugs/closed/bug_13276.v
@@ -0,0 +1,9 @@
+From Coq Require Import Floats.
+Open Scope float_scope.
+
+Lemma foo :
+ let n := opp 0 in sub n 0 = n.
+Proof.
+cbv.
+apply eq_refl.
+Qed.
diff --git a/test-suite/bugs/opened/bug_3395.v b/test-suite/bugs/opened/bug_3395.v
deleted file mode 100644
index 70b3a48a06..0000000000
--- a/test-suite/bugs/opened/bug_3395.v
+++ /dev/null
@@ -1,232 +0,0 @@
-Require Import TestSuite.admit.
-(* File reduced by coq-bug-finder from originally 10918 lines, then 3649 lines to 3177 lines, then from 3189 lines to 3164 lines, then from 2653 lines to 2496 lines, 2653 lines, then from 1642 lines to 651 lines, then from 736 lines to 473 lines, then from 433 lines to 275 lines, then from 258 lines to 235 lines. *)
-Generalizable All Variables.
-Set Implicit Arguments.
-
-Arguments fst {_ _} _.
-Arguments snd {_ _} _.
-
-Axiom cheat : forall {T}, T.
-
-Reserved Notation "g 'o' f" (at level 40, left associativity).
-
-Inductive paths {A : Type} (a : A) : A -> Type := idpath : paths a a.
-Arguments idpath {A a} , [A] a.
-Notation "x = y" := (paths x y) : type_scope.
-
-Definition symmetry {A : Type} {x y : A} (p : x = y) : y = x
- := match p with idpath => idpath end.
-
-Delimit Scope morphism_scope with morphism.
-Delimit Scope category_scope with category.
-Delimit Scope object_scope with object.
-Record PreCategory (object : Type) :=
- Build_PreCategory' {
- object :> Type := object;
- morphism : object -> object -> Type;
- identity : forall x, morphism x x;
- compose : forall s d d',
- morphism d d'
- -> morphism s d
- -> morphism s d'
- where "f 'o' g" := (compose f g);
- associativity : forall x1 x2 x3 x4
- (m1 : morphism x1 x2)
- (m2 : morphism x2 x3)
- (m3 : morphism x3 x4),
- (m3 o m2) o m1 = m3 o (m2 o m1);
- associativity_sym : forall x1 x2 x3 x4
- (m1 : morphism x1 x2)
- (m2 : morphism x2 x3)
- (m3 : morphism x3 x4),
- m3 o (m2 o m1) = (m3 o m2) o m1;
- left_identity : forall a b (f : morphism a b), identity b o f = f;
- right_identity : forall a b (f : morphism a b), f o identity a = f;
- identity_identity : forall x, identity x o identity x = identity x
- }.
-Bind Scope category_scope with PreCategory.
-Arguments PreCategory {_}.
-Arguments identity {_} [!C%category] x%object : rename.
-
-Arguments compose {_} [!C%category s%object d%object d'%object] m1%morphism m2%morphism : rename.
-
-Infix "o" := compose : morphism_scope.
-
-Delimit Scope functor_scope with functor.
-Local Open Scope morphism_scope.
-Record Functor `(C : @PreCategory objC, D : @PreCategory objD) :=
- {
- object_of :> C -> D;
- morphism_of : forall s d, morphism C s d
- -> morphism D (object_of s) (object_of d);
- composition_of : forall s d d'
- (m1 : morphism C s d) (m2: morphism C d d'),
- morphism_of _ _ (m2 o m1)
- = (morphism_of _ _ m2) o (morphism_of _ _ m1);
- identity_of : forall x, morphism_of _ _ (identity x)
- = identity (object_of x)
- }.
-Bind Scope functor_scope with Functor.
-
-Arguments morphism_of {_} [C%category] {_} [D%category] F%functor [s%object d%object] m%morphism : rename, simpl nomatch.
-
-Notation "F '_1' m" := (morphism_of F m) (at level 10, no associativity) : morphism_scope.
-
-Class IsIsomorphism `{C : @PreCategory objC} {s d} (m : morphism C s d) :=
- {
- morphism_inverse : morphism C d s;
- left_inverse : morphism_inverse o m = identity _;
- right_inverse : m o morphism_inverse = identity _
- }.
-
-Definition opposite `(C : @PreCategory objC) : PreCategory
- := @Build_PreCategory'
- C
- (fun s d => morphism C d s)
- (identity (C := C))
- (fun _ _ _ m1 m2 => m2 o m1)
- (fun _ _ _ _ _ _ _ => @associativity_sym _ _ _ _ _ _ _ _ _)
- (fun _ _ _ _ _ _ _ => @associativity _ _ _ _ _ _ _ _ _)
- (fun _ _ => @right_identity _ _ _ _)
- (fun _ _ => @left_identity _ _ _ _)
- (@identity_identity _ C).
-
-Notation "C ^op" := (opposite C) (at level 3) : category_scope.
-
-Definition prod `(C : @PreCategory objC, D : @PreCategory objD) : @PreCategory (objC * objD).
- refine (@Build_PreCategory'
- (C * D)%type
- (fun s d => (morphism C (fst s) (fst d)
- * morphism D (snd s) (snd d))%type)
- (fun x => (identity (fst x), identity (snd x)))
- (fun s d d' m2 m1 => (fst m2 o fst m1, snd m2 o snd m1))
- _
- _
- _
- _
- _); admit.
-Defined.
-Infix "*" := prod : category_scope.
-
-Definition compose_functor `(C : @PreCategory objC, D : @PreCategory objD, E : @PreCategory objE) (G : Functor D E) (F : Functor C D) : Functor C E
- := Build_Functor
- C E
- (fun c => G (F c))
- (fun _ _ m => morphism_of G (morphism_of F m))
- cheat
- cheat.
-
-Infix "o" := compose_functor : functor_scope.
-
-Record NaturalTransformation `(C : @PreCategory objC, D : @PreCategory objD) (F G : Functor C D) :=
- Build_NaturalTransformation' {
- components_of :> forall c, morphism D (F c) (G c);
- commutes : forall s d (m : morphism C s d),
- components_of d o F _1 m = G _1 m o components_of s;
-
- commutes_sym : forall s d (m : C.(morphism) s d),
- G _1 m o components_of s = components_of d o F _1 m
- }.
-Definition functor_category `(C : @PreCategory objC, D : @PreCategory objD) : PreCategory
- := @Build_PreCategory' (Functor C D)
- (@NaturalTransformation _ C _ D)
- cheat
- cheat
- cheat
- cheat
- cheat
- cheat
- cheat.
-
-Definition opposite_functor `(F : @Functor objC C objD D) : Functor C^op D^op
- := Build_Functor (C^op) (D^op)
- (object_of F)
- (fun s d => morphism_of F (s := d) (d := s))
- (fun d' d s m1 m2 => composition_of F s d d' m2 m1)
- (identity_of F).
-
-Definition opposite_invL `(F : @Functor objC C^op objD D) : Functor C D^op
- := Build_Functor C (D^op)
- (object_of F)
- (fun s d => morphism_of F (s := d) (d := s))
- (fun d' d s m1 m2 => composition_of F s d d' m2 m1)
- (identity_of F).
-Notation "F ^op" := (opposite_functor F) : functor_scope.
-
-Notation "F ^op'L" := (opposite_invL F) (at level 3) : functor_scope.
-Definition fst `{C : @PreCategory objC, D : @PreCategory objD} : Functor (C * D) C
- := Build_Functor (C * D) C
- (@fst _ _)
- (fun _ _ => @fst _ _)
- (fun _ _ _ _ _ => idpath)
- (fun _ => idpath).
-
-Definition snd `{C : @PreCategory objC, D : @PreCategory objD} : Functor (C * D) D
- := Build_Functor (C * D) D
- (@snd _ _)
- (fun _ _ => @snd _ _)
- (fun _ _ _ _ _ => idpath)
- (fun _ => idpath).
-Definition prod_functor `(F : @Functor objC C objD D, F' : @Functor objC C objD' D')
-: Functor C (D * D')
- := Build_Functor
- C (D * D')
- (fun c => (F c, F' c))
- (fun s d m => (F _1 m, F' _1 m))%morphism
- cheat
- cheat.
-Definition pair `(F : @Functor objC C objD D, F' : @Functor objC' C' objD' D') : Functor (C * C') (D * D')
- := (prod_functor (F o fst) (F' o snd))%functor.
-Notation cat_of obj :=
- (@Build_PreCategory' obj
- (fun x y => forall _ : x, y)
- (fun _ x => x)
- (fun _ _ _ f g x => f (g x))%core
- (fun _ _ _ _ _ _ _ => idpath)
- (fun _ _ _ _ _ _ _ => idpath)
- (fun _ _ _ => idpath)
- (fun _ _ _ => idpath)
- (fun _ => idpath)).
-
-Definition hom_functor `(C : @PreCategory objC) : Functor (C^op * C) (cat_of Type)
- := Build_Functor _ _ cheat cheat cheat cheat.
-
-Definition induced_hom_natural_transformation `(F : @Functor objC C objD D)
-: NaturalTransformation (hom_functor C) (hom_functor D o pair F^op F)
- := Build_NaturalTransformation' _ _ cheat cheat cheat.
-
-Class IsFullyFaithful `(F : @Functor objC C objD D)
- := is_fully_faithful
- : forall x y : C,
- IsIsomorphism (induced_hom_natural_transformation F (x, y)).
-
-Definition coyoneda `(A : @PreCategory objA) : Functor A^op (@functor_category _ A _ (cat_of Type))
- := cheat.
-
-Definition yoneda `(A : @PreCategory objA) : Functor A (@functor_category _ A^op _ (cat_of Type))
- := (((coyoneda A^op)^op'L)^op'L)%functor.
-Definition coyoneda_embedding `(A : @PreCategory objA) : @IsFullyFaithful _ _ _ _ (@coyoneda _ A).
-Admitted.
-
-Definition yoneda_embedding_fast `(A : @PreCategory objA) : @IsFullyFaithful _ _ _ _ (@yoneda _ A).
-Proof.
- intros a b.
- pose proof (coyoneda_embedding A^op a b) as CYE.
- unfold yoneda.
- Time let t := (type of CYE) in
- let t' := (eval simpl in t) in pose proof ((fun (x : t) => (x : t')) CYE) as CYE'. (* Finished transaction in 0. secs (0.216013u,0.004s) *)
- Fail Timeout 1 let t := match goal with |- ?G => constr:(G) end in
- let t' := (eval simpl in t) in exact ((fun (x : t') => (x : t)) CYE').
- Time let t := match goal with |- ?G => constr:(G) end in
- let t' := (eval simpl in t) in exact ((fun (x : t') => (x : t)) CYE'). (* Finished transaction in 0. secs (0.248016u,0.s) *)
-Fail Timeout 2 Defined.
-Time Defined. (* Finished transaction in 1. secs (0.432027u,0.s) *)
-
-Definition yoneda_embedding `(A : @PreCategory objA) : @IsFullyFaithful _ _ _ _ (@yoneda _ A).
-Proof.
- intros a b.
- pose proof (coyoneda_embedding A^op a b) as CYE.
- unfold yoneda; simpl in *.
- Fail Timeout 1 exact CYE.
- Time exact CYE. (* Finished transaction in 0. secs (0.012001u,0.s) *)
-Abort.
diff --git a/test-suite/output/ErrorLocation_13241_1.out b/test-suite/output/ErrorLocation_13241_1.out
new file mode 100644
index 0000000000..d899dd5d46
--- /dev/null
+++ b/test-suite/output/ErrorLocation_13241_1.out
@@ -0,0 +1,3 @@
+File "stdin", line 4, characters 0-1:
+Error: No product even after head-reduction.
+
diff --git a/test-suite/output/ErrorLocation_13241_1.v b/test-suite/output/ErrorLocation_13241_1.v
new file mode 100644
index 0000000000..3102b13fb8
--- /dev/null
+++ b/test-suite/output/ErrorLocation_13241_1.v
@@ -0,0 +1,5 @@
+Ltac a := intro.
+Ltac b := a.
+Goal True.
+b.
+Abort.
diff --git a/test-suite/output/ErrorLocation_13241_2.out b/test-suite/output/ErrorLocation_13241_2.out
new file mode 100644
index 0000000000..d899dd5d46
--- /dev/null
+++ b/test-suite/output/ErrorLocation_13241_2.out
@@ -0,0 +1,3 @@
+File "stdin", line 4, characters 0-1:
+Error: No product even after head-reduction.
+
diff --git a/test-suite/output/ErrorLocation_13241_2.v b/test-suite/output/ErrorLocation_13241_2.v
new file mode 100644
index 0000000000..b82f36ed6f
--- /dev/null
+++ b/test-suite/output/ErrorLocation_13241_2.v
@@ -0,0 +1,5 @@
+Ltac a _ := intro.
+Ltac b := a ().
+Goal True.
+b.
+Abort.
diff --git a/test-suite/output/Notations4.out b/test-suite/output/Notations4.out
index fa0c20bf73..a6fd39c29b 100644
--- a/test-suite/output/Notations4.out
+++ b/test-suite/output/Notations4.out
@@ -125,3 +125,57 @@ Warning: Notation "_ :=: _" was already used. [notation-overridden,parsing]
: Prop
fun x : nat => <{ x; (S x) }>
: nat -> nat
+exists p : nat, ▢_p (p >= 1)
+ : Prop
+▢_n (n >= 1)
+ : Prop
+The command has indeed failed with message:
+Found an inductive type while a variable name was expected.
+The command has indeed failed with message:
+Found a constructor while a variable name was expected.
+The command has indeed failed with message:
+Found a constant while a variable name was expected.
+exists x y : nat, ▢_(x, y) (x >= 1 /\ y >= 2)
+ : Prop
+▢_n (n >= 1)
+ : Prop
+The command has indeed failed with message:
+Found an inductive type while a pattern was expected.
+▢_tt (tt = tt)
+ : Prop
+The command has indeed failed with message:
+Found a constant while a pattern was expected.
+exists x y : nat, ▢_(x, y) (x >= 1 /\ y >= 2)
+ : Prop
+pseudo_force n (fun n : nat => n >= 1)
+ : Prop
+The command has indeed failed with message:
+Found an inductive type while a pattern was expected.
+▢_tt (tt = tt)
+ : Prop
+The command has indeed failed with message:
+Found a constant while a pattern was expected.
+exists x y : nat, myforce (x, y) (x >= 1 /\ y >= 2)
+ : Prop
+myforce n (n >= 1)
+ : Prop
+The command has indeed failed with message:
+Found an inductive type while a pattern was expected.
+myforce tt (tt = tt)
+ : Prop
+The command has indeed failed with message:
+Found a constant while a pattern was expected.
+id nat
+ : Set
+fun a : bool => id a
+ : bool -> bool
+fun nat : bool => id nat
+ : bool -> bool
+The command has indeed failed with message:
+Found an inductive type while a pattern was expected.
+!! nat, nat = true
+ : Prop
+!!! nat, nat = true
+ : Prop
+!!!! (nat, id), nat = true /\ id = false
+ : Prop
diff --git a/test-suite/output/Notations4.v b/test-suite/output/Notations4.v
index 6dadd8c7fe..0731819bba 100644
--- a/test-suite/output/Notations4.v
+++ b/test-suite/output/Notations4.v
@@ -124,7 +124,7 @@ Check r 2 3.
End I.
Require Import Coq.Numbers.Cyclic.Int63.Int63.
-Module NumeralNotations.
+Module NumberNotations.
Module Test17.
(** Test int63 *)
Declare Scope test17_scope.
@@ -134,7 +134,7 @@ Module NumeralNotations.
Number Notation myint63 of_int to_int : test17_scope.
Check let v := 0%test17 in v : myint63.
End Test17.
-End NumeralNotations.
+End NumberNotations.
Module K.
@@ -313,3 +313,104 @@ Notation "x" := x (in custom com_top at level 90, x custom com at level 90).
Check fun x => <{ x ; (S x) }>.
End CoercionEntryTransitivity.
+
+(* Some corner cases *)
+
+Module P.
+
+(* Basic rules:
+ - a section variable be used for itself and as a binding variable
+ - a global name cannot be used for itself and as a binding variable
+*)
+
+ Definition pseudo_force {A} (n:A) (P:A -> Prop) := forall n', n' = n -> P n'.
+
+ Module NotationMixedTermBinderAsIdent.
+
+ Notation "▢_ n P" := (pseudo_force n (fun n => P))
+ (at level 0, n ident, P at level 9, format "▢_ n P").
+ Check exists p, ▢_p (p >= 1).
+ Section S.
+ Variable n:nat.
+ Check ▢_n (n >= 1).
+ End S.
+ Fail Check ▢_nat (nat = bool).
+ Fail Check ▢_O (O >= 1).
+ Axiom n:nat.
+ Fail Check ▢_n (n >= 1).
+
+ End NotationMixedTermBinderAsIdent.
+
+ Module NotationMixedTermBinderAsPattern.
+
+ Notation "▢_ n P" := (pseudo_force n (fun n => P))
+ (at level 0, n pattern, P at level 9, format "▢_ n P").
+ Check exists x y, ▢_(x,y) (x >= 1 /\ y >= 2).
+ Section S.
+ Variable n:nat.
+ Check ▢_n (n >= 1).
+ End S.
+ Fail Check ▢_nat (nat = bool).
+ Check ▢_tt (tt = tt).
+ Axiom n:nat.
+ Fail Check ▢_n (n >= 1).
+
+ End NotationMixedTermBinderAsPattern.
+
+ Module NotationMixedTermBinderAsStrictPattern.
+
+ Notation "▢_ n P" := (pseudo_force n (fun n => P))
+ (at level 0, n strict pattern, P at level 9, format "▢_ n P").
+ Check exists x y, ▢_(x,y) (x >= 1 /\ y >= 2).
+ Section S.
+ Variable n:nat.
+ Check ▢_n (n >= 1).
+ End S.
+ Fail Check ▢_nat (nat = bool).
+ Check ▢_tt (tt = tt).
+ Axiom n:nat.
+ Fail Check ▢_n (n >= 1).
+
+ End NotationMixedTermBinderAsStrictPattern.
+
+ Module AbbreviationMixedTermBinderAsStrictPattern.
+
+ Notation myforce n P := (pseudo_force n (fun n => P)).
+ Check exists x y, myforce (x,y) (x >= 1 /\ y >= 2).
+ Section S.
+ Variable n:nat.
+ Check myforce n (n >= 1). (* strict hence not used for printing *)
+ End S.
+ Fail Check myforce nat (nat = bool).
+ Check myforce tt (tt = tt).
+ Axiom n:nat.
+ Fail Check myforce n (n >= 1).
+
+ End AbbreviationMixedTermBinderAsStrictPattern.
+
+ Module Bug4765Part.
+
+ Notation id x := ((fun y => y) x).
+ Check id nat.
+
+ Notation id' x := ((fun x => x) x).
+ Check fun a : bool => id' a.
+ Check fun nat : bool => id' nat.
+ Fail Check id' nat.
+
+ End Bug4765Part.
+
+ Module NotationBinderNotMixedWithTerms.
+
+ Notation "!! x , P" := (forall x, P) (at level 200, x pattern).
+ Check !! nat, nat = true.
+
+ Notation "!!! x , P" := (forall x, P) (at level 200).
+ Check !!! nat, nat = true.
+
+ Notation "!!!! x , P" := (forall x, P) (at level 200, x strict pattern).
+ Check !!!! (nat,id), nat = true /\ id = false.
+
+ End NotationBinderNotMixedWithTerms.
+
+End P.
diff --git a/test-suite/output/NumberNotations.out b/test-suite/output/NumberNotations.out
index 8065c8d311..60682edec8 100644
--- a/test-suite/output/NumberNotations.out
+++ b/test-suite/output/NumberNotations.out
@@ -1,9 +1,9 @@
The command has indeed failed with message:
-Unexpected term (nat -> nat) while parsing a numeral notation.
+Unexpected term (nat -> nat) while parsing a number notation.
The command has indeed failed with message:
-Unexpected non-option term opaque4 while parsing a numeral notation.
+Unexpected non-option term opaque4 while parsing a number notation.
The command has indeed failed with message:
-Unexpected term (fun (A : Type) (x : A) => x) while parsing a numeral
+Unexpected term (fun (A : Type) (x : A) => x) while parsing a number
notation.
let v := 0%ppp in v : punit
: punit
@@ -32,7 +32,7 @@ Warning: To avoid stack overflow, large numbers in punit are interpreted as
applications of pto_punits. [abstract-large-number,numbers]
The command has indeed failed with message:
In environment
-v := pto_punits (Numeral.UIntDec (Decimal.D1 Decimal.Nil)) : punit
+v := pto_punits (Number.UIntDecimal (Decimal.D1 Decimal.Nil)) : punit
The term "v" has type "punit@{Set}" while it is expected to have type
"punit@{u}".
S
@@ -61,7 +61,7 @@ The command has indeed failed with message:
In environment
v := 0 : nat
The term "v" has type "nat" while it is expected to have type "wuint".
- = {| unwrap := Numeral.UIntDec (Decimal.D0 Decimal.Nil) |}
+ = {| unwrap := Number.UIntDecimal (Decimal.D0 Decimal.Nil) |}
: wuint
let v := 0%wuint8' in v : wuint
: wuint
@@ -82,7 +82,7 @@ function (of_uint) targets an option type.
The command has indeed failed with message:
The 'abstract after' directive has no effect when the parsing function
(of_uint) targets an option type. [abstract-large-number-no-op,numbers]
-let v := of_uint (Numeral.UIntDec (Decimal.D1 Decimal.Nil)) in v : unit
+let v := of_uint (Number.UIntDecimal (Decimal.D1 Decimal.Nil)) in v : unit
: unit
let v := 0%test13 in v : unit
: unit
@@ -234,3 +234,282 @@ let v : ty := Build_ty Type type in v : ty
: Prop
1_000
: list nat
+0
+ : Set
+1
+ : Set
+2
+ : Set
+3
+ : Set
+Empty_set
+ : Set
+unit
+ : Set
+sum unit unit
+ : Set
+sum unit (sum unit unit)
+ : Set
+The command has indeed failed with message:
+Missing mapping for constructor Isum.
+The command has indeed failed with message:
+Iunit was already mapped to unit and cannot be remapped to unit.
+The command has indeed failed with message:
+add is not an inductive type.
+The command has indeed failed with message:
+add is not a constructor of an inductive type.
+The command has indeed failed with message:
+Missing mapping for constructor Iempty.
+File "stdin", line 574, characters 56-61:
+Warning: Type of I'sum seems incompatible with the type of sum.
+Expected type is: (I' -> I' -> I') instead of (I -> I' -> I').
+This might yield ill typed terms when using the notation.
+[via-type-mismatch,numbers]
+File "stdin", line 579, characters 32-33:
+Warning: I was already mapped to Set, mapping it also to
+nat might yield ill typed terms when using the notation.
+[via-type-remapping,numbers]
+File "stdin", line 579, characters 37-42:
+Warning: Type of Iunit seems incompatible with the type of O.
+Expected type is: I instead of I.
+This might yield ill typed terms when using the notation.
+[via-type-mismatch,numbers]
+The command has indeed failed with message:
+'via' and 'abstract' cannot be used together.
+File "stdin", line 659, characters 21-23:
+Warning: Type of I1 seems incompatible with the type of Fin.F1.
+Expected type is: (nat -> I) instead of I.
+This might yield ill typed terms when using the notation.
+[via-type-mismatch,numbers]
+File "stdin", line 659, characters 35-37:
+Warning: Type of IS seems incompatible with the type of Fin.FS.
+Expected type is: (nat -> I -> I) instead of (I -> I).
+This might yield ill typed terms when using the notation.
+[via-type-mismatch,numbers]
+The command has indeed failed with message:
+The term "0" has type "forall n : nat, Fin.t (S n)"
+while it is expected to have type "nat".
+0
+ : Fin.t (S ?n)
+where
+?n : [ |- nat]
+1
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat]
+2
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat]
+3
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat]
+0 : Fin.t 3
+ : Fin.t 3
+1 : Fin.t 3
+ : Fin.t 3
+2 : Fin.t 3
+ : Fin.t 3
+The command has indeed failed with message:
+The term "3" has type "Fin.t (S (S (S (S ?n))))"
+while it is expected to have type "Fin.t 3".
+@Fin.F1 ?n
+ : Fin.t (S ?n)
+where
+?n : [ |- nat]
+@Fin.FS (S ?n) (@Fin.F1 ?n)
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat]
+@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n))
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat]
+@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat]
+@Fin.F1 (S (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.F1 (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.FS (S O) (@Fin.F1 O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+The command has indeed failed with message:
+The term
+ "@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))"
+has type "Fin.t (S (S (S (S ?n))))" while it is expected to have type
+ "Fin.t (S (S (S O)))".
+0
+ : list unit
+1
+ : list unit
+2
+ : list unit
+2
+ : list unit
+0 :: 0 :: nil
+ : list nat
+0
+ : Ip nat bool
+1
+ : Ip nat bool
+2
+ : Ip nat bool
+3
+ : Ip nat bool
+1
+ : Ip nat bool
+1
+ : Ip nat bool
+1
+ : Ip nat bool
+1
+ : Ip nat bool
+Ip0 nat nat 1
+ : Ip nat nat
+Ip0 bool bool 1
+ : Ip bool bool
+Ip1 nat nat 1
+ : Ip nat nat
+Ip3 1 nat nat
+ : Ip nat nat
+Ip0 nat bool O
+ : Ip nat bool
+Ip1 bool nat (S O)
+ : Ip nat bool
+Ip2 nat (S (S O)) bool
+ : Ip nat bool
+Ip3 (S (S (S O))) nat bool
+ : Ip nat bool
+0
+ : 0 = 0
+eq_refl
+ : 1 = 1
+0
+ : 1 = 1
+2
+ : extra_list_unit
+cons O unit tt (cons O unit tt (nil O unit))
+ : extra_list unit
+0
+ : Set
+1
+ : Set
+2
+ : Set
+3
+ : Set
+Empty_set
+ : Set
+unit
+ : Set
+sum unit unit
+ : Set
+sum unit (sum unit unit)
+ : Set
+0
+ : Fin.t (S ?n)
+where
+?n : [ |- nat]
+1
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat]
+2
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat]
+3
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat]
+0 : Fin.t 3
+ : Fin.t 3
+1 : Fin.t 3
+ : Fin.t 3
+2 : Fin.t 3
+ : Fin.t 3
+The command has indeed failed with message:
+The term "3" has type "Fin.t (S (S (S (S ?n))))"
+while it is expected to have type "Fin.t 3".
+@Fin.F1 ?n
+ : Fin.t (S ?n)
+where
+?n : [ |- nat]
+@Fin.FS (S ?n) (@Fin.F1 ?n)
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat]
+@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n))
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat]
+@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat]
+@Fin.F1 (S (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.F1 (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.FS (S O) (@Fin.F1 O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+The command has indeed failed with message:
+The term
+ "@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))"
+has type "Fin.t (S (S (S (S ?n))))" while it is expected to have type
+ "Fin.t (S (S (S O)))".
+0
+ : Fin.t (S ?n)
+where
+?n : [ |- nat : Set]
+1
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat : Set]
+2
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat : Set]
+3
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat : Set]
+0 : Fin.t 3
+ : Fin.t 3
+1 : Fin.t 3
+ : Fin.t 3
+2 : Fin.t 3
+ : Fin.t 3
+The command has indeed failed with message:
+The term "3" has type "Fin.t (S (S (S (S ?n))))"
+while it is expected to have type "Fin.t 3".
+@Fin.F1 ?n
+ : Fin.t (S ?n)
+where
+?n : [ |- nat : Set]
+@Fin.FS (S ?n) (@Fin.F1 ?n)
+ : Fin.t (S (S ?n))
+where
+?n : [ |- nat : Set]
+@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n))
+ : Fin.t (S (S (S ?n)))
+where
+?n : [ |- nat : Set]
+@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))
+ : Fin.t (S (S (S (S ?n))))
+where
+?n : [ |- nat : Set]
+@Fin.F1 (S (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.F1 (S O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+@Fin.FS (S (S O)) (@Fin.FS (S O) (@Fin.F1 O)) : Fin.t (S (S (S O)))
+ : Fin.t (S (S (S O)))
+The command has indeed failed with message:
+The term
+ "@Fin.FS (S (S (S ?n))) (@Fin.FS (S (S ?n)) (@Fin.FS (S ?n) (@Fin.F1 ?n)))"
+has type "Fin.t (S (S (S (S ?n))))" while it is expected to have type
+ "Fin.t (S (S (S O)))".
diff --git a/test-suite/output/NumberNotations.v b/test-suite/output/NumberNotations.v
index e411005da3..718da13500 100644
--- a/test-suite/output/NumberNotations.v
+++ b/test-suite/output/NumberNotations.v
@@ -5,17 +5,17 @@ Declare Scope opaque_scope.
(* https://github.com/coq/coq/pull/8064#discussion_r202497516 *)
Module Test1.
Axiom hold : forall {A B C}, A -> B -> C.
- Definition opaque3 (x : Numeral.int) : Numeral.int := hold x (fix f (x : nat) : nat := match x with O => O | S n => S (f n) end).
- Number Notation Numeral.int opaque3 opaque3 : opaque_scope.
+ Definition opaque3 (x : Number.int) : Number.int := hold x (fix f (x : nat) : nat := match x with O => O | S n => S (f n) end).
+ Number Notation Number.int opaque3 opaque3 : opaque_scope.
Delimit Scope opaque_scope with opaque.
Fail Check 1%opaque.
End Test1.
(* https://github.com/coq/coq/pull/8064#discussion_r202497990 *)
Module Test2.
- Axiom opaque4 : option Numeral.int.
- Definition opaque6 (x : Numeral.int) : option Numeral.int := opaque4.
- Number Notation Numeral.int opaque6 opaque6 : opaque_scope.
+ Axiom opaque4 : option Number.int.
+ Definition opaque6 (x : Number.int) : option Number.int := opaque4.
+ Number Notation Number.int opaque6 opaque6 : opaque_scope.
Delimit Scope opaque_scope with opaque.
Open Scope opaque_scope.
Fail Check 1%opaque.
@@ -24,8 +24,8 @@ End Test2.
Declare Scope silly_scope.
Module Test3.
- Inductive silly := SILLY (v : Numeral.uint) (f : forall A, A -> A).
- Definition to_silly (v : Numeral.uint) := SILLY v (fun _ x => x).
+ Inductive silly := SILLY (v : Number.uint) (f : forall A, A -> A).
+ Definition to_silly (v : Number.uint) := SILLY v (fun _ x => x).
Definition of_silly (v : silly) := match v with SILLY v _ => v end.
Number Notation silly to_silly of_silly : silly_scope.
Delimit Scope silly_scope with silly.
@@ -45,15 +45,15 @@ Module Test4.
Declare Scope upp.
Declare Scope ppps.
Polymorphic NonCumulative Inductive punit := ptt.
- Polymorphic Definition pto_punit (v : Numeral.uint) : option punit := match Nat.of_num_uint v with O => Some ptt | _ => None end.
- Polymorphic Definition pto_punit_all (v : Numeral.uint) : punit := ptt.
- Polymorphic Definition pof_punit (v : punit) : Numeral.uint := Nat.to_num_uint 0.
- Definition to_punit (v : Numeral.uint) : option punit := match Nat.of_num_uint v with O => Some ptt | _ => None end.
- Definition of_punit (v : punit) : Numeral.uint := Nat.to_num_uint 0.
- Polymorphic Definition pto_unit (v : Numeral.uint) : option unit := match Nat.of_num_uint v with O => Some tt | _ => None end.
- Polymorphic Definition pof_unit (v : unit) : Numeral.uint := Nat.to_num_uint 0.
- Definition to_unit (v : Numeral.uint) : option unit := match Nat.of_num_uint v with O => Some tt | _ => None end.
- Definition of_unit (v : unit) : Numeral.uint := Nat.to_num_uint 0.
+ Polymorphic Definition pto_punit (v : Number.uint) : option punit := match Nat.of_num_uint v with O => Some ptt | _ => None end.
+ Polymorphic Definition pto_punit_all (v : Number.uint) : punit := ptt.
+ Polymorphic Definition pof_punit (v : punit) : Number.uint := Nat.to_num_uint 0.
+ Definition to_punit (v : Number.uint) : option punit := match Nat.of_num_uint v with O => Some ptt | _ => None end.
+ Definition of_punit (v : punit) : Number.uint := Nat.to_num_uint 0.
+ Polymorphic Definition pto_unit (v : Number.uint) : option unit := match Nat.of_num_uint v with O => Some tt | _ => None end.
+ Polymorphic Definition pof_unit (v : unit) : Number.uint := Nat.to_num_uint 0.
+ Definition to_unit (v : Number.uint) : option unit := match Nat.of_num_uint v with O => Some tt | _ => None end.
+ Definition of_unit (v : unit) : Number.uint := Nat.to_num_uint 0.
Number Notation punit to_punit of_punit : pto.
Number Notation punit pto_punit of_punit : ppo.
Number Notation punit to_punit pof_punit : ptp.
@@ -83,7 +83,7 @@ Module Test4.
Polymorphic Definition pto_punits := pto_punit_all@{Set}.
Polymorphic Definition pof_punits := pof_punit@{Set}.
- Number Notation punit pto_punits pof_punits : ppps (abstract after 1).
+ Number Notation punit pto_punits pof_punits (abstract after 1) : ppps.
Delimit Scope ppps with ppps.
Universe u.
Constraint Set < u.
@@ -96,7 +96,7 @@ Module Test5.
End Test5.
Module Test6.
- (* Check that numeral notations on enormous terms don't take forever to print/parse *)
+ (* Check that number notations on enormous terms don't take forever to print/parse *)
(* Ackerman definition from https://stackoverflow.com/a/10303475/377022 *)
Fixpoint ack (n m : nat) : nat :=
match n with
@@ -113,15 +113,15 @@ Module Test6.
Local Set Primitive Projections.
Record > wnat := wrap { unwrap :> nat }.
- Definition to_uint (x : wnat) : Numeral.uint := Nat.to_num_uint x.
- Definition of_uint (x : Numeral.uint) : wnat := Nat.of_num_uint x.
+ Definition to_uint (x : wnat) : Number.uint := Nat.to_num_uint x.
+ Definition of_uint (x : Number.uint) : wnat := Nat.of_num_uint x.
Module Export Scopes.
Declare Scope wnat_scope.
Delimit Scope wnat_scope with wnat.
End Scopes.
Module Export Notations.
Export Scopes.
- Number Notation wnat of_uint to_uint : wnat_scope (abstract after 5000).
+ Number Notation wnat of_uint to_uint (abstract after 5000) : wnat_scope.
End Notations.
Set Printing Coercions.
Check let v := 0%wnat in v : wnat.
@@ -138,7 +138,7 @@ End Test6_2.
Module Test7.
Local Set Primitive Projections.
- Record wuint := wrap { unwrap : Numeral.uint }.
+ Record wuint := wrap { unwrap : Number.uint }.
Declare Scope wuint_scope.
Delimit Scope wuint_scope with wuint.
Number Notation wuint wrap unwrap : wuint_scope.
@@ -148,7 +148,7 @@ End Test7.
Module Test8.
Local Set Primitive Projections.
- Record wuint := wrap { unwrap : Numeral.uint }.
+ Record wuint := wrap { unwrap : Number.uint }.
Declare Scope wuint8_scope.
Declare Scope wuint8'_scope.
Delimit Scope wuint8_scope with wuint8.
@@ -177,7 +177,7 @@ Module Test9.
Delimit Scope wuint9'_scope with wuint9'.
Section with_let.
Local Set Primitive Projections.
- Record wuint := wrap { unwrap : Numeral.uint }.
+ Record wuint := wrap { unwrap : Number.uint }.
Let wrap' := wrap.
Let unwrap' := unwrap.
Local Notation wrap'' := wrap.
@@ -194,26 +194,26 @@ End Test9.
Module Test10.
(* Test that it is only a warning to add abstract after to an optional parsing function *)
Definition to_uint (v : unit) := Nat.to_num_uint 0.
- Definition of_uint (v : Numeral.uint) := match Nat.of_num_uint v with O => Some tt | _ => None end.
- Definition of_any_uint (v : Numeral.uint) := tt.
+ Definition of_uint (v : Number.uint) := match Nat.of_num_uint v with O => Some tt | _ => None end.
+ Definition of_any_uint (v : Number.uint) := tt.
Declare Scope unit_scope.
Declare Scope unit2_scope.
Delimit Scope unit_scope with unit.
Delimit Scope unit2_scope with unit2.
- Number Notation unit of_uint to_uint : unit_scope (abstract after 1).
+ Number Notation unit of_uint to_uint (abstract after 1) : unit_scope.
Local Set Warnings Append "+abstract-large-number-no-op".
(* Check that there is actually a warning here *)
- Fail Number Notation unit of_uint to_uint : unit2_scope (abstract after 1).
+ Fail Number Notation unit of_uint to_uint (abstract after 1) : unit2_scope.
(* Check that there is no warning here *)
- Number Notation unit of_any_uint to_uint : unit2_scope (abstract after 1).
+ Number Notation unit of_any_uint to_uint (abstract after 1) : unit2_scope.
End Test10.
Module Test12.
- (* Test for numeral notations on context variables *)
+ (* Test for number notations on context variables *)
Declare Scope test12_scope.
Delimit Scope test12_scope with test12.
Section test12.
- Context (to_uint : unit -> Numeral.uint) (of_uint : Numeral.uint -> unit).
+ Context (to_uint : unit -> Number.uint) (of_uint : Number.uint -> unit).
Number Notation unit of_uint to_uint : test12_scope.
Check let v := 1%test12 in v : unit.
@@ -221,15 +221,15 @@ Module Test12.
End Test12.
Module Test13.
- (* Test for numeral notations on notations which do not denote references *)
+ (* Test for number notations on notations which do not denote references *)
Declare Scope test13_scope.
Declare Scope test13'_scope.
Declare Scope test13''_scope.
Delimit Scope test13_scope with test13.
Delimit Scope test13'_scope with test13'.
Delimit Scope test13''_scope with test13''.
- Definition to_uint (x y : unit) : Numeral.uint := Nat.to_num_uint O.
- Definition of_uint (x : Numeral.uint) : unit := tt.
+ Definition to_uint (x y : unit) : Number.uint := Nat.to_num_uint O.
+ Definition of_uint (x : Number.uint) : unit := tt.
Definition to_uint_good := to_uint tt.
Notation to_uint' := (to_uint tt).
Notation to_uint'' := (to_uint _).
@@ -242,7 +242,7 @@ Module Test13.
End Test13.
Module Test14.
- (* Test that numeral notations follow [Import], not [Require], and
+ (* Test that number notations follow [Import], not [Require], and
also test that [Local Number Notation]s do not escape modules
nor sections. *)
Declare Scope test14_scope.
@@ -254,8 +254,8 @@ Module Test14.
Delimit Scope test14''_scope with test14''.
Delimit Scope test14'''_scope with test14'''.
Module Inner.
- Definition to_uint (x : unit) : Numeral.uint := Nat.to_num_uint O.
- Definition of_uint (x : Numeral.uint) : unit := tt.
+ Definition to_uint (x : unit) : Number.uint := Nat.to_num_uint O.
+ Definition of_uint (x : Number.uint) : unit := tt.
Local Number Notation unit of_uint to_uint : test14_scope.
Global Number Notation unit of_uint to_uint : test14'_scope.
Check let v := 0%test14 in v : unit.
@@ -267,8 +267,8 @@ Module Test14.
Fail Check let v := 0%test14 in v : unit.
Check let v := 0%test14' in v : unit.
Section InnerSection.
- Definition to_uint (x : unit) : Numeral.uint := Nat.to_num_uint O.
- Definition of_uint (x : Numeral.uint) : unit := tt.
+ Definition to_uint (x : unit) : Number.uint := Nat.to_num_uint O.
+ Definition of_uint (x : Number.uint) : unit := tt.
Local Number Notation unit of_uint to_uint : test14''_scope.
Fail Global Number Notation unit of_uint to_uint : test14'''_scope.
Check let v := 0%test14'' in v : unit.
@@ -283,8 +283,8 @@ Module Test15.
Declare Scope test15_scope.
Delimit Scope test15_scope with test15.
Module Inner.
- Definition to_uint (x : unit) : Numeral.uint := Nat.to_num_uint O.
- Definition of_uint (x : Numeral.uint) : unit := tt.
+ Definition to_uint (x : unit) : Number.uint := Nat.to_num_uint O.
+ Definition of_uint (x : Number.uint) : unit := tt.
Number Notation unit of_uint to_uint : test15_scope.
Check let v := 0%test15 in v : unit.
End Inner.
@@ -306,8 +306,8 @@ Module Test16.
End A.
Module F (a : A).
Inductive Foo := foo (_ : a.T).
- Definition to_uint (x : Foo) : Numeral.uint := Nat.to_num_uint O.
- Definition of_uint (x : Numeral.uint) : Foo := foo a.t.
+ Definition to_uint (x : Foo) : Number.uint := Nat.to_num_uint O.
+ Definition of_uint (x : Number.uint) : Foo := foo a.t.
Global Number Notation Foo of_uint to_uint : test16_scope.
Check let v := 0%test16 in v : Foo.
End F.
@@ -352,8 +352,8 @@ Module Test18.
Definition Q_of_nat (x : nat) : Q := {| num := x ; den := 1 ; reduced := transparentify (nat_eq_dec _ _) (gcd_good _) |}.
Definition nat_of_Q (x : Q) : option nat
:= if Nat.eqb x.(den) 1 then Some (x.(num)) else None.
- Definition Q_of_uint (x : Numeral.uint) : Q := Q_of_nat (Nat.of_num_uint x).
- Definition uint_of_Q (x : Q) : option Numeral.uint
+ Definition Q_of_uint (x : Number.uint) : Q := Q_of_nat (Nat.of_num_uint x).
+ Definition uint_of_Q (x : Q) : option Number.uint
:= option_map Nat.to_num_uint (nat_of_Q x).
Number Notation Q Q_of_uint uint_of_Q : Q_scope.
@@ -411,7 +411,7 @@ Module Test20.
Record > ty := { t : Type ; kt : known_type t }.
- Definition ty_of_uint (x : Numeral.uint) : option ty
+ Definition ty_of_uint (x : Number.uint) : option ty
:= match Nat.of_num_uint x with
| 0 => @Some ty zero
| 1 => @Some ty one
@@ -421,7 +421,7 @@ Module Test20.
| 5 => @Some ty type
| _ => None
end.
- Definition uint_of_ty (x : ty) : Numeral.uint
+ Definition uint_of_ty (x : ty) : Number.uint
:= Nat.to_num_uint match kt x with
| prop => 3
| set => 4
@@ -487,3 +487,488 @@ Check (-0)%Z.
*)
End Test22.
+
+(* Test the via ... mapping ... option *)
+Module Test23.
+
+Inductive sum (A : Set) (B : Set) : Set := pair : A -> B -> sum A B.
+
+Inductive I :=
+| Iempty : I
+| Iunit : I
+| Isum : I -> I -> I.
+
+Definition of_uint (x : Number.uint) : I :=
+ let fix f n :=
+ match n with
+ | O => Iempty
+ | S O => Iunit
+ | S n => Isum Iunit (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition to_uint (x : I) : Number.uint :=
+ let fix f i :=
+ match i with
+ | Iempty => O
+ | Iunit => 1
+ | Isum i1 i2 => f i1 + f i2
+ end in
+ Nat.to_num_uint (f x).
+
+Notation nSet := (Set) (only parsing). (* needed as a reference is expected in Number Notation and Set is syntactically not a reference *)
+Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum])
+ : type_scope.
+
+Local Open Scope type_scope.
+
+Check Empty_set.
+Check unit.
+Check sum unit unit.
+Check sum unit (sum unit unit).
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Unset Printing All.
+
+(* Test error messages *)
+
+(* missing constructor *)
+Fail Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit])
+ : type_scope.
+
+(* duplicate constructor *)
+Fail Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum, unit => Iunit])
+ : type_scope.
+
+(* not an inductive *)
+Fail Number Notation nSet of_uint to_uint (via add
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum])
+ : type_scope.
+
+(* not a constructor *)
+Fail Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => add, sum => Isum])
+ : type_scope.
+
+(* put constructors of the wrong inductive ~~> missing constructors *)
+Fail Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => O, unit => S])
+ : type_scope.
+
+(* Test warnings *)
+
+(* wrong type *)
+Inductive I' :=
+| I'empty : I'
+| I'unit : I'
+| I'sum : I -> I' -> I'.
+Definition of_uint' (x : Number.uint) : I' := I'empty.
+Definition to_uint' (x : I') : Number.uint := Number.UIntDecimal Decimal.Nil.
+Number Notation nSet of_uint' to_uint' (via I'
+ mapping [Empty_set => I'empty, unit => I'unit, sum => I'sum])
+ : type_scope.
+
+(* wrong type mapping *)
+Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, O => Iunit, sum => Isum])
+ : type_scope.
+
+(* incompatibility with abstract (but warning is fine) *)
+Fail Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum],
+ abstract after 12)
+ : type_scope.
+Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum],
+ warning after 12)
+ : type_scope.
+
+(* Test reduction of types when building the notation *)
+
+Inductive foo := bar : match (true <: bool) with true => nat -> foo | false => True end.
+
+Definition foo_of_uint (x : Number.uint) : foo := bar (Nat.of_num_uint x).
+Definition foo_to_uint (x : foo) : Number.uint :=
+ match x with
+ | bar x => Nat.to_num_uint x
+ end.
+
+Number Notation foo foo_of_uint foo_to_uint (via foo mapping [bar => bar])
+ : type_scope.
+
+Inductive foo' := bar' : let n := nat in n -> foo'.
+
+Definition foo'_of_uint (x : Number.uint) : foo' := bar' (Nat.of_num_uint x).
+Definition foo'_to_uint (x : foo') : Number.uint :=
+ match x with
+ | bar' x => Nat.to_num_uint x
+ end.
+
+Number Notation foo' foo'_of_uint foo'_to_uint (via foo' mapping [bar' => bar'])
+ : type_scope.
+
+Inductive foo'' := bar'' : (nat <: Type) -> (foo'' <: Type).
+
+Definition foo''_of_uint (x : Number.uint) : foo'' := bar'' (Nat.of_num_uint x).
+Definition foo''_to_uint (x : foo'') : Number.uint :=
+ match x with
+ | bar'' x => Nat.to_num_uint x
+ end.
+
+Number Notation foo'' foo''_of_uint foo''_to_uint (via foo'' mapping [bar'' => bar''])
+ : type_scope.
+
+End Test23.
+
+(* Test the via ... mapping ... option with implicit arguments *)
+Require Vector.
+Module Test24.
+
+Import Vector.
+
+Inductive I :=
+| I1 : I
+| IS : I -> I.
+
+Definition of_uint (x : Number.uint) : I :=
+ let fix f n :=
+ match n with
+ | O => I1
+ | S n => IS (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition to_uint (x : I) : Number.uint :=
+ let fix f i :=
+ match i with
+ | I1 => O
+ | IS n => S (f n)
+ end in
+ Nat.to_num_uint (f x).
+
+Local Open Scope type_scope.
+
+(* ignoring implicit arguments doesn't work *)
+Number Notation Fin.t of_uint to_uint (via I
+ mapping [Fin.F1 => I1, Fin.FS => IS])
+ : type_scope.
+
+Fail Check 1.
+
+Number Notation Fin.t of_uint to_uint (via I
+ mapping [[Fin.F1] => I1, [Fin.FS] => IS])
+ : type_scope.
+
+Check Fin.F1.
+Check Fin.FS Fin.F1.
+Check Fin.FS (Fin.FS Fin.F1).
+Check Fin.FS (Fin.FS (Fin.FS Fin.F1)).
+Check Fin.F1 : Fin.t 3.
+Check Fin.FS Fin.F1 : Fin.t 3.
+Check Fin.FS (Fin.FS Fin.F1) : Fin.t 3.
+Fail Check Fin.FS (Fin.FS (Fin.FS Fin.F1)) : Fin.t 3.
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Check 0 : Fin.t 3.
+Check 1 : Fin.t 3.
+Check 2 : Fin.t 3.
+Fail Check 3 : Fin.t 3.
+Unset Printing All.
+
+End Test24.
+
+(* Test number notations for parameterized inductives *)
+Module Test25.
+
+Definition of_uint (u : Number.uint) : list unit :=
+ let fix f n :=
+ match n with
+ | O => nil
+ | S n => cons tt (f n)
+ end in
+ f (Nat.of_num_uint u).
+
+Definition to_uint (l : list unit) : Number.uint :=
+ let fix f n :=
+ match n with
+ | nil => O
+ | cons tt l => S (f l)
+ end in
+ Nat.to_num_uint (f l).
+
+Notation listunit := (list unit) (only parsing).
+Number Notation listunit of_uint to_uint : nat_scope.
+
+Check 0.
+Check 1.
+Check 2.
+
+Check cons tt (cons tt nil).
+Check cons O (cons O nil). (* printer not called on list nat *)
+
+(* inductive with multiple parameters that are not the first
+ parameters and not in the same order for each constructor *)
+Inductive Ip : Type -> Type -> Type :=
+| Ip0 : forall T T', nat -> Ip T T'
+| Ip1 : forall T' T, nat -> Ip T T'
+| Ip2 : forall T, nat -> forall T', Ip T T'
+| Ip3 : nat -> forall T T', Ip T T'.
+
+Definition Ip_of_uint (u : Number.uint) : option (Ip nat bool) :=
+ let f n :=
+ match n with
+ | O => Some (Ip0 nat bool O)
+ | S O => Some (Ip1 bool nat (S O))
+ | S (S O) => Some (Ip2 nat (S (S O)) bool)
+ | S (S (S O)) => Some (Ip3 (S (S (S O))) nat bool)
+ | _ => None
+ end in
+ f (Nat.of_num_uint u).
+
+Definition Ip_to_uint (l : Ip nat bool) : Number.uint :=
+ let f n :=
+ match n with
+ | Ip0 _ _ n => n
+ | Ip1 _ _ n => n
+ | Ip2 _ n _ => n
+ | Ip3 n _ _ => n
+ end in
+ Nat.to_num_uint (f l).
+
+Notation Ip_nat_bool := (Ip nat bool) (only parsing).
+Number Notation Ip_nat_bool Ip_of_uint Ip_to_uint : nat_scope.
+
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Check Ip0 nat bool (S O).
+Check Ip1 bool nat (S O).
+Check Ip2 nat (S O) bool.
+Check Ip3 (S O) nat bool.
+Check Ip0 nat nat (S O). (* not printed *)
+Check Ip0 bool bool (S O). (* not printed *)
+Check Ip1 nat nat (S O). (* not printed *)
+Check Ip3 (S O) nat nat. (* not printed *)
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Unset Printing All.
+
+Notation eqO := (eq _ O) (only parsing).
+Definition eqO_of_uint (x : Number.uint) : eqO := eq_refl O.
+Definition eqO_to_uint (x : O = O) : Number.uint :=
+ match x with
+ | eq_refl _ => Nat.to_num_uint O
+ end.
+Number Notation eqO eqO_of_uint eqO_to_uint : nat_scope.
+
+Check 42.
+Check eq_refl (S O). (* doesn't match eq _ O, printer not called *)
+
+Notation eq_ := (eq _ _) (only parsing).
+Number Notation eq_ eqO_of_uint eqO_to_uint : nat_scope.
+
+Check eq_refl (S O). (* matches eq _ _, printer called *)
+
+Inductive extra_list : Type -> Type :=
+| nil (n : nat) (v : Type) : extra_list v
+| cons (n : nat) (t : Type) (x : t) : extra_list t -> extra_list t.
+
+Definition extra_list_unit_of_uint (x : Number.uint) : extra_list unit :=
+ let fix f n :=
+ match n with
+ | O => nil O unit
+ | S n => cons O unit tt (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition extra_list_unit_to_uint (x : extra_list unit) : Number.uint :=
+ let fix f T (x : extra_list T) :=
+ match x with
+ | nil _ _ => O
+ | cons _ T _ x => S (f T x)
+ end in
+ Nat.to_num_uint (f unit x).
+
+Notation extra_list_unit := (extra_list unit).
+Number Notation extra_list_unit
+ extra_list_unit_of_uint extra_list_unit_to_uint : nat_scope.
+
+Check 2.
+Set Printing All.
+Check 2.
+Unset Printing All.
+
+End Test25.
+
+(* Test the via ... mapping ... option with let-binders, beta-redexes, delta-redexes, etc *)
+Module Test26.
+
+Inductive sum (A : Set) (B : Set) : Set := pair : A -> B -> sum A B.
+
+Inductive I (dummy:=O) :=
+| Iempty : let v := I in id v
+| Iunit : (fun x => x) I
+| Isum : let v := I in (fun A B => A -> B) (let v' := v in v') (forall x : match O with O => I | _ => Empty_set end, let dummy2 := x in I).
+
+Definition of_uint (x : (fun x => let v := I in x) Number.uint) : (fun x => let v := I in x) I :=
+ let fix f n :=
+ match n with
+ | O => Iempty
+ | S O => Iunit
+ | S n => Isum Iunit (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition to_uint (x : (fun x => let v := x in v) I) : match O with O => Number.uint | _ => Empty_set end :=
+ let fix f i :=
+ match i with
+ | Iempty => O
+ | Iunit => 1
+ | Isum i1 i2 => f i1 + f i2
+ end in
+ Nat.to_num_uint (f x).
+
+Notation nSet := (Set) (only parsing). (* needed as a reference is expected in Number Notation and Set is syntactically not a reference *)
+Number Notation nSet of_uint to_uint (via I
+ mapping [Empty_set => Iempty, unit => Iunit, sum => Isum])
+ : type_scope.
+
+Local Open Scope type_scope.
+
+Check Empty_set.
+Check unit.
+Check sum unit unit.
+Check sum unit (sum unit unit).
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Unset Printing All.
+End Test26.
+
+(* Test the via ... mapping ... option with implicit arguments with let binders, etc *)
+Module Test27.
+
+Module Fin.
+Inductive t0 (x:=O) :=
+with
+ t (x:=O) : forall y : nat, let z := y in Set :=
+| F1 (y:=O) {n} : match y with O => t (S n) | _ => Empty_set end
+| FS (y:=x) {n} (v:=n+y) (m:=n) : id (match y with O => id (t n) | _ => Empty_set end -> (fun x => x) t (S m))
+with t' (x:=O) := .
+End Fin.
+
+Inductive I (dummy:=O) :=
+| I1 : I
+| IS : let x := I in id x -> I.
+
+Definition of_uint (x : Number.uint) : I :=
+ let fix f n :=
+ match n with
+ | O => I1
+ | S n => IS (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition to_uint (x : I) : Number.uint :=
+ let fix f i :=
+ match i with
+ | I1 => O
+ | IS n => S (f n)
+ end in
+ Nat.to_num_uint (f x).
+
+Local Open Scope type_scope.
+
+Number Notation Fin.t of_uint to_uint (via I
+ mapping [[Fin.F1] => I1, [Fin.FS] => IS])
+ : type_scope.
+
+Check Fin.F1.
+Check Fin.FS Fin.F1.
+Check Fin.FS (Fin.FS Fin.F1).
+Check Fin.FS (Fin.FS (Fin.FS Fin.F1)).
+Check Fin.F1 : Fin.t 3.
+Check Fin.FS Fin.F1 : Fin.t 3.
+Check Fin.FS (Fin.FS Fin.F1) : Fin.t 3.
+Fail Check Fin.FS (Fin.FS (Fin.FS Fin.F1)) : Fin.t 3.
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Check 0 : Fin.t 3.
+Check 1 : Fin.t 3.
+Check 2 : Fin.t 3.
+Fail Check 3 : Fin.t 3.
+Unset Printing All.
+
+End Test27.
+
+Module Test28.
+Module Fin.
+Inductive t : nat -> Set :=
+| F1 {n : (nat : Set)} : (t (S n) : Set)
+| FS {n : (nat : Set)} : (t n : Set) -> (t (S n) : Set).
+End Fin.
+
+Inductive I :=
+| I1 : I
+| IS : I -> I.
+
+Definition of_uint (x : Number.uint) : I :=
+ let fix f n :=
+ match n with
+ | O => I1
+ | S n => IS (f n)
+ end in
+ f (Nat.of_num_uint x).
+
+Definition to_uint (x : I) : Number.uint :=
+ let fix f i :=
+ match i with
+ | I1 => O
+ | IS n => S (f n)
+ end in
+ Nat.to_num_uint (f x).
+
+Local Open Scope type_scope.
+
+Number Notation Fin.t of_uint to_uint (via I
+ mapping [[Fin.F1] => I1, [Fin.FS] => IS])
+ : type_scope.
+
+Check Fin.F1.
+Check Fin.FS Fin.F1.
+Check Fin.FS (Fin.FS Fin.F1).
+Check Fin.FS (Fin.FS (Fin.FS Fin.F1)).
+Check Fin.F1 : Fin.t 3.
+Check Fin.FS Fin.F1 : Fin.t 3.
+Check Fin.FS (Fin.FS Fin.F1) : Fin.t 3.
+Fail Check Fin.FS (Fin.FS (Fin.FS Fin.F1)) : Fin.t 3.
+Set Printing All.
+Check 0.
+Check 1.
+Check 2.
+Check 3.
+Check 0 : Fin.t 3.
+Check 1 : Fin.t 3.
+Check 2 : Fin.t 3.
+Fail Check 3 : Fin.t 3.
+Unset Printing All.
+
+End Test28.
diff --git a/test-suite/output/QArithSyntax.out b/test-suite/output/QArithSyntax.out
index 9b5c076cb4..ced52524f2 100644
--- a/test-suite/output/QArithSyntax.out
+++ b/test-suite/output/QArithSyntax.out
@@ -1,26 +1,72 @@
eq_refl : 1.02 = 1.02
: 1.02 = 1.02
-eq_refl : 10.2 = 10.2
- : 10.2 = 10.2
-eq_refl : 1020 = 1020
- : 1020 = 1020
-eq_refl : 102 = 102
- : 102 = 102
-eq_refl : 1.02 = 1.02
- : 1.02 = 1.02
-eq_refl : -1e-4 = -1e-4
- : -1e-4 = -1e-4
+1.02e1
+ : Q
+10.2
+ : Q
+1.02e3
+ : Q
+1020
+ : Q
+1.02e2
+ : Q
+102
+ : Q
+eq_refl : 10.2e-1 = 1.02
+ : 10.2e-1 = 1.02
+eq_refl : -0.0001 = -0.0001
+ : -0.0001 = -0.0001
eq_refl : -0.50 = -0.50
: -0.50 = -0.50
-eq_refl : -26 = -26
- : -26 = -26
-eq_refl : 2860 # 256 = 2860 # 256
- : 2860 # 256 = 2860 # 256
-eq_refl : -6882 = -6882
- : -6882 = -6882
-eq_refl : 2860 # 64 = 2860 # 64
- : 2860 # 64 = 2860 # 64
-eq_refl : 2860 = 2860
- : 2860 = 2860
-eq_refl : -2860 # 1024 = -2860 # 1024
- : -2860 # 1024 = -2860 # 1024
+0
+ : Q
+0
+ : Q
+42
+ : Q
+42
+ : Q
+1.23
+ : Q
+0x1.23%xQ
+ : Q
+0.0012
+ : Q
+42e3
+ : Q
+42e-3
+ : Q
+eq_refl : -0x1a = -0x1a
+ : -0x1a = -0x1a
+eq_refl : 0xb.2c = 0xb.2c
+ : 0xb.2c = 0xb.2c
+eq_refl : -0x1ae2 = -0x1ae2
+ : -0x1ae2 = -0x1ae2
+0xb.2cp2
+ : Q
+2860 # 64
+ : Q
+0xb.2cp8
+ : Q
+0xb2c
+ : Q
+eq_refl : -0xb.2cp-2 = -2860 # 1024
+ : -0xb.2cp-2 = -2860 # 1024
+0x0
+ : Q
+0x0
+ : Q
+0x2a
+ : Q
+0x2a
+ : Q
+1.23%Q
+ : Q
+0x1.23
+ : Q
+0x0.0012
+ : Q
+0x2ap3
+ : Q
+0x2ap-3
+ : Q
diff --git a/test-suite/output/QArithSyntax.v b/test-suite/output/QArithSyntax.v
index b5c6222bba..e979abca66 100644
--- a/test-suite/output/QArithSyntax.v
+++ b/test-suite/output/QArithSyntax.v
@@ -1,15 +1,39 @@
Require Import QArith.
Open Scope Q_scope.
Check (eq_refl : 1.02 = 102 # 100).
-Check (eq_refl : 1.02e1 = 102 # 10).
-Check (eq_refl : 1.02e+03 = 1020).
-Check (eq_refl : 1.02e+02 = 102 # 1).
+Check 1.02e1.
+Check 102 # 10.
+Check 1.02e+03.
+Check 1020.
+Check 1.02e+02.
+Check 102 # 1.
Check (eq_refl : 10.2e-1 = 1.02).
Check (eq_refl : -0.0001 = -1 # 10000).
Check (eq_refl : -0.50 = - 50 # 100).
+Check 0.
+Check 000.
+Check 42.
+Check 0x2a.
+Check 1.23.
+Check 0x1.23.
+Check 0.0012.
+Check 42e3.
+Check 42e-3.
+Open Scope hex_Q_scope.
Check (eq_refl : -0x1a = - 26 # 1).
Check (eq_refl : 0xb.2c = 2860 # 256).
Check (eq_refl : -0x1ae2 = -6882).
-Check (eq_refl : 0xb.2cp2 = 2860 # 64).
-Check (eq_refl : 0xb.2cp8 = 2860).
+Check 0xb.2cp2.
+Check 2860 # 64.
+Check 0xb.2cp8.
+Check 2860.
Check (eq_refl : -0xb.2cp-2 = -2860 # 1024).
+Check 0x0.
+Check 0x00.
+Check 42.
+Check 0x2a.
+Check 1.23.
+Check 0x1.23.
+Check 0x0.0012.
+Check 0x2ap3.
+Check 0x2ap-3.
diff --git a/test-suite/output/RealSyntax.out b/test-suite/output/RealSyntax.out
index a9386b2781..a7b7dabb20 100644
--- a/test-suite/output/RealSyntax.out
+++ b/test-suite/output/RealSyntax.out
@@ -4,34 +4,81 @@
: R
1.5%R
: R
-15%R
- : R
-eq_refl : 1.02 = 1.02
- : 1.02 = 1.02
-eq_refl : 10.2 = 10.2
- : 10.2 = 10.2
-eq_refl : 102e1 = 102e1
- : 102e1 = 102e1
-eq_refl : 102 = 102
- : 102 = 102
-eq_refl : 1.02 = 1.02
- : 1.02 = 1.02
-eq_refl : -1e-4 = -1e-4
- : -1e-4 = -1e-4
-eq_refl : -0.50 = -0.50
- : -0.50 = -0.50
+1.5e1%R
+ : R
+eq_refl : 1.02 = 102e-2
+ : 1.02 = 102e-2
+1.02e1
+ : R
+102e-1
+ : R
+1.02e3
+ : R
+102e1
+ : R
+1.02e2
+ : R
+102
+ : R
+10.2e-1
+ : R
+1.02
+ : R
+eq_refl : -0.0001 = -1e-4
+ : -0.0001 = -1e-4
+eq_refl : -0.50 = -50e-2
+ : -0.50 = -50e-2
eq_refl : -26 = -26
: -26 = -26
-eq_refl : 2860 / IZR (BinIntDef.Z.pow_pos 2 8) = 2860 / IZR (Z.pow_pos 2 8)
- : 2860 / IZR (BinIntDef.Z.pow_pos 2 8) = 2860 / IZR (Z.pow_pos 2 8)
+eq_refl : 0xb.2c%xR = 0xb2cp-8%xR
+ : 0xb.2c%xR = 0xb2cp-8%xR
eq_refl : -6882 = -6882
: -6882 = -6882
-eq_refl : 2860 / IZR (BinIntDef.Z.pow_pos 2 6) = 2860 / IZR (Z.pow_pos 2 6)
- : 2860 / IZR (BinIntDef.Z.pow_pos 2 6) = 2860 / IZR (Z.pow_pos 2 6)
-eq_refl : 2860 = 2860
- : 2860 = 2860
-eq_refl
-:
--2860 / IZR (BinIntDef.Z.pow_pos 2 10) = - (2860) / IZR (Z.pow_pos 2 10)
- : -2860 / IZR (BinIntDef.Z.pow_pos 2 10) =
- - (2860) / IZR (Z.pow_pos 2 10)
+0xb.2cp2%xR
+ : R
+0xb2cp-6%xR
+ : R
+0xb.2cp8%xR
+ : R
+2860
+ : R
+(-0xb.2cp-2)%xR
+ : R
+- 0xb2cp-10%xR
+ : R
+0
+ : R
+0
+ : R
+42
+ : R
+42
+ : R
+1.23
+ : R
+0x1.23%xR
+ : R
+0.0012
+ : R
+42e3
+ : R
+42e-3
+ : R
+0x0
+ : R
+0x0
+ : R
+0x2a
+ : R
+0x2a
+ : R
+1.23%R
+ : R
+0x1.23
+ : R
+0x0.0012
+ : R
+0x2ap3
+ : R
+0x2ap-3
+ : R
diff --git a/test-suite/output/RealSyntax.v b/test-suite/output/RealSyntax.v
index 69ce3ef5f9..790d5c654f 100644
--- a/test-suite/output/RealSyntax.v
+++ b/test-suite/output/RealSyntax.v
@@ -8,18 +8,48 @@ Check 1_.5_e1_%R.
Open Scope R_scope.
Check (eq_refl : 1.02 = IZR 102 / IZR (Z.pow_pos 10 2)).
-Check (eq_refl : 1.02e1 = IZR 102 / IZR (Z.pow_pos 10 1)).
-Check (eq_refl : 1.02e+03 = IZR 102 * IZR (Z.pow_pos 10 1)).
-Check (eq_refl : 1.02e+02 = IZR 102).
-Check (eq_refl : 10.2e-1 = 1.02).
+Check 1.02e1.
+Check IZR 102 / IZR (Z.pow_pos 10 1).
+Check 1.02e+03.
+Check IZR 102 * IZR (Z.pow_pos 10 1).
+Check 1.02e+02.
+Check IZR 102.
+Check 10.2e-1.
+Check 1.02.
Check (eq_refl : -0.0001 = IZR (-1) / IZR (Z.pow_pos 10 4)).
Check (eq_refl : -0.50 = IZR (-50) / IZR (Z.pow_pos 10 2)).
Check (eq_refl : -0x1a = - 26).
Check (eq_refl : 0xb.2c = IZR 2860 / IZR (Z.pow_pos 2 8)).
Check (eq_refl : -0x1ae2 = -6882).
-Check (eq_refl : 0xb.2cp2 = IZR 2860 / IZR (Z.pow_pos 2 6)).
-Check (eq_refl : 0xb.2cp8 = 2860).
-Check (eq_refl : -0xb.2cp-2 = - IZR 2860 / IZR (Z.pow_pos 2 10)).
+Check 0xb.2cp2.
+Check IZR 2860 / IZR (Z.pow_pos 2 6).
+Check 0xb.2cp8.
+Check 2860.
+Check -0xb.2cp-2.
+Check - (IZR 2860 / IZR (Z.pow_pos 2 10)).
+Check 0.
+Check 000.
+Check 42.
+Check 0x2a.
+Check 1.23.
+Check 0x1.23.
+Check 0.0012.
+Check 42e3.
+Check 42e-3.
+
+Open Scope hex_R_scope.
+
+Check 0x0.
+Check 0x000.
+Check 42.
+Check 0x2a.
+Check 1.23.
+Check 0x1.23.
+Check 0x0.0012.
+Check 0x2ap3.
+Check 0x2ap-3.
+
+Close Scope hex_R_scope.
Require Import Reals.
diff --git a/test-suite/output/Search.out b/test-suite/output/Search.out
index 09feca71e7..914e7f88c6 100644
--- a/test-suite/output/Search.out
+++ b/test-suite/output/Search.out
@@ -30,15 +30,15 @@ implb: bool -> bool -> bool
Nat.odd: nat -> bool
Nat.even: nat -> bool
BoolSpec: Prop -> Prop -> bool -> Prop
-Numeral.numeral_beq: Numeral.numeral -> Numeral.numeral -> bool
+Number.number_beq: Number.number -> Number.number -> bool
Nat.eqb: nat -> nat -> bool
Nat.testbit: nat -> nat -> bool
Decimal.decimal_beq: Decimal.decimal -> Decimal.decimal -> bool
-Numeral.uint_beq: Numeral.uint -> Numeral.uint -> bool
+Number.uint_beq: Number.uint -> Number.uint -> bool
Decimal.uint_beq: Decimal.uint -> Decimal.uint -> bool
Hexadecimal.hexadecimal_beq:
Hexadecimal.hexadecimal -> Hexadecimal.hexadecimal -> bool
-Numeral.int_beq: Numeral.int -> Numeral.int -> bool
+Number.int_beq: Number.int -> Number.int -> bool
Hexadecimal.uint_beq: Hexadecimal.uint -> Hexadecimal.uint -> bool
Nat.ltb: nat -> nat -> bool
Nat.leb: nat -> nat -> bool
@@ -64,34 +64,34 @@ eq_true_rec:
bool_ind: forall P : bool -> Prop, P true -> P false -> forall b : bool, P b
eq_true_sind:
forall P : bool -> SProp, P true -> forall b : bool, eq_true b -> P b
-Numeral.internal_uint_dec_bl1:
- forall x y : Numeral.uint, Numeral.uint_beq x y = true -> x = y
+Number.internal_uint_dec_bl1:
+ forall x y : Number.uint, Number.uint_beq x y = true -> x = y
Hexadecimal.internal_hexadecimal_dec_lb:
forall x y : Hexadecimal.hexadecimal,
x = y -> Hexadecimal.hexadecimal_beq x y = true
Hexadecimal.internal_int_dec_lb0:
forall x y : Hexadecimal.int, x = y -> Hexadecimal.int_beq x y = true
-Numeral.internal_numeral_dec_lb:
- forall x y : Numeral.numeral, x = y -> Numeral.numeral_beq x y = true
+Number.internal_number_dec_lb:
+ forall x y : Number.number, x = y -> Number.number_beq x y = true
Decimal.internal_decimal_dec_lb:
forall x y : Decimal.decimal, x = y -> Decimal.decimal_beq x y = true
Hexadecimal.internal_int_dec_bl0:
forall x y : Hexadecimal.int, Hexadecimal.int_beq x y = true -> x = y
-Numeral.internal_int_dec_lb1:
- forall x y : Numeral.int, x = y -> Numeral.int_beq x y = true
-Numeral.internal_int_dec_bl1:
- forall x y : Numeral.int, Numeral.int_beq x y = true -> x = y
+Number.internal_int_dec_lb1:
+ forall x y : Number.int, x = y -> Number.int_beq x y = true
+Number.internal_int_dec_bl1:
+ forall x y : Number.int, Number.int_beq x y = true -> x = y
Hexadecimal.internal_hexadecimal_dec_bl:
forall x y : Hexadecimal.hexadecimal,
Hexadecimal.hexadecimal_beq x y = true -> x = y
-Numeral.internal_uint_dec_lb1:
- forall x y : Numeral.uint, x = y -> Numeral.uint_beq x y = true
+Number.internal_uint_dec_lb1:
+ forall x y : Number.uint, x = y -> Number.uint_beq x y = true
Decimal.internal_int_dec_bl:
forall x y : Decimal.int, Decimal.int_beq x y = true -> x = y
Decimal.internal_int_dec_lb:
forall x y : Decimal.int, x = y -> Decimal.int_beq x y = true
-Numeral.internal_numeral_dec_bl:
- forall x y : Numeral.numeral, Numeral.numeral_beq x y = true -> x = y
+Number.internal_number_dec_bl:
+ forall x y : Number.number, Number.number_beq x y = true -> x = y
Byte.of_bits:
bool * (bool * (bool * (bool * (bool * (bool * (bool * bool)))))) ->
Byte.byte
@@ -160,21 +160,21 @@ f_equal2_mult:
f_equal2_nat:
forall (B : Type) (f : nat -> nat -> B) (x1 y1 x2 y2 : nat),
x1 = y1 -> x2 = y2 -> f x1 x2 = f y1 y2
-Numeral.internal_numeral_dec_lb:
- forall x y : Numeral.numeral, x = y -> Numeral.numeral_beq x y = true
-Numeral.internal_int_dec_lb1:
- forall x y : Numeral.int, x = y -> Numeral.int_beq x y = true
-Numeral.internal_numeral_dec_bl:
- forall x y : Numeral.numeral, Numeral.numeral_beq x y = true -> x = y
+Number.internal_number_dec_lb:
+ forall x y : Number.number, x = y -> Number.number_beq x y = true
+Number.internal_int_dec_lb1:
+ forall x y : Number.int, x = y -> Number.int_beq x y = true
+Number.internal_number_dec_bl:
+ forall x y : Number.number, Number.number_beq x y = true -> x = y
Hexadecimal.internal_hexadecimal_dec_lb:
forall x y : Hexadecimal.hexadecimal,
x = y -> Hexadecimal.hexadecimal_beq x y = true
-Numeral.internal_int_dec_bl1:
- forall x y : Numeral.int, Numeral.int_beq x y = true -> x = y
-Numeral.internal_uint_dec_lb1:
- forall x y : Numeral.uint, x = y -> Numeral.uint_beq x y = true
-Numeral.internal_uint_dec_bl1:
- forall x y : Numeral.uint, Numeral.uint_beq x y = true -> x = y
+Number.internal_int_dec_bl1:
+ forall x y : Number.int, Number.int_beq x y = true -> x = y
+Number.internal_uint_dec_lb1:
+ forall x y : Number.uint, x = y -> Number.uint_beq x y = true
+Number.internal_uint_dec_bl1:
+ forall x y : Number.uint, Number.uint_beq x y = true -> x = y
Decimal.internal_decimal_dec_lb:
forall x y : Decimal.decimal, x = y -> Decimal.decimal_beq x y = true
Hexadecimal.internal_hexadecimal_dec_bl:
@@ -213,18 +213,18 @@ bool_choice:
forall [S : Set] [R1 R2 : S -> Prop],
(forall x : S, {R1 x} + {R2 x}) ->
{f : S -> bool | forall x : S, f x = true /\ R1 x \/ f x = false /\ R2 x}
-Numeral.internal_numeral_dec_lb:
- forall x y : Numeral.numeral, x = y -> Numeral.numeral_beq x y = true
-Numeral.internal_numeral_dec_bl:
- forall x y : Numeral.numeral, Numeral.numeral_beq x y = true -> x = y
-Numeral.internal_int_dec_lb1:
- forall x y : Numeral.int, x = y -> Numeral.int_beq x y = true
-Numeral.internal_int_dec_bl1:
- forall x y : Numeral.int, Numeral.int_beq x y = true -> x = y
-Numeral.internal_uint_dec_lb1:
- forall x y : Numeral.uint, x = y -> Numeral.uint_beq x y = true
-Numeral.internal_uint_dec_bl1:
- forall x y : Numeral.uint, Numeral.uint_beq x y = true -> x = y
+Number.internal_number_dec_lb:
+ forall x y : Number.number, x = y -> Number.number_beq x y = true
+Number.internal_number_dec_bl:
+ forall x y : Number.number, Number.number_beq x y = true -> x = y
+Number.internal_int_dec_lb1:
+ forall x y : Number.int, x = y -> Number.int_beq x y = true
+Number.internal_int_dec_bl1:
+ forall x y : Number.int, Number.int_beq x y = true -> x = y
+Number.internal_uint_dec_lb1:
+ forall x y : Number.uint, x = y -> Number.uint_beq x y = true
+Number.internal_uint_dec_bl1:
+ forall x y : Number.uint, Number.uint_beq x y = true -> x = y
Hexadecimal.internal_hexadecimal_dec_lb:
forall x y : Hexadecimal.hexadecimal,
x = y -> Hexadecimal.hexadecimal_beq x y = true
@@ -306,12 +306,12 @@ nat_rect_plus:
(nat_rect (fun _ : nat => A) x (fun _ : nat => f) m)
(fun _ : nat => f) n
Nat.bitwise: (bool -> bool -> bool) -> nat -> nat -> nat -> nat
-Numeral.internal_numeral_dec_bl:
- forall x y : Numeral.numeral, Numeral.numeral_beq x y = true -> x = y
-Numeral.internal_int_dec_bl1:
- forall x y : Numeral.int, Numeral.int_beq x y = true -> x = y
-Numeral.internal_uint_dec_bl1:
- forall x y : Numeral.uint, Numeral.uint_beq x y = true -> x = y
+Number.internal_number_dec_bl:
+ forall x y : Number.number, Number.number_beq x y = true -> x = y
+Number.internal_int_dec_bl1:
+ forall x y : Number.int, Number.int_beq x y = true -> x = y
+Number.internal_uint_dec_bl1:
+ forall x y : Number.uint, Number.uint_beq x y = true -> x = y
Hexadecimal.internal_hexadecimal_dec_bl:
forall x y : Hexadecimal.hexadecimal,
Hexadecimal.hexadecimal_beq x y = true -> x = y
@@ -328,12 +328,12 @@ Byte.to_bits_of_bits:
forall
b : bool * (bool * (bool * (bool * (bool * (bool * (bool * bool)))))),
Byte.to_bits (Byte.of_bits b) = b
-Numeral.internal_numeral_dec_lb:
- forall x y : Numeral.numeral, x = y -> Numeral.numeral_beq x y = true
-Numeral.internal_uint_dec_lb1:
- forall x y : Numeral.uint, x = y -> Numeral.uint_beq x y = true
-Numeral.internal_int_dec_lb1:
- forall x y : Numeral.int, x = y -> Numeral.int_beq x y = true
+Number.internal_number_dec_lb:
+ forall x y : Number.number, x = y -> Number.number_beq x y = true
+Number.internal_uint_dec_lb1:
+ forall x y : Number.uint, x = y -> Number.uint_beq x y = true
+Number.internal_int_dec_lb1:
+ forall x y : Number.int, x = y -> Number.int_beq x y = true
Decimal.internal_int_dec_lb:
forall x y : Decimal.int, x = y -> Decimal.int_beq x y = true
Hexadecimal.internal_hexadecimal_dec_lb:
@@ -391,7 +391,7 @@ Nat.lor: nat -> nat -> nat
Nat.lxor: nat -> nat -> nat
Nat.of_hex_uint: Hexadecimal.uint -> nat
Nat.of_uint: Decimal.uint -> nat
-Nat.of_num_uint: Numeral.uint -> nat
+Nat.of_num_uint: Number.uint -> nat
length: forall [A : Type], list A -> nat
plus_n_O: forall n : nat, n = n + 0
plus_O_n: forall n : nat, 0 + n = n
diff --git a/test-suite/output/SearchHead.out b/test-suite/output/SearchHead.out
index 9554581ebe..2f0d854ac6 100644
--- a/test-suite/output/SearchHead.out
+++ b/test-suite/output/SearchHead.out
@@ -21,15 +21,15 @@ orb: bool -> bool -> bool
implb: bool -> bool -> bool
Nat.odd: nat -> bool
Nat.even: nat -> bool
-Numeral.uint_beq: Numeral.uint -> Numeral.uint -> bool
+Number.uint_beq: Number.uint -> Number.uint -> bool
Nat.testbit: nat -> nat -> bool
Nat.eqb: nat -> nat -> bool
Hexadecimal.hexadecimal_beq:
Hexadecimal.hexadecimal -> Hexadecimal.hexadecimal -> bool
Nat.ltb: nat -> nat -> bool
Nat.leb: nat -> nat -> bool
-Numeral.numeral_beq: Numeral.numeral -> Numeral.numeral -> bool
-Numeral.int_beq: Numeral.int -> Numeral.int -> bool
+Number.number_beq: Number.number -> Number.number -> bool
+Number.int_beq: Number.int -> Number.int -> bool
Hexadecimal.int_beq: Hexadecimal.int -> Hexadecimal.int -> bool
Hexadecimal.uint_beq: Hexadecimal.uint -> Hexadecimal.uint -> bool
Decimal.decimal_beq: Decimal.decimal -> Decimal.decimal -> bool
diff --git a/test-suite/output/SearchPattern.out b/test-suite/output/SearchPattern.out
index 80b03e8a0b..d705ec898b 100644
--- a/test-suite/output/SearchPattern.out
+++ b/test-suite/output/SearchPattern.out
@@ -7,15 +7,15 @@ orb: bool -> bool -> bool
implb: bool -> bool -> bool
Nat.odd: nat -> bool
Nat.even: nat -> bool
-Numeral.uint_beq: Numeral.uint -> Numeral.uint -> bool
+Number.uint_beq: Number.uint -> Number.uint -> bool
Nat.testbit: nat -> nat -> bool
Nat.eqb: nat -> nat -> bool
Hexadecimal.hexadecimal_beq:
Hexadecimal.hexadecimal -> Hexadecimal.hexadecimal -> bool
Nat.ltb: nat -> nat -> bool
Nat.leb: nat -> nat -> bool
-Numeral.numeral_beq: Numeral.numeral -> Numeral.numeral -> bool
-Numeral.int_beq: Numeral.int -> Numeral.int -> bool
+Number.number_beq: Number.number -> Number.number -> bool
+Number.int_beq: Number.int -> Number.int -> bool
Hexadecimal.int_beq: Hexadecimal.int -> Hexadecimal.int -> bool
Hexadecimal.uint_beq: Hexadecimal.uint -> Hexadecimal.uint -> bool
Decimal.decimal_beq: Decimal.decimal -> Decimal.decimal -> bool
@@ -50,7 +50,7 @@ Nat.lor: nat -> nat -> nat
Nat.gcd: nat -> nat -> nat
Hexadecimal.nb_digits: Hexadecimal.uint -> nat
Nat.of_hex_uint: Hexadecimal.uint -> nat
-Nat.of_num_uint: Numeral.uint -> nat
+Nat.of_num_uint: Number.uint -> nat
Nat.of_uint: Decimal.uint -> nat
Decimal.nb_digits: Decimal.uint -> nat
Nat.tail_addmul: nat -> nat -> nat -> nat
diff --git a/test-suite/output/Search_bug13298.out b/test-suite/output/Search_bug13298.out
new file mode 100644
index 0000000000..18488c790f
--- /dev/null
+++ b/test-suite/output/Search_bug13298.out
@@ -0,0 +1 @@
+snd: forall c : c, fst c = 0
diff --git a/test-suite/output/Search_bug13298.v b/test-suite/output/Search_bug13298.v
new file mode 100644
index 0000000000..9a75321c64
--- /dev/null
+++ b/test-suite/output/Search_bug13298.v
@@ -0,0 +1,3 @@
+Set Primitive Projections.
+Record c : Type := { fst : nat; snd : fst = 0 }.
+Search concl:fst.
diff --git a/test-suite/output/StringSyntax.out b/test-suite/output/StringSyntax.out
index e9cf4282dc..68ee7cfeb5 100644
--- a/test-suite/output/StringSyntax.out
+++ b/test-suite/output/StringSyntax.out
@@ -1051,7 +1051,7 @@ Arguments byte_ind _%function_scope _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
"127"
: byte
The command has indeed failed with message:
-Expects a single character or a three-digits ascii code.
+Expects a single character or a three-digit ASCII code.
"000"
: ascii
"a"
@@ -1059,7 +1059,7 @@ Expects a single character or a three-digits ascii code.
"127"
: ascii
The command has indeed failed with message:
-Expects a single character or a three-digits ascii code.
+Expects a single character or a three-digit ASCII code.
"000"
: string
"a"
@@ -1084,3 +1084,21 @@ Expects a single character or a three-digits ascii code.
= ["000"; "001"; "002"; "003"; "004"; "005"; "006"; "007"; "008"; "009"; "010"; "011"; "012"; "013"; "014"; "015"; "016"; "017"; "018"; "019"; "020"; "021"; "022"; "023"; "024"; "025"; "026"; "027"; "028"; "029"; "030"; "031"; " "; "!"; """"; "#"; "$"; "%"; "&"; "'"; "("; ")"; "*"; "+"; ","; "-"; "."; "/"; "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; ":"; ";"; "<"; "="; ">"; "?"; "@"; "A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J"; "K"; "L"; "M"; "N"; "O"; "P"; "Q"; "R"; "S"; "T"; "U"; "V"; "W"; "X"; "Y"; "Z"; "["; "\"; "]"; "^"; "_"; "`"; "a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"; "k"; "l"; "m"; "n"; "o"; "p"; "q"; "r"; "s"; "t"; "u"; "v"; "w"; "x"; "y"; "z"; "{"; "|"; "}"; "~"; "127"; "128"; "129"; "130"; "131"; "132"; "133"; "134"; "135"; "136"; "137"; "138"; "139"; "140"; "141"; "142"; "143"; "144"; "145"; "146"; "147"; "148"; "149"; "150"; "151"; "152"; "153"; "154"; "155"; "156"; "157"; "158"; "159"; "160"; "161"; "162"; "163"; "164"; "165"; "166"; "167";
"168"; "169"; "170"; "171"; "172"; "173"; "174"; "175"; "176"; "177"; "178"; "179"; "180"; "181"; "182"; "183"; "184"; "185"; "186"; "187"; "188"; "189"; "190"; "191"; "192"; "193"; "194"; "195"; "196"; "197"; "198"; "199"; "200"; "201"; "202"; "203"; "204"; "205"; "206"; "207"; "208"; "209"; "210"; "211"; "212"; "213"; "214"; "215"; "216"; "217"; "218"; "219"; "220"; "221"; "222"; "223"; "224"; "225"; "226"; "227"; "228"; "229"; "230"; "231"; "232"; "233"; "234"; "235"; "236"; "237"; "238"; "239"; "240"; "241"; "242"; "243"; "244"; "245"; "246"; "247"; "248"; "249"; "250"; "251"; "252"; "253"; "254"; "255"]
: list ascii
+"abc"
+ : string
+"000"
+ : nat
+"001"
+ : nat
+"002"
+ : nat
+"255"
+ : nat
+The command has indeed failed with message:
+Expects a single character or a three-digit ASCII code.
+"abc"
+ : string2
+"abc" : string2
+ : string2
+"abc" : string1
+ : string1
diff --git a/test-suite/output/StringSyntax.v b/test-suite/output/StringSyntax.v
index aab6e0bb03..a1ffe69527 100644
--- a/test-suite/output/StringSyntax.v
+++ b/test-suite/output/StringSyntax.v
@@ -50,3 +50,68 @@ Local Close Scope byte_scope.
Local Open Scope char_scope.
Compute List.map Ascii.ascii_of_nat (List.seq 0 256).
Local Close Scope char_scope.
+
+(* Test numeral notations for parameterized inductives *)
+Module Test2.
+
+Notation string := (list Byte.byte).
+Definition id_string := @id string.
+
+String Notation string id_string id_string : list_scope.
+
+Check "abc"%list.
+
+End Test2.
+
+(* Test the via ... using ... option *)
+Module Test3.
+
+Inductive I :=
+| IO : I
+| IS : I -> I.
+
+Definition of_byte (x : Byte.byte) : I :=
+ let fix f n :=
+ match n with
+ | O => IO
+ | S n => IS (f n)
+ end in
+ f (Byte.to_nat x).
+
+Definition to_byte (x : I) : option Byte.byte :=
+ let fix f i :=
+ match i with
+ | IO => O
+ | IS i => S (f i)
+ end in
+ Byte.of_nat (f x).
+
+String Notation nat of_byte to_byte (via I mapping [O => IO, S => IS]) : nat_scope.
+
+Check "000".
+Check "001".
+Check "002".
+Check "255".
+Fail Check "256".
+
+End Test3.
+
+(* Test overlapping string notations *)
+Module Test4.
+
+Notation string1 := (list Byte.byte).
+Definition id_string1 := @id string1.
+
+String Notation string1 id_string1 id_string1 : list_scope.
+
+Notation string2 := (list Ascii.ascii).
+Definition a2b := List.map byte_of_ascii.
+Definition b2a := List.map ascii_of_byte.
+
+String Notation string2 b2a a2b : list_scope.
+
+Check "abc"%list.
+Check ["a";"b";"c"]%char%list : string2.
+Check ["a";"b";"c"]%byte%list : string1.
+
+End Test4.
diff --git a/test-suite/output/ZSyntax.v b/test-suite/output/ZSyntax.v
index 7b2bb00ce0..67c4f85d5c 100644
--- a/test-suite/output/ZSyntax.v
+++ b/test-suite/output/ZSyntax.v
@@ -18,7 +18,7 @@ Require Import Arith.
Check (0 + Z.of_nat 11)%Z.
(* Check hexadecimal printing *)
-Definition to_num_int n := Numeral.IntHex (Z.to_hex_int n).
+Definition to_num_int n := Number.IntHexadecimal (Z.to_hex_int n).
Number Notation Z Z.of_num_int to_num_int : Z_scope.
Check 42%Z.
Check (-42)%Z.
diff --git a/test-suite/output/bug_12159.v b/test-suite/output/bug_12159.v
index 437b4a68e9..a7366f2d35 100644
--- a/test-suite/output/bug_12159.v
+++ b/test-suite/output/bug_12159.v
@@ -2,10 +2,10 @@ Declare Scope A.
Declare Scope B.
Delimit Scope A with A.
Delimit Scope B with B.
-Definition to_unit (v : Numeral.uint) : option unit
+Definition to_unit (v : Number.uint) : option unit
:= match Nat.of_num_uint v with O => Some tt | _ => None end.
-Definition of_unit (v : unit) : Numeral.uint := Nat.to_num_uint 0.
-Definition of_unit' (v : unit) : Numeral.uint := Nat.to_num_uint 1.
+Definition of_unit (v : unit) : Number.uint := Nat.to_num_uint 0.
+Definition of_unit' (v : unit) : Number.uint := Nat.to_num_uint 1.
Number Notation unit to_unit of_unit : A.
Number Notation unit to_unit of_unit' : B.
Definition f x : unit := x.
diff --git a/test-suite/output/bug_13004.out b/test-suite/output/bug_13004.out
index 2bd7d67535..28bc580202 100644
--- a/test-suite/output/bug_13004.out
+++ b/test-suite/output/bug_13004.out
@@ -1,2 +1,2 @@
-Ltac bug_13004.t := ltac2:(print (of_string "hi"))
-Ltac bug_13004.u := ident:(H)
+Ltac t := ltac2:(print (of_string "hi"))
+Ltac u := ident:(H)
diff --git a/test-suite/output/bug_13238.out b/test-suite/output/bug_13238.out
index bda21aa9e3..a17d05200d 100644
--- a/test-suite/output/bug_13238.out
+++ b/test-suite/output/bug_13238.out
@@ -1,4 +1,4 @@
-Ltac bug_13238.t1 x := replace (x x) with (x x)
-Ltac bug_13238.t2 x := case : x
-Ltac bug_13238.t3 := by move ->
-Ltac bug_13238.t4 := congr True
+Ltac t1 x := replace (x x) with (x x)
+Ltac t2 x := case : x
+Ltac t3 := by move ->
+Ltac t4 := congr True
diff --git a/test-suite/output/prim_array.out b/test-suite/output/prim_array.out
new file mode 100644
index 0000000000..6c12153ab9
--- /dev/null
+++ b/test-suite/output/prim_array.out
@@ -0,0 +1,9 @@
+[| | 0 : nat |]
+ : array nat
+[| 1; 2; 3 | 0 : nat |]
+ : array nat
+[| | 0 : nat |]@{Set}
+ : array@{Set} nat
+[| bool; list nat | nat : Set |]@{prim_array.4}
+ : array@{prim_array.4} Set
+(* {prim_array.4} |= Set < prim_array.4 *)
diff --git a/test-suite/output/prim_array.v b/test-suite/output/prim_array.v
new file mode 100644
index 0000000000..a82f6a16f1
--- /dev/null
+++ b/test-suite/output/prim_array.v
@@ -0,0 +1,10 @@
+Primitive array := #array_type.
+
+Check [| | 0 |].
+
+Check [| 1; 2; 3 | 0 |].
+
+Set Printing Universes.
+Check [| | 0 |].
+
+Check [| bool; list nat | nat |].
diff --git a/test-suite/success/NumeralNotationsNoLocal.v b/test-suite/success/NumberNotationsNoLocal.v
index fe97f10ddf..e19d06cfa7 100644
--- a/test-suite/success/NumeralNotationsNoLocal.v
+++ b/test-suite/success/NumberNotationsNoLocal.v
@@ -1,4 +1,4 @@
-(* Test that numeral notations don't work on proof-local variables, especially not ones containing evars *)
+(* Test that number notations don't work on proof-local variables, especially not ones containing evars *)
Inductive unit11 := tt11.
Declare Scope unit11_scope.
Delimit Scope unit11_scope with unit11.
diff --git a/test-suite/success/definition_using.v b/test-suite/success/definition_using.v
new file mode 100644
index 0000000000..120e62b145
--- /dev/null
+++ b/test-suite/success/definition_using.v
@@ -0,0 +1,68 @@
+Require Import Program.
+Axiom bogus : Type.
+
+Section A.
+Variable x : bogus.
+
+#[using="All"]
+Definition c1 : bool := true.
+
+#[using="All"]
+Fixpoint c2 n : bool :=
+ match n with
+ | O => true
+ | S p => c3 p
+ end
+with c3 n : bool :=
+ match n with
+ | O => true
+ | S p => c2 p
+end.
+
+#[using="All"]
+Definition c4 : bool. Proof. exact true. Qed.
+
+#[using="All"]
+Fixpoint c5 (n : nat) {struct n} : bool. Proof. destruct n as [|p]. exact true. exact (c5 p). Qed.
+
+#[using="All", program]
+Definition c6 : bool. Proof. exact true. Qed.
+
+#[using="All", program]
+Fixpoint c7 (n : nat) {struct n} : bool :=
+ match n with
+ | O => true
+ | S p => c7 p
+ end.
+
+End A.
+
+Check c1 : bogus -> bool.
+Check c2 : bogus -> nat -> bool.
+Check c3 : bogus -> nat -> bool.
+Check c4 : bogus -> bool.
+Check c5 : bogus -> nat -> bool.
+Check c6 : bogus -> bool.
+Check c7 : bogus -> nat -> bool.
+
+Section B.
+
+Variable a : bogus.
+Variable h : c1 a = true.
+
+#[using="a*"]
+Definition c8 : bogus := a.
+
+Collection ccc := a h.
+
+#[using="ccc"]
+Definition c9 : bogus := a.
+
+#[using="ccc - h"]
+Definition c10 : bogus := a.
+
+End B.
+
+Check c8 : forall a, c1 a = true -> bogus.
+Check c9 : forall a, c1 a = true -> bogus.
+Check c10: bogus -> bogus.
diff --git a/test-suite/success/sprop_uip.v b/test-suite/success/sprop_uip.v
index eae1b75689..c9377727db 100644
--- a/test-suite/success/sprop_uip.v
+++ b/test-suite/success/sprop_uip.v
@@ -121,6 +121,33 @@ Proof.
simpl. Fail check.
Abort.
+Module HoTTStyle.
+ (* a small proof which tests destruct in a tricky case *)
+
+ Definition ap {A B} (f:A -> B) {x y} (e : seq x y) : seq (f x) (f y).
+ Proof. destruct e. reflexivity. Defined.
+
+ Section S.
+ Context
+ (A : Type)
+ (B : Type)
+ (f : A -> B)
+ (g : B -> A)
+ (section : forall a, seq (g (f a)) a)
+ (retraction : forall b, seq (f (g b)) b).
+
+ Lemma bla (P : B -> Type) (a : A) (F : forall a, P (f a))
+ : seq_rect _ (f (g (f a))) (fun a _ => P a) (F (g (f a))) (f a) (retraction (f a)) = F a.
+ Proof.
+ lazy.
+ change (retraction (f a)) with (ap f (section a)).
+ destruct (section a).
+ reflexivity.
+ Qed.
+ End S.
+
+End HoTTStyle.
+
(* check that extraction doesn't fall apart on matches with special reduction *)
Require Extraction.
diff --git a/theories/Init/Byte.v b/theories/Init/Byte.v
index 7449b52d76..e03820ef22 100644
--- a/theories/Init/Byte.v
+++ b/theories/Init/Byte.v
@@ -16,7 +16,7 @@ Require Import Coq.Init.Logic.
Require Import Coq.Init.Specif.
Require Coq.Init.Nat.
-Declare ML Module "string_notation_plugin".
+Declare ML Module "number_string_notation_plugin".
(** We define an inductive for use with the [String Notation] command
which contains all ascii characters. We use 256 constructors for
diff --git a/theories/Init/Decimal.v b/theories/Init/Decimal.v
index 025264ab01..bb12f9ca3e 100644
--- a/theories/Init/Decimal.v
+++ b/theories/Init/Decimal.v
@@ -118,6 +118,12 @@ Definition opp (d:int) :=
| Neg d => Pos d
end.
+Definition abs (d:int) : uint :=
+ match d with
+ | Pos d => d
+ | Neg d => d
+ end.
+
(** For conversions with binary numbers, it is easier to operate
on little-endian numbers. *)
diff --git a/theories/Init/Hexadecimal.v b/theories/Init/Hexadecimal.v
index 36f5e5ad1f..7467aa1262 100644
--- a/theories/Init/Hexadecimal.v
+++ b/theories/Init/Hexadecimal.v
@@ -125,6 +125,12 @@ Definition opp (d:int) :=
| Neg d => Pos d
end.
+Definition abs (d:int) : uint :=
+ match d with
+ | Pos d => d
+ | Neg d => d
+ end.
+
(** For conversions with binary numbers, it is easier to operate
on little-endian numbers. *)
@@ -173,6 +179,38 @@ Definition nztail_int d :=
| Neg d => let (r, n) := nztail d in pair (Neg r) n
end.
+(** [del_head n d] removes [n] digits at beginning of [d]
+ or returns [zero] if [d] has less than [n] digits. *)
+
+Fixpoint del_head n d :=
+ match n with
+ | O => d
+ | S n =>
+ match d with
+ | Nil => zero
+ | D0 d | D1 d | D2 d | D3 d | D4 d | D5 d | D6 d | D7 d | D8 d | D9 d
+ | Da d | Db d | Dc d | Dd d | De d | Df d =>
+ del_head n d
+ end
+ end.
+
+Definition del_head_int n d :=
+ match d with
+ | Pos d => del_head n d
+ | Neg d => del_head n d
+ end.
+
+(** [del_tail n d] removes [n] digits at end of [d]
+ or returns [zero] if [d] has less than [n] digits. *)
+
+Definition del_tail n d := rev (del_head n (rev d)).
+
+Definition del_tail_int n d :=
+ match d with
+ | Pos d => Pos (del_tail n d)
+ | Neg d => Neg (del_tail n d)
+ end.
+
Module Little.
(** Successor of little-endian numbers *)
diff --git a/theories/Init/Nat.v b/theories/Init/Nat.v
index 7c8cf0b536..9a3a3ec99b 100644
--- a/theories/Init/Nat.v
+++ b/theories/Init/Nat.v
@@ -9,7 +9,7 @@
(************************************************************************)
Require Import Notations Logic Datatypes.
-Require Decimal Hexadecimal Numeral.
+Require Decimal Hexadecimal Number.
Local Open Scope nat_scope.
(**********************************************************************)
@@ -212,10 +212,10 @@ Fixpoint of_hex_uint_acc (d:Hexadecimal.uint)(acc:nat) :=
Definition of_hex_uint (d:Hexadecimal.uint) := of_hex_uint_acc d O.
-Definition of_num_uint (d:Numeral.uint) :=
+Definition of_num_uint (d:Number.uint) :=
match d with
- | Numeral.UIntDec d => of_uint d
- | Numeral.UIntHex d => of_hex_uint d
+ | Number.UIntDecimal d => of_uint d
+ | Number.UIntHexadecimal d => of_hex_uint d
end.
Fixpoint to_little_uint n acc :=
@@ -236,9 +236,9 @@ Fixpoint to_little_hex_uint n acc :=
Definition to_hex_uint n :=
Hexadecimal.rev (to_little_hex_uint n Hexadecimal.zero).
-Definition to_num_uint n := Numeral.UIntDec (to_uint n).
+Definition to_num_uint n := Number.UIntDecimal (to_uint n).
-Definition to_num_hex_uint n := Numeral.UIntHex (to_hex_uint n).
+Definition to_num_hex_uint n := Number.UIntHexadecimal (to_hex_uint n).
Definition of_int (d:Decimal.int) : option nat :=
match Decimal.norm d with
@@ -252,17 +252,17 @@ Definition of_hex_int (d:Hexadecimal.int) : option nat :=
| _ => None
end.
-Definition of_num_int (d:Numeral.int) : option nat :=
+Definition of_num_int (d:Number.int) : option nat :=
match d with
- | Numeral.IntDec d => of_int d
- | Numeral.IntHex d => of_hex_int d
+ | Number.IntDecimal d => of_int d
+ | Number.IntHexadecimal d => of_hex_int d
end.
Definition to_int n := Decimal.Pos (to_uint n).
Definition to_hex_int n := Hexadecimal.Pos (to_hex_uint n).
-Definition to_num_int n := Numeral.IntDec (to_int n).
+Definition to_num_int n := Number.IntDecimal (to_int n).
(** ** Euclidean division *)
diff --git a/theories/Init/Number.v b/theories/Init/Number.v
new file mode 100644
index 0000000000..eb9cc856ac
--- /dev/null
+++ b/theories/Init/Number.v
@@ -0,0 +1,45 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** * Decimal or Hexadecimal numbers *)
+
+Require Import Decimal Hexadecimal.
+
+Variant uint := UIntDecimal (u:Decimal.uint) | UIntHexadecimal (u:Hexadecimal.uint).
+#[deprecated(since="8.13",note="Use UintDecimal instead.")]
+Notation UIntDec := UIntDecimal (only parsing).
+#[deprecated(since="8.13",note="Use UintHexadecimal instead.")]
+Notation UIntHex := UIntHexadecimal (only parsing).
+
+Variant int := IntDecimal (i:Decimal.int) | IntHexadecimal (i:Hexadecimal.int).
+#[deprecated(since="8.13",note="Use IntDecimal instead.")]
+Notation IntDec := IntDecimal (only parsing).
+#[deprecated(since="8.13",note="Use IntHexadecimal instead.")]
+Notation IntHex := IntHexadecimal (only parsing).
+
+Variant number := Decimal (d:Decimal.decimal) | Hexadecimal (h:Hexadecimal.hexadecimal).
+#[deprecated(since="8.13",note="Use Decimal instead.")]
+Notation Dec := Decimal (only parsing).
+#[deprecated(since="8.13",note="Use Hexadecimal instead.")]
+Notation Hex := Hexadecimal (only parsing).
+
+Scheme Equality for uint.
+Scheme Equality for int.
+Scheme Equality for number.
+
+Register uint as num.num_uint.type.
+Register int as num.num_int.type.
+Register number as num.number.type.
+
+(** Pseudo-conversion functions used when declaring
+ Number Notations on [uint] and [int]. *)
+
+Definition uint_of_uint (i:uint) := i.
+Definition int_of_int (i:int) := i.
diff --git a/theories/Init/Numeral.v b/theories/Init/Numeral.v
index 179547d0b3..50fa312e7e 100644
--- a/theories/Init/Numeral.v
+++ b/theories/Init/Numeral.v
@@ -8,26 +8,47 @@
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
-(** * Decimal or Hexadecimal numbers *)
-
-Require Import Decimal Hexadecimal.
-
-Variant uint := UIntDec (u:Decimal.uint) | UIntHex (u:Hexadecimal.uint).
-
-Variant int := IntDec (i:Decimal.int) | IntHex (i:Hexadecimal.int).
-
-Variant numeral := Dec (d:Decimal.decimal) | Hex (h:Hexadecimal.hexadecimal).
-
-Scheme Equality for uint.
-Scheme Equality for int.
-Scheme Equality for numeral.
-
-Register uint as num.num_uint.type.
-Register int as num.num_int.type.
-Register numeral as num.numeral.type.
-
-(** Pseudo-conversion functions used when declaring
- Number Notations on [uint] and [int]. *)
-
-Definition uint_of_uint (i:uint) := i.
-Definition int_of_int (i:int) := i.
+(** * Deprecated: use Number.v instead *)
+
+Require Import Decimal Hexadecimal Number.
+
+#[deprecated(since="8.13",note="Use Number.uint instead.")]
+Notation uint := uint (only parsing).
+#[deprecated(since="8.13",note="Use Number.UintDecimal instead.")]
+Notation UIntDec := UIntDecimal (only parsing).
+#[deprecated(since="8.13",note="Use Number.UintHexadecimal instead.")]
+Notation UIntHex := UIntHexadecimal (only parsing).
+
+#[deprecated(since="8.13",note="Use Number.int instead.")]
+Notation int := int (only parsing).
+#[deprecated(since="8.13",note="Use Number.IntDecimal instead.")]
+Notation IntDec := IntDecimal (only parsing).
+#[deprecated(since="8.13",note="Use Number.IntHexadecimal instead.")]
+Notation IntHex := IntHexadecimal (only parsing).
+
+#[deprecated(since="8.13",note="Use Number.numeral instead.")]
+Notation numeral := number (only parsing).
+#[deprecated(since="8.13",note="Use Number.Decimal instead.")]
+Notation Dec := Decimal (only parsing).
+#[deprecated(since="8.13",note="Use Number.Hexadecimal instead.")]
+Notation Hex := Hexadecimal (only parsing).
+
+#[deprecated(since="8.13",note="Use Number.uint_beq instead.")]
+Notation uint_beq := uint_beq (only parsing).
+#[deprecated(since="8.13",note="Use Number.uint_eq_dec instead.")]
+Notation uint_eq_dec := uint_eq_dec (only parsing).
+#[deprecated(since="8.13",note="Use Number.int_beq instead.")]
+Notation int_beq := int_beq (only parsing).
+#[deprecated(since="8.13",note="Use Number.int_eq_dec instead.")]
+Notation int_eq_dec := int_eq_dec (only parsing).
+#[deprecated(since="8.13",note="Use Number.numeral_beq instead.")]
+Notation numeral_beq := number_beq (only parsing).
+#[deprecated(since="8.13",note="Use Number.numeral_eq_dec instead.")]
+Notation numeral_eq_dec := number_eq_dec (only parsing).
+
+Register number as num.numeral.type.
+
+#[deprecated(since="8.13",note="Use Number.uint_of_uint instead.")]
+Notation uint_of_uint := uint_of_uint (only parsing).
+#[deprecated(since="8.13",note="Use Number.int_of_int instead.")]
+Notation int_of_int := int_of_int (only parsing).
diff --git a/theories/Init/Prelude.v b/theories/Init/Prelude.v
index 0fe3d5491e..9f8a054b5c 100644
--- a/theories/Init/Prelude.v
+++ b/theories/Init/Prelude.v
@@ -17,6 +17,7 @@ Require Coq.Init.Byte.
Require Coq.Init.Decimal.
Require Coq.Init.Hexadecimal.
Require Coq.Init.Numeral.
+Require Coq.Init.Number.
Require Coq.Init.Nat.
Require Export Peano.
Require Export Coq.Init.Wf.
@@ -29,28 +30,26 @@ Require Export Coq.Init.Tauto.
*)
Declare ML Module "cc_plugin".
Declare ML Module "ground_plugin".
-Declare ML Module "numeral_notation_plugin".
-Declare ML Module "string_notation_plugin".
(* Parsing / printing of hexadecimal numbers *)
Arguments Nat.of_hex_uint d%hex_uint_scope.
Arguments Nat.of_hex_int d%hex_int_scope.
-Number Notation Numeral.uint Numeral.uint_of_uint Numeral.uint_of_uint
+Number Notation Number.uint Number.uint_of_uint Number.uint_of_uint
: hex_uint_scope.
-Number Notation Numeral.int Numeral.int_of_int Numeral.int_of_int
+Number Notation Number.int Number.int_of_int Number.int_of_int
: hex_int_scope.
(* Parsing / printing of decimal numbers *)
Arguments Nat.of_uint d%dec_uint_scope.
Arguments Nat.of_int d%dec_int_scope.
-Number Notation Numeral.uint Numeral.uint_of_uint Numeral.uint_of_uint
+Number Notation Number.uint Number.uint_of_uint Number.uint_of_uint
: dec_uint_scope.
-Number Notation Numeral.int Numeral.int_of_int Numeral.int_of_int
+Number Notation Number.int Number.int_of_int Number.int_of_int
: dec_int_scope.
(* Parsing / printing of [nat] numbers *)
-Number Notation nat Nat.of_num_uint Nat.to_num_hex_uint : hex_nat_scope (abstract after 5001).
-Number Notation nat Nat.of_num_uint Nat.to_num_uint : nat_scope (abstract after 5001).
+Number Notation nat Nat.of_num_uint Nat.to_num_hex_uint (abstract after 5001) : hex_nat_scope.
+Number Notation nat Nat.of_num_uint Nat.to_num_uint (abstract after 5001) : nat_scope.
(* Printing/Parsing of bytes *)
Export Byte.ByteSyntaxNotations.
diff --git a/theories/NArith/BinNatDef.v b/theories/NArith/BinNatDef.v
index 222e76c3e7..e57e5fe856 100644
--- a/theories/NArith/BinNatDef.v
+++ b/theories/NArith/BinNatDef.v
@@ -390,10 +390,10 @@ Definition of_uint (d:Decimal.uint) := Pos.of_uint d.
Definition of_hex_uint (d:Hexadecimal.uint) := Pos.of_hex_uint d.
-Definition of_num_uint (d:Numeral.uint) :=
+Definition of_num_uint (d:Number.uint) :=
match d with
- | Numeral.UIntDec d => of_uint d
- | Numeral.UIntHex d => of_hex_uint d
+ | Number.UIntDecimal d => of_uint d
+ | Number.UIntHexadecimal d => of_hex_uint d
end.
Definition of_int (d:Decimal.int) :=
@@ -408,10 +408,10 @@ Definition of_hex_int (d:Hexadecimal.int) :=
| Hexadecimal.Neg _ => None
end.
-Definition of_num_int (d:Numeral.int) :=
+Definition of_num_int (d:Number.int) :=
match d with
- | Numeral.IntDec d => of_int d
- | Numeral.IntHex d => of_hex_int d
+ | Number.IntDecimal d => of_int d
+ | Number.IntHexadecimal d => of_hex_int d
end.
Definition to_uint n :=
@@ -426,13 +426,13 @@ Definition to_hex_uint n :=
| pos p => Pos.to_hex_uint p
end.
-Definition to_num_uint n := Numeral.UIntDec (to_uint n).
+Definition to_num_uint n := Number.UIntDecimal (to_uint n).
Definition to_int n := Decimal.Pos (to_uint n).
Definition to_hex_int n := Hexadecimal.Pos (to_hex_uint n).
-Definition to_num_int n := Numeral.IntDec (to_int n).
+Definition to_num_int n := Number.IntDecimal (to_int n).
Number Notation N of_num_uint to_num_uint : N_scope.
diff --git a/theories/Numbers/AltBinNotations.v b/theories/Numbers/AltBinNotations.v
index 7c846571a7..c203c178f5 100644
--- a/theories/Numbers/AltBinNotations.v
+++ b/theories/Numbers/AltBinNotations.v
@@ -17,7 +17,7 @@
the [Decimal.int] representation. When working with numbers with
thousands of digits and more, conversion from/to [Decimal.int] can
become significantly slow. If that becomes a problem for your
- development, this file provides some alternative [Numeral
+ development, this file provides some alternative [Number
Notation] commands that use [Z] as bridge type. To enable these
commands, just be sure to [Require] this file after other files
defining numeral notations.
diff --git a/theories/Numbers/DecimalFacts.v b/theories/Numbers/DecimalFacts.v
index dd361562ba..87a9f704cd 100644
--- a/theories/Numbers/DecimalFacts.v
+++ b/theories/Numbers/DecimalFacts.v
@@ -10,175 +10,425 @@
(** * DecimalFacts : some facts about Decimal numbers *)
-Require Import Decimal Arith.
+Require Import Decimal Arith ZArith.
+
+Variant digits := d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | d8 | d9.
+
+Fixpoint to_list (u : uint) : list digits :=
+ match u with
+ | Nil => nil
+ | D0 u => cons d0 (to_list u)
+ | D1 u => cons d1 (to_list u)
+ | D2 u => cons d2 (to_list u)
+ | D3 u => cons d3 (to_list u)
+ | D4 u => cons d4 (to_list u)
+ | D5 u => cons d5 (to_list u)
+ | D6 u => cons d6 (to_list u)
+ | D7 u => cons d7 (to_list u)
+ | D8 u => cons d8 (to_list u)
+ | D9 u => cons d9 (to_list u)
+ end.
-Lemma uint_dec (d d' : uint) : { d = d' } + { d <> d' }.
-Proof.
- decide equality.
-Defined.
+Fixpoint of_list (l : list digits) : uint :=
+ match l with
+ | nil => Nil
+ | cons d0 l => D0 (of_list l)
+ | cons d1 l => D1 (of_list l)
+ | cons d2 l => D2 (of_list l)
+ | cons d3 l => D3 (of_list l)
+ | cons d4 l => D4 (of_list l)
+ | cons d5 l => D5 (of_list l)
+ | cons d6 l => D6 (of_list l)
+ | cons d7 l => D7 (of_list l)
+ | cons d8 l => D8 (of_list l)
+ | cons d9 l => D9 (of_list l)
+ end.
-Lemma rev_revapp d d' :
- rev (revapp d d') = revapp d' d.
+Lemma of_list_to_list u : of_list (to_list u) = u.
+Proof. now induction u; [|simpl; rewrite IHu..]. Qed.
+
+Lemma to_list_of_list l : to_list (of_list l) = l.
+Proof. now induction l as [|h t IHl]; [|case h; simpl; rewrite IHl]. Qed.
+
+Lemma to_list_inj u u' : to_list u = to_list u' -> u = u'.
Proof.
- revert d'. induction d; simpl; intros; now rewrite ?IHd.
+ now intro H; rewrite <-(of_list_to_list u), <-(of_list_to_list u'), H.
Qed.
-Lemma rev_rev d : rev (rev d) = d.
+Lemma of_list_inj u u' : of_list u = of_list u' -> u = u'.
Proof.
- apply rev_revapp.
+ now intro H; rewrite <-(to_list_of_list u), <-(to_list_of_list u'), H.
Qed.
-Lemma revapp_rev_nil d : revapp (rev d) Nil = d.
-Proof. now fold (rev (rev d)); rewrite rev_rev. Qed.
+Lemma nb_digits_spec u : nb_digits u = length (to_list u).
+Proof. now induction u; [|simpl; rewrite IHu..]. Qed.
-Lemma app_nil_r d : app d Nil = d.
-Proof. now unfold app; rewrite revapp_rev_nil. Qed.
+Fixpoint lnzhead l :=
+ match l with
+ | nil => nil
+ | cons d l' =>
+ match d with
+ | d0 => lnzhead l'
+ | _ => l
+ end
+ end.
-Lemma app_int_nil_r d : app_int d Nil = d.
-Proof. now case d; intro d'; simpl; rewrite app_nil_r. Qed.
+Lemma nzhead_spec u : to_list (nzhead u) = lnzhead (to_list u).
+Proof. now induction u; [|simpl; rewrite IHu|..]. Qed.
+
+Definition lzero := cons d0 nil.
+
+Definition lunorm l :=
+ match lnzhead l with
+ | nil => lzero
+ | d => d
+ end.
+
+Lemma unorm_spec u : to_list (unorm u) = lunorm (to_list u).
+Proof. now unfold unorm, lunorm; rewrite <-nzhead_spec; case (nzhead u). Qed.
-Lemma revapp_revapp_1 d d' d'' :
- nb_digits d <= 1 ->
- revapp (revapp d d') d'' = revapp d' (revapp d d'').
+Lemma revapp_spec d d' :
+ to_list (revapp d d') = List.rev_append (to_list d) (to_list d').
+Proof. now revert d'; induction d; intro d'; [|simpl; rewrite IHd..]. Qed.
+
+Lemma rev_spec d : to_list (rev d) = List.rev (to_list d).
+Proof. now unfold rev; rewrite revapp_spec, List.rev_alt; simpl. Qed.
+
+Lemma app_spec d d' :
+ to_list (app d d') = Datatypes.app (to_list d) (to_list d').
Proof.
- now case d; clear d; intro d;
- [|case d; clear d; intro d;
- [|simpl; case nb_digits; [|intros n]; intros Hn; exfalso;
- [apply (Nat.nle_succ_diag_l _ Hn)|
- apply (Nat.nle_succ_0 _ (le_S_n _ _ Hn))]..]..].
+ unfold app.
+ now rewrite revapp_spec, List.rev_append_rev, rev_spec, List.rev_involutive.
Qed.
-Lemma nb_digits_pos d : d <> Nil -> 0 < nb_digits d.
-Proof. now case d; [|intros d' _; apply Nat.lt_0_succ..]. Qed.
+Definition lnztail l :=
+ let fix aux l_rev :=
+ match l_rev with
+ | cons d0 l_rev => let (r, n) := aux l_rev in pair r (S n)
+ | _ => pair l_rev O
+ end in
+ let (r, n) := aux (List.rev l) in pair (List.rev r) n.
-Lemma nb_digits_revapp d d' :
- nb_digits (revapp d d') = nb_digits d + nb_digits d'.
+Lemma nztail_spec d :
+ let (r, n) := nztail d in
+ let (r', n') := lnztail (to_list d) in
+ to_list r = r' /\ n = n'.
Proof.
- now revert d'; induction d; [|intro d'; simpl; rewrite IHd; simpl..].
+ unfold nztail, lnztail.
+ set (f := fix aux d_rev := match d_rev with
+ | D0 d_rev => let (r, n) := aux d_rev in (r, S n)
+ | _ => (d_rev, 0) end).
+ set (f' := fix aux (l_rev : list digits) : list digits * nat :=
+ match l_rev with
+ | cons d0 l_rev => let (r, n) := aux l_rev in (r, S n)
+ | _ => (l_rev, 0)
+ end).
+ rewrite <-(of_list_to_list (rev d)), rev_spec.
+ induction (List.rev _) as [|h t IHl]; [now simpl|].
+ case h; simpl; [|now rewrite rev_spec; simpl; rewrite to_list_of_list..].
+ now revert IHl; case f; intros r n; case f'; intros r' n' [-> ->].
Qed.
-Lemma nb_digits_rev u : nb_digits (rev u) = nb_digits u.
-Proof. now unfold rev; rewrite nb_digits_revapp. Qed.
+Lemma del_head_spec_0 d : del_head 0 d = d.
+Proof. now simpl. Qed.
-Lemma nb_digits_nzhead u : nb_digits (nzhead u) <= nb_digits u.
-Proof. now induction u; [|apply le_S|..]. Qed.
+Lemma del_head_spec_small n d :
+ n <= length (to_list d) -> to_list (del_head n d) = List.skipn n (to_list d).
+Proof.
+ revert d; induction n as [|n IHn]; intro d; [now simpl|].
+ now case d; [|intros d' H; apply IHn, le_S_n..].
+Qed.
-Lemma del_head_nb_digits (u:uint) : del_head (nb_digits u) u = Nil.
-Proof. now induction u. Qed.
+Lemma del_head_spec_large n d : length (to_list d) < n -> del_head n d = zero.
+Proof.
+ revert d; induction n; intro d; [now case d|].
+ now case d; [|intro d'; simpl; intro H; rewrite (IHn _ (lt_S_n _ _ H))..].
+Qed.
-Lemma nb_digits_del_head n u :
- n <= nb_digits u -> nb_digits (del_head n u) = nb_digits u - n.
+Lemma nb_digits_0 d : nb_digits d = 0 -> d = Nil.
Proof.
- revert u; induction n; intros u; [now rewrite Nat.sub_0_r|].
- now case u; clear u; intro u; [|intro Hn; apply IHn, le_S_n..].
+ rewrite nb_digits_spec, <-(of_list_to_list d).
+ now case (to_list d) as [|h t]; [|rewrite to_list_of_list].
Qed.
+Lemma nb_digits_n0 d : nb_digits d <> 0 -> d <> Nil.
+Proof. now case d; [|intros u _..]. Qed.
+
Lemma nb_digits_iter_D0 n d :
nb_digits (Nat.iter n D0 d) = n + nb_digits d.
Proof. now induction n; simpl; [|rewrite IHn]. Qed.
-Fixpoint nth n u :=
- match n with
- | O =>
- match u with
- | Nil => Nil
- | D0 d => D0 Nil
- | D1 d => D1 Nil
- | D2 d => D2 Nil
- | D3 d => D3 Nil
- | D4 d => D4 Nil
- | D5 d => D5 Nil
- | D6 d => D6 Nil
- | D7 d => D7 Nil
- | D8 d => D8 Nil
- | D9 d => D9 Nil
- end
- | S n =>
- match u with
- | Nil => Nil
- | D0 d | D1 d | D2 d | D3 d | D4 d | D5 d | D6 d | D7 d | D8 d | D9 d =>
- nth n d
- end
- end.
+Lemma length_lnzhead l : length (lnzhead l) <= length l.
+Proof. now induction l as [|h t IHl]; [|case h; [apply le_S|..]]. Qed.
+
+Lemma nb_digits_nzhead u : nb_digits (nzhead u) <= nb_digits u.
+Proof. now induction u; [|apply le_S|..]. Qed.
+
+Lemma unorm_nzhead u : nzhead u <> Nil -> unorm u = nzhead u.
+Proof. now unfold unorm; case nzhead. Qed.
-Lemma nb_digits_nth n u : nb_digits (nth n u) <= 1.
+Lemma nb_digits_unorm u : u <> Nil -> nb_digits (unorm u) <= nb_digits u.
Proof.
- revert u; induction n.
- - now intro u; case u; [apply Nat.le_0_1|..].
- - intro u; case u; [apply Nat.le_0_1|intro u'; apply IHn..].
+ intro Hu; case (uint_eq_dec (nzhead u) Nil).
+ { unfold unorm; intros ->; simpl.
+ now revert Hu; case u; [|intros u' _; apply le_n_S, Nat.le_0_l..]. }
+ intro H; rewrite (unorm_nzhead _ H); apply nb_digits_nzhead.
Qed.
-Lemma del_head_nth n u :
- n < nb_digits u ->
- del_head n u = revapp (nth n u) (del_head (S n) u).
-Proof.
- revert u; induction n; intro u; [now case u|].
- now case u; [|intro u'; intro H; apply IHn, le_S_n..].
-Qed.
-
-Lemma nth_revapp_r n d d' :
- nb_digits d <= n ->
- nth n (revapp d d') = nth (n - nb_digits d) d'.
-Proof.
- revert d d'; induction n; intro d.
- - now case d; intro d';
- [case d'|intros d'' H; exfalso; revert H; apply Nat.nle_succ_0..].
- - now induction d;
- [intro d'; case d'|
- intros d' H;
- simpl revapp; rewrite IHd; [|now apply le_Sn_le];
- rewrite Nat.sub_succ_l; [|now apply le_S_n];
- simpl; rewrite <-(IHn _ _ (le_S_n _ _ H))..].
-Qed.
-
-Lemma nth_revapp_l n d d' :
- n < nb_digits d ->
- nth n (revapp d d') = nth (nb_digits d - n - 1) d.
-Proof.
- revert d d'; induction n; intro d.
- - rewrite Nat.sub_0_r.
- now induction d;
- [|intros d' _; simpl revapp;
- revert IHd; case d; clear d; [|intro d..]; intro IHd;
- [|rewrite IHd; [simpl nb_digits; rewrite (Nat.sub_succ_l _ (S _))|];
- [|apply le_n_S, Nat.le_0_l..]..]..].
- - now induction d;
- [|intros d' H;
- simpl revapp; simpl nb_digits;
- simpl in H; generalize (lt_S_n _ _ H); clear H; intro H;
- case (le_lt_eq_dec _ _ H); clear H; intro H;
- [rewrite (IHd _ H), Nat.sub_succ_l;
- [rewrite Nat.sub_succ_l; [|apply Nat.le_add_le_sub_r]|
- apply le_Sn_le]|
- rewrite nth_revapp_r; rewrite <-H;
- [rewrite Nat.sub_succ, Nat.sub_succ_l; [rewrite !Nat.sub_diag|]|]]..].
-Qed.
-
-Lemma app_del_tail_head (u:uint) n :
- n <= nb_digits u ->
- app (del_tail n u) (del_head (nb_digits u - n) u) = u.
-Proof.
- unfold app, del_tail; rewrite rev_rev.
- induction n.
- - intros _; rewrite Nat.sub_0_r, del_head_nb_digits; simpl.
- now rewrite revapp_rev_nil.
- - intro Hn.
- rewrite (del_head_nth (_ - _));
- [|now apply Nat.sub_lt; [|apply Nat.lt_0_succ]].
- rewrite Nat.sub_succ_r, <-Nat.sub_1_r.
- rewrite <-(nth_revapp_l _ _ Nil Hn); fold (rev u).
- rewrite <-revapp_revapp_1; [|now apply nb_digits_nth].
- rewrite <-(del_head_nth _ _); [|now rewrite nb_digits_rev].
- rewrite Nat.sub_1_r, Nat.succ_pred_pos; [|now apply Nat.lt_add_lt_sub_r].
- apply (IHn (le_Sn_le _ _ Hn)).
+Lemma nb_digits_rev d : nb_digits (rev d) = nb_digits d.
+Proof. now rewrite !nb_digits_spec, rev_spec, List.rev_length. Qed.
+
+Lemma nb_digits_del_head_sub d n :
+ n <= nb_digits d ->
+ nb_digits (del_head (nb_digits d - n) d) = n.
+Proof.
+ rewrite !nb_digits_spec; intro Hn.
+ rewrite del_head_spec_small; [|now apply Nat.le_sub_l].
+ rewrite List.skipn_length, <-(Nat2Z.id (_ - _)).
+ rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
+ rewrite (Nat2Z.inj_sub _ _ Hn).
+ rewrite Z.sub_sub_distr, Z.sub_diag; apply Nat2Z.id.
+Qed.
+
+Lemma unorm_D0 u : unorm (D0 u) = unorm u.
+Proof. reflexivity. Qed.
+
+Lemma app_nil_l d : app Nil d = d.
+Proof. now simpl. Qed.
+
+Lemma app_nil_r d : app d Nil = d.
+Proof. now apply to_list_inj; rewrite app_spec, List.app_nil_r. Qed.
+
+Lemma abs_app_int d d' : abs (app_int d d') = app (abs d) d'.
+Proof. now case d. Qed.
+
+Lemma abs_norm d : abs (norm d) = unorm (abs d).
+Proof. now case d as [u|u]; [|simpl; unfold unorm; case nzhead]. Qed.
+
+Lemma iter_D0_nzhead d :
+ Nat.iter (nb_digits d - nb_digits (nzhead d)) D0 (nzhead d) = d.
+Proof.
+ induction d; [now simpl| |now rewrite Nat.sub_diag..].
+ simpl nzhead; simpl nb_digits.
+ rewrite (Nat.sub_succ_l _ _ (nb_digits_nzhead _)).
+ now rewrite <-IHd at 4.
+Qed.
+
+Lemma iter_D0_unorm d :
+ d <> Nil ->
+ Nat.iter (nb_digits d - nb_digits (unorm d)) D0 (unorm d) = d.
+Proof.
+ case (uint_eq_dec (nzhead d) Nil); intro Hn.
+ { unfold unorm; rewrite Hn; simpl; intro H.
+ revert H Hn; induction d; [now simpl|intros _|now intros _..].
+ case (uint_eq_dec d Nil); simpl; intros H Hn; [now rewrite H|].
+ rewrite Nat.sub_0_r, (le_plus_minus 1 (nb_digits d)).
+ { now simpl; rewrite IHd. }
+ revert H; case d; [now simpl|intros u _; apply le_n_S, Nat.le_0_l..]. }
+ intros _; rewrite (unorm_nzhead _ Hn); apply iter_D0_nzhead.
+Qed.
+
+Lemma nzhead_app_l d d' :
+ nb_digits d' < nb_digits (nzhead (app d d')) ->
+ nzhead (app d d') = app (nzhead d) d'.
+Proof.
+ intro Hl; apply to_list_inj; revert Hl.
+ rewrite !nb_digits_spec, app_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl].
+ { now simpl; intro H; exfalso; revert H; apply le_not_lt, length_lnzhead. }
+ rewrite <-List.app_comm_cons.
+ now case h; [simpl; intro Hl; apply IHl|..].
+Qed.
+
+Lemma nzhead_app_r d d' :
+ nb_digits (nzhead (app d d')) <= nb_digits d' ->
+ nzhead (app d d') = nzhead d'.
+Proof.
+ intro Hl; apply to_list_inj; revert Hl.
+ rewrite !nb_digits_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ rewrite <-List.app_comm_cons.
+ now case h; [| simpl; rewrite List.app_length; intro Hl; exfalso; revert Hl;
+ apply le_not_lt, le_plus_r..].
+Qed.
+
+Lemma nzhead_app_nil_r d d' : nzhead (app d d') = Nil -> nzhead d' = Nil.
+Proof.
+now intro H; generalize H; rewrite nzhead_app_r; [|rewrite H; apply Nat.le_0_l].
+Qed.
+
+Lemma nzhead_app_nil d d' :
+ nb_digits (nzhead (app d d')) <= nb_digits d' -> nzhead d = Nil.
+Proof.
+ intro H; apply to_list_inj; revert H.
+ rewrite !nb_digits_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ now case h; [now simpl|..];
+ simpl;intro H; exfalso; revert H; apply le_not_lt;
+ rewrite List.app_length; apply le_plus_r.
+Qed.
+
+Lemma nzhead_app_nil_l d d' : nzhead (app d d') = Nil -> nzhead d = Nil.
+Proof.
+ intro H; apply to_list_inj; generalize (f_equal to_list H); clear H.
+ rewrite !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ now rewrite <-List.app_comm_cons; case h.
+Qed.
+
+Lemma unorm_app_zero d d' :
+ nb_digits (unorm (app d d')) <= nb_digits d' -> unorm d = zero.
+Proof.
+ unfold unorm.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { now intro Hn; rewrite Hn, (nzhead_app_nil_l _ _ Hn). }
+ intro H; fold (unorm (app d d')); rewrite (unorm_nzhead _ H); intro H'.
+ case (uint_eq_dec (nzhead d) Nil); [now intros->|].
+ intro H''; fold (unorm d); rewrite (unorm_nzhead _ H'').
+ exfalso; apply H''; revert H'; apply nzhead_app_nil.
+Qed.
+
+Lemma app_int_nil_r d : app_int d Nil = d.
+Proof.
+ now case d; intro d'; simpl;
+ rewrite <-(of_list_to_list (app _ _)), app_spec;
+ rewrite List.app_nil_r, of_list_to_list.
+Qed.
+
+Lemma unorm_app_l d d' :
+ nb_digits d' < nb_digits (unorm (app d d')) ->
+ unorm (app d d') = app (unorm d) d'.
+Proof.
+ case (uint_eq_dec d' Nil); [now intros->; rewrite !app_nil_r|intro Hd'].
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { unfold unorm; intros->; simpl; intro H; exfalso; revert H; apply le_not_lt.
+ now revert Hd'; case d'; [|intros d'' _; apply le_n_S, Peano.le_0_n..]. }
+ intro Ha; rewrite (unorm_nzhead _ Ha).
+ intro Hn; generalize Hn; rewrite (nzhead_app_l _ _ Hn).
+ rewrite !nb_digits_spec, app_spec, List.app_length.
+ case (uint_eq_dec (nzhead d) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply Nat.lt_irrefl. }
+ now intro H; rewrite (unorm_nzhead _ H).
+Qed.
+
+Lemma unorm_app_r d d' :
+ nb_digits (unorm (app d d')) <= nb_digits d' ->
+ unorm (app d d') = unorm d'.
+Proof.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { now unfold unorm; intro H; rewrite H, (nzhead_app_nil_r _ _ H). }
+ intro Ha; rewrite (unorm_nzhead _ Ha).
+ case (uint_eq_dec (nzhead d') Nil).
+ { now intros H H'; exfalso; apply Ha; rewrite nzhead_app_r. }
+ intro Hd'; rewrite (unorm_nzhead _ Hd'); apply nzhead_app_r.
+Qed.
+
+Lemma norm_app_int d d' :
+ nb_digits d' < nb_digits (unorm (app (abs d) d')) ->
+ norm (app_int d d') = app_int (norm d) d'.
+Proof.
+ case (uint_eq_dec d' Nil); [now intros->; rewrite !app_int_nil_r|intro Hd'].
+ case d as [d|d]; [now simpl; intro H; apply f_equal, unorm_app_l|].
+ simpl; unfold unorm.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply le_not_lt.
+ now revert Hd'; case d'; [|intros d'' _; apply le_n_S, Peano.le_0_n..]. }
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ intro Ha.
+ replace m with (nzhead (app d d')).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ intro Hn; generalize Hn; rewrite (nzhead_app_l _ _ Hn).
+ case (uint_eq_dec (app (nzhead d) d') Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply le_not_lt, Nat.le_0_l. }
+ clear m; set (m := match app _ _ with Nil => _ | _ => _ end).
+ intro Ha'.
+ replace m with (Neg (app (nzhead d) d')); [|now unfold m; revert Ha'; case app].
+ case (uint_eq_dec (nzhead d) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply Nat.lt_irrefl. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ intro Hd.
+ now replace m with (Neg (nzhead d)); [|unfold m; revert Hd; case nzhead].
+Qed.
+
+Lemma del_head_nb_digits d : del_head (nb_digits d) d = Nil.
+Proof.
+ apply to_list_inj.
+ rewrite nb_digits_spec, del_head_spec_small; [|now simpl].
+ now rewrite List.skipn_all.
+Qed.
+
+Lemma del_tail_nb_digits d : del_tail (nb_digits d) d = Nil.
+Proof. now unfold del_tail; rewrite <-nb_digits_rev, del_head_nb_digits. Qed.
+
+Lemma del_head_app n d d' :
+ n <= nb_digits d -> del_head n (app d d') = app (del_head n d) d'.
+Proof.
+ rewrite nb_digits_spec; intro Hn.
+ apply to_list_inj.
+ rewrite del_head_spec_small.
+ 2:{ now rewrite app_spec, List.app_length; apply le_plus_trans. }
+ rewrite !app_spec, (del_head_spec_small _ _ Hn).
+ rewrite List.skipn_app.
+ now rewrite (proj2 (Nat.sub_0_le _ _) Hn).
+Qed.
+
+Lemma del_tail_app n d d' :
+ n <= nb_digits d' -> del_tail n (app d d') = app d (del_tail n d').
+Proof.
+ rewrite nb_digits_spec; intro Hn.
+ unfold del_tail.
+ rewrite <-(of_list_to_list (rev (app d d'))), rev_spec, app_spec.
+ rewrite List.rev_app_distr, <-!rev_spec, <-app_spec, of_list_to_list.
+ rewrite del_head_app; [|now rewrite nb_digits_spec, rev_spec, List.rev_length].
+ apply to_list_inj.
+ rewrite rev_spec, !app_spec, !rev_spec.
+ now rewrite List.rev_app_distr, List.rev_involutive.
+Qed.
+
+Lemma del_tail_app_int n d d' :
+ n <= nb_digits d' -> del_tail_int n (app_int d d') = app_int d (del_tail n d').
+Proof. now case d as [d|d]; simpl; intro H; rewrite del_tail_app. Qed.
+
+Lemma app_del_tail_head n (d:uint) :
+ n <= nb_digits d -> app (del_tail n d) (del_head (nb_digits d - n) d) = d.
+Proof.
+ rewrite nb_digits_spec; intro Hn; unfold del_tail.
+ rewrite <-(of_list_to_list (app _ _)), app_spec, rev_spec.
+ rewrite del_head_spec_small; [|now rewrite rev_spec, List.rev_length].
+ rewrite del_head_spec_small; [|now apply Nat.le_sub_l].
+ rewrite rev_spec.
+ set (n' := _ - n).
+ assert (Hn' : n = length (to_list d) - n').
+ { now apply plus_minus; rewrite Nat.add_comm; symmetry; apply le_plus_minus_r. }
+ now rewrite Hn', <-List.firstn_skipn_rev, List.firstn_skipn, of_list_to_list.
Qed.
Lemma app_int_del_tail_head n (d:int) :
- let ad := match d with Pos d | Neg d => d end in
- n <= nb_digits ad ->
- app_int (del_tail_int n d) (del_head (nb_digits ad - n) ad) = d.
+ n <= nb_digits (abs d) ->
+ app_int (del_tail_int n d) (del_head (nb_digits (abs d) - n) (abs d)) = d.
Proof. now case d; clear d; simpl; intros u Hu; rewrite app_del_tail_head. Qed.
+Lemma del_head_app_int_exact i f :
+ nb_digits f < nb_digits (unorm (app (abs i) f)) ->
+ del_head (nb_digits (unorm (app (abs i) f)) - nb_digits f) (unorm (app (abs i) f)) = f.
+Proof.
+ simpl; intro Hnb; generalize Hnb; rewrite (unorm_app_l _ _ Hnb); clear Hnb.
+ replace (_ - _) with (nb_digits (unorm (abs i))).
+ - now rewrite del_head_app; [rewrite del_head_nb_digits|].
+ - rewrite !nb_digits_spec, app_spec, List.app_length.
+ now rewrite Nat.add_comm, minus_plus.
+Qed.
+
+Lemma del_tail_app_int_exact i f :
+ nb_digits f < nb_digits (unorm (app (abs i) f)) ->
+ del_tail_int (nb_digits f) (norm (app_int i f)) = norm i.
+Proof.
+ simpl; intro Hnb.
+ rewrite (norm_app_int _ _ Hnb).
+ rewrite del_tail_app_int; [|now simpl].
+ now rewrite del_tail_nb_digits, app_int_nil_r.
+Qed.
+
(** Normalization on little-endian numbers *)
Fixpoint nztail d :=
@@ -224,10 +474,13 @@ Proof.
apply nzhead_revapp.
Qed.
+Lemma rev_rev d : rev (rev d) = d.
+Proof. now apply to_list_inj; rewrite !rev_spec, List.rev_involutive. Qed.
+
Lemma rev_nztail_rev d :
rev (nztail (rev d)) = nzhead d.
Proof.
- destruct (uint_dec (nztail (rev d)) Nil) as [H|H].
+ destruct (uint_eq_dec (nztail (rev d)) Nil) as [H|H].
- rewrite H. unfold rev; simpl.
rewrite <- (rev_rev d). symmetry.
now apply nzhead_revapp_0.
@@ -278,21 +531,9 @@ Proof.
unfold unorm. now destruct nzhead.
Qed.
-Lemma unorm_D0 u : unorm (D0 u) = unorm u.
-Proof. reflexivity. Qed.
-
Lemma unorm_iter_D0 n u : unorm (Nat.iter n D0 u) = unorm u.
Proof. now induction n. Qed.
-Lemma nb_digits_unorm u :
- u <> Nil -> nb_digits (unorm u) <= nb_digits u.
-Proof.
- case u; clear u; [now simpl|intro u..]; [|now simpl..].
- intros _; unfold unorm.
- case_eq (nzhead (D0 u)); [|now intros u' <-; apply nb_digits_nzhead..].
- intros _; apply le_n_S, Nat.le_0_l.
-Qed.
-
Lemma del_head_nonnil n u :
n < nb_digits u -> del_head n u <> Nil.
Proof.
@@ -311,73 +552,78 @@ Proof.
now apply del_head_nonnil.
Qed.
-Lemma nzhead_invol d : nzhead (nzhead d) = nzhead d.
+Lemma nzhead_involutive d : nzhead (nzhead d) = nzhead d.
Proof.
now induction d.
Qed.
+#[deprecated(since="8.13",note="Use nzhead_involutive instead.")]
+Notation nzhead_invol := nzhead_involutive (only parsing).
-Lemma nztail_invol d : nztail (nztail d) = nztail d.
+Lemma nztail_involutive d : nztail (nztail d) = nztail d.
Proof.
rewrite <-(rev_rev (nztail _)), <-(rev_rev (nztail d)), <-(rev_rev d).
- now rewrite !rev_nztail_rev, nzhead_invol.
+ now rewrite !rev_nztail_rev, nzhead_involutive.
Qed.
+#[deprecated(since="8.13",note="Use nztail_involutive instead.")]
+Notation nztail_invol := nztail_involutive (only parsing).
-Lemma unorm_invol d : unorm (unorm d) = unorm d.
+Lemma unorm_involutive d : unorm (unorm d) = unorm d.
Proof.
unfold unorm.
destruct (nzhead d) eqn:E; trivial.
destruct (nzhead_nonzero _ _ E).
Qed.
+#[deprecated(since="8.13",note="Use unorm_involutive instead.")]
+Notation unorm_invol := unorm_involutive (only parsing).
-Lemma norm_invol d : norm (norm d) = norm d.
+Lemma norm_involutive d : norm (norm d) = norm d.
Proof.
unfold norm.
destruct d.
- - f_equal. apply unorm_invol.
+ - f_equal. apply unorm_involutive.
- destruct (nzhead d) eqn:E; auto.
destruct (nzhead_nonzero _ _ E).
Qed.
+#[deprecated(since="8.13",note="Use norm_involutive instead.")]
+Notation norm_invol := norm_involutive (only parsing).
+
+Lemma lnzhead_neq_d0_head l l' : ~(lnzhead l = cons d0 l').
+Proof. now induction l as [|h t Il]; [|case h]. Qed.
+
+Lemma lnzhead_head_nd0 h t : h <> d0 -> lnzhead (cons h t) = cons h t.
+Proof. now case h. Qed.
Lemma nzhead_del_tail_nzhead_eq n u :
nzhead u = u ->
n < nb_digits u ->
nzhead (del_tail n u) = del_tail n u.
Proof.
+ rewrite nb_digits_spec, <-List.rev_length.
intros Hu Hn.
- assert (Hhd : forall u,
- nzhead u = u <-> match nth 0 u with D0 _ => False | _ => True end).
- { clear n u Hu Hn; intro u.
- case u; clear u; [|intro u..]; [now simpl| |now simpl..]; simpl.
- split; [|now simpl].
- apply nzhead_nonzero. }
- assert (Hhd' : nth 0 (del_tail n u) = nth 0 u).
- { rewrite <-(app_del_tail_head _ _ (le_Sn_le _ _ Hn)) at 2.
- unfold app.
- rewrite nth_revapp_l.
- - rewrite <-(nth_revapp_l _ _ Nil).
- + now fold (rev (rev (del_tail n u))); rewrite rev_rev.
- + unfold del_tail; rewrite rev_rev.
- rewrite nb_digits_del_head; rewrite nb_digits_rev.
- * now rewrite <-Nat.lt_add_lt_sub_r.
- * now apply Nat.lt_le_incl.
- - unfold del_tail; rewrite rev_rev.
- rewrite nb_digits_del_head; rewrite nb_digits_rev.
- + now rewrite <-Nat.lt_add_lt_sub_r.
- + now apply Nat.lt_le_incl. }
- revert Hu; rewrite Hhd; intro Hu.
- now rewrite Hhd, Hhd'.
+ apply to_list_inj; unfold del_tail.
+ rewrite nzhead_spec, rev_spec.
+ rewrite del_head_spec_small; [|now rewrite rev_spec; apply Nat.lt_le_incl].
+ rewrite rev_spec.
+ rewrite List.skipn_rev, List.rev_involutive.
+ generalize (f_equal to_list Hu) Hn; rewrite nzhead_spec; intro Hu'.
+ case (to_list u) as [|h t].
+ { simpl; intro H; exfalso; revert H; apply le_not_lt, Peano.le_0_n. }
+ intro Hn'; generalize (Nat.sub_gt _ _ Hn'); rewrite List.rev_length.
+ case (_ - _); [now simpl|]; intros n' _.
+ rewrite List.firstn_cons, lnzhead_head_nd0; [now simpl|].
+ intro Hh; revert Hu'; rewrite Hh; apply lnzhead_neq_d0_head.
Qed.
Lemma nzhead_del_tail_nzhead n u :
n < nb_digits (nzhead u) ->
nzhead (del_tail n (nzhead u)) = del_tail n (nzhead u).
-Proof. apply nzhead_del_tail_nzhead_eq, nzhead_invol. Qed.
+Proof. apply nzhead_del_tail_nzhead_eq, nzhead_involutive. Qed.
Lemma unorm_del_tail_unorm n u :
n < nb_digits (unorm u) ->
unorm (del_tail n (unorm u)) = del_tail n (unorm u).
Proof.
- case (uint_dec (nzhead u) Nil).
+ case (uint_eq_dec (nzhead u) Nil).
- unfold unorm; intros->; case n; [now simpl|]; intro n'.
now simpl; intro H; exfalso; generalize (lt_S_n _ _ H).
- unfold unorm.
@@ -396,7 +642,7 @@ Lemma norm_del_tail_int_norm n d :
Proof.
case d; clear d; intros u; simpl.
- now intro H; simpl; rewrite unorm_del_tail_unorm.
- - case (uint_dec (nzhead u) Nil); intro Hu.
+ - case (uint_eq_dec (nzhead u) Nil); intro Hu.
+ now rewrite Hu; case n; [|intros n' Hn'; generalize (lt_S_n _ _ Hn')].
+ set (m := match nzhead u with Nil => Pos zero | _ => _ end).
replace m with (Neg (nzhead u)); [|now unfold m; revert Hu; case nzhead].
@@ -418,7 +664,7 @@ Proof.
generalize (nzhead_revapp d d').
generalize (nzhead_revapp_0 (nztail d) d').
generalize (nzhead_revapp (nztail d) d').
- rewrite nztail_invol.
+ rewrite nztail_involutive.
now case nztail;
[intros _ H _ H'; rewrite (H eq_refl), (H' eq_refl)
|intros d'' H _ H' _; rewrite H; [rewrite H'|]..].
@@ -455,5 +701,10 @@ Proof.
|rewrite H'; unfold r; clear m r H'];
unfold norm;
rewrite rev_rev, <-Hd'';
- rewrite nzhead_revapp; rewrite nztail_invol; [|rewrite Hd'']..].
+ rewrite nzhead_revapp; rewrite nztail_involutive; [|rewrite Hd'']..].
+Qed.
+
+Lemma unorm_app_l_nil d d' : nzhead d = Nil -> unorm (app d d') = unorm d'.
+Proof.
+ now unfold unorm; rewrite <-nzhead_app_nzhead; intros->; rewrite app_nil_l.
Qed.
diff --git a/theories/Numbers/DecimalN.v b/theories/Numbers/DecimalN.v
index 8bc5c38fb5..a5dd97f24b 100644
--- a/theories/Numbers/DecimalN.v
+++ b/theories/Numbers/DecimalN.v
@@ -74,7 +74,7 @@ Proof.
destruct (norm d) eqn:Hd; intros [= <-].
unfold N.to_int. rewrite Unsigned.to_of. f_equal.
revert Hd; destruct d; simpl.
- - intros [= <-]. apply unorm_invol.
+ - intros [= <-]. apply unorm_involutive.
- destruct (nzhead d); now intros [= <-].
Qed.
@@ -93,7 +93,7 @@ Qed.
Lemma of_int_norm d : N.of_int (norm d) = N.of_int d.
Proof.
- unfold N.of_int. now rewrite norm_invol.
+ unfold N.of_int. now rewrite norm_involutive.
Qed.
Lemma of_inj_pos d d' :
diff --git a/theories/Numbers/DecimalNat.v b/theories/Numbers/DecimalNat.v
index 1962ac5d9d..4fee40caa2 100644
--- a/theories/Numbers/DecimalNat.v
+++ b/theories/Numbers/DecimalNat.v
@@ -270,7 +270,7 @@ Proof.
destruct (norm d) eqn:Hd; intros [= <-].
unfold Nat.to_int. rewrite Unsigned.to_of. f_equal.
revert Hd; destruct d; simpl.
- - intros [= <-]. apply unorm_invol.
+ - intros [= <-]. apply unorm_involutive.
- destruct (nzhead d); now intros [= <-].
Qed.
@@ -289,7 +289,7 @@ Qed.
Lemma of_int_norm d : Nat.of_int (norm d) = Nat.of_int d.
Proof.
- unfold Nat.of_int. now rewrite norm_invol.
+ unfold Nat.of_int. now rewrite norm_involutive.
Qed.
Lemma of_inj_pos d d' :
diff --git a/theories/Numbers/DecimalQ.v b/theories/Numbers/DecimalQ.v
index c51cced024..2027813eec 100644
--- a/theories/Numbers/DecimalQ.v
+++ b/theories/Numbers/DecimalQ.v
@@ -15,455 +15,413 @@
Require Import Decimal DecimalFacts DecimalPos DecimalN DecimalZ QArith.
-Lemma of_to (q:Q) : forall d, to_decimal q = Some d -> of_decimal d = q.
+Lemma of_IQmake_to_decimal num den :
+ match IQmake_to_decimal num den with
+ | None => True
+ | Some (DecimalExp _ _ _) => False
+ | Some (Decimal i f) => of_decimal (Decimal i f) = IQmake (IZ_of_Z num) den
+ end.
Proof.
- cut (match to_decimal q with None => True | Some d => of_decimal d = q end).
- { now case to_decimal; [intros d <- d' Hd'; injection Hd'; intros ->|]. }
- destruct q as (num, den).
- unfold to_decimal; simpl.
- generalize (DecimalPos.Unsigned.nztail_to_uint den).
- case Decimal.nztail; intros u n.
- case u; clear u; [intros; exact I|intros; exact I|intro u|intros; exact I..].
- case u; clear u; [|intros; exact I..].
- unfold Pos.of_uint, Pos.of_uint_acc; rewrite N.mul_1_l.
- case n.
- - unfold of_decimal, app_int, app, Z.to_int; simpl.
- intro H; inversion H as (H1); clear H H1.
- case num; [reflexivity|intro pnum; fold (rev (rev (Pos.to_uint pnum)))..].
- + rewrite rev_rev; simpl.
- now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
- + rewrite rev_rev; simpl.
- now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
- - clear n; intros n H.
- injection H; clear H; intros ->.
- case Nat.ltb.
- + unfold of_decimal.
- rewrite of_to.
- apply f_equal2; [|now simpl].
- unfold app_int, app, Z.to_int; simpl.
- now case num;
- [|intro pnum; fold (rev (rev (Pos.to_uint pnum)));
- rewrite rev_rev; unfold Z.of_int, Z.of_uint;
- rewrite DecimalPos.Unsigned.of_to..].
- + unfold of_decimal; case Nat.ltb_spec; intro Hn; simpl.
- * rewrite nb_digits_del_head; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply le_Sn_le].
- rewrite Z.sub_sub_distr, Z.sub_diag; simpl.
- rewrite <-(of_to num) at 4.
- now revert Hn; case Z.to_int; clear num; intros pnum Hn; simpl;
- (rewrite app_del_tail_head; [|now apply le_Sn_le]).
- * revert Hn.
- set (anum := match Z.to_int num with Pos i => i | _ => _ end).
- intro Hn.
- assert (H : exists l, nb_digits anum = S l).
- { exists (Nat.pred (nb_digits anum)); apply S_pred_pos.
- now unfold anum; case num;
- [apply Nat.lt_0_1|
- intro pnum; apply nb_digits_pos, Unsigned.to_uint_nonnil..]. }
- destruct H as (l, Hl); rewrite Hl.
- assert (H : forall n d, (nb_digits (Nat.iter n D0 d) = n + nb_digits d)%nat).
- { now intros n'; induction n'; intro d; [|simpl; rewrite IHn']. }
- rewrite H, Hl.
- rewrite Nat.add_succ_r, Nat.sub_add; [|now apply le_S_n; rewrite <-Hl].
- assert (H' : forall n d, Pos.of_uint (Nat.iter n D0 d) = Pos.of_uint d).
- { now intro n'; induction n'; intro d; [|simpl; rewrite IHn']. }
- now unfold anum; case num; simpl; [|intro pnum..];
- unfold app, Z.of_uint; simpl;
- rewrite H', ?DecimalPos.Unsigned.of_to.
+ unfold IQmake_to_decimal.
+ generalize (Unsigned.nztail_to_uint den).
+ case Decimal.nztail; intros den' e_den'.
+ case den'; [now simpl|now simpl| |now simpl..]; clear den'; intro den'.
+ case den'; [ |now simpl..]; clear den'.
+ case e_den' as [|e_den']; simpl; intro H; injection H; clear H; intros->.
+ { now unfold of_decimal; simpl; rewrite app_int_nil_r, DecimalZ.of_to. }
+ replace (10 ^ _)%positive with (Nat.iter (S e_den') (Pos.mul 10) 1%positive).
+ 2:{ induction e_den' as [|n IHn]; [now simpl| ].
+ now rewrite SuccNat2Pos.inj_succ, Pos.pow_succ_r, <-IHn. }
+ case Nat.ltb_spec; intro He_den'.
+ - unfold of_decimal; simpl.
+ rewrite app_int_del_tail_head; [|now apply Nat.lt_le_incl].
+ rewrite DecimalZ.of_to.
+ now rewrite nb_digits_del_head_sub; [|now apply Nat.lt_le_incl].
+ - unfold of_decimal; simpl.
+ rewrite nb_digits_iter_D0.
+ apply f_equal2.
+ + apply f_equal, DecimalZ.to_int_inj.
+ rewrite DecimalZ.to_of.
+ rewrite <-(DecimalZ.of_to num), DecimalZ.to_of.
+ case (Z.to_int num); clear He_den' num; intro num; simpl.
+ * unfold app; simpl.
+ now rewrite unorm_D0, unorm_iter_D0, unorm_involutive.
+ * case (uint_eq_dec (nzhead num) Nil); [|intro Hn].
+ { intros->; simpl; unfold app; simpl.
+ now rewrite unorm_D0, unorm_iter_D0. }
+ replace (match nzhead num with Nil => _ | _ => _ end)
+ with (Neg (nzhead num)); [|now revert Hn; case nzhead].
+ simpl.
+ rewrite nzhead_iter_D0, nzhead_involutive.
+ now revert Hn; case nzhead.
+ + revert He_den'; case nb_digits as [|n]; [now simpl; rewrite Nat.add_0_r|].
+ intro Hn.
+ rewrite Nat.add_succ_r, Nat.add_comm.
+ now rewrite <-le_plus_minus; [|apply le_S_n].
Qed.
-(* normalize without fractional part, for instance norme 12.3e-1 is 123e-2 *)
-Definition dnorme (d:decimal) : decimal :=
- let '(i, f, e) :=
- match d with
- | Decimal i f => (i, f, Pos Nil)
- | DecimalExp i f e => (i, f, e)
- end in
- let i := norm (app_int i f) in
- let e := norm (Z.to_int (Z.of_int e - Z.of_nat (nb_digits f))) in
- match e with
- | Pos zero => Decimal i Nil
- | _ => DecimalExp i Nil e
+Lemma IZ_of_Z_IZ_to_Z z z' : IZ_to_Z z = Some z' -> IZ_of_Z z' = z.
+Proof. now case z as [| |p|p]; [|intro H; injection H; intros<-..]. Qed.
+
+Lemma of_IQmake_to_decimal' num den :
+ match IQmake_to_decimal' num den with
+ | None => True
+ | Some (DecimalExp _ _ _) => False
+ | Some (Decimal i f) => of_decimal (Decimal i f) = IQmake num den
end.
+Proof.
+ unfold IQmake_to_decimal'.
+ case_eq (IZ_to_Z num); [intros num' Hnum'|now simpl].
+ generalize (of_IQmake_to_decimal num' den).
+ case IQmake_to_decimal as [d|]; [|now simpl].
+ case d as [i f|]; [|now simpl].
+ now rewrite (IZ_of_Z_IZ_to_Z _ _ Hnum').
+Qed.
+
+Lemma of_to (q:IQ) : forall d, to_decimal q = Some d -> of_decimal d = q.
+Proof.
+ intro d.
+ case q as [num den|q q'|q q']; simpl.
+ - generalize (of_IQmake_to_decimal' num den).
+ case IQmake_to_decimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ now intros H H'; injection H'; clear H'; intros <-.
+ - case q as [num den| |]; [|now simpl..].
+ case q' as [num' den'| |]; [|now simpl..].
+ case num' as [z p| | |]; [|now simpl..].
+ case (Z.eq_dec z 10); [intros->|].
+ 2:{ case z; [now simpl| |now simpl]; intro pz'.
+ case pz'; [intros d0..| ]; [now simpl| |now simpl].
+ case d0; [intros d1..| ]; [ |now simpl..].
+ case d1; [intros d2..| ]; [now simpl| |now simpl].
+ now case d2. }
+ case (Pos.eq_dec den' 1%positive); [intros->|now case den'].
+ generalize (of_IQmake_to_decimal' num den).
+ case IQmake_to_decimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros <-; clear num den.
+ intros H; injection H; clear H; intros<-.
+ unfold of_decimal; simpl.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ - case q as [num den| |]; [|now simpl..].
+ case q' as [num' den'| |]; [|now simpl..].
+ case num' as [z p| | |]; [|now simpl..].
+ case (Z.eq_dec z 10); [intros->|].
+ 2:{ case z; [now simpl| |now simpl]; intro pz'.
+ case pz'; [intros d0..| ]; [now simpl| |now simpl].
+ case d0; [intros d1..| ]; [ |now simpl..].
+ case d1; [intros d2..| ]; [now simpl| |now simpl].
+ now case d2. }
+ case (Pos.eq_dec den' 1%positive); [intros->|now case den'].
+ generalize (of_IQmake_to_decimal' num den).
+ case IQmake_to_decimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros <-; clear num den.
+ intros H; injection H; clear H; intros<-.
+ unfold of_decimal; simpl.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+Qed.
-(* normalize without exponent part, for instance norme 12.3e-1 is 1.23 *)
-Definition dnormf (d:decimal) : decimal :=
- match dnorme d with
- | Decimal i _ => Decimal i Nil
- | DecimalExp i _ e =>
- match Z.of_int e with
- | Z0 => Decimal i Nil
- | Zpos e => Decimal (norm (app_int i (Pos.iter D0 Nil e))) Nil
- | Zneg e =>
- let ne := Pos.to_nat e in
- let ai := match i with Pos d | Neg d => d end in
- let ni := nb_digits ai in
- if ne <? ni then
- Decimal (del_tail_int ne i) (del_head (ni - ne) ai)
- else
- let z := match i with Pos _ => Pos zero | Neg _ => Neg zero end in
- Decimal z (Nat.iter (ne - ni) D0 ai)
+Definition dnorm (d:decimal) : decimal :=
+ let norm_i i f :=
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i => match nzhead (app i f) with Nil => Pos zero | _ => Neg (unorm i) end
+ end in
+ match d with
+ | Decimal i f => Decimal (norm_i i f) f
+ | DecimalExp i f e =>
+ match norm e with
+ | Pos zero => Decimal (norm_i i f) f
+ | e => DecimalExp (norm_i i f) f e
end
end.
-Lemma dnorme_spec d :
- match dnorme d with
- | Decimal i Nil => i = norm i
- | DecimalExp i Nil e => i = norm i /\ e = norm e /\ e <> Pos zero
- | _ => False
+Lemma dnorm_spec_i d :
+ let (i, f) :=
+ match d with Decimal i f => (i, f) | DecimalExp i f _ => (i, f) end in
+ let i' := match dnorm d with Decimal i _ => i | DecimalExp i _ _ => i end in
+ match i with
+ | Pos i => i' = Pos (unorm i)
+ | Neg i =>
+ (i' = Neg (unorm i) /\ (nzhead i <> Nil \/ nzhead f <> Nil))
+ \/ (i' = Pos zero /\ (nzhead i = Nil /\ nzhead f = Nil))
end.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold dnorme; simpl.
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); [intros->|intro Hne'].
- + now rewrite norm_invol.
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- replace m with r; [now unfold r; rewrite !norm_invol|].
- unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..].
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); [intros->|intro Hne'].
- + now rewrite norm_invol.
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- replace m with r; [now unfold r; rewrite !norm_invol|].
- unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..].
+ case d as [i f|i f e]; case i as [i|i].
+ - now simpl.
+ - simpl; case (uint_eq_dec (nzhead (app i f)) Nil); intro Ha.
+ + rewrite Ha; right; split; [now simpl|split].
+ * now unfold unorm; rewrite (nzhead_app_nil_l _ _ Ha).
+ * now unfold unorm; rewrite (nzhead_app_nil_r _ _ Ha).
+ + left; split; [now revert Ha; case nzhead|].
+ case (uint_eq_dec (nzhead i) Nil).
+ * intro Hi; right; intro Hf; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now intro H; left.
+ - simpl; case (norm e); clear e; intro e; [|now simpl].
+ now case e; clear e; [|intro e..]; [|case e|..].
+ - simpl.
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ set (m' := match _ with Decimal _ _ => _ | _ => _ end).
+ replace m' with m.
+ 2:{ unfold m'; case (norm e); clear m' e; intro e; [|now simpl].
+ now case e; clear e; [|intro e..]; [|case e|..]. }
+ unfold m; case (uint_eq_dec (nzhead (app i f)) Nil); intro Ha.
+ + rewrite Ha; right; split; [now simpl|split].
+ * now unfold unorm; rewrite (nzhead_app_nil_l _ _ Ha).
+ * now unfold unorm; rewrite (nzhead_app_nil_r _ _ Ha).
+ + left; split; [now revert Ha; case nzhead|].
+ case (uint_eq_dec (nzhead i) Nil).
+ * intro Hi; right; intro Hf; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now intro H; left.
+Qed.
+
+Lemma dnorm_spec_f d :
+ let f := match d with Decimal _ f => f | DecimalExp _ f _ => f end in
+ let f' := match dnorm d with Decimal _ f => f | DecimalExp _ f _ => f end in
+ f' = f.
+Proof.
+ case d as [i f|i f e]; [now simpl|].
+ simpl; case (int_eq_dec (norm e) (Pos zero)); [now intros->|intro He].
+ set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match norm e with Pos Nil => _ | _ => _ end).
+ replace m with (DecimalExp i' f (norm e)); [now simpl|].
+ unfold m; revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
Qed.
-Lemma dnormf_spec d :
- match dnormf d with
- | Decimal i f => i = Neg zero \/ i = norm i
- | _ => False
+Lemma dnorm_spec_e d :
+ match d, dnorm d with
+ | Decimal _ _, Decimal _ _ => True
+ | DecimalExp _ _ e, Decimal _ _ => norm e = Pos zero
+ | DecimalExp _ _ e, DecimalExp _ _ e' => e' = norm e /\ e' <> Pos zero
+ | Decimal _ _, DecimalExp _ _ _ => False
end.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold dnormf, dnorme; simpl.
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); [intros->|intro Hne'].
- + now right; rewrite norm_invol.
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- case_eq (Z.of_int e'); [|intros pe'..]; intro Hpe';
- [now right; rewrite norm_invol..|].
- case Nat.ltb_spec.
- * now intro H; rewrite (norm_del_tail_int_norm _ _ H); right.
- * now intros _; case norm; intros _; [right|left].
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); [intros->|intro Hne'].
- + now right; rewrite norm_invol.
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- case_eq (Z.of_int e'); [|intros pe'..]; intro Hpe';
- [now right; rewrite norm_invol..|].
- case Nat.ltb_spec.
- * now intro H; rewrite (norm_del_tail_int_norm _ _ H); right.
- * now intros _; case norm; intros _; [right|left].
+ case d as [i f|i f e]; [now simpl|].
+ simpl; case (int_eq_dec (norm e) (Pos zero)); [now intros->|intro He].
+ set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match norm e with Pos Nil => _ | _ => _ end).
+ replace m with (DecimalExp i' f (norm e)); [now simpl|].
+ unfold m; revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
Qed.
-Lemma dnorme_invol d : dnorme (dnorme d) = dnorme d.
+Lemma dnorm_involutive d : dnorm (dnorm d) = dnorm d.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold dnorme; simpl.
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); intro Hne'.
- + rewrite Hne'; simpl; rewrite app_int_nil_r, norm_invol.
- revert Hne'.
- rewrite <-to_of.
- change (Pos zero) with (Z.to_int 0).
- intro H; generalize (to_int_inj _ _ H); clear H.
- unfold e'; rewrite DecimalZ.of_to.
- now case f; [rewrite app_int_nil_r|..].
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- unfold nb_digits, Z.of_nat; rewrite Z.sub_0_r, to_of, norm_invol.
- rewrite app_int_nil_r, norm_invol.
- set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..].
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); intro Hne'.
- + rewrite Hne'; simpl; rewrite app_int_nil_r, norm_invol.
- revert Hne'.
- rewrite <-to_of.
- change (Pos zero) with (Z.to_int 0).
- intro H; generalize (to_int_inj _ _ H); clear H.
- unfold e'; rewrite DecimalZ.of_to.
- now case f; [rewrite app_int_nil_r|..].
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- unfold nb_digits, Z.of_nat; rewrite Z.sub_0_r, to_of, norm_invol.
- rewrite app_int_nil_r, norm_invol.
- set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..].
+ case d as [i f|i f e]; case i as [i|i].
+ - now simpl; rewrite unorm_involutive.
+ - simpl; case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ set (m := match nzhead _ with Nil =>_ | _ => _ end).
+ replace m with (Neg (unorm i)).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ + unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ * intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now case nzhead.
+ + rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
+ - simpl; case (int_eq_dec (norm e) (Pos zero)); intro He.
+ + now rewrite He; simpl; rewrite unorm_involutive.
+ + set (m := match norm e with Pos Nil => _ | _ => _ end).
+ replace m with (DecimalExp (Pos (unorm i)) f (norm e)).
+ 2:{ unfold m; revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ simpl; rewrite norm_involutive, unorm_involutive.
+ revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
+ - simpl; case (int_eq_dec (norm e) (Pos zero)); intro He.
+ + rewrite He; simpl.
+ case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ set (m := match nzhead _ with Nil =>_ | _ => _ end).
+ replace m with (Neg (unorm i)).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ * unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ -- intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ -- now case nzhead.
+ * rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
+ + set (m := match norm e with Pos Nil => _ | _ => _ end).
+ pose (i' := match nzhead (app i f) with Nil => Pos zero | _ => Neg (unorm i) end).
+ replace m with (DecimalExp i' f (norm e)).
+ 2:{ unfold m; revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ simpl; rewrite norm_involutive.
+ set (i'' := match i' with Pos _ => _ | _ => _ end).
+ clear m; set (m := match norm e with Pos Nil => _ | _ => _ end).
+ replace m with (DecimalExp i'' f (norm e)).
+ 2:{ unfold m; revert He; case (norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ unfold i'', i'.
+ case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ fold i'; replace i' with (Neg (unorm i)).
+ 2:{ now unfold i'; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ * unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ -- intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ -- now case nzhead.
+ * rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
Qed.
-Lemma dnormf_invol d : dnormf (dnormf d) = dnormf d.
+Lemma IZ_to_Z_IZ_of_Z z : IZ_to_Z (IZ_of_Z z) = Some z.
+Proof. now case z. Qed.
+
+Lemma dnorm_i_exact i f :
+ (nb_digits f < nb_digits (unorm (app (abs i) f)))%nat ->
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i =>
+ match nzhead (app i f) with
+ | Nil => Pos zero
+ | _ => Neg (unorm i)
+ end
+ end = norm i.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold dnormf, dnorme; simpl.
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); intro Hne'.
- + rewrite Hne'; simpl; rewrite app_int_nil_r, norm_invol.
- revert Hne'.
- rewrite <-to_of.
- change (Pos zero) with (Z.to_int 0).
- intro H; generalize (to_int_inj _ _ H); clear H.
- unfold e'; rewrite DecimalZ.of_to.
- now case f; [rewrite app_int_nil_r|..].
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite of_int_norm.
- case_eq (Z.of_int e'); [|intro pe'..]; intro Hnpe';
- [now simpl; rewrite app_int_nil_r, norm_invol..|].
- case Nat.ltb_spec; intro Hpe'.
- * rewrite nb_digits_del_head; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.lt_le_incl].
- simpl.
- rewrite Z.sub_sub_distr, Z.sub_diag, Z.add_0_l.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- rewrite positive_nat_Z; simpl.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- rewrite app_int_del_tail_head; [|now apply Nat.lt_le_incl].
- now rewrite norm_invol, (proj2 (Nat.ltb_lt _ _) Hpe').
- * simpl.
- rewrite nb_digits_iter_D0.
- rewrite (Nat.sub_add _ _ Hpe').
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- rewrite positive_nat_Z; simpl.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- revert Hpe'.
- set (i' := norm (app_int i f)).
- case_eq i'; intros u Hu Hpe'.
- ++ simpl; unfold app; simpl.
- rewrite unorm_D0, unorm_iter_D0.
- assert (Hu' : unorm u = u).
- { generalize (f_equal norm Hu).
- unfold i'; rewrite norm_invol; fold i'.
- now simpl; rewrite Hu; intro H; injection H. }
- now rewrite Hu', (proj2 (Nat.ltb_ge _ _) Hpe').
- ++ simpl; rewrite nzhead_iter_D0.
- assert (Hu' : nzhead u = u).
- { generalize (f_equal norm Hu).
- unfold i'; rewrite norm_invol; fold i'.
- now rewrite Hu; simpl; case (nzhead u); [|intros u' H; injection H..]. }
- rewrite Hu'.
- assert (Hu'' : u <> Nil).
- { intro H; revert Hu; rewrite H; unfold i'.
- now case app_int; intro u'; [|simpl; case nzhead]. }
- set (m := match u with Nil => Pos zero | _ => _ end).
- assert (H : m = Neg u); [|rewrite H; clear m H].
- { now revert Hu''; unfold m; case u. }
- now rewrite (proj2 (Nat.ltb_ge _ _) Hpe').
- - set (e' := Z.to_int _).
- case (int_eq_dec (norm e') (Pos zero)); intro Hne'.
- + rewrite Hne'; simpl; rewrite app_int_nil_r, norm_invol.
- revert Hne'.
- rewrite <-to_of.
- change (Pos zero) with (Z.to_int 0).
- intro H; generalize (to_int_inj _ _ H); clear H.
- unfold e'; rewrite DecimalZ.of_to.
- now case f; [rewrite app_int_nil_r|..].
- + set (r := DecimalExp _ _ _).
- set (m := match norm e' with Pos zero => _ | _ => _ end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { unfold m; revert Hne'; case (norm e'); intro e''; [|now simpl].
- now case e''; [|intro e'''; case e'''..]. }
- rewrite of_int_norm.
- case_eq (Z.of_int e'); [|intro pe'..]; intro Hnpe';
- [now simpl; rewrite app_int_nil_r, norm_invol..|].
- case Nat.ltb_spec; intro Hpe'.
- * rewrite nb_digits_del_head; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.lt_le_incl].
- simpl.
- rewrite Z.sub_sub_distr, Z.sub_diag, Z.add_0_l.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- rewrite positive_nat_Z; simpl.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- rewrite app_int_del_tail_head; [|now apply Nat.lt_le_incl].
- now rewrite norm_invol, (proj2 (Nat.ltb_lt _ _) Hpe').
- * simpl.
- rewrite nb_digits_iter_D0.
- rewrite (Nat.sub_add _ _ Hpe').
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- rewrite positive_nat_Z; simpl.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- revert Hpe'.
- set (i' := norm (app_int i f)).
- case_eq i'; intros u Hu Hpe'.
- ++ simpl; unfold app; simpl.
- rewrite unorm_D0, unorm_iter_D0.
- assert (Hu' : unorm u = u).
- { generalize (f_equal norm Hu).
- unfold i'; rewrite norm_invol; fold i'.
- now simpl; rewrite Hu; intro H; injection H. }
- now rewrite Hu', (proj2 (Nat.ltb_ge _ _) Hpe').
- ++ simpl; rewrite nzhead_iter_D0.
- assert (Hu' : nzhead u = u).
- { generalize (f_equal norm Hu).
- unfold i'; rewrite norm_invol; fold i'.
- now rewrite Hu; simpl; case (nzhead u); [|intros u' H; injection H..]. }
- rewrite Hu'.
- assert (Hu'' : u <> Nil).
- { intro H; revert Hu; rewrite H; unfold i'.
- now case app_int; intro u'; [|simpl; case nzhead]. }
- set (m := match u with Nil => Pos zero | _ => _ end).
- assert (H : m = Neg u); [|rewrite H; clear m H].
- { now revert Hu''; unfold m; case u. }
- now rewrite (proj2 (Nat.ltb_ge _ _) Hpe').
+ case i as [ni|ni]; [now simpl|]; simpl.
+ case (uint_eq_dec (nzhead (app ni f)) Nil); intro Ha.
+ { now rewrite Ha, (nzhead_app_nil_l _ _ Ha). }
+ rewrite (unorm_nzhead _ Ha).
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (unorm ni)); [|now unfold m; revert Ha; case nzhead].
+ case (uint_eq_dec (nzhead ni) Nil); intro Hni.
+ { rewrite <-nzhead_app_nzhead, Hni, app_nil_l.
+ intro H; exfalso; revert H; apply le_not_lt, nb_digits_nzhead. }
+ clear m; set (m := match nzhead ni with Nil => _ | _ => _ end).
+ replace m with (Neg (nzhead ni)); [|now unfold m; revert Hni; case nzhead].
+ now rewrite (unorm_nzhead _ Hni).
+Qed.
+
+Lemma dnorm_i_exact' i f :
+ (nb_digits (unorm (app (abs i) f)) <= nb_digits f)%nat ->
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i =>
+ match nzhead (app i f) with
+ | Nil => Pos zero
+ | _ => Neg (unorm i)
+ end
+ end =
+ match norm (app_int i f) with
+ | Pos _ => Pos zero
+ | Neg _ => Neg zero
+ end.
+Proof.
+ case i as [ni|ni]; simpl.
+ { now intro Hnb; rewrite (unorm_app_zero _ _ Hnb). }
+ unfold unorm.
+ case (uint_eq_dec (nzhead (app ni f)) Nil); intro Hn.
+ { now rewrite Hn. }
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (nzhead (app ni f)).
+ 2:{ now unfold m; revert Hn; case nzhead. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (unorm ni)).
+ 2:{ now unfold m, unorm; revert Hn; case nzhead. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (nzhead (app ni f))).
+ 2:{ now unfold m; revert Hn; case nzhead. }
+ rewrite <-(unorm_nzhead _ Hn).
+ now intro H; rewrite (unorm_app_zero _ _ H).
Qed.
-Lemma to_of (d:decimal) :
- to_decimal (of_decimal d) = Some (dnorme d)
- \/ to_decimal (of_decimal d) = Some (dnormf d).
+Lemma to_of (d:decimal) : to_decimal (of_decimal d) = Some (dnorm d).
Proof.
- unfold to_decimal.
- pose (t10 := fun y => ((y + y~0~0)~0)%positive).
- assert (H : exists e_den,
- Decimal.nztail (Pos.to_uint (Qden (of_decimal d))) = (D1 Nil, e_den)).
- { assert (H : forall p,
- Decimal.nztail (Pos.to_uint (Pos.iter t10 1%positive p))
- = (D1 Nil, Pos.to_nat p)).
- { intro p; rewrite Pos2Nat.inj_iter.
- fold (Nat.iter (Pos.to_nat p) t10 1%positive).
- induction (Pos.to_nat p); [now simpl|].
- rewrite DecimalPos.Unsigned.nat_iter_S.
- unfold Pos.to_uint.
- change (Pos.to_little_uint _)
- with (Unsigned.to_lu (10 * N.pos (Nat.iter n t10 1%positive))).
- rewrite Unsigned.to_ldec_tenfold.
- revert IHn; unfold Pos.to_uint.
- unfold Decimal.nztail; rewrite !rev_rev; simpl.
- set (f'' := _ (Pos.to_little_uint _)).
- now case f''; intros r n' H; inversion H. }
- case d; intros i f; [|intro e]; unfold of_decimal; simpl.
- - case (- Z.of_nat _)%Z; [|intro p..]; simpl; [now exists O..|].
- exists (Pos.to_nat p); apply H.
- - case (_ - _)%Z; [|intros p..]; simpl; [now exists O..|].
- exists (Pos.to_nat p); apply H. }
- generalize (DecimalPos.Unsigned.nztail_to_uint (Qden (of_decimal d))).
- destruct H as (e, He); rewrite He; clear He; simpl.
- assert (Hn1 : forall p, N.pos (Pos.iter t10 1%positive p) = 1%N -> False).
- { intro p.
- rewrite Pos2Nat.inj_iter.
- case_eq (Pos.to_nat p); [|now simpl].
- intro H; exfalso; apply (lt_irrefl O).
- rewrite <-H at 2; apply Pos2Nat.is_pos. }
- assert (Ht10inj : forall n m, t10 n = t10 m -> n = m).
- { intros n m H; generalize (f_equal Z.pos H); clear H.
- change (Z.pos (t10 n)) with (Z.mul 10 (Z.pos n)).
- change (Z.pos (t10 m)) with (Z.mul 10 (Z.pos m)).
- rewrite Z.mul_comm, (Z.mul_comm 10).
- intro H; generalize (f_equal (fun z => Z.div z 10) H); clear H.
- now rewrite !Z.div_mul; [|now simpl..]; intro H; inversion H. }
- assert (Hinj : forall n m,
- Nat.iter n t10 1%positive = Nat.iter m t10 1%positive -> n = m).
- { induction n; [now intro m; case m|].
- intro m; case m; [now simpl|]; clear m; intro m.
- rewrite !Unsigned.nat_iter_S.
- intro H; generalize (Ht10inj _ _ H); clear H; intro H.
- now rewrite (IHn _ H). }
- case e; clear e; [|intro e]; simpl; unfold of_decimal, dnormf, dnorme.
- - case d; clear d; intros i f; [|intro e]; simpl.
- + intro H; left; revert H.
- generalize (nb_digits_pos f).
- case f;
- [|now clear f; intro f; intros H1 H2; exfalso; revert H1 H2;
- case nb_digits; simpl;
- [intros H _; apply (lt_irrefl O), H|intros n _; apply Hn1]..].
- now intros _ _; simpl; rewrite to_of.
- + intro H; right; revert H.
- rewrite <-to_of, DecimalZ.of_to.
- set (emf := (_ - _)%Z).
- case_eq emf; [|intro pemf..].
- * now simpl; rewrite to_of.
- * set (r := DecimalExp _ _ _).
- set (m := match _ with Pos _ => _ | _ => r end).
- assert (H : m = r).
- { unfold m, Z.to_int.
- generalize (Unsigned.to_uint_nonzero pemf).
- now case Pos.to_uint; [|intro u; case u..]. }
- rewrite H; unfold r; clear H m r.
- rewrite DecimalZ.of_to.
- simpl Qnum.
- intros Hpemf _.
- apply f_equal; apply f_equal2; [|reflexivity].
- rewrite !Pos2Nat.inj_iter.
- set (n := _ pemf).
- fold (Nat.iter n (Z.mul 10) (Z.of_int (app_int i f))).
- fold (Nat.iter n D0 Nil).
- rewrite <-of_int_iter_D0, to_of.
- now rewrite norm_app_int_norm; [|induction n].
- * simpl Qden; intros _ H; exfalso; revert H; apply Hn1.
- - case d; clear d; intros i f; [|intro e']; simpl.
- + case_eq (nb_digits f); [|intros nf' Hnf'];
- [now simpl; intros _ H; exfalso; symmetry in H; revert H; apply Hn1|].
- unfold Z.of_nat, Z.opp.
- simpl Qden.
- intro H; injection H; clear H; unfold Pos.pow.
- rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (SuccNat2Pos.inj _ _ ((Pos2Nat.inj _ _ H))); clear H.
- intro He; rewrite <-He; clear e He.
- simpl Qnum.
- case Nat.ltb; [left|right].
- * now rewrite <-to_of, DecimalZ.of_to, to_of.
- * rewrite to_of.
- set (nif := norm _).
- set (anif := match nif with Pos i0 => i0 | _ => _ end).
- set (r := DecimalExp nif Nil _).
- set (m := match _ with Pos _ => _ | _ => r end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { now unfold m; rewrite <-to_of, DecimalZ.of_to. }
- rewrite <-to_of, !DecimalZ.of_to.
- fold anif.
- now rewrite SuccNat2Pos.id_succ.
- + set (nemf := (_ - _)%Z); intro H.
- assert (H' : exists pnemf, nemf = Z.neg pnemf); [|revert H].
- { revert H; case nemf; [|intro pnemf..]; [..|now intros _; exists pnemf];
- simpl Qden; intro H; exfalso; symmetry in H; revert H; apply Hn1. }
- destruct H' as (pnemf,Hpnemf); rewrite Hpnemf.
- simpl Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H.
- intro H; revert Hpnemf; rewrite H; clear pnemf H; intro Hnemf.
- simpl Qnum.
- case Nat.ltb; [left|right].
- * now rewrite <-to_of, DecimalZ.of_to, to_of.
- * rewrite to_of.
- set (nif := norm _).
- set (anif := match nif with Pos i0 => i0 | _ => _ end).
- set (r := DecimalExp nif Nil _).
- set (m := match _ with Pos _ => _ | _ => r end).
- assert (H : m = r); [|rewrite H; unfold m, r; clear m r H].
- { now unfold m; rewrite <-to_of, DecimalZ.of_to. }
- rewrite <-to_of, !DecimalZ.of_to.
- fold anif.
- now rewrite SuccNat2Pos.id_succ.
+ case d as [i f|i f e].
+ - unfold of_decimal; simpl; unfold IQmake_to_decimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_decimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 10).
+ rewrite nztail_to_uint_pow10, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ + rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ + rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ * rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ * rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ - unfold of_decimal; simpl.
+ rewrite <-to_of.
+ case (Z.of_int e); clear e; [|intro e..]; simpl.
+ + unfold IQmake_to_decimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_decimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 10).
+ rewrite nztail_to_uint_pow10, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ + unfold IQmake_to_decimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_decimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 10).
+ rewrite nztail_to_uint_pow10, to_of.
+ generalize (Unsigned.to_uint_nonzero e); intro He.
+ set (dnorm_i := match i with Pos _ => _ | _ => _ end).
+ set (m := match Pos.to_uint e with Nil => _ | _ => _ end).
+ replace m with (DecimalExp dnorm_i f (Pos (Pos.to_uint e))).
+ 2:{ now unfold m; revert He; case (Pos.to_uint e); [|intro u; case u|..]. }
+ clear m; unfold dnorm_i.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ + unfold IQmake_to_decimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_decimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 10).
+ rewrite nztail_to_uint_pow10, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
Qed.
(** Some consequences *)
@@ -478,84 +436,24 @@ Proof.
now intros d _ H1 H2; rewrite <-(H1 d eq_refl), <-(H2 d eq_refl).
Qed.
-Lemma to_decimal_surj d :
- exists q, to_decimal q = Some (dnorme d) \/ to_decimal q = Some (dnormf d).
+Lemma to_decimal_surj d : exists q, to_decimal q = Some (dnorm d).
Proof.
exists (of_decimal d). apply to_of.
Qed.
-Lemma of_decimal_dnorme d : of_decimal (dnorme d) = of_decimal d.
+Lemma of_decimal_dnorm d : of_decimal (dnorm d) = of_decimal d.
+Proof. now apply to_decimal_inj; rewrite !to_of; [|rewrite dnorm_involutive]. Qed.
+
+Lemma of_inj d d' : of_decimal d = of_decimal d' -> dnorm d = dnorm d'.
Proof.
- unfold of_decimal, dnorme.
- destruct d.
- - rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- case_eq (nb_digits f); [|intro nf]; intro Hnf.
- + now simpl; rewrite app_int_nil_r, <-DecimalZ.to_of, DecimalZ.of_to.
- + simpl; rewrite Z.sub_0_r.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- rewrite app_int_nil_r.
- now rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- - rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- set (emf := (_ - _)%Z).
- case_eq emf; [|intro pemf..]; intro Hemf.
- + now simpl; rewrite app_int_nil_r, <-DecimalZ.to_of, DecimalZ.of_to.
- + simpl.
- set (r := DecimalExp _ Nil _).
- set (m := match Pos.to_uint pemf with zero => _ | _ => r end).
- assert (H : m = r); [|rewrite H; unfold r; clear m r H].
- { generalize (Unsigned.to_uint_nonzero pemf).
- now unfold m; case Pos.to_uint; [|intro u; case u|..]. }
- simpl; rewrite Z.sub_0_r.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- rewrite app_int_nil_r.
- now rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- + simpl.
- unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
- rewrite app_int_nil_r.
- now rewrite <-DecimalZ.to_of, DecimalZ.of_to.
+ intro H.
+ apply (@f_equal _ _ (fun x => match x with Some x => x | _ => d end)
+ (Some (dnorm d)) (Some (dnorm d'))).
+ now rewrite <- !to_of, H.
Qed.
-Lemma of_decimal_dnormf d : of_decimal (dnormf d) = of_decimal d.
+Lemma of_iff d d' : of_decimal d = of_decimal d' <-> dnorm d = dnorm d'.
Proof.
- rewrite <-(of_decimal_dnorme d).
- unfold of_decimal, dnormf.
- assert (H : match dnorme d with Decimal _ f | DecimalExp _ f _ => f end = Nil).
- { now unfold dnorme; destruct d;
- (case norm; intro d; [case d; [|intro u; case u|..]|]). }
- revert H; generalize (dnorme d); clear d; intro d.
- destruct d; intro H; rewrite H; clear H; [now simpl|].
- case (Z.of_int e); clear e; [|intro e..].
- - now simpl.
- - simpl.
- rewrite app_int_nil_r.
- apply f_equal2; [|reflexivity].
- rewrite app_int_nil_r.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- rewrite !Pos2Nat.inj_iter.
- fold (Nat.iter (Pos.to_nat e) D0 Nil).
- now rewrite of_int_iter_D0.
- - simpl.
- set (ai := match i with Pos _ => _ | _ => _ end).
- rewrite app_int_nil_r.
- case Nat.ltb_spec; intro Hei; simpl.
- + rewrite nb_digits_del_head; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
- rewrite Nat2Z.inj_sub; [|now apply le_Sn_le].
- rewrite Z.sub_sub_distr, Z.sub_diag; simpl.
- rewrite positive_nat_Z; simpl.
- now revert Hei; unfold ai; case i; clear i ai; intros i Hei; simpl;
- (rewrite app_del_tail_head; [|now apply le_Sn_le]).
- + set (n := nb_digits _).
- assert (H : (n = Pos.to_nat e - nb_digits ai + nb_digits ai)%nat).
- { unfold n; induction (_ - _)%nat; [now simpl|].
- now rewrite Unsigned.nat_iter_S; simpl; rewrite IHn0. }
- rewrite H; clear n H.
- rewrite Nat2Z.inj_add, (Nat2Z.inj_sub _ _ Hei).
- rewrite <-Z.sub_sub_distr, Z.sub_diag, Z.sub_0_r.
- rewrite positive_nat_Z; simpl.
- rewrite <-(DecimalZ.of_to (Z.of_int (app_int _ _))), DecimalZ.to_of.
- rewrite <-(DecimalZ.of_to (Z.of_int i)), DecimalZ.to_of.
- apply f_equal2; [|reflexivity]; apply f_equal.
- now unfold ai; case i; clear i ai Hei; intro i;
- (induction (_ - _)%nat; [|rewrite <-IHn]).
+ split. apply of_inj. intros E. rewrite <- of_decimal_dnorm, E.
+ apply of_decimal_dnorm.
Qed.
diff --git a/theories/Numbers/DecimalR.v b/theories/Numbers/DecimalR.v
new file mode 100644
index 0000000000..9b65a7dc20
--- /dev/null
+++ b/theories/Numbers/DecimalR.v
@@ -0,0 +1,312 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** * DecimalR
+
+ Proofs that conversions between decimal numbers and [R]
+ are bijections. *)
+
+Require Import Decimal DecimalFacts DecimalPos DecimalZ DecimalQ Rdefinitions.
+
+Lemma of_IQmake_to_decimal num den :
+ match IQmake_to_decimal num den with
+ | None => True
+ | Some (DecimalExp _ _ _) => False
+ | Some (Decimal i f) =>
+ of_decimal (Decimal i f) = IRQ (QArith_base.Qmake num den)
+ end.
+Proof.
+ unfold IQmake_to_decimal.
+ case (Pos.eq_dec den 1); [now intros->|intro Hden].
+ assert (Hf : match QArith_base.IQmake_to_decimal num den with
+ | Some (Decimal i f) => f <> Nil
+ | _ => True
+ end).
+ { unfold QArith_base.IQmake_to_decimal; simpl.
+ generalize (Unsigned.nztail_to_uint den).
+ case Decimal.nztail as [den' e_den'].
+ case den'; [now simpl|now simpl| |now simpl..]; clear den'; intro den'.
+ case den'; [ |now simpl..]; clear den'.
+ case e_den' as [|e_den']; [now simpl; intros H _; apply Hden; injection H|].
+ intros _.
+ case Nat.ltb_spec; intro He_den'.
+ - apply del_head_nonnil.
+ revert He_den'; case nb_digits as [|n]; [now simpl|].
+ now intro H; simpl; apply le_lt_n_Sm, Nat.le_sub_l.
+ - apply nb_digits_n0.
+ now rewrite nb_digits_iter_D0, Nat.sub_add. }
+ replace (match den with 1%positive => _ | _ => _ end)
+ with (QArith_base.IQmake_to_decimal num den); [|now revert Hden; case den].
+ generalize (of_IQmake_to_decimal num den).
+ case QArith_base.IQmake_to_decimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ unfold of_decimal; simpl.
+ intro H; injection H; clear H; intros <-.
+ intro H; generalize (f_equal QArith_base.IZ_to_Z H); clear H.
+ rewrite !IZ_to_Z_IZ_of_Z; intro H; injection H; clear H; intros<-.
+ now revert Hf; case f.
+Qed.
+
+Lemma of_to (q:IR) : forall d, to_decimal q = Some d -> of_decimal d = q.
+Proof.
+ intro d.
+ case q as [z|q|r r'|r r']; simpl.
+ - case z as [z p| |p|p].
+ + now simpl.
+ + now simpl; intro H; injection H; clear H; intros<-.
+ + simpl; intro H; injection H; clear H; intros<-.
+ now unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to.
+ + simpl; intro H; injection H; clear H; intros<-.
+ now unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to.
+ - case q as [num den].
+ generalize (of_IQmake_to_decimal num den).
+ case IQmake_to_decimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ now intros H H'; injection H'; intros<-.
+ - case r as [z|q| |]; [|case q as[num den]|now simpl..];
+ (case r' as [z'| | |]; [|now simpl..]);
+ (case z' as [p e| | |]; [|now simpl..]).
+ + case (Z.eq_dec p 10); [intros->|intro Hp].
+ 2:{ revert Hp; case p; [now simpl|intro d0..];
+ (case d0; [intro d1..|]; [now simpl| |now simpl];
+ case d1; [intro d2..|]; [|now simpl..];
+ case d2; [intro d3..|]; [now simpl| |now simpl];
+ now case d3). }
+ case z as [| |p|p]; [now simpl|..]; intro H; injection H; intros<-.
+ * now unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to.
+ * unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to; simpl.
+ now rewrite Unsigned.of_to.
+ * unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to; simpl.
+ now rewrite Unsigned.of_to.
+ + case (Z.eq_dec p 10); [intros->|intro Hp].
+ 2:{ revert Hp; case p; [now simpl|intro d0..];
+ (case d0; [intro d1..|]; [now simpl| |now simpl];
+ case d1; [intro d2..|]; [|now simpl..];
+ case d2; [intro d3..|]; [now simpl| |now simpl];
+ now case d3). }
+ generalize (of_IQmake_to_decimal num den).
+ case IQmake_to_decimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros H H'; injection H'; clear H'; intros<-.
+ unfold of_decimal; simpl.
+ change (match f with Nil => _ | _ => _ end) with (of_decimal (Decimal i f)).
+ rewrite H; clear H.
+ now unfold Z.of_uint; rewrite Unsigned.of_to.
+ - case r as [z|q| |]; [|case q as[num den]|now simpl..];
+ (case r' as [z'| | |]; [|now simpl..]);
+ (case z' as [p e| | |]; [|now simpl..]).
+ + case (Z.eq_dec p 10); [intros->|intro Hp].
+ 2:{ revert Hp; case p; [now simpl|intro d0..];
+ (case d0; [intro d1..|]; [now simpl| |now simpl];
+ case d1; [intro d2..|]; [|now simpl..];
+ case d2; [intro d3..|]; [now simpl| |now simpl];
+ now case d3). }
+ case z as [| |p|p]; [now simpl|..]; intro H; injection H; intros<-.
+ * now unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to.
+ * unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to; simpl.
+ now rewrite Unsigned.of_to.
+ * unfold of_decimal; simpl; unfold Z.of_uint; rewrite Unsigned.of_to; simpl.
+ now rewrite Unsigned.of_to.
+ + case (Z.eq_dec p 10); [intros->|intro Hp].
+ 2:{ revert Hp; case p; [now simpl|intro d0..];
+ (case d0; [intro d1..|]; [now simpl| |now simpl];
+ case d1; [intro d2..|]; [|now simpl..];
+ case d2; [intro d3..|]; [now simpl| |now simpl];
+ now case d3). }
+ generalize (of_IQmake_to_decimal num den).
+ case IQmake_to_decimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros H H'; injection H'; clear H'; intros<-.
+ unfold of_decimal; simpl.
+ change (match f with Nil => _ | _ => _ end) with (of_decimal (Decimal i f)).
+ rewrite H; clear H.
+ now unfold Z.of_uint; rewrite Unsigned.of_to.
+Qed.
+
+Lemma to_of (d:decimal) : to_decimal (of_decimal d) = Some (dnorm d).
+Proof.
+ case d as [i f|i f e].
+ - unfold of_decimal; simpl.
+ case (uint_eq_dec f Nil); intro Hf.
+ + rewrite Hf; clear f Hf.
+ unfold to_decimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, DecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ + set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_decimal; simpl.
+ unfold IQmake_to_decimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_decimal (Z.of_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_decimal, n; simpl.
+ rewrite nztail_to_uint_pow10.
+ clear r; set (r := if _ <? _ then Some (Decimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite DecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ * rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ * rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ - unfold of_decimal; simpl.
+ rewrite <-(DecimalZ.to_of e).
+ case (Z.of_int e); clear e; [|intro e..]; simpl.
+ + case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_decimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, DecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_decimal; simpl.
+ unfold IQmake_to_decimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_decimal (Z.of_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_decimal, n; simpl.
+ rewrite nztail_to_uint_pow10.
+ clear r; set (r := if _ <? _ then Some (Decimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite DecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ + set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match Pos.to_uint e with Nil => _ | _ => _ end).
+ replace m with (DecimalExp i' f (Pos (Pos.to_uint e))).
+ 2:{ unfold m; generalize (Unsigned.to_uint_nonzero e).
+ now case Pos.to_uint; [|intro u; case u|..]. }
+ unfold i'; clear i' m.
+ case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_decimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, DecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_decimal; simpl.
+ unfold IQmake_to_decimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_decimal (Z.of_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_decimal, n; simpl.
+ rewrite nztail_to_uint_pow10.
+ clear r; set (r := if _ <? _ then Some (Decimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite DecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ + case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_decimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, DecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_decimal; simpl.
+ unfold IQmake_to_decimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_decimal (Z.of_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_decimal, n; simpl.
+ rewrite nztail_to_uint_pow10.
+ clear r; set (r := if _ <? _ then Some (Decimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite DecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+Qed.
+
+(** Some consequences *)
+
+Lemma to_decimal_inj q q' :
+ to_decimal q <> None -> to_decimal q = to_decimal q' -> q = q'.
+Proof.
+ intros Hnone EQ.
+ generalize (of_to q) (of_to q').
+ rewrite <-EQ.
+ revert Hnone; case to_decimal; [|now simpl].
+ now intros d _ H1 H2; rewrite <-(H1 d eq_refl), <-(H2 d eq_refl).
+Qed.
+
+Lemma to_decimal_surj d : exists q, to_decimal q = Some (dnorm d).
+Proof.
+ exists (of_decimal d). apply to_of.
+Qed.
+
+Lemma of_decimal_dnorm d : of_decimal (dnorm d) = of_decimal d.
+Proof. now apply to_decimal_inj; rewrite !to_of; [|rewrite dnorm_involutive]. Qed.
+
+Lemma of_inj d d' : of_decimal d = of_decimal d' -> dnorm d = dnorm d'.
+Proof.
+ intro H.
+ apply (@f_equal _ _ (fun x => match x with Some x => x | _ => d end)
+ (Some (dnorm d)) (Some (dnorm d'))).
+ now rewrite <- !to_of, H.
+Qed.
+
+Lemma of_iff d d' : of_decimal d = of_decimal d' <-> dnorm d = dnorm d'.
+Proof.
+ split. apply of_inj. intros E. rewrite <- of_decimal_dnorm, E.
+ apply of_decimal_dnorm.
+Qed.
diff --git a/theories/Numbers/DecimalZ.v b/theories/Numbers/DecimalZ.v
index 69d8073fc7..faaf8a3932 100644
--- a/theories/Numbers/DecimalZ.v
+++ b/theories/Numbers/DecimalZ.v
@@ -79,9 +79,11 @@ Qed.
Lemma of_uint_iter_D0 d n :
Z.of_uint (app d (Nat.iter n D0 Nil)) = Nat.iter n (Z.mul 10) (Z.of_uint d).
Proof.
- unfold Z.of_uint.
- unfold app; rewrite <-rev_revapp.
- rewrite Unsigned.of_lu_rev, Unsigned.of_lu_revapp.
+ rewrite <-(rev_rev (app _ _)), <-(of_list_to_list (rev (app _ _))).
+ rewrite rev_spec, app_spec, List.rev_app_distr.
+ rewrite <-!rev_spec, <-app_spec, of_list_to_list.
+ unfold Z.of_uint; rewrite Unsigned.of_lu_rev.
+ unfold app; rewrite Unsigned.of_lu_revapp, !rev_rev.
rewrite <-!Unsigned.of_lu_rev, !rev_rev.
assert (H' : Pos.of_uint (Nat.iter n D0 Nil) = 0%N).
{ now induction n; [|rewrite Unsigned.nat_iter_S]. }
@@ -100,3 +102,22 @@ Proof.
- rewrite of_uint_iter_D0; induction n; [now simpl|].
rewrite !Unsigned.nat_iter_S, <-IHn; ring.
Qed.
+
+Lemma nztail_to_uint_pow10 n :
+ Decimal.nztail (Pos.to_uint (Nat.iter n (Pos.mul 10) 1%positive))
+ = (D1 Nil, n).
+Proof.
+ case n as [|n]; [now simpl|].
+ rewrite <-(Nat2Pos.id (S n)); [|now simpl].
+ generalize (Pos.of_nat (S n)); clear n; intro p.
+ induction (Pos.to_nat p); [now simpl|].
+ rewrite Unsigned.nat_iter_S.
+ unfold Pos.to_uint.
+ change (Pos.to_little_uint _)
+ with (Unsigned.to_lu (10 * N.pos (Nat.iter n (Pos.mul 10) 1%positive))).
+ rewrite Unsigned.to_ldec_tenfold.
+ revert IHn; unfold Pos.to_uint.
+ unfold Decimal.nztail; rewrite !rev_rev; simpl.
+ set (f'' := _ (Pos.to_little_uint _)).
+ now case f''; intros r n' H; inversion H.
+Qed.
diff --git a/theories/Numbers/HexadecimalFacts.v b/theories/Numbers/HexadecimalFacts.v
index 7328b2303d..c624b4e6b9 100644
--- a/theories/Numbers/HexadecimalFacts.v
+++ b/theories/Numbers/HexadecimalFacts.v
@@ -10,136 +10,437 @@
(** * HexadecimalFacts : some facts about Hexadecimal numbers *)
-Require Import Hexadecimal Arith.
+Require Import Hexadecimal Arith ZArith.
+
+Variant digits :=
+ | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | d8 | d9
+ | da | db | dc | dd | de | df.
+
+Fixpoint to_list (u : uint) : list digits :=
+ match u with
+ | Nil => nil
+ | D0 u => cons d0 (to_list u)
+ | D1 u => cons d1 (to_list u)
+ | D2 u => cons d2 (to_list u)
+ | D3 u => cons d3 (to_list u)
+ | D4 u => cons d4 (to_list u)
+ | D5 u => cons d5 (to_list u)
+ | D6 u => cons d6 (to_list u)
+ | D7 u => cons d7 (to_list u)
+ | D8 u => cons d8 (to_list u)
+ | D9 u => cons d9 (to_list u)
+ | Da u => cons da (to_list u)
+ | Db u => cons db (to_list u)
+ | Dc u => cons dc (to_list u)
+ | Dd u => cons dd (to_list u)
+ | De u => cons de (to_list u)
+ | Df u => cons df (to_list u)
+ end.
+
+Fixpoint of_list (l : list digits) : uint :=
+ match l with
+ | nil => Nil
+ | cons d0 l => D0 (of_list l)
+ | cons d1 l => D1 (of_list l)
+ | cons d2 l => D2 (of_list l)
+ | cons d3 l => D3 (of_list l)
+ | cons d4 l => D4 (of_list l)
+ | cons d5 l => D5 (of_list l)
+ | cons d6 l => D6 (of_list l)
+ | cons d7 l => D7 (of_list l)
+ | cons d8 l => D8 (of_list l)
+ | cons d9 l => D9 (of_list l)
+ | cons da l => Da (of_list l)
+ | cons db l => Db (of_list l)
+ | cons dc l => Dc (of_list l)
+ | cons dd l => Dd (of_list l)
+ | cons de l => De (of_list l)
+ | cons df l => Df (of_list l)
+ end.
-Scheme Equality for uint.
+Lemma of_list_to_list u : of_list (to_list u) = u.
+Proof. now induction u; [|simpl; rewrite IHu..]. Qed.
-Scheme Equality for int.
+Lemma to_list_of_list l : to_list (of_list l) = l.
+Proof. now induction l as [|h t IHl]; [|case h; simpl; rewrite IHl]. Qed.
-Lemma rev_revapp d d' :
- rev (revapp d d') = revapp d' d.
+Lemma to_list_inj u u' : to_list u = to_list u' -> u = u'.
Proof.
- revert d'. induction d; simpl; intros; now rewrite ?IHd.
+ now intro H; rewrite <-(of_list_to_list u), <-(of_list_to_list u'), H.
Qed.
-Lemma rev_rev d : rev (rev d) = d.
+Lemma of_list_inj u u' : of_list u = of_list u' -> u = u'.
Proof.
- apply rev_revapp.
+ now intro H; rewrite <-(to_list_of_list u), <-(to_list_of_list u'), H.
Qed.
-Lemma revapp_rev_nil d : revapp (rev d) Nil = d.
-Proof. now fold (rev (rev d)); rewrite rev_rev. Qed.
+Lemma nb_digits_spec u : nb_digits u = length (to_list u).
+Proof. now induction u; [|simpl; rewrite IHu..]. Qed.
-Lemma app_nil_r d : app d Nil = d.
-Proof. now unfold app; rewrite revapp_rev_nil. Qed.
+Fixpoint lnzhead l :=
+ match l with
+ | nil => nil
+ | cons d l' =>
+ match d with
+ | d0 => lnzhead l'
+ | _ => l
+ end
+ end.
-Lemma app_int_nil_r d : app_int d Nil = d.
-Proof. now case d; intro d'; simpl; rewrite app_nil_r. Qed.
+Lemma nzhead_spec u : to_list (nzhead u) = lnzhead (to_list u).
+Proof. now induction u; [|simpl; rewrite IHu|..]. Qed.
+
+Definition lzero := cons d0 nil.
+
+Definition lunorm l :=
+ match lnzhead l with
+ | nil => lzero
+ | d => d
+ end.
+
+Lemma unorm_spec u : to_list (unorm u) = lunorm (to_list u).
+Proof. now unfold unorm, lunorm; rewrite <-nzhead_spec; case (nzhead u). Qed.
+
+Lemma revapp_spec d d' :
+ to_list (revapp d d') = List.rev_append (to_list d) (to_list d').
+Proof. now revert d'; induction d; intro d'; [|simpl; rewrite IHd..]. Qed.
+
+Lemma rev_spec d : to_list (rev d) = List.rev (to_list d).
+Proof. now unfold rev; rewrite revapp_spec, List.rev_alt; simpl. Qed.
+
+Lemma app_spec d d' :
+ to_list (app d d') = Datatypes.app (to_list d) (to_list d').
+Proof.
+ unfold app.
+ now rewrite revapp_spec, List.rev_append_rev, rev_spec, List.rev_involutive.
+Qed.
-Lemma revapp_revapp_1 d d' d'' :
- nb_digits d <= 1 ->
- revapp (revapp d d') d'' = revapp d' (revapp d d'').
+Definition lnztail l :=
+ let fix aux l_rev :=
+ match l_rev with
+ | cons d0 l_rev => let (r, n) := aux l_rev in pair r (S n)
+ | _ => pair l_rev O
+ end in
+ let (r, n) := aux (List.rev l) in pair (List.rev r) n.
+
+Lemma nztail_spec d :
+ let (r, n) := nztail d in
+ let (r', n') := lnztail (to_list d) in
+ to_list r = r' /\ n = n'.
Proof.
- now case d; clear d; intro d;
- [|case d; clear d; intro d;
- [|simpl; case nb_digits; [|intros n]; intros Hn; exfalso;
- [apply (Nat.nle_succ_diag_l _ Hn)|
- apply (Nat.nle_succ_0 _ (le_S_n _ _ Hn))]..]..].
+ unfold nztail, lnztail.
+ set (f := fix aux d_rev := match d_rev with
+ | D0 d_rev => let (r, n) := aux d_rev in (r, S n)
+ | _ => (d_rev, 0) end).
+ set (f' := fix aux (l_rev : list digits) : list digits * nat :=
+ match l_rev with
+ | cons d0 l_rev => let (r, n) := aux l_rev in (r, S n)
+ | _ => (l_rev, 0)
+ end).
+ rewrite <-(of_list_to_list (rev d)), rev_spec.
+ induction (List.rev _) as [|h t IHl]; [now simpl|].
+ case h; simpl; [|now rewrite rev_spec; simpl; rewrite to_list_of_list..].
+ now revert IHl; case f; intros r n; case f'; intros r' n' [-> ->].
Qed.
-Lemma nb_digits_pos d : d <> Nil -> 0 < nb_digits d.
-Proof. now case d; [|intros d' _; apply Nat.lt_0_succ..]. Qed.
+Lemma del_head_spec_0 d : del_head 0 d = d.
+Proof. now simpl. Qed.
-Lemma nb_digits_revapp d d' :
- nb_digits (revapp d d') = nb_digits d + nb_digits d'.
+Lemma del_head_spec_small n d :
+ n <= length (to_list d) -> to_list (del_head n d) = List.skipn n (to_list d).
Proof.
- now revert d'; induction d; [|intro d'; simpl; rewrite IHd; simpl..].
+ revert d; induction n as [|n IHn]; intro d; [now simpl|].
+ now case d; [|intros d' H; apply IHn, le_S_n..].
Qed.
-Lemma nb_digits_rev u : nb_digits (rev u) = nb_digits u.
-Proof. now unfold rev; rewrite nb_digits_revapp. Qed.
+Lemma del_head_spec_large n d : length (to_list d) < n -> del_head n d = zero.
+Proof.
+ revert d; induction n; intro d; [now case d|].
+ now case d; [|intro d'; simpl; intro H; rewrite (IHn _ (lt_S_n _ _ H))..].
+Qed.
-Lemma nb_digits_nzhead u : nb_digits (nzhead u) <= nb_digits u.
-Proof. now induction u; [|apply le_S|..]. Qed.
+Lemma nb_digits_0 d : nb_digits d = 0 -> d = Nil.
+Proof.
+ rewrite nb_digits_spec, <-(of_list_to_list d).
+ now case (to_list d) as [|h t]; [|rewrite to_list_of_list].
+Qed.
+
+Lemma nb_digits_n0 d : nb_digits d <> 0 -> d <> Nil.
+Proof. now case d; [|intros u _..]. Qed.
Lemma nb_digits_iter_D0 n d :
nb_digits (Nat.iter n D0 d) = n + nb_digits d.
Proof. now induction n; simpl; [|rewrite IHn]. Qed.
-Fixpoint nth n u :=
- match n with
- | O =>
- match u with
- | Nil => Nil
- | D0 d => D0 Nil
- | D1 d => D1 Nil
- | D2 d => D2 Nil
- | D3 d => D3 Nil
- | D4 d => D4 Nil
- | D5 d => D5 Nil
- | D6 d => D6 Nil
- | D7 d => D7 Nil
- | D8 d => D8 Nil
- | D9 d => D9 Nil
- | Da d => Da Nil
- | Db d => Db Nil
- | Dc d => Dc Nil
- | Dd d => Dd Nil
- | De d => De Nil
- | Df d => Df Nil
- end
- | S n =>
- match u with
- | Nil => Nil
- | D0 d | D1 d | D2 d | D3 d | D4 d | D5 d | D6 d | D7 d | D8 d | D9 d
- | Da d | Db d | Dc d | Dd d | De d | Df d =>
- nth n d
- end
- end.
+Lemma length_lnzhead l : length (lnzhead l) <= length l.
+Proof. now induction l as [|h t IHl]; [|case h; [apply le_S|..]]. Qed.
+
+Lemma nb_digits_nzhead u : nb_digits (nzhead u) <= nb_digits u.
+Proof. now induction u; [|apply le_S|..]. Qed.
-Lemma nb_digits_nth n u : nb_digits (nth n u) <= 1.
-Proof.
- revert u; induction n.
- - now intro u; case u; [apply Nat.le_0_1|..].
- - intro u; case u; [apply Nat.le_0_1|intro u'; apply IHn..].
-Qed.
-
-Lemma nth_revapp_r n d d' :
- nb_digits d <= n ->
- nth n (revapp d d') = nth (n - nb_digits d) d'.
-Proof.
- revert d d'; induction n; intro d.
- - now case d; intro d';
- [case d'|intros d'' H; exfalso; revert H; apply Nat.nle_succ_0..].
- - now induction d;
- [intro d'; case d'|
- intros d' H;
- simpl revapp; rewrite IHd; [|now apply le_Sn_le];
- rewrite Nat.sub_succ_l; [|now apply le_S_n];
- simpl; rewrite <-(IHn _ _ (le_S_n _ _ H))..].
-Qed.
-
-Lemma nth_revapp_l n d d' :
- n < nb_digits d ->
- nth n (revapp d d') = nth (nb_digits d - n - 1) d.
-Proof.
- revert d d'; induction n; intro d.
- - rewrite Nat.sub_0_r.
- now induction d;
- [|intros d' _; simpl revapp;
- revert IHd; case d; clear d; [|intro d..]; intro IHd;
- [|rewrite IHd; [simpl nb_digits; rewrite (Nat.sub_succ_l _ (S _))|];
- [|apply le_n_S, Nat.le_0_l..]..]..].
- - now induction d;
- [|intros d' H;
- simpl revapp; simpl nb_digits;
- simpl in H; generalize (lt_S_n _ _ H); clear H; intro H;
- case (le_lt_eq_dec _ _ H); clear H; intro H;
- [rewrite (IHd _ H), Nat.sub_succ_l;
- [rewrite Nat.sub_succ_l; [|apply Nat.le_add_le_sub_r]|
- apply le_Sn_le]|
- rewrite nth_revapp_r; rewrite <-H;
- [rewrite Nat.sub_succ, Nat.sub_succ_l; [rewrite !Nat.sub_diag|]|]]..].
+Lemma unorm_nzhead u : nzhead u <> Nil -> unorm u = nzhead u.
+Proof. now unfold unorm; case nzhead. Qed.
+
+Lemma nb_digits_unorm u : u <> Nil -> nb_digits (unorm u) <= nb_digits u.
+Proof.
+ intro Hu; case (uint_eq_dec (nzhead u) Nil).
+ { unfold unorm; intros ->; simpl.
+ now revert Hu; case u; [|intros u' _; apply le_n_S, Nat.le_0_l..]. }
+ intro H; rewrite (unorm_nzhead _ H); apply nb_digits_nzhead.
+Qed.
+
+Lemma nb_digits_rev d : nb_digits (rev d) = nb_digits d.
+Proof. now rewrite !nb_digits_spec, rev_spec, List.rev_length. Qed.
+
+Lemma nb_digits_del_head_sub d n :
+ n <= nb_digits d ->
+ nb_digits (del_head (nb_digits d - n) d) = n.
+Proof.
+ rewrite !nb_digits_spec; intro Hn.
+ rewrite del_head_spec_small; [|now apply Nat.le_sub_l].
+ rewrite List.skipn_length, <-(Nat2Z.id (_ - _)).
+ rewrite Nat2Z.inj_sub; [|now apply Nat.le_sub_l].
+ rewrite (Nat2Z.inj_sub _ _ Hn).
+ rewrite Z.sub_sub_distr, Z.sub_diag; apply Nat2Z.id.
+Qed.
+
+Lemma unorm_D0 u : unorm (D0 u) = unorm u.
+Proof. reflexivity. Qed.
+
+Lemma app_nil_l d : app Nil d = d.
+Proof. now simpl. Qed.
+
+Lemma app_nil_r d : app d Nil = d.
+Proof. now apply to_list_inj; rewrite app_spec, List.app_nil_r. Qed.
+
+Lemma abs_app_int d d' : abs (app_int d d') = app (abs d) d'.
+Proof. now case d. Qed.
+
+Lemma abs_norm d : abs (norm d) = unorm (abs d).
+Proof. now case d as [u|u]; [|simpl; unfold unorm; case nzhead]. Qed.
+
+Lemma iter_D0_nzhead d :
+ Nat.iter (nb_digits d - nb_digits (nzhead d)) D0 (nzhead d) = d.
+Proof.
+ induction d; [now simpl| |now rewrite Nat.sub_diag..].
+ simpl nzhead; simpl nb_digits.
+ rewrite (Nat.sub_succ_l _ _ (nb_digits_nzhead _)).
+ now rewrite <-IHd at 4.
+Qed.
+
+Lemma iter_D0_unorm d :
+ d <> Nil ->
+ Nat.iter (nb_digits d - nb_digits (unorm d)) D0 (unorm d) = d.
+Proof.
+ case (uint_eq_dec (nzhead d) Nil); intro Hn.
+ { unfold unorm; rewrite Hn; simpl; intro H.
+ revert H Hn; induction d; [now simpl|intros _|now intros _..].
+ case (uint_eq_dec d Nil); simpl; intros H Hn; [now rewrite H|].
+ rewrite Nat.sub_0_r, (le_plus_minus 1 (nb_digits d)).
+ { now simpl; rewrite IHd. }
+ revert H; case d; [now simpl|intros u _; apply le_n_S, Nat.le_0_l..]. }
+ intros _; rewrite (unorm_nzhead _ Hn); apply iter_D0_nzhead.
+Qed.
+
+Lemma nzhead_app_l d d' :
+ nb_digits d' < nb_digits (nzhead (app d d')) ->
+ nzhead (app d d') = app (nzhead d) d'.
+Proof.
+ intro Hl; apply to_list_inj; revert Hl.
+ rewrite !nb_digits_spec, app_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl].
+ { now simpl; intro H; exfalso; revert H; apply le_not_lt, length_lnzhead. }
+ rewrite <-List.app_comm_cons.
+ now case h; [simpl; intro Hl; apply IHl|..].
+Qed.
+
+Lemma nzhead_app_r d d' :
+ nb_digits (nzhead (app d d')) <= nb_digits d' ->
+ nzhead (app d d') = nzhead d'.
+Proof.
+ intro Hl; apply to_list_inj; revert Hl.
+ rewrite !nb_digits_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ rewrite <-List.app_comm_cons.
+ now case h; [| simpl; rewrite List.app_length; intro Hl; exfalso; revert Hl;
+ apply le_not_lt, le_plus_r..].
+Qed.
+
+Lemma nzhead_app_nil_r d d' : nzhead (app d d') = Nil -> nzhead d' = Nil.
+Proof.
+now intro H; generalize H; rewrite nzhead_app_r; [|rewrite H; apply Nat.le_0_l].
+Qed.
+
+Lemma nzhead_app_nil d d' :
+ nb_digits (nzhead (app d d')) <= nb_digits d' -> nzhead d = Nil.
+Proof.
+ intro H; apply to_list_inj; revert H.
+ rewrite !nb_digits_spec, !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ now case h; [now simpl|..];
+ simpl;intro H; exfalso; revert H; apply le_not_lt;
+ rewrite List.app_length; apply le_plus_r.
+Qed.
+
+Lemma nzhead_app_nil_l d d' : nzhead (app d d') = Nil -> nzhead d = Nil.
+Proof.
+ intro H; apply to_list_inj; generalize (f_equal to_list H); clear H.
+ rewrite !nzhead_spec, app_spec.
+ induction (to_list d) as [|h t IHl]; [now simpl|].
+ now rewrite <-List.app_comm_cons; case h.
+Qed.
+
+Lemma unorm_app_zero d d' :
+ nb_digits (unorm (app d d')) <= nb_digits d' -> unorm d = zero.
+Proof.
+ unfold unorm.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { now intro Hn; rewrite Hn, (nzhead_app_nil_l _ _ Hn). }
+ intro H; fold (unorm (app d d')); rewrite (unorm_nzhead _ H); intro H'.
+ case (uint_eq_dec (nzhead d) Nil); [now intros->|].
+ intro H''; fold (unorm d); rewrite (unorm_nzhead _ H'').
+ exfalso; apply H''; revert H'; apply nzhead_app_nil.
+Qed.
+
+Lemma app_int_nil_r d : app_int d Nil = d.
+Proof.
+ now case d; intro d'; simpl;
+ rewrite <-(of_list_to_list (app _ _)), app_spec;
+ rewrite List.app_nil_r, of_list_to_list.
+Qed.
+
+Lemma unorm_app_l d d' :
+ nb_digits d' < nb_digits (unorm (app d d')) ->
+ unorm (app d d') = app (unorm d) d'.
+Proof.
+ case (uint_eq_dec d' Nil); [now intros->; rewrite !app_nil_r|intro Hd'].
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { unfold unorm; intros->; simpl; intro H; exfalso; revert H; apply le_not_lt.
+ now revert Hd'; case d'; [|intros d'' _; apply le_n_S, Peano.le_0_n..]. }
+ intro Ha; rewrite (unorm_nzhead _ Ha).
+ intro Hn; generalize Hn; rewrite (nzhead_app_l _ _ Hn).
+ rewrite !nb_digits_spec, app_spec, List.app_length.
+ case (uint_eq_dec (nzhead d) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply Nat.lt_irrefl. }
+ now intro H; rewrite (unorm_nzhead _ H).
+Qed.
+
+Lemma unorm_app_r d d' :
+ nb_digits (unorm (app d d')) <= nb_digits d' ->
+ unorm (app d d') = unorm d'.
+Proof.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { now unfold unorm; intro H; rewrite H, (nzhead_app_nil_r _ _ H). }
+ intro Ha; rewrite (unorm_nzhead _ Ha).
+ case (uint_eq_dec (nzhead d') Nil).
+ { now intros H H'; exfalso; apply Ha; rewrite nzhead_app_r. }
+ intro Hd'; rewrite (unorm_nzhead _ Hd'); apply nzhead_app_r.
+Qed.
+
+Lemma norm_app_int d d' :
+ nb_digits d' < nb_digits (unorm (app (abs d) d')) ->
+ norm (app_int d d') = app_int (norm d) d'.
+Proof.
+ case (uint_eq_dec d' Nil); [now intros->; rewrite !app_int_nil_r|intro Hd'].
+ case d as [d|d]; [now simpl; intro H; apply f_equal, unorm_app_l|].
+ simpl; unfold unorm.
+ case (uint_eq_dec (nzhead (app d d')) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply le_not_lt.
+ now revert Hd'; case d'; [|intros d'' _; apply le_n_S, Peano.le_0_n..]. }
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ intro Ha.
+ replace m with (nzhead (app d d')).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ intro Hn; generalize Hn; rewrite (nzhead_app_l _ _ Hn).
+ case (uint_eq_dec (app (nzhead d) d') Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply le_not_lt, Nat.le_0_l. }
+ clear m; set (m := match app _ _ with Nil => _ | _ => _ end).
+ intro Ha'.
+ replace m with (Neg (app (nzhead d) d')); [|now unfold m; revert Ha'; case app].
+ case (uint_eq_dec (nzhead d) Nil).
+ { intros->; simpl; intro H; exfalso; revert H; apply Nat.lt_irrefl. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ intro Hd.
+ now replace m with (Neg (nzhead d)); [|unfold m; revert Hd; case nzhead].
+Qed.
+
+Lemma del_head_nb_digits d : del_head (nb_digits d) d = Nil.
+Proof.
+ apply to_list_inj.
+ rewrite nb_digits_spec, del_head_spec_small; [|now simpl].
+ now rewrite List.skipn_all.
+Qed.
+
+Lemma del_tail_nb_digits d : del_tail (nb_digits d) d = Nil.
+Proof. now unfold del_tail; rewrite <-nb_digits_rev, del_head_nb_digits. Qed.
+
+Lemma del_head_app n d d' :
+ n <= nb_digits d -> del_head n (app d d') = app (del_head n d) d'.
+Proof.
+ rewrite nb_digits_spec; intro Hn.
+ apply to_list_inj.
+ rewrite del_head_spec_small.
+ 2:{ now rewrite app_spec, List.app_length; apply le_plus_trans. }
+ rewrite !app_spec, (del_head_spec_small _ _ Hn).
+ rewrite List.skipn_app.
+ now rewrite (proj2 (Nat.sub_0_le _ _) Hn).
+Qed.
+
+Lemma del_tail_app n d d' :
+ n <= nb_digits d' -> del_tail n (app d d') = app d (del_tail n d').
+Proof.
+ rewrite nb_digits_spec; intro Hn.
+ unfold del_tail.
+ rewrite <-(of_list_to_list (rev (app d d'))), rev_spec, app_spec.
+ rewrite List.rev_app_distr, <-!rev_spec, <-app_spec, of_list_to_list.
+ rewrite del_head_app; [|now rewrite nb_digits_spec, rev_spec, List.rev_length].
+ apply to_list_inj.
+ rewrite rev_spec, !app_spec, !rev_spec.
+ now rewrite List.rev_app_distr, List.rev_involutive.
+Qed.
+
+Lemma del_tail_app_int n d d' :
+ n <= nb_digits d' -> del_tail_int n (app_int d d') = app_int d (del_tail n d').
+Proof. now case d as [d|d]; simpl; intro H; rewrite del_tail_app. Qed.
+
+Lemma app_del_tail_head n (d:uint) :
+ n <= nb_digits d -> app (del_tail n d) (del_head (nb_digits d - n) d) = d.
+Proof.
+ rewrite nb_digits_spec; intro Hn; unfold del_tail.
+ rewrite <-(of_list_to_list (app _ _)), app_spec, rev_spec.
+ rewrite del_head_spec_small; [|now rewrite rev_spec, List.rev_length].
+ rewrite del_head_spec_small; [|now apply Nat.le_sub_l].
+ rewrite rev_spec.
+ set (n' := _ - n).
+ assert (Hn' : n = length (to_list d) - n').
+ { now apply plus_minus; rewrite Nat.add_comm; symmetry; apply le_plus_minus_r. }
+ now rewrite Hn', <-List.firstn_skipn_rev, List.firstn_skipn, of_list_to_list.
+Qed.
+
+Lemma app_int_del_tail_head n (d:int) :
+ n <= nb_digits (abs d) ->
+ app_int (del_tail_int n d) (del_head (nb_digits (abs d) - n) (abs d)) = d.
+Proof. now case d; clear d; simpl; intros u Hu; rewrite app_del_tail_head. Qed.
+
+Lemma del_head_app_int_exact i f :
+ nb_digits f < nb_digits (unorm (app (abs i) f)) ->
+ del_head (nb_digits (unorm (app (abs i) f)) - nb_digits f) (unorm (app (abs i) f)) = f.
+Proof.
+ simpl; intro Hnb; generalize Hnb; rewrite (unorm_app_l _ _ Hnb); clear Hnb.
+ replace (_ - _) with (nb_digits (unorm (abs i))).
+ - now rewrite del_head_app; [rewrite del_head_nb_digits|].
+ - rewrite !nb_digits_spec, app_spec, List.app_length.
+ now rewrite Nat.add_comm, minus_plus.
+Qed.
+
+Lemma del_tail_app_int_exact i f :
+ nb_digits f < nb_digits (unorm (app (abs i) f)) ->
+ del_tail_int (nb_digits f) (norm (app_int i f)) = norm i.
+Proof.
+ simpl; intro Hnb.
+ rewrite (norm_app_int _ _ Hnb).
+ rewrite del_tail_app_int; [|now simpl].
+ now rewrite del_tail_nb_digits, app_int_nil_r.
Qed.
(** Normalization on little-endian numbers *)
@@ -193,6 +494,9 @@ Proof.
apply nzhead_revapp.
Qed.
+Lemma rev_rev d : rev (rev d) = d.
+Proof. now apply to_list_inj; rewrite !rev_spec, List.rev_involutive. Qed.
+
Lemma rev_nztail_rev d :
rev (nztail (rev d)) = nzhead d.
Proof.
@@ -247,47 +551,128 @@ Proof.
unfold unorm. now destruct nzhead.
Qed.
-Lemma unorm_D0 u : unorm (D0 u) = unorm u.
-Proof. reflexivity. Qed.
-
Lemma unorm_iter_D0 n u : unorm (Nat.iter n D0 u) = unorm u.
Proof. now induction n. Qed.
-Lemma nb_digits_unorm u :
- u <> Nil -> nb_digits (unorm u) <= nb_digits u.
+Lemma del_head_nonnil n u :
+ n < nb_digits u -> del_head n u <> Nil.
Proof.
- case u; clear u; [now simpl|intro u..]; [|now simpl..].
- intros _; unfold unorm.
- case_eq (nzhead (D0 u)); [|now intros u' <-; apply nb_digits_nzhead..].
- intros _; apply le_n_S, Nat.le_0_l.
+ now revert n; induction u; intro n;
+ [|case n; [|intro n'; simpl; intro H; apply IHu, lt_S_n]..].
Qed.
-Lemma nzhead_invol d : nzhead (nzhead d) = nzhead d.
+Lemma del_tail_nonnil n u :
+ n < nb_digits u -> del_tail n u <> Nil.
+Proof.
+ unfold del_tail.
+ rewrite <-nb_digits_rev.
+ generalize (rev u); clear u; intro u.
+ intros Hu H.
+ generalize (rev_nil_inv _ H); clear H.
+ now apply del_head_nonnil.
+Qed.
+
+Lemma nzhead_involutive d : nzhead (nzhead d) = nzhead d.
Proof.
now induction d.
Qed.
+#[deprecated(since="8.13",note="Use nzhead_involutive instead.")]
+Notation nzhead_invol := nzhead_involutive (only parsing).
-Lemma nztail_invol d : nztail (nztail d) = nztail d.
+Lemma nztail_involutive d : nztail (nztail d) = nztail d.
Proof.
rewrite <-(rev_rev (nztail _)), <-(rev_rev (nztail d)), <-(rev_rev d).
- now rewrite !rev_nztail_rev, nzhead_invol.
+ now rewrite !rev_nztail_rev, nzhead_involutive.
Qed.
+#[deprecated(since="8.13",note="Use nztail_involutive instead.")]
+Notation nztail_invol := nztail_involutive (only parsing).
-Lemma unorm_invol d : unorm (unorm d) = unorm d.
+Lemma unorm_involutive d : unorm (unorm d) = unorm d.
Proof.
unfold unorm.
destruct (nzhead d) eqn:E; trivial.
destruct (nzhead_nonzero _ _ E).
Qed.
+#[deprecated(since="8.13",note="Use unorm_involutive instead.")]
+Notation unorm_invol := unorm_involutive (only parsing).
-Lemma norm_invol d : norm (norm d) = norm d.
+Lemma norm_involutive d : norm (norm d) = norm d.
Proof.
unfold norm.
destruct d.
- - f_equal. apply unorm_invol.
+ - f_equal. apply unorm_involutive.
- destruct (nzhead d) eqn:E; auto.
destruct (nzhead_nonzero _ _ E).
Qed.
+#[deprecated(since="8.13",note="Use norm_involutive instead.")]
+Notation norm_invol := norm_involutive (only parsing).
+
+Lemma lnzhead_neq_d0_head l l' : ~(lnzhead l = cons d0 l').
+Proof. now induction l as [|h t Il]; [|case h]. Qed.
+
+Lemma lnzhead_head_nd0 h t : h <> d0 -> lnzhead (cons h t) = cons h t.
+Proof. now case h. Qed.
+
+Lemma nzhead_del_tail_nzhead_eq n u :
+ nzhead u = u ->
+ n < nb_digits u ->
+ nzhead (del_tail n u) = del_tail n u.
+Proof.
+ rewrite nb_digits_spec, <-List.rev_length.
+ intros Hu Hn.
+ apply to_list_inj; unfold del_tail.
+ rewrite nzhead_spec, rev_spec.
+ rewrite del_head_spec_small; [|now rewrite rev_spec; apply Nat.lt_le_incl].
+ rewrite rev_spec.
+ rewrite List.skipn_rev, List.rev_involutive.
+ generalize (f_equal to_list Hu) Hn; rewrite nzhead_spec; intro Hu'.
+ case (to_list u) as [|h t].
+ { simpl; intro H; exfalso; revert H; apply le_not_lt, Peano.le_0_n. }
+ intro Hn'; generalize (Nat.sub_gt _ _ Hn'); rewrite List.rev_length.
+ case (_ - _); [now simpl|]; intros n' _.
+ rewrite List.firstn_cons, lnzhead_head_nd0; [now simpl|].
+ intro Hh; revert Hu'; rewrite Hh; apply lnzhead_neq_d0_head.
+Qed.
+
+Lemma nzhead_del_tail_nzhead n u :
+ n < nb_digits (nzhead u) ->
+ nzhead (del_tail n (nzhead u)) = del_tail n (nzhead u).
+Proof. apply nzhead_del_tail_nzhead_eq, nzhead_involutive. Qed.
+
+Lemma unorm_del_tail_unorm n u :
+ n < nb_digits (unorm u) ->
+ unorm (del_tail n (unorm u)) = del_tail n (unorm u).
+Proof.
+ case (uint_eq_dec (nzhead u) Nil).
+ - unfold unorm; intros->; case n; [now simpl|]; intro n'.
+ now simpl; intro H; exfalso; generalize (lt_S_n _ _ H).
+ - unfold unorm.
+ set (m := match nzhead u with Nil => zero | _ => _ end).
+ intros H.
+ replace m with (nzhead u).
+ + intros H'.
+ rewrite (nzhead_del_tail_nzhead _ _ H').
+ now generalize (del_tail_nonnil _ _ H'); case del_tail.
+ + now unfold m; revert H; case nzhead.
+Qed.
+
+Lemma norm_del_tail_int_norm n d :
+ n < nb_digits (match norm d with Pos d | Neg d => d end) ->
+ norm (del_tail_int n (norm d)) = del_tail_int n (norm d).
+Proof.
+ case d; clear d; intros u; simpl.
+ - now intro H; simpl; rewrite unorm_del_tail_unorm.
+ - case (uint_eq_dec (nzhead u) Nil); intro Hu.
+ + now rewrite Hu; case n; [|intros n' Hn'; generalize (lt_S_n _ _ Hn')].
+ + set (m := match nzhead u with Nil => Pos zero | _ => _ end).
+ replace m with (Neg (nzhead u)); [|now unfold m; revert Hu; case nzhead].
+ unfold del_tail_int.
+ clear m Hu.
+ simpl.
+ intro H; generalize (del_tail_nonnil _ _ H).
+ rewrite (nzhead_del_tail_nzhead _ _ H).
+ now case del_tail.
+Qed.
Lemma nzhead_app_nzhead d d' :
nzhead (app (nzhead d) d') = nzhead (app d d').
@@ -299,7 +684,7 @@ Proof.
generalize (nzhead_revapp d d').
generalize (nzhead_revapp_0 (nztail d) d').
generalize (nzhead_revapp (nztail d) d').
- rewrite nztail_invol.
+ rewrite nztail_involutive.
now case nztail;
[intros _ H _ H'; rewrite (H eq_refl), (H' eq_refl)
|intros d'' H _ H' _; rewrite H; [rewrite H'|]..].
@@ -336,5 +721,5 @@ Proof.
|rewrite H'; unfold r; clear m r H'];
unfold norm;
rewrite rev_rev, <-Hd'';
- rewrite nzhead_revapp; rewrite nztail_invol; [|rewrite Hd'']..].
+ rewrite nzhead_revapp; rewrite nztail_involutive; [|rewrite Hd'']..].
Qed.
diff --git a/theories/Numbers/HexadecimalN.v b/theories/Numbers/HexadecimalN.v
index f333e2b7f6..93ba82d14a 100644
--- a/theories/Numbers/HexadecimalN.v
+++ b/theories/Numbers/HexadecimalN.v
@@ -74,7 +74,7 @@ Proof.
destruct (norm d) eqn:Hd; intros [= <-].
unfold N.to_hex_int. rewrite Unsigned.to_of. f_equal.
revert Hd; destruct d; simpl.
- - intros [= <-]. apply unorm_invol.
+ - intros [= <-]. apply unorm_involutive.
- destruct (nzhead d); now intros [= <-].
Qed.
@@ -93,7 +93,7 @@ Qed.
Lemma of_int_norm d : N.of_hex_int (norm d) = N.of_hex_int d.
Proof.
- unfold N.of_hex_int. now rewrite norm_invol.
+ unfold N.of_hex_int. now rewrite norm_involutive.
Qed.
Lemma of_inj_pos d d' :
diff --git a/theories/Numbers/HexadecimalNat.v b/theories/Numbers/HexadecimalNat.v
index b05184e821..94a14b90bd 100644
--- a/theories/Numbers/HexadecimalNat.v
+++ b/theories/Numbers/HexadecimalNat.v
@@ -289,7 +289,7 @@ Proof.
destruct (norm d) eqn:Hd; intros [= <-].
unfold Nat.to_hex_int. rewrite Unsigned.to_of. f_equal.
revert Hd; destruct d; simpl.
- - intros [= <-]. apply unorm_invol.
+ - intros [= <-]. apply unorm_involutive.
- destruct (nzhead d); now intros [= <-].
Qed.
@@ -308,7 +308,7 @@ Qed.
Lemma of_int_norm d : Nat.of_hex_int (norm d) = Nat.of_hex_int d.
Proof.
- unfold Nat.of_hex_int. now rewrite norm_invol.
+ unfold Nat.of_hex_int. now rewrite norm_involutive.
Qed.
Lemma of_inj_pos d d' :
diff --git a/theories/Numbers/HexadecimalQ.v b/theories/Numbers/HexadecimalQ.v
index 9bf43ceb88..a32019767c 100644
--- a/theories/Numbers/HexadecimalQ.v
+++ b/theories/Numbers/HexadecimalQ.v
@@ -16,442 +16,412 @@
Require Import Decimal DecimalFacts DecimalPos DecimalN DecimalZ.
Require Import Hexadecimal HexadecimalFacts HexadecimalPos HexadecimalN HexadecimalZ QArith.
-Lemma of_to (q:Q) : forall d, to_hexadecimal q = Some d -> of_hexadecimal d = q.
+Lemma of_IQmake_to_hexadecimal num den :
+ match IQmake_to_hexadecimal num den with
+ | None => True
+ | Some (HexadecimalExp _ _ _) => False
+ | Some (Hexadecimal i f) => of_hexadecimal (Hexadecimal i f) = IQmake (IZ_of_Z num) den
+ end.
+Proof.
+ unfold IQmake_to_hexadecimal.
+ generalize (Unsigned.nztail_to_hex_uint den).
+ case Hexadecimal.nztail; intros den' e_den'.
+ case den'; [now simpl|now simpl| |now simpl..]; clear den'; intro den'.
+ case den'; [ |now simpl..]; clear den'.
+ case e_den' as [|e_den']; simpl; intro H; injection H; clear H; intros->.
+ { now unfold of_hexadecimal; simpl; rewrite app_int_nil_r, HexadecimalZ.of_to. }
+ replace (16 ^ _)%positive with (Nat.iter (S e_den') (Pos.mul 16) 1%positive).
+ 2:{ induction e_den' as [|n IHn]; [now simpl| ].
+ now rewrite SuccNat2Pos.inj_succ, Pos.pow_succ_r, <-IHn. }
+ case Nat.ltb_spec; intro He_den'.
+ - unfold of_hexadecimal; simpl.
+ rewrite app_int_del_tail_head; [|now apply Nat.lt_le_incl].
+ rewrite HexadecimalZ.of_to.
+ now rewrite nb_digits_del_head_sub; [|now apply Nat.lt_le_incl].
+ - unfold of_hexadecimal; simpl.
+ rewrite nb_digits_iter_D0.
+ apply f_equal2.
+ + apply f_equal, HexadecimalZ.to_int_inj.
+ rewrite HexadecimalZ.to_of.
+ rewrite <-(HexadecimalZ.of_to num), HexadecimalZ.to_of.
+ case (Z.to_hex_int num); clear He_den' num; intro num; simpl.
+ * unfold app; simpl.
+ now rewrite unorm_D0, unorm_iter_D0, unorm_involutive.
+ * case (uint_eq_dec (nzhead num) Nil); [|intro Hn].
+ { intros->; simpl; unfold app; simpl.
+ now rewrite unorm_D0, unorm_iter_D0. }
+ replace (match nzhead num with Nil => _ | _ => _ end)
+ with (Neg (nzhead num)); [|now revert Hn; case nzhead].
+ simpl.
+ rewrite nzhead_iter_D0, nzhead_involutive.
+ now revert Hn; case nzhead.
+ + revert He_den'; case nb_digits as [|n]; [now simpl; rewrite Nat.add_0_r|].
+ intro Hn.
+ rewrite Nat.add_succ_r, Nat.add_comm.
+ now rewrite <-le_plus_minus; [|apply le_S_n].
+Qed.
+
+Lemma IZ_of_Z_IZ_to_Z z z' : IZ_to_Z z = Some z' -> IZ_of_Z z' = z.
+Proof. now case z as [| |p|p]; [|intro H; injection H; intros<-..]. Qed.
+
+Lemma of_IQmake_to_hexadecimal' num den :
+ match IQmake_to_hexadecimal' num den with
+ | None => True
+ | Some (HexadecimalExp _ _ _) => False
+ | Some (Hexadecimal i f) => of_hexadecimal (Hexadecimal i f) = IQmake num den
+ end.
+Proof.
+ unfold IQmake_to_hexadecimal'.
+ case_eq (IZ_to_Z num); [intros num' Hnum'|now simpl].
+ generalize (of_IQmake_to_hexadecimal num' den).
+ case IQmake_to_hexadecimal as [d|]; [|now simpl].
+ case d as [i f|]; [|now simpl].
+ now rewrite (IZ_of_Z_IZ_to_Z _ _ Hnum').
+Qed.
+
+Lemma of_to (q:IQ) : forall d, to_hexadecimal q = Some d -> of_hexadecimal d = q.
Proof.
- cut (match to_hexadecimal q with None => True | Some d => of_hexadecimal d = q end).
- { now case to_hexadecimal; [intros d <- d' Hd'; injection Hd'; intros ->|]. }
- destruct q as (num, den).
- unfold to_hexadecimal; simpl Qnum; simpl Qden.
- generalize (HexadecimalPos.Unsigned.nztail_to_hex_uint den).
- case Hexadecimal.nztail; intros u n.
- change 16%N with (2^4)%N; rewrite <-N.pow_mul_r.
- change 4%N with (N.of_nat 4); rewrite <-Nnat.Nat2N.inj_mul.
- change 4%Z with (Z.of_nat 4); rewrite <-Nat2Z.inj_mul.
- case u; clear u; try (intros; exact I); [| | |]; intro u;
- (case u; clear u; [|intros; exact I..]).
- - unfold Pos.of_hex_uint, Pos.of_hex_uint_acc; rewrite N.mul_1_l.
- case n.
- + unfold of_hexadecimal, app_int, app, Z.to_hex_int; simpl.
- intro H; inversion H as (H1); clear H H1.
- case num; [reflexivity|intro pnum; fold (rev (rev (Pos.to_hex_uint pnum)))..].
- * rewrite rev_rev; simpl.
- now unfold Z.of_hex_uint; rewrite HexadecimalPos.Unsigned.of_to.
- * rewrite rev_rev; simpl.
- now unfold Z.of_hex_uint; rewrite HexadecimalPos.Unsigned.of_to.
- + clear n; intros n.
- intro H; injection H; intros ->; clear H.
- unfold of_hexadecimal.
- rewrite DecimalZ.of_to.
- simpl nb_digits; rewrite Nat2Z.inj_0, Z.mul_0_r, Z.sub_0_r.
- now apply f_equal2; [rewrite app_int_nil_r, of_to|].
- - unfold Pos.of_hex_uint, Pos.of_hex_uint_acc.
- rewrite <-N.pow_succ_r', <-Nnat.Nat2N.inj_succ.
- intro H; injection H; intros ->; clear H.
- fold (4 * n)%nat.
- change 1%Z with (Z.of_nat 1); rewrite <-Znat.Nat2Z.inj_add.
- unfold of_hexadecimal.
- rewrite DecimalZ.of_to.
- simpl nb_digits; rewrite Nat2Z.inj_0, Z.mul_0_r, Z.sub_0_r.
- now apply f_equal2; [rewrite app_int_nil_r, of_to|].
- - change 2%Z with (Z.of_nat 2); rewrite <-Znat.Nat2Z.inj_add.
- unfold Pos.of_hex_uint, Pos.of_hex_uint_acc.
- change 4%N with (2^2)%N; rewrite <-N.pow_add_r.
- change 2%N with (N.of_nat 2); rewrite <-Nnat.Nat2N.inj_add.
- intro H; injection H; intros ->; clear H.
- fold (4 * n)%nat.
- unfold of_hexadecimal.
- rewrite DecimalZ.of_to.
- simpl nb_digits; rewrite Nat2Z.inj_0, Z.mul_0_r, Z.sub_0_r.
- now apply f_equal2; [rewrite app_int_nil_r, of_to|].
- - change 3%Z with (Z.of_nat 3); rewrite <-Znat.Nat2Z.inj_add.
- unfold Pos.of_hex_uint, Pos.of_hex_uint_acc.
- change 8%N with (2^3)%N; rewrite <-N.pow_add_r.
- change 3%N with (N.of_nat 3); rewrite <-Nnat.Nat2N.inj_add.
- intro H; injection H; intros ->; clear H.
- fold (4 * n)%nat.
- unfold of_hexadecimal.
- rewrite DecimalZ.of_to.
- simpl nb_digits; rewrite Nat2Z.inj_0, Z.mul_0_r, Z.sub_0_r.
- now apply f_equal2; [rewrite app_int_nil_r, of_to|].
+ intro d.
+ case q as [num den|q q'|q q']; simpl.
+ - generalize (of_IQmake_to_hexadecimal' num den).
+ case IQmake_to_hexadecimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ now intros H H'; injection H'; clear H'; intros <-.
+ - case q as [num den| |]; [|now simpl..].
+ case q' as [num' den'| |]; [|now simpl..].
+ case num' as [z p| | |]; [|now simpl..].
+ case (Z.eq_dec z 2); [intros->|].
+ 2:{ case z; [now simpl| |now simpl]; intro pz'.
+ case pz'; [intros d0..| ]; [now simpl| |now simpl].
+ now case d0. }
+ case (Pos.eq_dec den' 1%positive); [intros->|now case den'].
+ generalize (of_IQmake_to_hexadecimal' num den).
+ case IQmake_to_hexadecimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros <-; clear num den.
+ intros H; injection H; clear H; intros<-.
+ unfold of_hexadecimal; simpl.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ - case q as [num den| |]; [|now simpl..].
+ case q' as [num' den'| |]; [|now simpl..].
+ case num' as [z p| | |]; [|now simpl..].
+ case (Z.eq_dec z 2); [intros->|].
+ 2:{ case z; [now simpl| |now simpl]; intro pz'.
+ case pz'; [intros d0..| ]; [now simpl| |now simpl].
+ now case d0. }
+ case (Pos.eq_dec den' 1%positive); [intros->|now case den'].
+ generalize (of_IQmake_to_hexadecimal' num den).
+ case IQmake_to_hexadecimal' as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros <-; clear num den.
+ intros H; injection H; clear H; intros<-.
+ unfold of_hexadecimal; simpl.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
Qed.
-(* normalize without fractional part, for instance norme 0x1.2p-1 is 0x12e-5 *)
-Definition hnorme (d:hexadecimal) : hexadecimal :=
- let '(i, f, e) :=
- match d with
- | Hexadecimal i f => (i, f, Decimal.Pos Decimal.Nil)
- | HexadecimalExp i f e => (i, f, e)
+
+Definition dnorm (d:hexadecimal) : hexadecimal :=
+ let norm_i i f :=
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i => match nzhead (app i f) with Nil => Pos zero | _ => Neg (unorm i) end
end in
- let i := norm (app_int i f) in
- let e := (Z.of_int e - 4 * Z.of_nat (nb_digits f))%Z in
- match e with
- | Z0 => Hexadecimal i Nil
- | Zpos e => Hexadecimal (Pos.iter double i e) Nil
- | Zneg _ => HexadecimalExp i Nil (Decimal.norm (Z.to_int e))
+ match d with
+ | Hexadecimal i f => Hexadecimal (norm_i i f) f
+ | HexadecimalExp i f e =>
+ match Decimal.norm e with
+ | Decimal.Pos Decimal.zero => Hexadecimal (norm_i i f) f
+ | e => HexadecimalExp (norm_i i f) f e
+ end
end.
-Lemma hnorme_spec d :
- match hnorme d with
- | Hexadecimal i Nil => i = norm i
- | HexadecimalExp i Nil e =>
- i = norm i /\ e = Decimal.norm e /\ e <> Decimal.Pos Decimal.zero
- | _ => False
+Lemma dnorm_spec_i d :
+ let (i, f) :=
+ match d with Hexadecimal i f => (i, f) | HexadecimalExp i f _ => (i, f) end in
+ let i' := match dnorm d with Hexadecimal i _ => i | HexadecimalExp i _ _ => i end in
+ match i with
+ | Pos i => i' = Pos (unorm i)
+ | Neg i =>
+ (i' = Neg (unorm i) /\ (nzhead i <> Nil \/ nzhead f <> Nil))
+ \/ (i' = Pos zero /\ (nzhead i = Nil /\ nzhead f = Nil))
end.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold hnorme; simpl.
- - case_eq (nb_digits f); [now simpl; rewrite norm_invol|]; intros nf Hnf.
- split; [now simpl; rewrite norm_invol|].
- unfold Z.of_nat.
- now rewrite <-!DecimalZ.to_of, !DecimalZ.of_to.
- - set (e' := (_ - _)%Z).
- case_eq e'; [|intro pe'..]; intro He'.
- + now rewrite norm_invol.
- + rewrite Pos2Nat.inj_iter.
- set (ne' := Pos.to_nat pe').
- fold (Nat.iter ne' double (norm (app_int i f))).
- induction ne'; [now simpl; rewrite norm_invol|].
- now rewrite Unsigned.nat_iter_S, <-double_norm, IHne', norm_invol.
- + split; [now rewrite norm_invol|].
- split; [now rewrite DecimalFacts.norm_invol|].
- rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- change (Decimal.Pos _) with (Z.to_int 0).
- now intro H; generalize (DecimalZ.to_int_inj _ _ H).
+ case d as [i f|i f e]; case i as [i|i].
+ - now simpl.
+ - simpl; case (uint_eq_dec (nzhead (app i f)) Nil); intro Ha.
+ + rewrite Ha; right; split; [now simpl|split].
+ * now unfold unorm; rewrite (nzhead_app_nil_l _ _ Ha).
+ * now unfold unorm; rewrite (nzhead_app_nil_r _ _ Ha).
+ + left; split; [now revert Ha; case nzhead|].
+ case (uint_eq_dec (nzhead i) Nil).
+ * intro Hi; right; intro Hf; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now intro H; left.
+ - simpl; case (Decimal.norm e); clear e; intro e; [|now simpl].
+ now case e; clear e; [|intro e..]; [|case e|..].
+ - simpl.
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ set (m' := match _ with Hexadecimal _ _ => _ | _ => _ end).
+ replace m' with m.
+ 2:{ unfold m'; case (Decimal.norm e); clear m' e; intro e; [|now simpl].
+ now case e; clear e; [|intro e..]; [|case e|..]. }
+ unfold m; case (uint_eq_dec (nzhead (app i f)) Nil); intro Ha.
+ + rewrite Ha; right; split; [now simpl|split].
+ * now unfold unorm; rewrite (nzhead_app_nil_l _ _ Ha).
+ * now unfold unorm; rewrite (nzhead_app_nil_r _ _ Ha).
+ + left; split; [now revert Ha; case nzhead|].
+ case (uint_eq_dec (nzhead i) Nil).
+ * intro Hi; right; intro Hf; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now intro H; left.
Qed.
-Lemma hnorme_invol d : hnorme (hnorme d) = hnorme d.
+Lemma dnorm_spec_f d :
+ let f := match d with Hexadecimal _ f => f | HexadecimalExp _ f _ => f end in
+ let f' := match dnorm d with Hexadecimal _ f => f | HexadecimalExp _ f _ => f end in
+ f' = f.
+Proof.
+ case d as [i f|i f e]; [now simpl|].
+ simpl; case (Decimal.int_eq_dec (Decimal.norm e) (Decimal.Pos Decimal.zero)); [now intros->|intro He].
+ set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match Decimal.norm e with Decimal.Pos _ => _ | _ => _ end).
+ replace m with (HexadecimalExp i' f (Decimal.norm e)); [now simpl|].
+ unfold m; revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
+Qed.
+
+Lemma dnorm_spec_e d :
+ match d, dnorm d with
+ | Hexadecimal _ _, Hexadecimal _ _ => True
+ | HexadecimalExp _ _ e, Hexadecimal _ _ =>
+ Decimal.norm e = Decimal.Pos Decimal.zero
+ | HexadecimalExp _ _ e, HexadecimalExp _ _ e' =>
+ e' = Decimal.norm e /\ e' <> Decimal.Pos Decimal.zero
+ | Hexadecimal _ _, HexadecimalExp _ _ _ => False
+ end.
Proof.
- case d; clear d; intros i f; [|intro e]; unfold hnorme; simpl.
- - case_eq (nb_digits f); [now simpl; rewrite app_int_nil_r, norm_invol|].
- intros nf Hnf.
- unfold Z.of_nat.
- simpl.
- set (pnf := Pos.to_uint _).
- set (nz := Decimal.nzhead pnf).
- assert (Hnz : nz <> Decimal.Nil).
- { unfold nz, pnf.
- rewrite <-DecimalFacts.unorm_0.
- rewrite <-DecimalPos.Unsigned.to_of.
- rewrite DecimalPos.Unsigned.of_to.
- change Decimal.zero with (N.to_uint 0).
- now intro H; generalize (DecimalN.Unsigned.to_uint_inj _ _ H). }
- set (m := match nz with Decimal.Nil => _ | _ => _ end).
- assert (Hm : m = (Decimal.Neg (Decimal.unorm pnf))).
- { now revert Hnz; unfold m, nz, Decimal.unorm; fold nz; case nz. }
- rewrite Hm; unfold pnf.
- rewrite <-DecimalPos.Unsigned.to_of, DecimalPos.Unsigned.of_to.
- simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
- rewrite Z.sub_0_r; simpl.
- fold pnf; fold nz; fold m; rewrite Hm; unfold pnf.
- rewrite <-DecimalPos.Unsigned.to_of, DecimalPos.Unsigned.of_to.
- now rewrite app_int_nil_r, norm_invol.
- - set (e' := (_ - _)%Z).
- case_eq e'; [|intro pe'..]; intro Hpe'.
- + now simpl; rewrite app_int_nil_r, norm_invol.
- + simpl; rewrite app_int_nil_r.
- apply f_equal2; [|reflexivity].
- rewrite Pos2Nat.inj_iter.
- set (ne' := Pos.to_nat pe').
- fold (Nat.iter ne' double (norm (app_int i f))).
- induction ne'; [now simpl; rewrite norm_invol|].
- now rewrite Unsigned.nat_iter_S, <-double_norm, IHne'.
- + rewrite <-DecimalZ.to_of, !DecimalZ.of_to; simpl.
- rewrite app_int_nil_r, norm_invol.
- set (pnf := Pos.to_uint _).
- set (nz := Decimal.nzhead pnf).
- assert (Hnz : nz <> Decimal.Nil).
- { unfold nz, pnf.
- rewrite <-DecimalFacts.unorm_0.
- rewrite <-DecimalPos.Unsigned.to_of.
- rewrite DecimalPos.Unsigned.of_to.
- change Decimal.zero with (N.to_uint 0).
- now intro H; generalize (DecimalN.Unsigned.to_uint_inj _ _ H). }
- set (m := match nz with Decimal.Nil => _ | _ => _ end).
- assert (Hm : m = (Decimal.Neg (Decimal.unorm pnf))).
- { now revert Hnz; unfold m, nz, Decimal.unorm; fold nz; case nz. }
- rewrite Hm; unfold pnf.
- now rewrite <-DecimalPos.Unsigned.to_of, DecimalPos.Unsigned.of_to.
+ case d as [i f|i f e]; [now simpl|].
+ simpl; case (Decimal.int_eq_dec (Decimal.norm e) (Decimal.Pos Decimal.zero)); [now intros->|intro He].
+ set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match Decimal.norm e with Decimal.Pos _ => _ | _ => _ end).
+ replace m with (HexadecimalExp i' f (Decimal.norm e)); [now simpl|].
+ unfold m; revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
Qed.
-Lemma to_of (d:hexadecimal) :
- to_hexadecimal (of_hexadecimal d) = Some (hnorme d).
+Lemma dnorm_involutive d : dnorm (dnorm d) = dnorm d.
Proof.
- unfold to_hexadecimal.
- pose (t10 := fun y => (y~0~0~0~0)%positive).
- assert (H : exists h e_den,
- Hexadecimal.nztail (Pos.to_hex_uint (Qden (of_hexadecimal d)))
- = (h, e_den)
- /\ (h = D1 Nil \/ h = D2 Nil \/ h = D4 Nil \/ h = D8 Nil)).
- { assert (H : forall p,
- Hexadecimal.nztail (Pos.to_hex_uint (Pos.iter (Pos.mul 2) 1%positive p))
- = ((match (Pos.to_nat p) mod 4 with 0%nat => D1 | 1 => D2 | 2 => D4 | _ => D8 end)%nat Nil,
- (Pos.to_nat p / 4)%nat)).
- { intro p; clear d; rewrite Pos2Nat.inj_iter.
- fold (Nat.iter (Pos.to_nat p) (Pos.mul 2) 1%positive).
- set (n := Pos.to_nat p).
- fold (Nat.iter n t10 1%positive).
- set (nm4 := (n mod 4)%nat); set (nd4 := (n / 4)%nat).
- rewrite (Nat.div_mod n 4); [|now simpl].
- unfold nm4, nd4; clear nm4 nd4.
- generalize (Nat.mod_upper_bound n 4 ltac:(now simpl)).
- generalize (n mod 4); generalize (n / 4)%nat.
- intros d r Hr; clear p n.
- induction d.
- { simpl; revert Hr.
- do 4 (case r; [now simpl|clear r; intro r]).
- intro H; exfalso.
- now do 4 (generalize (lt_S_n _ _ H); clear H; intro H). }
- rewrite Nat.mul_succ_r, <-Nat.add_assoc, (Nat.add_comm 4), Nat.add_assoc.
- rewrite (Nat.add_comm _ 4).
- change (4 + _)%nat with (S (S (S (S (4 * d + r))))).
- rewrite !Unsigned.nat_iter_S.
- rewrite !Pos.mul_assoc.
- unfold Pos.to_hex_uint.
- change (2 * 2 * 2 * 2)%positive with 0x10%positive.
- set (n := Nat.iter _ _ _).
- change (Pos.to_little_hex_uint _) with (Unsigned.to_lu (16 * N.pos n)).
- rewrite Unsigned.to_lhex_tenfold.
- unfold Hexadecimal.nztail; rewrite rev_rev.
- rewrite <-(rev_rev (Unsigned.to_lu _)).
- set (m := _ (rev _)).
- replace m with (let (r, n) := let (r, n) := m in (rev r, n) in (rev r, n)).
- 2:{ now case m; intros r' n'; rewrite rev_rev. }
- change (let (r, n) := m in (rev r, n))
- with (Hexadecimal.nztail (Pos.to_hex_uint n)).
- now unfold n; rewrite IHd, rev_rev; clear n m. }
- unfold of_hexadecimal.
- case d; intros i f; [|intro e]; unfold of_hexadecimal; simpl.
- - case (Z.of_nat _)%Z; [|intro p..];
- [now exists (D1 Nil), O; split; [|left]
- | |now exists (D1 Nil), O; split; [|left]].
- exists (D1 Nil), (Pos.to_nat p).
- split; [|now left]; simpl.
- change (Pos.iter _ _ _) with (Pos.iter (Pos.mul 2) 1%positive (4 * p)).
- rewrite H.
- rewrite Pos2Nat.inj_mul, Nat.mul_comm, Nat.div_mul; [|now simpl].
- now rewrite Nat.mod_mul; [|now simpl].
- - case (_ - _)%Z; [|intros p..]; [now exists (D1 Nil), O; split; [|left]..|].
- simpl Qden; rewrite H.
- eexists; eexists; split; [reflexivity|].
- case (_ mod _); [now left|intro n].
- case n; [now right; left|clear n; intro n].
- case n; [now right; right; left|clear n; intro n].
- now right; right; right. }
- generalize (HexadecimalPos.Unsigned.nztail_to_hex_uint (Qden (of_hexadecimal d))).
- destruct H as (h, (e, (He, Hh))); rewrite He; clear He.
- assert (Hn1 : forall p, N.pos (Pos.iter (Pos.mul 2) 1%positive p) = 1%N -> False).
- { intro p.
- rewrite Pos2Nat.inj_iter.
- case_eq (Pos.to_nat p); [|now simpl].
- intro H; exfalso; apply (lt_irrefl O).
- rewrite <-H at 2; apply Pos2Nat.is_pos. }
- assert (H16_2 : forall p, (16^p = 2^(4 * p))%positive).
- { intro p.
- apply (@f_equal _ _ (fun z => match z with Z.pos p => p | _ => 1%positive end)
- (Z.pos _) (Z.pos _)).
- rewrite !Pos2Z.inj_pow_pos, !Z.pow_pos_fold, Pos2Z.inj_mul.
- now change 16%Z with (2^4)%Z; rewrite <-Z.pow_mul_r. }
- assert (HN16_2 : forall n, (16^n = 2^(4 * n))%N).
- { intro n.
- apply N2Z.inj; rewrite !N2Z.inj_pow, N2Z.inj_mul.
- change (Z.of_N 16) with (2^4)%Z.
- now rewrite <-Z.pow_mul_r; [| |apply N2Z.is_nonneg]. }
- assert (Hn1' : forall p, N.pos (Pos.iter (Pos.mul 16) 1%positive p) = 1%N -> False).
- { intro p; fold (16^p)%positive; rewrite H16_2; apply Hn1. }
- assert (Ht10inj : forall n m, t10 n = t10 m -> n = m).
- { intros n m H; generalize (f_equal Z.pos H); clear H.
- change (Z.pos (t10 n)) with (Z.mul 0x10 (Z.pos n)).
- change (Z.pos (t10 m)) with (Z.mul 0x10 (Z.pos m)).
- rewrite Z.mul_comm, (Z.mul_comm 0x10).
- intro H; generalize (f_equal (fun z => Z.div z 0x10) H); clear H.
- now rewrite !Z.div_mul; [|now simpl..]; intro H; inversion H. }
- assert (Ht2inj : forall n m, Pos.mul 2 n = Pos.mul 2 m -> n = m).
- { intros n m H; generalize (f_equal Z.pos H); clear H.
- change (Z.pos (Pos.mul 2 n)) with (Z.mul 2 (Z.pos n)).
- change (Z.pos (Pos.mul 2 m)) with (Z.mul 2 (Z.pos m)).
- rewrite Z.mul_comm, (Z.mul_comm 2).
- intro H; generalize (f_equal (fun z => Z.div z 2) H); clear H.
- now rewrite !Z.div_mul; [|now simpl..]; intro H; inversion H. }
- assert (Hinj : forall n m,
- Nat.iter n (Pos.mul 2) 1%positive = Nat.iter m (Pos.mul 2) 1%positive
- -> n = m).
- { induction n; [now intro m; case m|].
- intro m; case m; [now simpl|]; clear m; intro m.
- rewrite !Unsigned.nat_iter_S.
- intro H; generalize (Ht2inj _ _ H); clear H; intro H.
- now rewrite (IHn _ H). }
- change 4%Z with (Z.of_nat 4); rewrite <-Nat2Z.inj_mul.
- change 1%Z with (Z.of_nat 1); rewrite <-Nat2Z.inj_add.
- change 2%Z with (Z.of_nat 2); rewrite <-Nat2Z.inj_add.
- change 3%Z with (Z.of_nat 3); rewrite <-Nat2Z.inj_add.
- destruct Hh as [Hh|[Hh|[Hh|Hh]]]; rewrite Hh; clear h Hh.
- - case e; clear e; [|intro e]; simpl; unfold of_hexadecimal, hnorme.
- + case d; clear d; intros i f; [|intro e].
- * generalize (nb_digits_pos f).
- case f;
- [|now clear f; intro f; intros H1 H2; exfalso; revert H1 H2;
- case nb_digits;
- [intros H _; apply (lt_irrefl O), H|intros n _; apply Hn1]..].
- now intros _ _; simpl; rewrite to_of.
- * rewrite <-DecimalZ.to_of, DecimalZ.of_to.
- set (emf := (_ - _)%Z).
- case_eq emf; [|intro pemf..].
- ++ now simpl; rewrite to_of.
- ++ intros Hemf _; simpl.
- apply f_equal, f_equal2; [|reflexivity].
- rewrite !Pos2Nat.inj_iter.
- fold (Nat.iter (Pos.to_nat pemf) (Z.mul 2) (Z.of_hex_int (app_int i f))).
- fold (Nat.iter (Pos.to_nat pemf) double (norm (app_int i f))).
- induction Pos.to_nat; [now simpl; rewrite HexadecimalZ.to_of|].
- now rewrite !Unsigned.nat_iter_S, <-IHn, double_to_hex_int.
- ++ simpl Qden; intros _ H; exfalso; revert H; apply Hn1.
- + case d; clear d; intros i f; [|intro e'].
- * simpl; case_eq (nb_digits f); [|intros nf' Hnf'];
- [now simpl; intros _ H; exfalso; symmetry in H; revert H; apply Hn1'|].
- unfold Z.of_nat, Z.opp, Qnum, Qden.
- rewrite H16_2.
- fold (Pos.mul 2); fold (2^(Pos.of_succ_nat nf')~0~0)%positive.
- intro H; injection H; clear H.
- unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intro H; injection H.
- clear H; intro H; generalize (SuccNat2Pos.inj _ _ H); clear H.
- intros <-.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite SuccNat2Pos.id_succ.
- change (_~0)%positive with (4 * Pos.of_succ_nat nf')%positive.
- now rewrite Pos2Nat.inj_mul, SuccNat2Pos.id_succ.
- * set (nemf := (_ - _)%Z); intro H.
- assert (H' : exists pnemf, nemf = Z.neg pnemf); [|revert H].
- { revert H; case nemf; [|intro pnemf..]; [..|now intros _; exists pnemf];
- simpl Qden; intro H; exfalso; symmetry in H; revert H; apply Hn1'. }
- destruct H' as (pnemf,Hpnemf); rewrite Hpnemf.
- unfold Qnum, Qden.
- rewrite H16_2.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H.
- intro H; revert Hpnemf; rewrite H; clear pnemf H; intro Hnemf.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite SuccNat2Pos.id_succ.
- change (_~0)%positive with (4 * Pos.of_succ_nat e)%positive.
- now rewrite Pos2Nat.inj_mul, SuccNat2Pos.id_succ.
- - simpl Pos.of_hex_uint.
- rewrite HN16_2.
- rewrite <-N.pow_succ_r; [|now apply N.le_0_l].
- rewrite <-N.succ_pos_spec.
- case d; clear d; intros i f; [|intro e']; unfold of_hexadecimal, hnorme.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
- - simpl Pos.of_hex_uint.
- rewrite HN16_2.
- change 4%N with (2 * 2)%N at 1; rewrite <-!N.mul_assoc.
- do 2 (rewrite <-N.pow_succ_r; [|now apply N.le_0_l]).
- rewrite <-N.succ_pos_spec.
- case d; clear d; intros i f; [|intro e']; unfold of_hexadecimal, hnorme.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite <-SuccNat2Pos.inj_succ.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite <-SuccNat2Pos.inj_succ.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
- - simpl Pos.of_hex_uint.
- rewrite HN16_2.
- change 8%N with (2 * 2 * 2)%N; rewrite <-!N.mul_assoc.
- do 3 (rewrite <-N.pow_succ_r; [|now apply N.le_0_l]).
- rewrite <-N.succ_pos_spec.
- case d; clear d; intros i f; [|intro e']; unfold of_hexadecimal, hnorme.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite <-!SuccNat2Pos.inj_succ.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
- + set (em4f := (_ - _)%Z).
- case_eq em4f; [|intros pem4f..]; intro Hpem4f;
- [now simpl; intros H; exfalso; symmetry in H; revert H; apply Hn1..|].
- unfold Qnum, Qden.
- intro H; injection H; clear H; unfold Pos.pow; rewrite !Pos2Nat.inj_iter.
- intro H; generalize (Hinj _ _ H); clear H; intro H.
- generalize (Pos2Nat.inj _ _ H); clear H; intros ->.
- rewrite to_of.
- rewrite <-DecimalZ.to_of, DecimalZ.of_to; simpl.
- do 4 apply f_equal.
- apply Pos2Nat.inj.
- rewrite <-!SuccNat2Pos.inj_succ.
- rewrite SuccNat2Pos.id_succ.
- case e; [now simpl|intro e'']; simpl.
- unfold Pos.to_nat; simpl.
- now rewrite Pmult_nat_mult, SuccNat2Pos.id_succ, Nat.mul_comm.
+ case d as [i f|i f e]; case i as [i|i].
+ - now simpl; rewrite unorm_involutive.
+ - simpl; case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ set (m := match nzhead _ with Nil =>_ | _ => _ end).
+ replace m with (Neg (unorm i)).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ + unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ * intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ * now case nzhead.
+ + rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
+ - simpl; case (Decimal.int_eq_dec (Decimal.norm e) (Decimal.Pos Decimal.zero)); intro He.
+ + now rewrite He; simpl; rewrite unorm_involutive.
+ + set (m := match Decimal.norm e with Decimal.Pos _ => _ | _ => _ end).
+ replace m with (HexadecimalExp (Pos (unorm i)) f (Decimal.norm e)).
+ 2:{ unfold m; revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ simpl; rewrite DecimalFacts.norm_involutive, unorm_involutive.
+ revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..].
+ - simpl; case (Decimal.int_eq_dec (Decimal.norm e) (Decimal.Pos Decimal.zero)); intro He.
+ + rewrite He; simpl.
+ case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ set (m := match nzhead _ with Nil =>_ | _ => _ end).
+ replace m with (Neg (unorm i)).
+ 2:{ now unfold m; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ * unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ -- intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ -- now case nzhead.
+ * rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
+ + set (m := match Decimal.norm e with Decimal.Pos _ => _ | _ => _ end).
+ pose (i' := match nzhead (app i f) with Nil => Pos zero | _ => Neg (unorm i) end).
+ replace m with (HexadecimalExp i' f (Decimal.norm e)).
+ 2:{ unfold m; revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ simpl; rewrite DecimalFacts.norm_involutive.
+ set (i'' := match i' with Pos _ => _ | _ => _ end).
+ clear m; set (m := match Decimal.norm e with Decimal.Pos _ => _ | _ => _ end).
+ replace m with (HexadecimalExp i'' f (Decimal.norm e)).
+ 2:{ unfold m; revert He; case (Decimal.norm e); clear m e; intro e; [|now simpl].
+ now case e; clear e; [|intro e; case e|..]. }
+ unfold i'', i'.
+ case (uint_eq_dec (nzhead (app i f)) Nil); [now intros->|intro Ha].
+ fold i'; replace i' with (Neg (unorm i)).
+ 2:{ now unfold i'; revert Ha; case nzhead. }
+ case (uint_eq_dec (nzhead i) Nil); intro Hi.
+ * unfold unorm; rewrite Hi; simpl.
+ case (uint_eq_dec (nzhead f) Nil).
+ -- intro Hf; exfalso; apply Ha.
+ now rewrite <-nzhead_app_nzhead, Hi, app_nil_l.
+ -- now case nzhead.
+ * rewrite unorm_involutive, (unorm_nzhead _ Hi), nzhead_app_nzhead.
+ now revert Ha; case nzhead.
+Qed.
+
+Lemma IZ_to_Z_IZ_of_Z z : IZ_to_Z (IZ_of_Z z) = Some z.
+Proof. now case z. Qed.
+
+Lemma dnorm_i_exact i f :
+ (nb_digits f < nb_digits (unorm (app (abs i) f)))%nat ->
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i =>
+ match nzhead (app i f) with
+ | Nil => Pos zero
+ | _ => Neg (unorm i)
+ end
+ end = norm i.
+Proof.
+ case i as [ni|ni]; [now simpl|]; simpl.
+ case (uint_eq_dec (nzhead (app ni f)) Nil); intro Ha.
+ { now rewrite Ha, (nzhead_app_nil_l _ _ Ha). }
+ rewrite (unorm_nzhead _ Ha).
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (unorm ni)); [|now unfold m; revert Ha; case nzhead].
+ case (uint_eq_dec (nzhead ni) Nil); intro Hni.
+ { rewrite <-nzhead_app_nzhead, Hni, app_nil_l.
+ intro H; exfalso; revert H; apply le_not_lt, nb_digits_nzhead. }
+ clear m; set (m := match nzhead ni with Nil => _ | _ => _ end).
+ replace m with (Neg (nzhead ni)); [|now unfold m; revert Hni; case nzhead].
+ now rewrite (unorm_nzhead _ Hni).
+Qed.
+
+Lemma dnorm_i_exact' i f :
+ (nb_digits (unorm (app (abs i) f)) <= nb_digits f)%nat ->
+ match i with
+ | Pos i => Pos (unorm i)
+ | Neg i =>
+ match nzhead (app i f) with
+ | Nil => Pos zero
+ | _ => Neg (unorm i)
+ end
+ end =
+ match norm (app_int i f) with
+ | Pos _ => Pos zero
+ | Neg _ => Neg zero
+ end.
+Proof.
+ case i as [ni|ni]; simpl.
+ { now intro Hnb; rewrite (unorm_app_zero _ _ Hnb). }
+ unfold unorm.
+ case (uint_eq_dec (nzhead (app ni f)) Nil); intro Hn.
+ { now rewrite Hn. }
+ set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (nzhead (app ni f)).
+ 2:{ now unfold m; revert Hn; case nzhead. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (unorm ni)).
+ 2:{ now unfold m, unorm; revert Hn; case nzhead. }
+ clear m; set (m := match nzhead _ with Nil => _ | _ => _ end).
+ replace m with (Neg (nzhead (app ni f))).
+ 2:{ now unfold m; revert Hn; case nzhead. }
+ rewrite <-(unorm_nzhead _ Hn).
+ now intro H; rewrite (unorm_app_zero _ _ H).
+Qed.
+
+Lemma to_of (d:hexadecimal) : to_hexadecimal (of_hexadecimal d) = Some (dnorm d).
+Proof.
+ case d as [i f|i f e].
+ - unfold of_hexadecimal; simpl; unfold IQmake_to_hexadecimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_hexadecimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 16).
+ rewrite nztail_to_hex_uint_pow16, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ + rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ + rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ * rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ * rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ - unfold of_hexadecimal; simpl.
+ rewrite <-DecimalZ.to_of.
+ case (Z.of_int e); clear e; [|intro e..]; simpl.
+ + unfold IQmake_to_hexadecimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_hexadecimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 16).
+ rewrite nztail_to_hex_uint_pow16, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ + unfold IQmake_to_hexadecimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_hexadecimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 16).
+ rewrite nztail_to_hex_uint_pow16, to_of.
+ generalize (DecimalPos.Unsigned.to_uint_nonzero e); intro He.
+ set (dnorm_i := match i with Pos _ => _ | _ => _ end).
+ set (m := match Pos.to_uint e with Decimal.Nil => _ | _ => _ end).
+ replace m with (HexadecimalExp dnorm_i f (Decimal.Pos (Pos.to_uint e))).
+ 2:{ now unfold m; revert He; case (Pos.to_uint e); [|intro u; case u|..]. }
+ clear m; unfold dnorm_i.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
+ + unfold IQmake_to_hexadecimal'.
+ rewrite IZ_to_Z_IZ_of_Z.
+ unfold IQmake_to_hexadecimal; simpl.
+ change (fun _ : positive => _) with (Pos.mul 16).
+ rewrite nztail_to_hex_uint_pow16, to_of.
+ case_eq (nb_digits f); [|intro nb]; intro Hnb.
+ * rewrite (nb_digits_0 _ Hnb), app_int_nil_r.
+ case i as [ni|ni]; [now simpl|].
+ rewrite app_nil_r; simpl; unfold unorm.
+ now case (nzhead ni).
+ * rewrite <-Hnb.
+ rewrite abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnb'.
+ -- rewrite (del_tail_app_int_exact _ _ Hnb').
+ rewrite (del_head_app_int_exact _ _ Hnb').
+ now rewrite (dnorm_i_exact _ _ Hnb').
+ -- rewrite (unorm_app_r _ _ Hnb').
+ rewrite iter_D0_unorm; [|now apply nb_digits_n0; rewrite Hnb].
+ now rewrite dnorm_i_exact'.
Qed.
(** Some consequences *)
@@ -466,68 +436,24 @@ Proof.
now intros d _ H1 H2; rewrite <-(H1 d eq_refl), <-(H2 d eq_refl).
Qed.
-Lemma to_hexadecimal_surj d : exists q, to_hexadecimal q = Some (hnorme d).
+Lemma to_hexadecimal_surj d : exists q, to_hexadecimal q = Some (dnorm d).
Proof.
exists (of_hexadecimal d). apply to_of.
Qed.
-Lemma of_hexadecimal_hnorme d : of_hexadecimal (hnorme d) = of_hexadecimal d.
-Proof.
- unfold of_hexadecimal, hnorme.
- destruct d.
- - simpl Z.of_int; unfold Z.of_uint, Z.of_N, Pos.of_uint.
- rewrite Z.sub_0_l.
- set (n4f := (- _)%Z).
- case_eq n4f; [|intro pn4f..]; intro Hn4f.
- + apply f_equal2; [|reflexivity].
- rewrite app_int_nil_r.
- now rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to.
- + apply f_equal2; [|reflexivity].
- rewrite app_int_nil_r.
- generalize (app_int i f); intro i'.
- rewrite !Pos2Nat.inj_iter.
- generalize (Pos.to_nat pn4f); intro n.
- fold (Nat.iter n double (norm i')).
- fold (Nat.iter n (Z.mul 2) (Z.of_hex_int i')).
- induction n; [now simpl; rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to|].
- now rewrite !Unsigned.nat_iter_S, <-IHn, of_hex_int_double.
- + unfold nb_digits, Z.of_nat.
- rewrite Z.mul_0_r, Z.sub_0_r.
- rewrite <-DecimalZ.to_of, !DecimalZ.of_to.
- rewrite app_int_nil_r.
- now rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to.
- - set (nem4f := (_ - _)%Z).
- case_eq nem4f; [|intro pnem4f..]; intro Hnem4f.
- + apply f_equal2; [|reflexivity].
- rewrite app_int_nil_r.
- now rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to.
- + apply f_equal2; [|reflexivity].
- rewrite app_int_nil_r.
- generalize (app_int i f); intro i'.
- rewrite !Pos2Nat.inj_iter.
- generalize (Pos.to_nat pnem4f); intro n.
- fold (Nat.iter n double (norm i')).
- fold (Nat.iter n (Z.mul 2) (Z.of_hex_int i')).
- induction n; [now simpl; rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to|].
- now rewrite !Unsigned.nat_iter_S, <-IHn, of_hex_int_double.
- + unfold nb_digits, Z.of_nat.
- rewrite Z.mul_0_r, Z.sub_0_r.
- rewrite <-DecimalZ.to_of, !DecimalZ.of_to.
- rewrite app_int_nil_r.
- now rewrite <-HexadecimalZ.to_of, HexadecimalZ.of_to.
-Qed.
+Lemma of_hexadecimal_dnorm d : of_hexadecimal (dnorm d) = of_hexadecimal d.
+Proof. now apply to_hexadecimal_inj; rewrite !to_of; [|rewrite dnorm_involutive]. Qed.
-Lemma of_inj d d' :
- of_hexadecimal d = of_hexadecimal d' -> hnorme d = hnorme d'.
+Lemma of_inj d d' : of_hexadecimal d = of_hexadecimal d' -> dnorm d = dnorm d'.
Proof.
- intros.
- cut (Some (hnorme d) = Some (hnorme d')); [now intro H'; injection H'|].
- rewrite <- !to_of. now f_equal.
+ intro H.
+ apply (@f_equal _ _ (fun x => match x with Some x => x | _ => d end)
+ (Some (dnorm d)) (Some (dnorm d'))).
+ now rewrite <- !to_of, H.
Qed.
-Lemma of_iff d d' :
- of_hexadecimal d = of_hexadecimal d' <-> hnorme d = hnorme d'.
+Lemma of_iff d d' : of_hexadecimal d = of_hexadecimal d' <-> dnorm d = dnorm d'.
Proof.
- split. apply of_inj. intros E. rewrite <- of_hexadecimal_hnorme, E.
- apply of_hexadecimal_hnorme.
+ split. apply of_inj. intros E. rewrite <- of_hexadecimal_dnorm, E.
+ apply of_hexadecimal_dnorm.
Qed.
diff --git a/theories/Numbers/HexadecimalR.v b/theories/Numbers/HexadecimalR.v
new file mode 100644
index 0000000000..2deecc5847
--- /dev/null
+++ b/theories/Numbers/HexadecimalR.v
@@ -0,0 +1,302 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+(** * HexadecimalR
+
+ Proofs that conversions between hexadecimal numbers and [R]
+ are bijections. *)
+
+Require Import Decimal DecimalFacts.
+Require Import Hexadecimal HexadecimalFacts HexadecimalPos HexadecimalZ.
+Require Import HexadecimalQ Rdefinitions.
+
+Lemma of_IQmake_to_hexadecimal num den :
+ match IQmake_to_hexadecimal num den with
+ | None => True
+ | Some (HexadecimalExp _ _ _) => False
+ | Some (Hexadecimal i f) =>
+ of_hexadecimal (Hexadecimal i f) = IRQ (QArith_base.Qmake num den)
+ end.
+Proof.
+ unfold IQmake_to_hexadecimal.
+ case (Pos.eq_dec den 1); [now intros->|intro Hden].
+ assert (Hf : match QArith_base.IQmake_to_hexadecimal num den with
+ | Some (Hexadecimal i f) => f <> Nil
+ | _ => True
+ end).
+ { unfold QArith_base.IQmake_to_hexadecimal; simpl.
+ generalize (Unsigned.nztail_to_hex_uint den).
+ case Hexadecimal.nztail as [den' e_den'].
+ case den'; [now simpl|now simpl| |now simpl..]; clear den'; intro den'.
+ case den'; [ |now simpl..]; clear den'.
+ case e_den' as [|e_den']; [now simpl; intros H _; apply Hden; injection H|].
+ intros _.
+ case Nat.ltb_spec; intro He_den'.
+ - apply del_head_nonnil.
+ revert He_den'; case nb_digits as [|n]; [now simpl|].
+ now intro H; simpl; apply le_lt_n_Sm, Nat.le_sub_l.
+ - apply nb_digits_n0.
+ now rewrite nb_digits_iter_D0, Nat.sub_add. }
+ replace (match den with 1%positive => _ | _ => _ end)
+ with (QArith_base.IQmake_to_hexadecimal num den); [|now revert Hden; case den].
+ generalize (of_IQmake_to_hexadecimal num den).
+ case QArith_base.IQmake_to_hexadecimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ unfold of_hexadecimal; simpl.
+ intro H; injection H; clear H; intros <-.
+ intro H; generalize (f_equal QArith_base.IZ_to_Z H); clear H.
+ rewrite !IZ_to_Z_IZ_of_Z; intro H; injection H; clear H; intros<-.
+ now revert Hf; case f.
+Qed.
+
+Lemma of_to (q:IR) : forall d, to_hexadecimal q = Some d -> of_hexadecimal d = q.
+Proof.
+ intro d.
+ case q as [z|q|r r'|r r']; simpl.
+ - case z as [z p| |p|p].
+ + now simpl.
+ + now simpl; intro H; injection H; clear H; intros<-.
+ + simpl; intro H; injection H; clear H; intros<-.
+ now unfold of_hexadecimal; simpl; unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ + simpl; intro H; injection H; clear H; intros<-.
+ now unfold of_hexadecimal; simpl; unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ - case q as [num den].
+ generalize (of_IQmake_to_hexadecimal num den).
+ case IQmake_to_hexadecimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ now intros H H'; injection H'; intros<-.
+ - case r as [z|q| |]; [|case q as[num den]|now simpl..];
+ (case r' as [z'| | |]; [|now simpl..]);
+ (case z' as [p e| | |]; [|now simpl..]).
+ + case (Z.eq_dec p 2); [intros->|intro Hp].
+ 2:{ now revert Hp; case p;
+ [|intro d0; case d0; [intro d1..|]; [|case d1|]..]. }
+ case z as [| |p|p]; [now simpl|..]; intro H; injection H; intros<-.
+ * now unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
+ * unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ now unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ * unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ now unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ + case (Z.eq_dec p 2); [intros->|intro Hp].
+ 2:{ now revert Hp; case p;
+ [|intro d0; case d0; [intro d1..|]; [|case d1|]..]. }
+ generalize (of_IQmake_to_hexadecimal num den).
+ case IQmake_to_hexadecimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros H H'; injection H'; clear H'; intros<-.
+ unfold of_hexadecimal; simpl.
+ change (match f with Nil => _ | _ => _ end) with (of_hexadecimal (Hexadecimal i f)).
+ rewrite H; clear H.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
+ - case r as [z|q| |]; [|case q as[num den]|now simpl..];
+ (case r' as [z'| | |]; [|now simpl..]);
+ (case z' as [p e| | |]; [|now simpl..]).
+ + case (Z.eq_dec p 2); [intros->|intro Hp].
+ 2:{ now revert Hp; case p;
+ [|intro d0; case d0; [intro d1..|]; [|case d1|]..]. }
+ case z as [| |p|p]; [now simpl|..]; intro H; injection H; intros<-.
+ * now unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
+ * unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ now unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ * unfold of_hexadecimal; simpl; unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to; simpl.
+ now unfold Z.of_hex_uint; rewrite Unsigned.of_to.
+ + case (Z.eq_dec p 2); [intros->|intro Hp].
+ 2:{ now revert Hp; case p;
+ [|intro d0; case d0; [intro d1..|]; [|case d1|]..]. }
+ generalize (of_IQmake_to_hexadecimal num den).
+ case IQmake_to_hexadecimal as [d'|]; [|now simpl].
+ case d' as [i f|]; [|now simpl].
+ intros H H'; injection H'; clear H'; intros<-.
+ unfold of_hexadecimal; simpl.
+ change (match f with Nil => _ | _ => _ end) with (of_hexadecimal (Hexadecimal i f)).
+ rewrite H; clear H.
+ now unfold Z.of_uint; rewrite DecimalPos.Unsigned.of_to.
+Qed.
+
+Lemma to_of (d:hexadecimal) : to_hexadecimal (of_hexadecimal d) = Some (dnorm d).
+Proof.
+ case d as [i f|i f e].
+ - unfold of_hexadecimal; simpl.
+ case (uint_eq_dec f Nil); intro Hf.
+ + rewrite Hf; clear f Hf.
+ unfold to_hexadecimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, HexadecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ + set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_hexadecimal; simpl.
+ unfold IQmake_to_hexadecimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_hexadecimal (Z.of_hex_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_hexadecimal, n; simpl.
+ rewrite nztail_to_hex_uint_pow16.
+ clear r; set (r := if _ <? _ then Some (Hexadecimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite HexadecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ * rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ * rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ - unfold of_hexadecimal; simpl.
+ rewrite <-(DecimalZ.to_of e).
+ case (Z.of_int e); clear e; [|intro e..]; simpl.
+ + case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_hexadecimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, HexadecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_hexadecimal; simpl.
+ unfold IQmake_to_hexadecimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_hexadecimal (Z.of_hex_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_hexadecimal, n; simpl.
+ rewrite nztail_to_hex_uint_pow16.
+ clear r; set (r := if _ <? _ then Some (Hexadecimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite HexadecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ + set (i' := match i with Pos _ => _ | _ => _ end).
+ set (m := match Pos.to_uint e with Decimal.Nil => _ | _ => _ end).
+ replace m with (HexadecimalExp i' f (Decimal.Pos (Pos.to_uint e))).
+ 2:{ unfold m; generalize (DecimalPos.Unsigned.to_uint_nonzero e).
+ now case Pos.to_uint; [|intro u; case u|..]. }
+ unfold i'; clear i' m.
+ case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_hexadecimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, HexadecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_hexadecimal; simpl.
+ unfold IQmake_to_hexadecimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_hexadecimal (Z.of_hex_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_hexadecimal, n; simpl.
+ rewrite nztail_to_hex_uint_pow16.
+ clear r; set (r := if _ <? _ then Some (Hexadecimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite HexadecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+ + case (uint_eq_dec f Nil); intro Hf.
+ * rewrite Hf; clear f Hf.
+ unfold to_hexadecimal; simpl.
+ rewrite IZ_to_Z_IZ_of_Z, HexadecimalZ.to_of.
+ case i as [i|i]; [now simpl|]; simpl.
+ rewrite app_nil_r.
+ case (uint_eq_dec (nzhead i) Nil); [now intros->|intro Hi].
+ now rewrite (unorm_nzhead _ Hi); revert Hi; case nzhead.
+ * set (r := IRQ _).
+ set (m := match f with Nil => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ unfold to_hexadecimal; simpl.
+ unfold IQmake_to_hexadecimal; simpl.
+ set (n := Nat.iter _ _ _).
+ case (Pos.eq_dec n 1); intro Hn.
+ exfalso; apply Hf.
+ { now apply nb_digits_0; revert Hn; unfold n; case nb_digits. }
+ clear m; set (m := match n with 1%positive | _ => _ end).
+ replace m with (QArith_base.IQmake_to_hexadecimal (Z.of_hex_int (app_int i f)) n).
+ 2:{ now unfold m; revert Hn; case n. }
+ unfold QArith_base.IQmake_to_hexadecimal, n; simpl.
+ rewrite nztail_to_hex_uint_pow16.
+ clear r; set (r := if _ <? _ then Some (Hexadecimal _ _) else Some _).
+ clear m; set (m := match nb_digits f with 0 => _ | _ => _ end).
+ replace m with r; [unfold r|now unfold m; revert Hf; case f].
+ rewrite HexadecimalZ.to_of, abs_norm, abs_app_int.
+ case Nat.ltb_spec; intro Hnf.
+ -- rewrite (del_tail_app_int_exact _ _ Hnf).
+ rewrite (del_head_app_int_exact _ _ Hnf).
+ now rewrite (dnorm_i_exact _ _ Hnf).
+ -- rewrite (unorm_app_r _ _ Hnf).
+ rewrite (iter_D0_unorm _ Hf).
+ now rewrite dnorm_i_exact'.
+Qed.
+
+(** Some consequences *)
+
+Lemma to_hexadecimal_inj q q' :
+ to_hexadecimal q <> None -> to_hexadecimal q = to_hexadecimal q' -> q = q'.
+Proof.
+ intros Hnone EQ.
+ generalize (of_to q) (of_to q').
+ rewrite <-EQ.
+ revert Hnone; case to_hexadecimal; [|now simpl].
+ now intros d _ H1 H2; rewrite <-(H1 d eq_refl), <-(H2 d eq_refl).
+Qed.
+
+Lemma to_hexadecimal_surj d : exists q, to_hexadecimal q = Some (dnorm d).
+Proof.
+ exists (of_hexadecimal d). apply to_of.
+Qed.
+
+Lemma of_hexadecimal_dnorm d : of_hexadecimal (dnorm d) = of_hexadecimal d.
+Proof. now apply to_hexadecimal_inj; rewrite !to_of; [|rewrite dnorm_involutive]. Qed.
+
+Lemma of_inj d d' : of_hexadecimal d = of_hexadecimal d' -> dnorm d = dnorm d'.
+Proof.
+ intro H.
+ apply (@f_equal _ _ (fun x => match x with Some x => x | _ => d end)
+ (Some (dnorm d)) (Some (dnorm d'))).
+ now rewrite <- !to_of, H.
+Qed.
+
+Lemma of_iff d d' : of_hexadecimal d = of_hexadecimal d' <-> dnorm d = dnorm d'.
+Proof.
+ split. apply of_inj. intros E. rewrite <- of_hexadecimal_dnorm, E.
+ apply of_hexadecimal_dnorm.
+Qed.
diff --git a/theories/Numbers/HexadecimalZ.v b/theories/Numbers/HexadecimalZ.v
index c5ed0b5b28..1d78ad1ad2 100644
--- a/theories/Numbers/HexadecimalZ.v
+++ b/theories/Numbers/HexadecimalZ.v
@@ -80,9 +80,11 @@ Lemma of_hex_uint_iter_D0 d n :
Z.of_hex_uint (app d (Nat.iter n D0 Nil))
= Nat.iter n (Z.mul 0x10) (Z.of_hex_uint d).
Proof.
- unfold Z.of_hex_uint.
- unfold app; rewrite <-rev_revapp.
- rewrite Unsigned.of_lu_rev, Unsigned.of_lu_revapp.
+ rewrite <-(rev_rev (app _ _)), <-(of_list_to_list (rev (app _ _))).
+ rewrite rev_spec, app_spec, List.rev_app_distr.
+ rewrite <-!rev_spec, <-app_spec, of_list_to_list.
+ unfold Z.of_hex_uint; rewrite Unsigned.of_lu_rev.
+ unfold app; rewrite Unsigned.of_lu_revapp, !rev_rev.
rewrite <-!Unsigned.of_lu_rev, !rev_rev.
assert (H' : Pos.of_hex_uint (Nat.iter n D0 Nil) = 0%N).
{ now induction n; [|rewrite Unsigned.nat_iter_S]. }
@@ -140,3 +142,22 @@ Qed.
Lemma double_to_hex_int n :
double (Z.to_hex_int n) = Z.to_hex_int (Z.double n).
Proof. now rewrite <-(of_to n), <-of_hex_int_double, !to_of, double_norm. Qed.
+
+Lemma nztail_to_hex_uint_pow16 n :
+ Hexadecimal.nztail (Pos.to_hex_uint (Nat.iter n (Pos.mul 16) 1%positive))
+ = (D1 Nil, n).
+Proof.
+ case n as [|n]; [now simpl|].
+ rewrite <-(Nat2Pos.id (S n)); [|now simpl].
+ generalize (Pos.of_nat (S n)); clear n; intro p.
+ induction (Pos.to_nat p); [now simpl|].
+ rewrite Unsigned.nat_iter_S.
+ unfold Pos.to_hex_uint.
+ change (Pos.to_little_hex_uint _)
+ with (Unsigned.to_lu (16 * N.pos (Nat.iter n (Pos.mul 16) 1%positive))).
+ rewrite Unsigned.to_lhex_tenfold.
+ revert IHn; unfold Pos.to_hex_uint.
+ unfold Hexadecimal.nztail; rewrite !rev_rev; simpl.
+ set (f'' := _ (Pos.to_little_hex_uint _)).
+ now case f''; intros r n' H; inversion H.
+Qed.
diff --git a/theories/PArith/BinPosDef.v b/theories/PArith/BinPosDef.v
index b41cd571dc..2ec9f4d871 100644
--- a/theories/PArith/BinPosDef.v
+++ b/theories/PArith/BinPosDef.v
@@ -639,10 +639,10 @@ Fixpoint of_hex_uint (d:Hexadecimal.uint) : N :=
| Hexadecimal.Df l => Npos (of_hex_uint_acc l 1~1~1~1)
end.
-Definition of_num_uint (d:Numeral.uint) : N :=
+Definition of_num_uint (d:Number.uint) : N :=
match d with
- | Numeral.UIntDec d => of_uint d
- | Numeral.UIntHex d => of_hex_uint d
+ | Number.UIntDecimal d => of_uint d
+ | Number.UIntHexadecimal d => of_hex_uint d
end.
Definition of_int (d:Decimal.int) : option positive :=
@@ -665,10 +665,10 @@ Definition of_hex_int (d:Hexadecimal.int) : option positive :=
| Hexadecimal.Neg _ => None
end.
-Definition of_num_int (d:Numeral.int) : option positive :=
+Definition of_num_int (d:Number.int) : option positive :=
match d with
- | Numeral.IntDec d => of_int d
- | Numeral.IntHex d => of_hex_int d
+ | Number.IntDecimal d => of_int d
+ | Number.IntHexadecimal d => of_hex_int d
end.
Fixpoint to_little_uint p :=
@@ -689,13 +689,13 @@ Fixpoint to_little_hex_uint p :=
Definition to_hex_uint p := Hexadecimal.rev (to_little_hex_uint p).
-Definition to_num_uint p := Numeral.UIntDec (to_uint p).
+Definition to_num_uint p := Number.UIntDecimal (to_uint p).
Definition to_int n := Decimal.Pos (to_uint n).
Definition to_hex_int p := Hexadecimal.Pos (to_hex_uint p).
-Definition to_num_int n := Numeral.IntDec (to_int n).
+Definition to_num_int n := Number.IntDecimal (to_int n).
Number Notation positive of_num_int to_num_uint : positive_scope.
diff --git a/theories/QArith/QArith_base.v b/theories/QArith/QArith_base.v
index 192dcd885b..fa4f9134cc 100644
--- a/theories/QArith/QArith_base.v
+++ b/theories/QArith/QArith_base.v
@@ -18,6 +18,9 @@ Require Export Morphisms Setoid Bool.
Record Q : Set := Qmake {Qnum : Z; Qden : positive}.
+Declare Scope hex_Q_scope.
+Delimit Scope hex_Q_scope with xQ.
+
Declare Scope Q_scope.
Delimit Scope Q_scope with Q.
Bind Scope Q_scope with Q.
@@ -33,104 +36,6 @@ Ltac simpl_mult := rewrite ?Pos2Z.inj_mul.
Notation "a # b" := (Qmake a b) (at level 55, no associativity) : Q_scope.
-Definition of_decimal (d:Decimal.decimal) : Q :=
- let '(i, f, e) :=
- match d with
- | Decimal.Decimal i f => (i, f, Decimal.Pos Decimal.Nil)
- | Decimal.DecimalExp i f e => (i, f, e)
- end in
- let num := Z.of_int (Decimal.app_int i f) in
- let e := Z.sub (Z.of_int e) (Z.of_nat (Decimal.nb_digits f)) in
- match e with
- | Z0 => Qmake num 1
- | Zpos e => Qmake (Pos.iter (Z.mul 10) num e) 1
- | Zneg e => Qmake num (Pos.iter (Pos.mul 10) 1%positive e)
- end.
-
-Definition to_decimal (q:Q) : option Decimal.decimal :=
- (* choose between 123e-2 and 1.23, this is purely heuristic
- and doesn't play any soundness role *)
- let choose_exponent i ne :=
- let i := match i with Decimal.Pos i | Decimal.Neg i => i end in
- let li := Decimal.nb_digits i in
- let le := Decimal.nb_digits (Nat.to_uint ne) in
- Nat.ltb (Nat.add li le) ne in
- (* print 123 / 100 as 123e-2 *)
- let decimal_exponent i ne :=
- let e := Z.to_int (Z.opp (Z.of_nat ne)) in
- Decimal.DecimalExp i Decimal.Nil e in
- (* print 123 / 100 as 1.23 *)
- let decimal_dot i ne :=
- let ai := match i with Decimal.Pos i | Decimal.Neg i => i end in
- let ni := Decimal.nb_digits ai in
- if Nat.ltb ne ni then
- let i := Decimal.del_tail_int ne i in
- let f := Decimal.del_head (Nat.sub ni ne) ai in
- Decimal.Decimal i f
- else
- let z := match i with
- | Decimal.Pos _ => Decimal.Pos (Decimal.zero)
- | Decimal.Neg _ => Decimal.Neg (Decimal.zero) end in
- Decimal.Decimal z (Nat.iter (Nat.sub ne ni) Decimal.D0 ai) in
- let num := Z.to_int (Qnum q) in
- let (den, e_den) := Decimal.nztail (Pos.to_uint (Qden q)) in
- match den with
- | Decimal.D1 Decimal.Nil =>
- match e_den with
- | O => Some (Decimal.Decimal num Decimal.Nil)
- | ne =>
- if choose_exponent num ne then Some (decimal_exponent num ne)
- else Some (decimal_dot num ne)
- end
- | _ => None
- end.
-
-Definition of_hexadecimal (d:Hexadecimal.hexadecimal) : Q :=
- let '(i, f, e) :=
- match d with
- | Hexadecimal.Hexadecimal i f => (i, f, Decimal.Pos Decimal.Nil)
- | Hexadecimal.HexadecimalExp i f e => (i, f, e)
- end in
- let num := Z.of_hex_int (Hexadecimal.app_int i f) in
- let e := Z.sub (Z.of_int e) (Z.mul 4 (Z.of_nat (Hexadecimal.nb_digits f))) in
- match e with
- | Z0 => Qmake num 1
- | Zpos e => Qmake (Pos.iter (Z.mul 2) num e) 1
- | Zneg e => Qmake num (Pos.iter (Pos.mul 2) 1%positive e)
- end.
-
-Definition to_hexadecimal (q:Q) : option Hexadecimal.hexadecimal :=
- let mk_exp i e :=
- Hexadecimal.HexadecimalExp i Hexadecimal.Nil (Z.to_int (Z.opp e)) in
- let num := Z.to_hex_int (Qnum q) in
- let (den, e_den) := Hexadecimal.nztail (Pos.to_hex_uint (Qden q)) in
- let e := Z.of_nat e_den in
- match den with
- | Hexadecimal.D1 Hexadecimal.Nil =>
- match e_den with
- | O => Some (Hexadecimal.Hexadecimal num Hexadecimal.Nil)
- | _ => Some (mk_exp num (4 * e)%Z)
- end
- | Hexadecimal.D2 Hexadecimal.Nil => Some (mk_exp num (1 + 4 * e)%Z)
- | Hexadecimal.D4 Hexadecimal.Nil => Some (mk_exp num (2 + 4 * e)%Z)
- | Hexadecimal.D8 Hexadecimal.Nil => Some (mk_exp num (3 + 4 * e)%Z)
- | _ => None
- end.
-
-Definition of_numeral (d:Numeral.numeral) : option Q :=
- match d with
- | Numeral.Dec d => Some (of_decimal d)
- | Numeral.Hex d => Some (of_hexadecimal d)
- end.
-
-Definition to_numeral (q:Q) : option Numeral.numeral :=
- match to_decimal q with
- | None => None
- | Some q => Some (Numeral.Dec q)
- end.
-
-Number Notation Q of_numeral to_numeral : Q_scope.
-
Definition inject_Z (x : Z) := Qmake x 1.
Arguments inject_Z x%Z.
@@ -316,7 +221,7 @@ Definition Qminus (x y : Q) := Qplus x (Qopp y).
Definition Qinv (x : Q) :=
match Qnum x with
- | Z0 => 0
+ | Z0 => 0#1
| Zpos p => (QDen x)#p
| Zneg p => (Zneg (Qden x))#p
end.
@@ -335,6 +240,188 @@ Register Qminus as rat.Q.Qminus.
Register Qopp as rat.Q.Qopp.
Register Qmult as rat.Q.Qmult.
+(** Number notation for constants *)
+
+Inductive IZ :=
+ | IZpow_pos : Z -> positive -> IZ
+ | IZ0 : IZ
+ | IZpos : positive -> IZ
+ | IZneg : positive -> IZ.
+
+Inductive IQ :=
+ | IQmake : IZ -> positive -> IQ
+ | IQmult : IQ -> IQ -> IQ
+ | IQdiv : IQ -> IQ -> IQ.
+
+Definition IZ_of_Z z :=
+ match z with
+ | Z0 => IZ0
+ | Zpos e => IZpos e
+ | Zneg e => IZneg e
+ end.
+
+Definition IZ_to_Z z :=
+ match z with
+ | IZ0 => Some Z0
+ | IZpos e => Some (Zpos e)
+ | IZneg e => Some (Zneg e)
+ | IZpow_pos _ _ => None
+ end.
+
+Definition of_decimal (d:Decimal.decimal) : IQ :=
+ let '(i, f, e) :=
+ match d with
+ | Decimal.Decimal i f => (i, f, Decimal.Pos Decimal.Nil)
+ | Decimal.DecimalExp i f e => (i, f, e)
+ end in
+ let num := Z.of_int (Decimal.app_int i f) in
+ let den := Nat.iter (Decimal.nb_digits f) (Pos.mul 10) 1%positive in
+ let q := IQmake (IZ_of_Z num) den in
+ let e := Z.of_int e in
+ match e with
+ | Z0 => q
+ | Zpos e => IQmult q (IQmake (IZpow_pos 10 e) 1)
+ | Zneg e => IQdiv q (IQmake (IZpow_pos 10 e) 1)
+ end.
+
+Definition IQmake_to_decimal num den :=
+ let num := Z.to_int num in
+ let (den, e_den) := Decimal.nztail (Pos.to_uint den) in
+ match den with
+ | Decimal.D1 Decimal.Nil =>
+ match e_den with
+ | O => Some (Decimal.Decimal num Decimal.Nil)
+ | ne =>
+ let ai := Decimal.abs num in
+ let ni := Decimal.nb_digits ai in
+ if Nat.ltb ne ni then
+ let i := Decimal.del_tail_int ne num in
+ let f := Decimal.del_head (Nat.sub ni ne) ai in
+ Some (Decimal.Decimal i f)
+ else
+ let z := match num with
+ | Decimal.Pos _ => Decimal.Pos (Decimal.zero)
+ | Decimal.Neg _ => Decimal.Neg (Decimal.zero) end in
+ Some (Decimal.Decimal z (Nat.iter (Nat.sub ne ni) Decimal.D0 ai))
+ end
+ | _ => None
+ end.
+
+Definition IQmake_to_decimal' num den :=
+ match IZ_to_Z num with
+ | None => None
+ | Some num => IQmake_to_decimal num den
+ end.
+
+Definition to_decimal (n : IQ) : option Decimal.decimal :=
+ match n with
+ | IQmake num den => IQmake_to_decimal' num den
+ | IQmult (IQmake num den) (IQmake (IZpow_pos 10 e) 1) =>
+ match IQmake_to_decimal' num den with
+ | Some (Decimal.Decimal i f) =>
+ Some (Decimal.DecimalExp i f (Pos.to_int e))
+ | _ => None
+ end
+ | IQdiv (IQmake num den) (IQmake (IZpow_pos 10 e) 1) =>
+ match IQmake_to_decimal' num den with
+ | Some (Decimal.Decimal i f) =>
+ Some (Decimal.DecimalExp i f (Decimal.Neg (Pos.to_uint e)))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Definition of_hexadecimal (d:Hexadecimal.hexadecimal) : IQ :=
+ let '(i, f, e) :=
+ match d with
+ | Hexadecimal.Hexadecimal i f => (i, f, Decimal.Pos Decimal.Nil)
+ | Hexadecimal.HexadecimalExp i f e => (i, f, e)
+ end in
+ let num := Z.of_hex_int (Hexadecimal.app_int i f) in
+ let den := Nat.iter (Hexadecimal.nb_digits f) (Pos.mul 16) 1%positive in
+ let q := IQmake (IZ_of_Z num) den in
+ let e := Z.of_int e in
+ match e with
+ | Z0 => q
+ | Zpos e => IQmult q (IQmake (IZpow_pos 2 e) 1)
+ | Zneg e => IQdiv q (IQmake (IZpow_pos 2 e) 1)
+ end.
+
+Definition IQmake_to_hexadecimal num den :=
+ let num := Z.to_hex_int num in
+ let (den, e_den) := Hexadecimal.nztail (Pos.to_hex_uint den) in
+ match den with
+ | Hexadecimal.D1 Hexadecimal.Nil =>
+ match e_den with
+ | O => Some (Hexadecimal.Hexadecimal num Hexadecimal.Nil)
+ | ne =>
+ let ai := Hexadecimal.abs num in
+ let ni := Hexadecimal.nb_digits ai in
+ if Nat.ltb ne ni then
+ let i := Hexadecimal.del_tail_int ne num in
+ let f := Hexadecimal.del_head (Nat.sub ni ne) ai in
+ Some (Hexadecimal.Hexadecimal i f)
+ else
+ let z := match num with
+ | Hexadecimal.Pos _ => Hexadecimal.Pos (Hexadecimal.zero)
+ | Hexadecimal.Neg _ => Hexadecimal.Neg (Hexadecimal.zero) end in
+ Some (Hexadecimal.Hexadecimal z (Nat.iter (Nat.sub ne ni) Hexadecimal.D0 ai))
+ end
+ | _ => None
+ end.
+
+Definition IQmake_to_hexadecimal' num den :=
+ match IZ_to_Z num with
+ | None => None
+ | Some num => IQmake_to_hexadecimal num den
+ end.
+
+Definition to_hexadecimal (n : IQ) : option Hexadecimal.hexadecimal :=
+ match n with
+ | IQmake num den => IQmake_to_hexadecimal' num den
+ | IQmult (IQmake num den) (IQmake (IZpow_pos 2 e) 1) =>
+ match IQmake_to_hexadecimal' num den with
+ | Some (Hexadecimal.Hexadecimal i f) =>
+ Some (Hexadecimal.HexadecimalExp i f (Pos.to_int e))
+ | _ => None
+ end
+ | IQdiv (IQmake num den) (IQmake (IZpow_pos 2 e) 1) =>
+ match IQmake_to_hexadecimal' num den with
+ | Some (Hexadecimal.Hexadecimal i f) =>
+ Some (Hexadecimal.HexadecimalExp i f (Decimal.Neg (Pos.to_uint e)))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Definition of_number (n : Number.number) : IQ :=
+ match n with
+ | Number.Decimal d => of_decimal d
+ | Number.Hexadecimal h => of_hexadecimal h
+ end.
+
+Definition to_number (q:IQ) : option Number.number :=
+ match to_decimal q with
+ | None => None
+ | Some q => Some (Number.Decimal q)
+ end.
+
+Definition to_hex_number q :=
+ match to_hexadecimal q with
+ | None => None
+ | Some q => Some (Number.Hexadecimal q)
+ end.
+
+Number Notation Q of_number to_hex_number (via IQ
+ mapping [Qmake => IQmake, Qmult => IQmult, Qdiv => IQdiv,
+ Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
+ : hex_Q_scope.
+
+Number Notation Q of_number to_number (via IQ
+ mapping [Qmake => IQmake, Qmult => IQmult, Qdiv => IQdiv,
+ Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
+ : Q_scope.
+
(** A light notation for [Zpos] *)
Lemma Qmake_Qdiv a b : a#b==inject_Z a/inject_Z (Zpos b).
diff --git a/theories/QArith/Qreals.v b/theories/QArith/Qreals.v
index 1baefd6bf7..20b5cb236b 100644
--- a/theories/QArith/Qreals.v
+++ b/theories/QArith/Qreals.v
@@ -13,8 +13,6 @@ Require Export QArith_base.
(** Injection of rational numbers into real numbers. *)
-Definition Q2R (x : Q) : R := (IZR (Qnum x) * / IZR (QDen x))%R.
-
Lemma IZR_nz : forall p : positive, IZR (Zpos p) <> 0%R.
Proof.
intros.
diff --git a/theories/Reals/Rdefinitions.v b/theories/Reals/Rdefinitions.v
index affa129771..40736c61f2 100644
--- a/theories/Reals/Rdefinitions.v
+++ b/theories/Reals/Rdefinitions.v
@@ -22,11 +22,12 @@ Require Import ConstructiveRcomplete.
Require Import ClassicalDedekindReals.
-(* Declare primitive numeral notations for Scope R_scope *)
+(* Declare primitive number notations for Scope R_scope *)
+Declare Scope hex_R_scope.
Declare Scope R_scope.
-Declare ML Module "r_syntax_plugin".
(* Declare Scope R_scope with Key R *)
+Delimit Scope hex_R_scope with xR.
Delimit Scope R_scope with R.
Local Open Scope R_scope.
@@ -224,3 +225,165 @@ Proof.
- (* x = n-1 *) exact n.
- exact (Z.pred n).
Defined.
+
+(** Injection of rational numbers into real numbers. *)
+
+Definition Q2R (x : Q) : R := (IZR (Qnum x) * / IZR (QDen x))%R.
+
+(**********************************************************)
+(** * Number notation for constants *)
+(**********************************************************)
+
+Inductive IR :=
+ | IRZ : IZ -> IR
+ | IRQ : Q -> IR
+ | IRmult : IR -> IR -> IR
+ | IRdiv : IR -> IR -> IR.
+
+Definition of_decimal (d : Decimal.decimal) : IR :=
+ let '(i, f, e) :=
+ match d with
+ | Decimal.Decimal i f => (i, f, Decimal.Pos Decimal.Nil)
+ | Decimal.DecimalExp i f e => (i, f, e)
+ end in
+ let zq := match f with
+ | Decimal.Nil => IRZ (IZ_of_Z (Z.of_int i))
+ | _ =>
+ let num := Z.of_int (Decimal.app_int i f) in
+ let den := Nat.iter (Decimal.nb_digits f) (Pos.mul 10) 1%positive in
+ IRQ (Qmake num den) end in
+ let e := Z.of_int e in
+ match e with
+ | Z0 => zq
+ | Zpos e => IRmult zq (IRZ (IZpow_pos 10 e))
+ | Zneg e => IRdiv zq (IRZ (IZpow_pos 10 e))
+ end.
+
+Definition of_hexadecimal (d : Hexadecimal.hexadecimal) : IR :=
+ let '(i, f, e) :=
+ match d with
+ | Hexadecimal.Hexadecimal i f => (i, f, Decimal.Pos Decimal.Nil)
+ | Hexadecimal.HexadecimalExp i f e => (i, f, e)
+ end in
+ let zq := match f with
+ | Hexadecimal.Nil => IRZ (IZ_of_Z (Z.of_hex_int i))
+ | _ =>
+ let num := Z.of_hex_int (Hexadecimal.app_int i f) in
+ let den := Nat.iter (Hexadecimal.nb_digits f) (Pos.mul 16) 1%positive in
+ IRQ (Qmake num den) end in
+ let e := Z.of_int e in
+ match e with
+ | Z0 => zq
+ | Zpos e => IRmult zq (IRZ (IZpow_pos 2 e))
+ | Zneg e => IRdiv zq (IRZ (IZpow_pos 2 e))
+ end.
+
+Definition of_number (n : Number.number) : IR :=
+ match n with
+ | Number.Decimal d => of_decimal d
+ | Number.Hexadecimal h => of_hexadecimal h
+ end.
+
+Definition IQmake_to_decimal num den :=
+ match den with
+ | 1%positive => None (* this should be encoded as IRZ *)
+ | _ => IQmake_to_decimal num den
+ end.
+
+Definition to_decimal (n : IR) : option Decimal.decimal :=
+ match n with
+ | IRZ z =>
+ match IZ_to_Z z with
+ | Some z => Some (Decimal.Decimal (Z.to_int z) Decimal.Nil)
+ | None => None
+ end
+ | IRQ (Qmake num den) => IQmake_to_decimal num den
+ | IRmult (IRZ z) (IRZ (IZpow_pos 10 e)) =>
+ match IZ_to_Z z with
+ | Some z =>
+ Some (Decimal.DecimalExp (Z.to_int z) Decimal.Nil (Pos.to_int e))
+ | None => None
+ end
+ | IRmult (IRQ (Qmake num den)) (IRZ (IZpow_pos 10 e)) =>
+ match IQmake_to_decimal num den with
+ | Some (Decimal.Decimal i f) =>
+ Some (Decimal.DecimalExp i f (Pos.to_int e))
+ | _ => None
+ end
+ | IRdiv (IRZ z) (IRZ (IZpow_pos 10 e)) =>
+ match IZ_to_Z z with
+ | Some z =>
+ Some (Decimal.DecimalExp (Z.to_int z) Decimal.Nil (Decimal.Neg (Pos.to_uint e)))
+ | None => None
+ end
+ | IRdiv (IRQ (Qmake num den)) (IRZ (IZpow_pos 10 e)) =>
+ match IQmake_to_decimal num den with
+ | Some (Decimal.Decimal i f) =>
+ Some (Decimal.DecimalExp i f (Decimal.Neg (Pos.to_uint e)))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Definition IQmake_to_hexadecimal num den :=
+ match den with
+ | 1%positive => None (* this should be encoded as IRZ *)
+ | _ => IQmake_to_hexadecimal num den
+ end.
+
+Definition to_hexadecimal (n : IR) : option Hexadecimal.hexadecimal :=
+ match n with
+ | IRZ z =>
+ match IZ_to_Z z with
+ | Some z => Some (Hexadecimal.Hexadecimal (Z.to_hex_int z) Hexadecimal.Nil)
+ | None => None
+ end
+ | IRQ (Qmake num den) => IQmake_to_hexadecimal num den
+ | IRmult (IRZ z) (IRZ (IZpow_pos 2 e)) =>
+ match IZ_to_Z z with
+ | Some z =>
+ Some (Hexadecimal.HexadecimalExp (Z.to_hex_int z) Hexadecimal.Nil (Pos.to_int e))
+ | None => None
+ end
+ | IRmult (IRQ (Qmake num den)) (IRZ (IZpow_pos 2 e)) =>
+ match IQmake_to_hexadecimal num den with
+ | Some (Hexadecimal.Hexadecimal i f) =>
+ Some (Hexadecimal.HexadecimalExp i f (Pos.to_int e))
+ | _ => None
+ end
+ | IRdiv (IRZ z) (IRZ (IZpow_pos 2 e)) =>
+ match IZ_to_Z z with
+ | Some z =>
+ Some (Hexadecimal.HexadecimalExp (Z.to_hex_int z) Hexadecimal.Nil (Decimal.Neg (Pos.to_uint e)))
+ | None => None
+ end
+ | IRdiv (IRQ (Qmake num den)) (IRZ (IZpow_pos 2 e)) =>
+ match IQmake_to_hexadecimal num den with
+ | Some (Hexadecimal.Hexadecimal i f) =>
+ Some (Hexadecimal.HexadecimalExp i f (Decimal.Neg (Pos.to_uint e)))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Definition to_number q :=
+ match to_decimal q with
+ | None => None
+ | Some q => Some (Number.Decimal q)
+ end.
+
+Definition to_hex_number q :=
+ match to_hexadecimal q with
+ | None => None
+ | Some q => Some (Number.Hexadecimal q)
+ end.
+
+Number Notation R of_number to_hex_number (via IR
+ mapping [IZR => IRZ, Q2R => IRQ, Rmult => IRmult, Rdiv => IRdiv,
+ Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
+ : hex_R_scope.
+
+Number Notation R of_number to_number (via IR
+ mapping [IZR => IRZ, Q2R => IRQ, Rmult => IRmult, Rdiv => IRdiv,
+ Z.pow_pos => IZpow_pos, Z0 => IZ0, Zpos => IZpos, Zneg => IZneg])
+ : R_scope.
diff --git a/theories/Reals/Rregisternames.v b/theories/Reals/Rregisternames.v
index 8b078f2cf3..8117d975fe 100644
--- a/theories/Reals/Rregisternames.v
+++ b/theories/Reals/Rregisternames.v
@@ -8,7 +8,7 @@
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
-Require Import Raxioms Rfunctions Qreals.
+Require Import Raxioms Rfunctions.
(*****************************************************************)
(** Register names for use in plugins *)
@@ -31,4 +31,4 @@ Register IZR as reals.R.IZR.
Register Rabs as reals.R.Rabs.
Register powerRZ as reals.R.powerRZ.
Register pow as reals.R.pow.
-Register Qreals.Q2R as reals.R.Q2R.
+Register Q2R as reals.R.Q2R.
diff --git a/theories/ZArith/BinIntDef.v b/theories/ZArith/BinIntDef.v
index 69ed101f24..58bc75b62c 100644
--- a/theories/ZArith/BinIntDef.v
+++ b/theories/ZArith/BinIntDef.v
@@ -311,10 +311,10 @@ Definition of_uint (d:Decimal.uint) := of_N (Pos.of_uint d).
Definition of_hex_uint (d:Hexadecimal.uint) := of_N (Pos.of_hex_uint d).
-Definition of_num_uint (d:Numeral.uint) :=
+Definition of_num_uint (d:Number.uint) :=
match d with
- | Numeral.UIntDec d => of_uint d
- | Numeral.UIntHex d => of_hex_uint d
+ | Number.UIntDecimal d => of_uint d
+ | Number.UIntHexadecimal d => of_hex_uint d
end.
Definition of_int (d:Decimal.int) :=
@@ -329,10 +329,10 @@ Definition of_hex_int (d:Hexadecimal.int) :=
| Hexadecimal.Neg d => opp (of_hex_uint d)
end.
-Definition of_num_int (d:Numeral.int) :=
+Definition of_num_int (d:Number.int) :=
match d with
- | Numeral.IntDec d => of_int d
- | Numeral.IntHex d => of_hex_int d
+ | Number.IntDecimal d => of_int d
+ | Number.IntHexadecimal d => of_hex_int d
end.
Definition to_int n :=
@@ -349,7 +349,7 @@ Definition to_hex_int n :=
| neg p => Hexadecimal.Neg (Pos.to_hex_uint p)
end.
-Definition to_num_int n := Numeral.IntDec (to_int n).
+Definition to_num_int n := Number.IntDecimal (to_int n).
(** ** Iteration of a function
diff --git a/theories/dune b/theories/dune
index c2d8197ee4..18e000cfe1 100644
--- a/theories/dune
+++ b/theories/dune
@@ -14,10 +14,8 @@
coq.plugins.cc
coq.plugins.firstorder
- coq.plugins.numeral_notation
- coq.plugins.string_notation
+ coq.plugins.number_string_notation
coq.plugins.int63_syntax
- coq.plugins.r_syntax
coq.plugins.float_syntax
coq.plugins.btauto
diff --git a/user-contrib/Ltac2/g_ltac2.mlg b/user-contrib/Ltac2/g_ltac2.mlg
index 6749169e8c..65b61a0d93 100644
--- a/user-contrib/Ltac2/g_ltac2.mlg
+++ b/user-contrib/Ltac2/g_ltac2.mlg
@@ -146,6 +146,8 @@ GRAMMAR EXTEND Gram
{ CAst.make ~loc @@ CTacLet (isrec, lc, e) }
| "match"; e = ltac2_expr LEVEL "5"; "with"; bl = branches; "end" ->
{ CAst.make ~loc @@ CTacCse (e, bl) }
+ | "if"; e = ltac2_expr LEVEL "5"; "then"; e1 = ltac2_expr LEVEL "5"; "else"; e2 = ltac2_expr LEVEL "5" ->
+ { CAst.make ~loc @@ CTacIft (e, e1, e2) }
]
| "4" LEFTA [ ]
| "3" [ e0 = SELF; ","; el = LIST1 NEXT SEP "," ->
diff --git a/user-contrib/Ltac2/tac2expr.mli b/user-contrib/Ltac2/tac2expr.mli
index 548655f561..0ae016265a 100644
--- a/user-contrib/Ltac2/tac2expr.mli
+++ b/user-contrib/Ltac2/tac2expr.mli
@@ -105,6 +105,7 @@ type raw_tacexpr_r =
| CTacLet of rec_flag * (raw_patexpr * raw_tacexpr) list * raw_tacexpr
| CTacCnv of raw_tacexpr * raw_typexpr
| CTacSeq of raw_tacexpr * raw_tacexpr
+| CTacIft of raw_tacexpr * raw_tacexpr * raw_tacexpr
| CTacCse of raw_tacexpr * raw_taccase list
| CTacRec of raw_recexpr
| CTacPrj of raw_tacexpr * ltac_projection or_relid
diff --git a/user-contrib/Ltac2/tac2intern.ml b/user-contrib/Ltac2/tac2intern.ml
index 797f72702d..ddf70a5a65 100644
--- a/user-contrib/Ltac2/tac2intern.ml
+++ b/user-contrib/Ltac2/tac2intern.ml
@@ -29,6 +29,7 @@ let t_string = coq_type "string"
let t_constr = coq_type "constr"
let t_ltac1 = ltac1_type "t"
let t_preterm = coq_type "preterm"
+let t_bool = coq_type "bool"
(** Union find *)
@@ -749,6 +750,15 @@ let rec intern_rec env {loc;v=e} = match e with
let (e2, t2) = intern_rec env e2 in
let () = check_elt_unit loc1 env t1 in
(GTacLet (false, [Anonymous, e1], e2), t2)
+| CTacIft (e, e1, e2) ->
+ let loc = e.loc in
+ let loc1 = e1.loc in
+ let (e, t) = intern_rec env e in
+ let (e1, t1) = intern_rec env e1 in
+ let (e2, t2) = intern_rec env e2 in
+ let () = unify ?loc env t (GTypRef (Other t_bool, [])) in
+ let () = unify ?loc:loc1 env t1 t2 in
+ (GTacCse (e, Other t_bool, [|e1; e2|], [||]), t2)
| CTacCse (e, pl) ->
intern_case env loc e pl
| CTacRec fs ->
@@ -1271,6 +1281,11 @@ let rec globalize ids ({loc;v=er} as e) = match er with
let e1 = globalize ids e1 in
let e2 = globalize ids e2 in
CAst.make ?loc @@ CTacSeq (e1, e2)
+| CTacIft (e, e1, e2) ->
+ let e = globalize ids e in
+ let e1 = globalize ids e1 in
+ let e2 = globalize ids e2 in
+ CAst.make ?loc @@ CTacIft (e, e1, e2)
| CTacCse (e, bl) ->
let e = globalize ids e in
let bl = List.map (fun b -> globalize_case ids b) bl in
@@ -1486,6 +1501,11 @@ let rec subst_rawexpr subst ({loc;v=tr} as t) = match tr with
let e1' = subst_rawexpr subst e1 in
let e2' = subst_rawexpr subst e2 in
if e1' == e1 && e2' == e2 then t else CAst.make ?loc @@ CTacSeq (e1', e2')
+| CTacIft (e, e1, e2) ->
+ let e' = subst_rawexpr subst e in
+ let e1' = subst_rawexpr subst e1 in
+ let e2' = subst_rawexpr subst e2 in
+ if e' == e && e1' == e1 && e2' == e2 then t else CAst.make ?loc @@ CTacIft (e', e1', e2')
| CTacCse (e, bl) ->
let map (p, e as x) =
let p' = subst_rawpattern subst p in
diff --git a/vernac/attributes.ml b/vernac/attributes.ml
index fb308fd316..efba6d332a 100644
--- a/vernac/attributes.ml
+++ b/vernac/attributes.ml
@@ -224,3 +224,11 @@ let canonical_field =
enable_attribute ~key:"canonical" ~default:(fun () -> true)
let canonical_instance =
enable_attribute ~key:"canonical" ~default:(fun () -> false)
+
+let uses_parser : string key_parser = fun orig args ->
+ assert_once ~name:"using" orig;
+ match args with
+ | VernacFlagLeaf 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 51bab79938..1969665082 100644
--- a/vernac/attributes.mli
+++ b/vernac/attributes.mli
@@ -51,6 +51,7 @@ val option_locality : Goptions.option_locality attribute
val deprecation : Deprecation.t option attribute
val canonical_field : bool attribute
val canonical_instance : bool attribute
+val using : string option attribute
val program_mode_option_name : string list
(** For internal use when messing with the global option. *)
diff --git a/vernac/comDefinition.ml b/vernac/comDefinition.ml
index c1dbf0a1ea..3fc74cba5b 100644
--- a/vernac/comDefinition.ml
+++ b/vernac/comDefinition.ml
@@ -110,7 +110,7 @@ let interp_definition ~program_mode env evd impl_env bl red_option c ctypopt =
let tyopt = Option.map (fun ty -> EConstr.it_mkProd_or_LetIn ty ctx) tyopt in
evd, (c, tyopt), imps
-let do_definition ?hook ~name ~scope ~poly ~kind udecl bl red_option c ctypopt =
+let do_definition ?hook ~name ~scope ~poly ~kind ?using udecl bl red_option c ctypopt =
let program_mode = false in
let env = Global.env() in
(* Explicitly bound universes and constraints *)
@@ -118,14 +118,19 @@ let do_definition ?hook ~name ~scope ~poly ~kind udecl bl red_option c ctypopt =
let evd, (body, types), impargs =
interp_definition ~program_mode env evd empty_internalization_env bl red_option c ctypopt
in
+ let using = using |> Option.map (fun expr ->
+ let terms = body :: match types with Some x -> [x] | None -> [] in
+ let l = Proof_using.process_expr (Global.env()) evd expr terms in
+ Names.Id.Set.(List.fold_right add l empty))
+ in
let kind = Decls.IsDefinition kind in
- let cinfo = Declare.CInfo.make ~name ~impargs ~typ:types () in
+ let cinfo = Declare.CInfo.make ~name ~impargs ~typ:types ?using () in
let info = Declare.Info.make ~scope ~kind ?hook ~udecl ~poly () in
let _ : Names.GlobRef.t =
Declare.declare_definition ~info ~cinfo ~opaque:false ~body evd
in ()
-let do_definition_program ?hook ~pm ~name ~scope ~poly ~kind udecl bl red_option c ctypopt =
+let do_definition_program ?hook ~pm ~name ~scope ~poly ~kind ?using udecl bl red_option c ctypopt =
let program_mode = true in
let env = Global.env() in
(* Explicitly bound universes and constraints *)
@@ -133,9 +138,14 @@ let do_definition_program ?hook ~pm ~name ~scope ~poly ~kind udecl bl red_option
let evd, (body, types), impargs =
interp_definition ~program_mode env evd empty_internalization_env bl red_option c ctypopt
in
+ let using = using |> Option.map (fun expr ->
+ let terms = body :: match types with Some x -> [x] | None -> [] in
+ let l = Proof_using.process_expr (Global.env()) evd expr terms in
+ Names.Id.Set.(List.fold_right add l empty))
+ in
let term, typ, uctx, obls = Declare.Obls.prepare_obligation ~name ~body ~types evd in
let pm, _ =
- let cinfo = Declare.CInfo.make ~name ~typ ~impargs () in
+ let cinfo = Declare.CInfo.make ~name ~typ ~impargs ?using () in
let info = Declare.Info.make ~udecl ~scope ~poly ~kind ?hook () in
Declare.Obls.add_definition ~pm ~cinfo ~info ~term ~uctx obls
in pm
diff --git a/vernac/comDefinition.mli b/vernac/comDefinition.mli
index 7420235449..5e1b705ae4 100644
--- a/vernac/comDefinition.mli
+++ b/vernac/comDefinition.mli
@@ -31,6 +31,7 @@ val do_definition
-> scope:Locality.locality
-> poly:bool
-> kind:Decls.definition_object_kind
+ -> ?using:Vernacexpr.section_subset_expr
-> universe_decl_expr option
-> local_binder_expr list
-> red_expr option
@@ -45,6 +46,7 @@ val do_definition_program
-> scope:Locality.locality
-> poly:bool
-> kind:Decls.logical_kind
+ -> ?using:Vernacexpr.section_subset_expr
-> universe_decl_expr option
-> local_binder_expr list
-> red_expr option
diff --git a/vernac/comFixpoint.ml b/vernac/comFixpoint.ml
index 78572c6aa6..29bf5fbcc2 100644
--- a/vernac/comFixpoint.ml
+++ b/vernac/comFixpoint.ml
@@ -251,15 +251,22 @@ let interp_fixpoint ?(check_recursivity=true) ~cofix l :
let uctx,fix = ground_fixpoint env evd fix in
(fix,pl,uctx,info)
-let build_recthms ~indexes fixnames fixtypes fiximps =
+let build_recthms ~indexes ?using fixnames fixtypes fiximps =
let fix_kind, cofix = match indexes with
| Some indexes -> Decls.Fixpoint, false
| None -> Decls.CoFixpoint, true
in
let thms =
List.map3 (fun name typ (ctx,impargs,_) ->
+ let using = using |> Option.map (fun expr ->
+ let terms = [EConstr.of_constr typ] in
+ let env = Global.env() in
+ let sigma = Evd.from_env env in
+ let l = Proof_using.process_expr env sigma expr terms in
+ Names.Id.Set.(List.fold_right add l empty))
+ in
let args = List.map Context.Rel.Declaration.get_name ctx in
- Declare.CInfo.make ~name ~typ ~args ~impargs ()
+ Declare.CInfo.make ~name ~typ ~args ~impargs ?using ()
) fixnames fixtypes fiximps
in
fix_kind, cofix, thms
@@ -277,9 +284,9 @@ let declare_fixpoint_interactive_generic ?indexes ~scope ~poly ((fixnames,_fixrs
List.iter (Metasyntax.add_notation_interpretation (Global.env())) ntns;
lemma
-let declare_fixpoint_generic ?indexes ~scope ~poly ((fixnames,fixrs,fixdefs,fixtypes),udecl,uctx,fiximps) ntns =
+let declare_fixpoint_generic ?indexes ~scope ~poly ?using ((fixnames,fixrs,fixdefs,fixtypes),udecl,uctx,fiximps) ntns =
(* We shortcut the proof process *)
- let fix_kind, cofix, fixitems = build_recthms ~indexes fixnames fixtypes fiximps in
+ let fix_kind, cofix, fixitems = build_recthms ~indexes ?using fixnames fixtypes fiximps in
let fixdefs = List.map Option.get fixdefs in
let rec_declaration = prepare_recursive_declaration fixnames fixrs fixtypes fixdefs in
let fix_kind = Decls.IsDefinition fix_kind in
@@ -328,9 +335,9 @@ let do_fixpoint_interactive ~scope ~poly l : Declare.Proof.t =
let lemma = declare_fixpoint_interactive_generic ~indexes:possible_indexes ~scope ~poly fix ntns in
lemma
-let do_fixpoint ~scope ~poly l =
+let do_fixpoint ~scope ~poly ?using l =
let fixl, ntns, fix, possible_indexes = do_fixpoint_common l in
- declare_fixpoint_generic ~indexes:possible_indexes ~scope ~poly fix ntns
+ declare_fixpoint_generic ~indexes:possible_indexes ~scope ~poly ?using fix ntns
let do_cofixpoint_common (fixl : Vernacexpr.cofixpoint_expr list) =
let fixl = List.map (fun fix -> {fix with Vernacexpr.rec_order = None}) fixl in
@@ -342,6 +349,6 @@ let do_cofixpoint_interactive ~scope ~poly l =
let lemma = declare_fixpoint_interactive_generic ~scope ~poly cofix ntns in
lemma
-let do_cofixpoint ~scope ~poly l =
+let do_cofixpoint ~scope ~poly ?using l =
let cofix, ntns = do_cofixpoint_common l in
- declare_fixpoint_generic ~scope ~poly cofix ntns
+ declare_fixpoint_generic ~scope ~poly ?using cofix ntns
diff --git a/vernac/comFixpoint.mli b/vernac/comFixpoint.mli
index aa5446205c..a36aba7672 100644
--- a/vernac/comFixpoint.mli
+++ b/vernac/comFixpoint.mli
@@ -19,13 +19,13 @@ val do_fixpoint_interactive :
scope:Locality.locality -> poly:bool -> fixpoint_expr list -> Declare.Proof.t
val do_fixpoint :
- scope:Locality.locality -> poly:bool -> fixpoint_expr list -> unit
+ scope:Locality.locality -> poly:bool -> ?using:Vernacexpr.section_subset_expr -> fixpoint_expr list -> unit
val do_cofixpoint_interactive :
scope:Locality.locality -> poly:bool -> cofixpoint_expr list -> Declare.Proof.t
val do_cofixpoint :
- scope:Locality.locality -> poly:bool -> cofixpoint_expr list -> unit
+ scope:Locality.locality -> poly:bool -> ?using:Vernacexpr.section_subset_expr -> cofixpoint_expr list -> unit
(************************************************************************)
(** Internal API *)
diff --git a/vernac/comProgramFixpoint.ml b/vernac/comProgramFixpoint.ml
index 55901fd604..9623317ddf 100644
--- a/vernac/comProgramFixpoint.ml
+++ b/vernac/comProgramFixpoint.ml
@@ -109,7 +109,7 @@ let telescope env sigma l =
let nf_evar_context sigma ctx =
List.map (map_constr (fun c -> Evarutil.nf_evar sigma c)) ctx
-let build_wellfounded pm (recname,pl,bl,arityc,body) poly r measure notation =
+let build_wellfounded pm (recname,pl,bl,arityc,body) poly ?using r measure notation =
let open EConstr in
let open Vars in
let lift_rel_context n l = Termops.map_rel_context_with_binders (liftn n) l in
@@ -259,8 +259,13 @@ let build_wellfounded pm (recname,pl,bl,arityc,body) poly r measure notation =
let evars, _, evars_def, evars_typ =
RetrieveObl.retrieve_obligations env recname sigma 0 def typ
in
+ let using = using |> Option.map (fun expr ->
+ let terms = List.map EConstr.of_constr [evars_def; evars_typ] in
+ let l = Proof_using.process_expr env sigma expr terms in
+ Names.Id.Set.(List.fold_right add l empty))
+ in
let uctx = Evd.evar_universe_context sigma in
- let cinfo = Declare.CInfo.make ~name:recname ~typ:evars_typ () in
+ let cinfo = Declare.CInfo.make ~name:recname ~typ:evars_typ ?using () in
let info = Declare.Info.make ~udecl ~poly ~hook () in
let pm, _ =
Declare.Obls.add_definition ~pm ~cinfo ~info ~term:evars_def ~uctx evars in
@@ -275,7 +280,7 @@ let collect_evars_of_term evd c ty =
Evar.Set.fold (fun ev acc -> Evd.add acc ev (Evd.find_undefined evd ev))
evars (Evd.from_ctx (Evd.evar_universe_context evd))
-let do_program_recursive ~pm ~scope ~poly fixkind fixl =
+let do_program_recursive ~pm ~scope ~poly ?using fixkind fixl =
let cofix = fixkind = Declare.Obls.IsCoFixpoint in
let (env, rec_sign, udecl, evd), fix, info =
interp_recursive ~cofix ~program_mode:true fixl
@@ -287,13 +292,18 @@ let do_program_recursive ~pm ~scope ~poly fixkind fixl =
let evd = nf_evar_map_undefined evd in
let collect_evars name def typ impargs =
(* Generalize by the recursive prototypes *)
+ let using = using |> Option.map (fun expr ->
+ let terms = [def; typ] in
+ let l = Proof_using.process_expr env evd expr terms in
+ Names.Id.Set.(List.fold_right add l empty))
+ in
let def = nf_evar evd (Termops.it_mkNamedLambda_or_LetIn def rec_sign) in
let typ = nf_evar evd (Termops.it_mkNamedProd_or_LetIn typ rec_sign) in
let evm = collect_evars_of_term evd def typ in
let evars, _, def, typ =
RetrieveObl.retrieve_obligations env name evm
(List.length rec_sign) def typ in
- let cinfo = Declare.CInfo.make ~name ~typ ~impargs () in
+ let cinfo = Declare.CInfo.make ~name ~typ ~impargs ?using () in
(cinfo, def, evars)
in
let (fixnames,fixrs,fixdefs,fixtypes) = fix in
@@ -325,13 +335,13 @@ let do_program_recursive ~pm ~scope ~poly fixkind fixl =
let info = Declare.Info.make ~poly ~scope ~kind ~udecl () in
Declare.Obls.add_mutual_definitions ~pm defs ~info ~uctx ~ntns fixkind
-let do_fixpoint ~pm ~scope ~poly l =
+let do_fixpoint ~pm ~scope ~poly ?using l =
let g = List.map (fun { Vernacexpr.rec_order } -> rec_order) l in
match g, l with
| [Some { CAst.v = CWfRec (n,r) }],
[ Vernacexpr.{fname={CAst.v=id}; univs; binders; rtype; body_def; notations} ] ->
let recarg = mkIdentC n.CAst.v in
- build_wellfounded pm (id, univs, binders, rtype, out_def body_def) poly r recarg notations
+ build_wellfounded pm (id, univs, binders, rtype, out_def body_def) poly ?using r recarg notations
| [Some { CAst.v = CMeasureRec (n, m, r) }],
[Vernacexpr.{fname={CAst.v=id}; univs; binders; rtype; body_def; notations }] ->
@@ -344,7 +354,7 @@ let do_fixpoint ~pm ~scope ~poly l =
user_err Pp.(str"Measure takes only two arguments in Program Fixpoint.")
| _, _ -> r
in
- build_wellfounded pm (id, univs, binders, rtype, out_def body_def) poly
+ build_wellfounded pm (id, univs, binders, rtype, out_def body_def) poly ?using
(Option.default (CAst.make @@ CRef (lt_ref,None)) r) m notations
| _, _ when List.for_all (fun ro -> match ro with None | Some { CAst.v = CStructRec _} -> true | _ -> false) g ->
@@ -352,11 +362,11 @@ let do_fixpoint ~pm ~scope ~poly l =
Vernacexpr.(ComFixpoint.adjust_rec_order ~structonly:true fix.binders fix.rec_order)) l in
let fixkind = Declare.Obls.IsFixpoint annots in
let l = List.map2 (fun fix rec_order -> { fix with Vernacexpr.rec_order }) l annots in
- do_program_recursive ~pm ~scope ~poly fixkind l
+ do_program_recursive ~pm ~scope ~poly ?using fixkind l
| _, _ ->
CErrors.user_err ~hdr:"do_fixpoint"
(str "Well-founded fixpoints not allowed in mutually recursive blocks")
-let do_cofixpoint ~pm ~scope ~poly fixl =
+let do_cofixpoint ~pm ~scope ~poly ?using fixl =
let fixl = List.map (fun fix -> { fix with Vernacexpr.rec_order = None }) fixl in
- do_program_recursive ~pm ~scope ~poly Declare.Obls.IsCoFixpoint fixl
+ do_program_recursive ~pm ~scope ~poly ?using Declare.Obls.IsCoFixpoint fixl
diff --git a/vernac/comProgramFixpoint.mli b/vernac/comProgramFixpoint.mli
index 7935cf27fb..30bf3ae8f8 100644
--- a/vernac/comProgramFixpoint.mli
+++ b/vernac/comProgramFixpoint.mli
@@ -15,6 +15,7 @@ val do_fixpoint :
pm:Declare.OblState.t
-> scope:Locality.locality
-> poly:bool
+ -> ?using:Vernacexpr.section_subset_expr
-> fixpoint_expr list
-> Declare.OblState.t
@@ -22,5 +23,6 @@ val do_cofixpoint :
pm:Declare.OblState.t
-> scope:Locality.locality
-> poly:bool
+ -> ?using:Vernacexpr.section_subset_expr
-> cofixpoint_expr list
-> Declare.OblState.t
diff --git a/vernac/declare.ml b/vernac/declare.ml
index 3a8ceb0e0f..0baae6eca5 100644
--- a/vernac/declare.ml
+++ b/vernac/declare.ml
@@ -55,11 +55,13 @@ module CInfo = struct
(** Names to pre-introduce *)
; impargs : Impargs.manual_implicits
(** Explicitily declared implicit arguments *)
+ ; using : Names.Id.Set.t option
+ (** Explicit declaration of section variables used by the constant *)
}
- let make ~name ~typ ?(args=[]) ?(impargs=[]) () =
- { name; typ; args; impargs }
+ let make ~name ~typ ?(args=[]) ?(impargs=[]) ?using () =
+ { name; typ; args; impargs; using }
let to_constr sigma thm = { thm with typ = EConstr.to_constr sigma thm.typ }
@@ -108,10 +110,10 @@ let default_univ_entry = Entries.Monomorphic_entry Univ.ContextSet.empty
(** [univsbody] are universe-constraints attached to the body-only,
used in vio-delayed opaque constants and private poly universes *)
-let definition_entry_core ?(opaque=false) ?(inline=false) ?feedback_id ?section_vars ?types
+let definition_entry_core ?(opaque=false) ?using ?(inline=false) ?feedback_id ?types
?(univs=default_univ_entry) ?(eff=Evd.empty_side_effects) ?(univsbody=Univ.ContextSet.empty) body =
{ proof_entry_body = Future.from_val ((body,univsbody), eff);
- proof_entry_secctx = section_vars;
+ proof_entry_secctx = using;
proof_entry_type = types;
proof_entry_universes = univs;
proof_entry_opaque = opaque;
@@ -119,7 +121,7 @@ let definition_entry_core ?(opaque=false) ?(inline=false) ?feedback_id ?section_
proof_entry_inline_code = inline}
let definition_entry =
- definition_entry_core ?eff:None ?univsbody:None ?feedback_id:None ?section_vars:None
+ definition_entry_core ?eff:None ?univsbody:None ?feedback_id:None
type 'a constant_entry =
| DefinitionEntry of 'a proof_entry
@@ -236,9 +238,9 @@ let pure_definition_entry ?(opaque=false) ?(inline=false) ?types
proof_entry_feedback = None;
proof_entry_inline_code = inline}
-let delayed_definition_entry ~opaque ?feedback_id ~section_vars ~univs ?types body =
+let delayed_definition_entry ~opaque ?feedback_id ~using ~univs ?types body =
{ proof_entry_body = body
- ; proof_entry_secctx = section_vars
+ ; proof_entry_secctx = using
; proof_entry_type = types
; proof_entry_universes = univs
; proof_entry_opaque = opaque
@@ -608,8 +610,8 @@ let declare_mutually_recursive_core ~info ~cinfo ~opaque ~ntns ~uctx ~rec_declar
uctx, univs
in
let csts = CList.map2
- (fun CInfo.{ name; typ; impargs } body ->
- let entry = definition_entry ~opaque ~types:typ ~univs body in
+ (fun CInfo.{ name; typ; impargs; using } body ->
+ let entry = definition_entry ~opaque ~types:typ ~univs ?using body in
declare_entry ~name ~scope ~kind ~impargs ~uctx entry)
cinfo fixdecls
in
@@ -660,7 +662,7 @@ let check_evars_are_solved env sigma t =
let evars = Evarutil.undefined_evars_of_term sigma t in
if not (Evar.Set.is_empty evars) then error_unresolved_evars env sigma t evars
-let prepare_definition ~info ~opaque ~body ~typ sigma =
+let prepare_definition ~info ~opaque ?using ~body ~typ sigma =
let { Info.poly; udecl; inline; _ } = info in
let env = Global.env () in
let sigma, (body, types) = Evarutil.finalize ~abort_on_undefined_evars:false
@@ -669,13 +671,13 @@ let prepare_definition ~info ~opaque ~body ~typ sigma =
Option.iter (check_evars_are_solved env sigma) types;
check_evars_are_solved env sigma body;
let univs = Evd.check_univ_decl ~poly sigma udecl in
- let entry = definition_entry ~opaque ~inline ?types ~univs body in
+ let entry = definition_entry ~opaque ?using ~inline ?types ~univs body in
let uctx = Evd.evar_universe_context sigma in
entry, uctx
let declare_definition_core ~info ~cinfo ~opaque ~obls ~body sigma =
- let { CInfo.name; impargs; typ; _ } = cinfo in
- let entry, uctx = prepare_definition ~info ~opaque ~body ~typ sigma in
+ let { CInfo.name; impargs; typ; using; _ } = cinfo in
+ let entry, uctx = prepare_definition ~info ~opaque ?using ~body ~typ sigma in
let { Info.scope; kind; hook; _ } = info in
declare_entry_core ~name ~scope ~kind ~impargs ~obls ?hook ~uctx entry, uctx
@@ -803,6 +805,7 @@ module ProgramDecl = struct
let set_uctx ~uctx prg = {prg with prg_uctx = uctx}
let get_poly prg = prg.prg_info.Info.poly
let get_obligations prg = prg.prg_obligations
+ let get_using prg = prg.prg_cinfo.CInfo.using
end
end
@@ -1137,7 +1140,7 @@ let declare_mutual_definition ~pm l =
in
let term = EConstr.to_constr sigma term in
let typ = EConstr.to_constr sigma typ in
- let def = (x.prg_reduce term, r, x.prg_reduce typ, x.prg_cinfo.CInfo.impargs) in
+ let def = (x.prg_reduce term, r, x.prg_reduce typ, x.prg_cinfo.CInfo.impargs, x.prg_cinfo.CInfo.using) in
let oblsubst = List.map (fun (id, (_, c)) -> (id, c)) oblsubst in
(def, oblsubst)
in
@@ -1151,11 +1154,11 @@ let declare_mutual_definition ~pm l =
(* let fixdefs = List.map reduce_fix fixdefs in *)
let fixdefs, fixrs, fixtypes, fixitems =
List.fold_right2
- (fun (d, r, typ, impargs) name (a1, a2, a3, a4) ->
+ (fun (d, r, typ, impargs, using) name (a1, a2, a3, a4) ->
( d :: a1
, r :: a2
, typ :: a3
- , CInfo.{name; typ; impargs; args = []} :: a4 ))
+ , CInfo.{name; typ; impargs; args = []; using } :: a4 ))
defs first.prg_deps ([], [], [], [])
in
let fixkind = Option.get first.prg_fixkind in
@@ -1376,7 +1379,7 @@ end
type t =
{ endline_tactic : Genarg.glob_generic_argument option
- ; section_vars : Id.Set.t option
+ ; using : Id.Set.t option
; proof : Proof.t
; initial_euctx : UState.t
(** The initial universe context (for the statement) *)
@@ -1435,7 +1438,7 @@ let start_proof_core ~name ~typ ~pinfo ?(sign=initialize_named_context_for_proof
let initial_euctx = Evd.evar_universe_context Proof.((data proof).sigma) in
{ proof
; endline_tactic = None
- ; section_vars = None
+ ; using = None
; initial_euctx
; pinfo
}
@@ -1458,7 +1461,7 @@ let start_dependent ~info ~name ~proof_ending goals =
let pinfo = Proof_info.make ~info ~cinfo ~proof_ending () in
{ proof
; endline_tactic = None
- ; section_vars = None
+ ; using = None
; initial_euctx
; pinfo
}
@@ -1523,7 +1526,7 @@ let start_mutual_with_initialization ~info ~cinfo ~mutual_info sigma snl =
map lemma ~f:(fun p ->
pi1 @@ Proof.run_tactic Global.(env ()) init_tac p)
-let get_used_variables pf = pf.section_vars
+let get_used_variables pf = pf.using
let get_universe_decl pf = pf.pinfo.Proof_info.info.Info.udecl
let set_used_variables ps l =
@@ -1547,9 +1550,9 @@ let set_used_variables ps l =
else (ctx, all_safe) in
let ctx, _ =
Environ.fold_named_context aux env ~init:(ctx,ctx_set) in
- if not (Option.is_empty ps.section_vars) then
+ if not (Option.is_empty ps.using) then
CErrors.user_err Pp.(str "Used section variables can be declared only once");
- ctx, { ps with section_vars = Some (Context.Named.to_vars ctx) }
+ ctx, { ps with using = Some (Context.Named.to_vars ctx) }
let get_open_goals ps =
let Proof.{ goals; stack; sigma } = Proof.data ps.proof in
@@ -1646,7 +1649,7 @@ let make_univs ~poly ~uctx ~udecl (used_univs_typ, typ) (used_univs_body, body)
let close_proof ~opaque ~keep_body_ucst_separate ps =
- let { section_vars; proof; initial_euctx; pinfo } = ps in
+ let { using; proof; initial_euctx; pinfo } = ps in
let { Proof_info.info = { Info.udecl } } = pinfo in
let { Proof.name; poly } = Proof.data proof in
let unsafe_typ = keep_body_ucst_separate && not poly in
@@ -1667,7 +1670,7 @@ let close_proof ~opaque ~keep_body_ucst_separate ps =
then make_univs_private_poly ~poly ~uctx ~udecl t b
else make_univs ~poly ~uctx ~udecl t b
in
- definition_entry_core ~opaque ?section_vars ~univs:utyp ~univsbody:ubody ~types:typ ~eff body
+ definition_entry_core ~opaque ?using ~univs:utyp ~univsbody:ubody ~types:typ ~eff body
in
let entries = CList.map make_entry elist in
{ name; entries; uctx }
@@ -1675,7 +1678,7 @@ let close_proof ~opaque ~keep_body_ucst_separate ps =
type closed_proof_output = (Constr.t * Evd.side_effects) list * UState.t
let close_proof_delayed ~feedback_id ps (fpl : closed_proof_output Future.computation) =
- let { section_vars; proof; initial_euctx; pinfo } = ps in
+ let { using; proof; initial_euctx; pinfo } = ps in
let { Proof_info.info = { Info.udecl } } = pinfo in
let { Proof.name; poly; entry; sigma } = Proof.data proof in
@@ -1712,7 +1715,7 @@ let close_proof_delayed ~feedback_id ps (fpl : closed_proof_output Future.comput
let univs = UState.restrict uctx used_univs in
let univs = UState.check_mono_univ_decl univs udecl in
(pt,univs),eff)
- |> delayed_definition_entry ~opaque ~feedback_id ~section_vars ~univs ~types
+ |> delayed_definition_entry ~opaque ~feedback_id ~using ~univs ~types
in
let entries = Future.map2 make_entry fpl (Proofview.initial_goals entry) in
{ name; entries; uctx = initial_euctx }
@@ -2289,7 +2292,8 @@ let rec solve_obligation prg num tac =
let name = Internal.get_name prg in
Proof_ending.End_obligation {name; num; auto}
in
- let cinfo = CInfo.make ~name:obl.obl_name ~typ:(EConstr.of_constr obl.obl_type) () in
+ let using = Internal.get_using prg in
+ let cinfo = CInfo.make ~name:obl.obl_name ~typ:(EConstr.of_constr obl.obl_type) ?using () in
let poly = Internal.get_poly prg in
let info = Info.make ~scope ~kind ~poly () in
let lemma = Proof.start_core ~cinfo ~info ~proof_ending evd in
diff --git a/vernac/declare.mli b/vernac/declare.mli
index 1ad79928d5..0520bf8717 100644
--- a/vernac/declare.mli
+++ b/vernac/declare.mli
@@ -79,6 +79,7 @@ module CInfo : sig
-> typ:'constr
-> ?args:Name.t list
-> ?impargs:Impargs.manual_implicits
+ -> ?using:Names.Id.Set.t
-> unit
-> 'constr t
@@ -244,6 +245,12 @@ module Proof : sig
* (w.r.t. type dependencies and let-ins covered by it) *)
val set_used_variables : t -> Names.Id.t list -> Constr.named_context * t
+ (** Gets the set of variables declared to be used by the proof. None means
+ no "Proof using" or #[using] was given *)
+ val get_used_variables : t -> Id.Set.t option
+
+ (** Compacts the representation of the proof by pruning all intermediate
+ terms *)
val compact : t -> t
(** Update the proof's universe information typically after a
@@ -333,6 +340,7 @@ type 'a proof_entry
val definition_entry
: ?opaque:bool
+ -> ?using:Names.Id.Set.t
-> ?inline:bool
-> ?types:Constr.types
-> ?univs:Entries.universes_entry
diff --git a/vernac/egramcoq.ml b/vernac/egramcoq.ml
index 123ea2c24e..efe4e17d0b 100644
--- a/vernac/egramcoq.ml
+++ b/vernac/egramcoq.ml
@@ -408,8 +408,8 @@ match e with
| TTClosedBinderList _ -> { subst with binderlists = List.flatten v :: subst.binderlists }
| TTBigint ->
begin match forpat with
- | ForConstr -> push_constr subst (CAst.make @@ CPrim (Numeral (NumTok.Signed.of_int_string v)))
- | ForPattern -> push_constr subst (CAst.make @@ CPatPrim (Numeral (NumTok.Signed.of_int_string v)))
+ | ForConstr -> push_constr subst (CAst.make @@ CPrim (Number (NumTok.Signed.of_int_string v)))
+ | ForPattern -> push_constr subst (CAst.make @@ CPatPrim (Number (NumTok.Signed.of_int_string v)))
end
| TTReference ->
begin match forpat with
diff --git a/vernac/g_vernac.mlg b/vernac/g_vernac.mlg
index 3d6a93c888..f192d67624 100644
--- a/vernac/g_vernac.mlg
+++ b/vernac/g_vernac.mlg
@@ -113,7 +113,8 @@ GRAMMAR EXTEND Gram
]
;
attribute:
- [ [ k = ident ; v = attr_value -> { Names.Id.to_string k, v } ]
+ [ [ k = ident ; v = attr_value -> { Names.Id.to_string k, v }
+ | "using" ; v = attr_value -> { "using", v } ]
]
;
attr_value:
diff --git a/vernac/metasyntax.ml b/vernac/metasyntax.ml
index 185abcf35b..8477870cb4 100644
--- a/vernac/metasyntax.ml
+++ b/vernac/metasyntax.ml
@@ -1042,6 +1042,13 @@ let interp_non_syntax_modifiers mods =
in
List.fold_left (fun st modif -> Option.bind st @@ set modif) (Some (false,false,InConstrEntry)) mods
+(* Check if an interpretation can be used for printing a cases printing *)
+let has_no_binders_type =
+ List.for_all (fun (_,(_,typ)) ->
+ match typ with
+ | NtnTypeBinder _ | NtnTypeBinderList -> false
+ | NtnTypeConstr | NtnTypeConstrList -> true)
+
(* Compute precedences from modifiers (or find default ones) *)
let set_entry_type from n etyps (x,typ) =
@@ -1226,6 +1233,9 @@ let find_precedence custom lev etyps symbols onlyprint =
| _ ->
user_err Pp.(str "A notation starting with an atomic expression must be at level 0.")
end
+ | (ETPattern _ | ETBinder _), InConstrEntry when not onlyprint ->
+ (* Don't know exactly if we can make sense of this case *)
+ user_err Pp.(str "Binders or patterns not supported in leftmost position.")
| (ETPattern _ | ETBinder _ | ETConstr _), _ ->
(* Give a default ? *)
if Option.is_empty lev then
@@ -1416,6 +1426,7 @@ type notation_obj = {
notobj_deprecation : Deprecation.t option;
notobj_notation : notation * notation_location;
notobj_specific_pp_rules : syntax_printing_extension option;
+ notobj_also_in_cases_pattern : bool;
}
let load_notation_common silently_define_scope_if_undefined _ (_, nobj) =
@@ -1438,9 +1449,10 @@ let open_notation i (_, nobj) =
let pat = nobj.notobj_interp in
let deprecation = nobj.notobj_deprecation in
let scope = match scope with None -> LastLonelyNotation | Some sc -> NotationInScope sc in
+ let also_in_cases_pattern = nobj.notobj_also_in_cases_pattern in
(* Declare the notation *)
(match nobj.notobj_use with
- | Some use -> Notation.declare_notation (scope,ntn) pat df ~use nobj.notobj_coercion deprecation
+ | Some use -> Notation.declare_notation (scope,ntn) pat df ~use ~also_in_cases_pattern nobj.notobj_coercion deprecation
| None -> ());
(* Declare specific format if any *)
(match nobj.notobj_specific_pp_rules with
@@ -1621,19 +1633,21 @@ let add_notation_in_scope ~local deprecation df env c mods scope =
let (acvars, ac, reversibility) = interp_notation_constr env nenv c in
let interp = make_interpretation_vars sd.recvars (pi2 sd.level) acvars (fst sd.pa_syntax_data) in
let map (x, _) = try Some (x, Id.Map.find x interp) with Not_found -> None in
+ let vars = List.map_filter map i_vars in (* Order of elements is important here! *)
+ let also_in_cases_pattern = has_no_binders_type vars in
let onlyparse,coe = printability (Some sd.level) sd.subentries sd.only_parsing reversibility ac in
let notation, location = sd.info in
let use = make_use true onlyparse sd.only_printing in
let notation = {
notobj_local = local;
notobj_scope = scope;
- notobj_interp = (List.map_filter map i_vars, ac);
- (* Order is important here! *)
notobj_use = use;
+ notobj_interp = (vars, ac);
notobj_coercion = coe;
notobj_deprecation = sd.deprecation;
notobj_notation = (notation, location);
notobj_specific_pp_rules = sy_pp_rules;
+ notobj_also_in_cases_pattern = also_in_cases_pattern;
} in
(* Ready to change the global state *)
List.iter (fun f -> f ()) sd.msgs;
@@ -1665,18 +1679,20 @@ let add_notation_interpretation_core ~local df env ?(impls=empty_internalization
let plevel = match level with Some (from,level,l) -> level | None (* numeral: irrelevant )*) -> 0 in
let interp = make_interpretation_vars recvars plevel acvars (List.combine mainvars i_typs) in
let map (x, _) = try Some (x, Id.Map.find x interp) with Not_found -> None in
+ let vars = List.map_filter map i_vars in (* Order of elements is important here! *)
+ let also_in_cases_pattern = has_no_binders_type vars in
let onlyparse,coe = printability level i_typs onlyparse reversibility ac in
let use = make_use false onlyparse onlyprint in
let notation = {
notobj_local = local;
notobj_scope = scope;
- notobj_interp = (List.map_filter map i_vars, ac);
- (* Order is important here! *)
notobj_use = use;
+ notobj_interp = (vars, ac);
notobj_coercion = coe;
notobj_deprecation = deprecation;
notobj_notation = df';
notobj_specific_pp_rules = pp_sy;
+ notobj_also_in_cases_pattern = also_in_cases_pattern;
} in
Lib.add_anonymous_leaf (inNotation notation);
df'
@@ -1850,8 +1866,9 @@ let add_syntactic_definition ~local deprecation env ident (vars,c) { onlyparsing
let in_pat id = (id,ETConstr (Constrexpr.InConstrEntry,None,(NextLevel,InternalProd))) in
let interp = make_interpretation_vars ~default_if_binding:AsIdentOrPattern [] 0 acvars (List.map in_pat vars) in
let vars = List.map (fun x -> (x, Id.Map.find x interp)) vars in
+ let also_in_cases_pattern = has_no_binders_type vars in
let onlyparsing = onlyparsing || fst (printability None [] false reversibility pat) in
- Syntax_def.declare_syntactic_definition ~local deprecation ident ~onlyparsing (vars,pat)
+ Syntax_def.declare_syntactic_definition ~local ~also_in_cases_pattern deprecation ident ~onlyparsing (vars,pat)
(**********************************************************************)
(* Declaration of custom entry *)
diff --git a/vernac/proof_using.ml b/vernac/proof_using.ml
index 95680c2a4e..bdb0cabacf 100644
--- a/vernac/proof_using.ml
+++ b/vernac/proof_using.ml
@@ -18,30 +18,30 @@ module NamedDecl = Context.Named.Declaration
let known_names = Summary.ref [] ~name:"proofusing-nameset"
-let rec close_fwd e s =
+let rec close_fwd env sigma s =
let s' =
List.fold_left (fun s decl ->
let vb = match decl with
| LocalAssum _ -> Id.Set.empty
- | LocalDef (_,b,_) -> global_vars_set e b
+ | LocalDef (_,b,_) -> Termops.global_vars_set env sigma b
in
- let vty = global_vars_set e (NamedDecl.get_type decl) in
+ let vty = Termops.global_vars_set env sigma (NamedDecl.get_type decl) in
let vbty = Id.Set.union vb vty in
if Id.Set.exists (fun v -> Id.Set.mem v s) vbty
then Id.Set.add (NamedDecl.get_id decl) (Id.Set.union s vbty) else s)
- s (named_context e)
+ s (EConstr.named_context env)
in
- if Id.Set.equal s s' then s else close_fwd e s'
+ if Id.Set.equal s s' then s else close_fwd env sigma s'
-let set_of_type env ty =
+let set_of_type env sigma ty =
List.fold_left (fun acc ty ->
- Id.Set.union (global_vars_set env ty) acc)
+ Id.Set.union (Termops.global_vars_set env sigma ty) acc)
Id.Set.empty ty
let full_set env =
List.fold_right Id.Set.add (List.map NamedDecl.get_id (named_context env)) Id.Set.empty
-let process_expr env e v_ty =
+let process_expr env sigma e v_ty =
let rec aux = function
| SsEmpty -> Id.Set.empty
| SsType -> v_ty
@@ -49,7 +49,7 @@ let process_expr env e v_ty =
| SsUnion(e1,e2) -> Id.Set.union (aux e1) (aux e2)
| SsSubstr(e1,e2) -> Id.Set.diff (aux e1) (aux e2)
| SsCompl e -> Id.Set.diff (full_set env) (aux e)
- | SsFwdClose e -> close_fwd env (aux e)
+ | SsFwdClose e -> close_fwd env sigma (aux e)
and set_of_id id =
if Id.to_string id = "All" then
full_set env
@@ -59,9 +59,9 @@ let process_expr env e v_ty =
in
aux e
-let process_expr env e ty =
- let v_ty = set_of_type env ty in
- let s = Id.Set.union v_ty (process_expr env e v_ty) in
+let process_expr env sigma e ty =
+ let v_ty = set_of_type env sigma ty in
+ let s = Id.Set.union v_ty (process_expr env sigma e v_ty) in
Id.Set.elements s
let name_set id expr = known_names := (id,expr) :: !known_names
@@ -110,7 +110,7 @@ let suggest_common env ppid used ids_typ skip =
S.empty (named_context env)
in
let all = S.diff all skip in
- let fwd_typ = close_fwd env ids_typ in
+ let fwd_typ = close_fwd env (Evd.from_env env) ids_typ in
if !Flags.debug then begin
print (str "All " ++ pr_set false all);
print (str "Type " ++ pr_set false ids_typ);
diff --git a/vernac/proof_using.mli b/vernac/proof_using.mli
index dfc233e8fa..93dbd33ae4 100644
--- a/vernac/proof_using.mli
+++ b/vernac/proof_using.mli
@@ -11,7 +11,8 @@
(** Utility code for section variables handling in Proof using... *)
val process_expr :
- Environ.env -> Vernacexpr.section_subset_expr -> Constr.types list ->
+ Environ.env -> Evd.evar_map ->
+ Vernacexpr.section_subset_expr -> EConstr.types list ->
Names.Id.t list
val name_set : Names.Id.t -> Vernacexpr.section_subset_expr -> unit
@@ -24,3 +25,5 @@ val get_default_proof_using : unit -> Vernacexpr.section_subset_expr option
val proof_using_opt_name : string list
(** For the stm *)
+
+val using_from_string : string -> Vernacexpr.section_subset_expr
diff --git a/vernac/search.ml b/vernac/search.ml
index abefeab779..501e5b1a91 100644
--- a/vernac/search.ml
+++ b/vernac/search.ml
@@ -216,18 +216,16 @@ let name_of_reference ref = Id.to_string (Nametab.basename_of_global ref)
let search_filter query gr kind env sigma typ = match query with
| GlobSearchSubPattern (where,head,pat) ->
let open Context.Rel.Declaration in
- let collect_hyps ctx =
- List.fold_left (fun acc d -> match get_value d with
- | None -> get_type d :: acc
- | Some b -> b :: get_type d :: acc) [] ctx in
+ let rec collect env hyps typ =
+ match Constr.kind typ with
+ | LetIn (na,b,t,c) -> collect (push_rel (LocalDef (na,b,t)) env) ((env,b) :: (env,t) :: hyps) c
+ | Prod (na,t,c) -> collect (push_rel (LocalAssum (na,t)) env) ((env,t) :: hyps) c
+ | _ -> (hyps,(env,typ)) in
let typl= match where with
- | InHyp -> collect_hyps (fst (Term.decompose_prod_assum typ))
- | InConcl -> [snd (Term.decompose_prod_assum typ)]
- | Anywhere ->
- if head then
- let ctx, ccl = Term.decompose_prod_assum typ in ccl :: collect_hyps ctx
- else [typ] in
- List.exists (fun typ ->
+ | InHyp -> fst (collect env [] typ)
+ | InConcl -> [snd (collect env [] typ)]
+ | Anywhere -> if head then let hyps, ccl = collect env [] typ in ccl :: hyps else [env,typ] in
+ List.exists (fun (env,typ) ->
let f =
if head then Constr_matching.is_matching_head
else Constr_matching.is_matching_appsubterm ~closed:false in
diff --git a/vernac/vernacentries.ml b/vernac/vernacentries.ml
index 3ced38d6ea..ef8631fbb6 100644
--- a/vernac/vernacentries.ml
+++ b/vernac/vernacentries.ml
@@ -57,14 +57,16 @@ module DefAttributes = struct
program : bool;
deprecated : Deprecation.t option;
canonical_instance : bool;
+ using : Vernacexpr.section_subset_expr option;
}
let parse f =
let open Attributes in
- let (((locality, deprecated), polymorphic), program), canonical_instance =
- parse Notations.(locality ++ deprecation ++ polymorphic ++ program ++ canonical_instance) f
+ let ((((locality, deprecated), polymorphic), program), canonical_instance), using =
+ parse Notations.(locality ++ deprecation ++ polymorphic ++ program ++ canonical_instance ++ using) f
in
- { polymorphic; program; locality; deprecated; canonical_instance }
+ let using = Option.map Proof_using.using_from_string using in
+ { polymorphic; program; locality; deprecated; canonical_instance; using }
end
let module_locality = Attributes.Notations.(locality >>= fun l -> return (make_module_locality l))
@@ -496,6 +498,25 @@ let program_inference_hook env sigma ev =
user_err Pp.(str "The statement obligations could not be resolved \
automatically, write a statement definition first.")
+let vernac_set_used_variables ~pstate e : Declare.Proof.t =
+ let env = Global.env () in
+ let sigma, _ = Declare.Proof.get_current_context pstate in
+ let initial_goals pf = Proofview.initial_goals Proof.((data pf).entry) in
+ let tys = List.map snd (initial_goals (Declare.Proof.get pstate)) in
+ let l = Proof_using.process_expr env sigma e tys in
+ let vars = Environ.named_context env in
+ List.iter (fun id ->
+ if not (List.exists (NamedDecl.get_id %> Id.equal id) vars) then
+ user_err ~hdr:"vernac_set_used_variables"
+ (str "Unknown variable: " ++ Id.print id))
+ l;
+ let _, pstate = Declare.Proof.set_used_variables pstate l in
+ pstate
+let vernac_set_used_variables_opt ?using pstate =
+ match using with
+ | None -> pstate
+ | Some expr -> vernac_set_used_variables ~pstate expr
+
(* XXX: Interpretation of lemma command, duplication with ComFixpoint
/ ComDefinition ? *)
let interp_lemma ~program_mode ~flags ~scope env0 evd thms =
@@ -525,7 +546,7 @@ let post_check_evd ~udecl ~poly evd =
else (* We fix the variables to ensure they won't be lowered to Set *)
Evd.fix_undefined_variables evd
-let start_lemma_com ~program_mode ~poly ~scope ~kind ?hook thms =
+let start_lemma_com ~program_mode ~poly ~scope ~kind ?using ?hook thms =
let env0 = Global.env () in
let flags = Pretyping.{ all_no_fail_flags with program_mode } in
let decl = fst (List.hd thms) in
@@ -533,17 +554,20 @@ let start_lemma_com ~program_mode ~poly ~scope ~kind ?hook thms =
let evd, thms = interp_lemma ~program_mode ~flags ~scope env0 evd thms in
let mut_analysis = RecLemmas.look_for_possibly_mutual_statements evd thms in
let evd = Evd.minimize_universes evd in
- match mut_analysis with
- | RecLemmas.NonMutual thm ->
- let thm = Declare.CInfo.to_constr evd thm in
- let evd = post_check_evd ~udecl ~poly evd in
- let info = Declare.Info.make ?hook ~poly ~scope ~kind ~udecl () in
- Declare.Proof.start_with_initialization ~info ~cinfo:thm evd
- | RecLemmas.Mutual { mutual_info; cinfo ; possible_guards } ->
- let cinfo = List.map (Declare.CInfo.to_constr evd) cinfo in
- let evd = post_check_evd ~udecl ~poly evd in
- let info = Declare.Info.make ?hook ~poly ~scope ~kind ~udecl () in
- Declare.Proof.start_mutual_with_initialization ~info ~cinfo evd ~mutual_info (Some possible_guards)
+ let pstate =
+ match mut_analysis with
+ | RecLemmas.NonMutual thm ->
+ let thm = Declare.CInfo.to_constr evd thm in
+ let evd = post_check_evd ~udecl ~poly evd in
+ let info = Declare.Info.make ?hook ~poly ~scope ~kind ~udecl () in
+ Declare.Proof.start_with_initialization ~info ~cinfo:thm evd
+ | RecLemmas.Mutual { mutual_info; cinfo ; possible_guards } ->
+ let cinfo = List.map (Declare.CInfo.to_constr evd) cinfo in
+ let evd = post_check_evd ~udecl ~poly evd in
+ let info = Declare.Info.make ?hook ~poly ~scope ~kind ~udecl () in
+ Declare.Proof.start_mutual_with_initialization ~info ~cinfo evd ~mutual_info (Some possible_guards)
+ in
+ vernac_set_used_variables_opt ?using pstate
let vernac_definition_hook ~canonical_instance ~local ~poly = let open Decls in function
| Coercion ->
@@ -583,7 +607,7 @@ let vernac_definition_interactive ~atts (discharge, kind) (lid, pl) bl t =
let program_mode = atts.program in
let poly = atts.polymorphic in
let name = vernac_definition_name lid local in
- start_lemma_com ~program_mode ~poly ~scope:local ~kind:(Decls.IsDefinition kind) ?hook [(name, pl), (bl, t)]
+ start_lemma_com ~program_mode ~poly ~scope:local ~kind:(Decls.IsDefinition kind) ?using:atts.using ?hook [(name, pl), (bl, t)]
let vernac_definition ~atts ~pm (discharge, kind) (lid, pl) bl red_option c typ_opt =
let open DefAttributes in
@@ -604,7 +628,7 @@ let vernac_definition ~atts ~pm (discharge, kind) (lid, pl) bl red_option c typ_
else
let () =
ComDefinition.do_definition ~name:name.v
- ~poly:atts.polymorphic ~scope ~kind pl bl red_option c typ_opt ?hook in
+ ~poly:atts.polymorphic ~scope ~kind ?using:atts.using pl bl red_option c typ_opt ?hook in
pm
(* NB: pstate argument to use combinators easily *)
@@ -613,7 +637,7 @@ let vernac_start_proof ~atts kind l =
let scope = enforce_locality_exp atts.locality NoDischarge in
if Dumpglob.dump () then
List.iter (fun ((id, _), _) -> Dumpglob.dump_definition id false "prf") l;
- start_lemma_com ~program_mode:atts.program ~poly:atts.polymorphic ~scope ~kind:(Decls.IsProof kind) l
+ start_lemma_com ~program_mode:atts.program ~poly:atts.polymorphic ~scope ~kind:(Decls.IsProof kind) ?using:atts.using l
let vernac_end_proof ~lemma ~pm = let open Vernacexpr in function
| Admitted ->
@@ -639,6 +663,8 @@ let vernac_assumption ~atts discharge kind l nl =
match scope with
| Global _ -> Dumpglob.dump_definition lid false "ax"
| Discharge -> Dumpglob.dump_definition lid true "var") idl) l;
+ if Option.has_some atts.using then
+ Attributes.unsupported_attributes ["using",VernacFlagEmpty];
ComAssumption.do_assumptions ~poly:atts.polymorphic ~program_mode:atts.program ~scope ~kind nl l
let is_polymorphic_inductive_cumulativity =
@@ -842,16 +868,17 @@ let vernac_fixpoint_interactive ~atts discharge l =
let scope = vernac_fixpoint_common ~atts discharge l in
if atts.program then
CErrors.user_err Pp.(str"Program Fixpoint requires a body");
- ComFixpoint.do_fixpoint_interactive ~scope ~poly:atts.polymorphic l
+ vernac_set_used_variables_opt ?using:atts.using
+ (ComFixpoint.do_fixpoint_interactive ~scope ~poly:atts.polymorphic l)
let vernac_fixpoint ~atts ~pm discharge l =
let open DefAttributes in
let scope = vernac_fixpoint_common ~atts discharge l in
if atts.program then
(* XXX: Switch to the attribute system and match on ~atts *)
- ComProgramFixpoint.do_fixpoint ~pm ~scope ~poly:atts.polymorphic l
+ ComProgramFixpoint.do_fixpoint ~pm ~scope ~poly:atts.polymorphic ?using:atts.using l
else
- let () = ComFixpoint.do_fixpoint ~scope ~poly:atts.polymorphic l in
+ let () = ComFixpoint.do_fixpoint ~scope ~poly:atts.polymorphic ?using:atts.using l in
pm
let vernac_cofixpoint_common ~atts discharge l =
@@ -864,15 +891,16 @@ let vernac_cofixpoint_interactive ~atts discharge l =
let scope = vernac_cofixpoint_common ~atts discharge l in
if atts.program then
CErrors.user_err Pp.(str"Program CoFixpoint requires a body");
- ComFixpoint.do_cofixpoint_interactive ~scope ~poly:atts.polymorphic l
+ vernac_set_used_variables_opt ?using:atts.using
+ (ComFixpoint.do_cofixpoint_interactive ~scope ~poly:atts.polymorphic l)
let vernac_cofixpoint ~atts ~pm discharge l =
let open DefAttributes in
let scope = vernac_cofixpoint_common ~atts discharge l in
if atts.program then
- ComProgramFixpoint.do_cofixpoint ~pm ~scope ~poly:atts.polymorphic l
+ ComProgramFixpoint.do_cofixpoint ~pm ~scope ~poly:atts.polymorphic ?using:atts.using l
else
- let () = ComFixpoint.do_cofixpoint ~scope ~poly:atts.polymorphic l in
+ let () = ComFixpoint.do_cofixpoint ~scope ~poly:atts.polymorphic ?using:atts.using l in
pm
let vernac_scheme l =
@@ -957,9 +985,15 @@ let interp_filter_in m = function
let vernac_import export refl =
let import_mod (qid,f) =
- let m = try Nametab.locate_module qid
+ let loc = qid.loc in
+ let m = try
+ let m = Nametab.locate_module qid in
+ let () = if Modops.is_functor (Global.lookup_module m).Declarations.mod_type
+ then CErrors.user_err ?loc Pp.(str "Cannot import functor " ++ pr_qualid qid ++ str".")
+ in
+ m
with Not_found ->
- CErrors.user_err Pp.(str "Cannot find module " ++ pr_qualid qid)
+ CErrors.user_err ?loc Pp.(str "Cannot find module " ++ pr_qualid qid)
in
let f = interp_filter_in m f in
Declaremods.import_module f ~export m
@@ -1223,21 +1257,6 @@ let vernac_set_end_tac ~pstate tac =
(* TO DO verifier s'il faut pas mettre exist s | TacId s ici*)
Declare.Proof.set_endline_tactic tac pstate
-let vernac_set_used_variables ~pstate e : Declare.Proof.t =
- let env = Global.env () in
- let initial_goals pf = Proofview.initial_goals Proof.(data pf).Proof.entry in
- let tys = List.map snd (initial_goals (Declare.Proof.get pstate)) in
- let tys = List.map EConstr.Unsafe.to_constr tys in
- let l = Proof_using.process_expr env e tys in
- let vars = Environ.named_context env in
- List.iter (fun id ->
- if not (List.exists (NamedDecl.get_id %> Id.equal id) vars) then
- user_err ~hdr:"vernac_set_used_variables"
- (str "Unknown variable: " ++ Id.print id))
- l;
- let _, pstate = Declare.Proof.set_used_variables pstate l in
- pstate
-
(*****************************)
(* Auxiliary file management *)