diff --git a/clib/unicode.ml b/clib/unicode.ml
index 266059bd5e7a..6465e399de2d 100644
--- a/clib/unicode.ml
+++ b/clib/unicode.ml
@@ -122,6 +122,7 @@ let classify =
mk_lookup_table_from_unicode_tables_for IdentSep
[
single 0x005F; (* Underscore. *)
+ single 0x2017; (* Double low line. *)
single 0x00A0; (* Non breaking space, overrides Sep *)
];
mk_lookup_table_from_unicode_tables_for IdentPart
diff --git a/doc/Makefile.docgram b/doc/Makefile.docgram
index e78384058722..5f158279158a 100644
--- a/doc/Makefile.docgram
+++ b/doc/Makefile.docgram
@@ -38,7 +38,7 @@ REAL_DOC_MLGS := $(wildcard */*.mlg plugins/*/*.mlg)
# omit SSR MLGS and chapter for now
SSR_MLGS := \
plugins/ssr/ssrparser.mlg plugins/ssr/ssrtacs.mlg plugins/ssr/ssrvernac.mlg \
- plugins/ssrmatching/g_ssrmatching.mlg
+ plugins/ssrmatching/g_ssrmatching.mlg plugins/ssrrewrite/ssrrewrite.mlg
REAL_DOC_MLGS := $(filter-out $(SSR_MLGS),$(REAL_DOC_MLGS))
SSR_RSTS := doc/sphinx/proof-engine/ssreflect-proof-language.rst
DOC_RSTS := $(filter-out $(SSR_RSTS),$(DOC_RSTS))
diff --git a/doc/changelog/07-ssreflect/21478-ssreflect-rw-Changed.rst b/doc/changelog/07-ssreflect/21478-ssreflect-rw-Changed.rst
new file mode 100644
index 000000000000..82bf5fe59af0
--- /dev/null
+++ b/doc/changelog/07-ssreflect/21478-ssreflect-rw-Changed.rst
@@ -0,0 +1,12 @@
+- **Changed:**
+ ``rewrite`` tactic for ``rw``. Since this was the major cause of
+ conflict with legacy tactics, ssreflect can now be loaded with less
+ conflicts through ``From Corelib Require Import ssreflect_rw.``.
+ For backward compatibility
+ ``From Corelib Require Import ssreflect.``
+ still loads a ``rewrite`` wrapper to ``rw`` as well as the
+ ``if is then else ``
+ and ``if isn't then else ``
+ syntactic sugars for match
+ (`#21478 `_,
+ by Pierre Roux).
diff --git a/doc/corelib/index-list.html.template b/doc/corelib/index-list.html.template
index 6923703a666c..43b5d3498687 100644
--- a/doc/corelib/index-list.html.template
+++ b/doc/corelib/index-list.html.template
@@ -113,6 +113,7 @@ through the Require Import command.
theories/Corelib/ssrmatching/ssrmatching.v
theories/Corelib/ssr/ssrclasses.v
+ theories/Corelib/ssr/ssreflect_rw.v
theories/Corelib/ssr/ssreflect.v
theories/Corelib/ssr/ssrbool.v
theories/Corelib/ssr/ssrfun.v
diff --git a/doc/sphinx/addendum/generalized-rewriting.rst b/doc/sphinx/addendum/generalized-rewriting.rst
index 5bb8b9770bdf..0c6366c5dd7d 100644
--- a/doc/sphinx/addendum/generalized-rewriting.rst
+++ b/doc/sphinx/addendum/generalized-rewriting.rst
@@ -484,7 +484,7 @@ It is used in two cases:
constraint can be automatically discharged.
+ Compatibility with ssreflect's rewrite:
- The :tacn:`rewrite (ssreflect)` tactic uses generalized rewriting when possible, by
+ The :tacn:`rw` tactic uses generalized rewriting when possible, by
checking that a ``RewriteRelation R`` instance exists when rewriting with a
term of type ``R t u``.
diff --git a/doc/sphinx/changes.rst b/doc/sphinx/changes.rst
index 6450a6b721e3..73e7fab18dea 100644
--- a/doc/sphinx/changes.rst
+++ b/doc/sphinx/changes.rst
@@ -10079,7 +10079,7 @@ Changes in 8.11+beta1
relation. More precisely, assume the given context lemma has type
`forall f1 f2, .. -> (forall i, R1 (f1 i) (f2 i)) -> R2 f1 f2`. The
first step performed by :tacn:`under` (since Coq 8.10) amounts to
- calling the tactic :tacn:`rewrite `, which
+ calling the tactic :tacn:`rw`, which
itself relies on :tacn:`setoid_rewrite` if need be. So this step was
already compatible with a double implication or setoid equality for
the conclusion head symbol `R2`. But a further step consists in
@@ -11109,7 +11109,7 @@ Many bug fixes and documentation improvements, in particular:
by Andreas Lynge, review by Enrico Tassi)
- Make the ``rewrite /t`` tactic work together with
:flag:`Universe Polymorphism`.
- This makes :tacn:`rewrite ` compatible with the HoTT
+ This makes :tacn:`rw` compatible with the HoTT
library https://github.com/HoTT/HoTT
(`#10305 `_,
fixes `#9336 `_,
diff --git a/doc/sphinx/proof-engine/ssreflect-proof-language.rst b/doc/sphinx/proof-engine/ssreflect-proof-language.rst
index f947b7a21f29..a94a6d1cdd2d 100644
--- a/doc/sphinx/proof-engine/ssreflect-proof-language.rst
+++ b/doc/sphinx/proof-engine/ssreflect-proof-language.rst
@@ -55,11 +55,11 @@ such as tactics to mix forward steps and generalizations as
|SSR| adopts the point of view that rewriting, definition
expansion and partial evaluation participate all to a same concept of
rewriting a goal in a larger sense. As such, all these functionalities
-are provided by the :tacn:`rewrite ` tactic.
+are provided by the :tacn:`rw` tactic.
|SSR| includes a little language of patterns to select subterms in
tactics or tacticals where it matters. Its most notable application is
-in the :tacn:`rewrite ` tactic, where patterns are
+in the :tacn:`rw` tactic, where patterns are
used to specify where the rewriting step has to take place.
Finally, |SSR| supports so-called reflection steps, typically
@@ -68,8 +68,7 @@ logical view of a concept.
To conclude, it is worth mentioning that |SSR| tactics can be mixed
with non-|SSR| tactics in the same proof, or in the same Ltac
-expression. The few exceptions to this statement are described in
-section :ref:`compatibility_issues_ssr`.
+expression.
Acknowledgments
@@ -86,9 +85,15 @@ Usage
Getting started
~~~~~~~~~~~~~~~
-To be available, the tactics presented in this manual need the
-following minimal set of libraries to be loaded: ``ssreflect.v``,
-``ssrfun.v`` and ``ssrbool.v``.
+To be available, the tactics presented in this manual need
+``ssreflect_rw.v`` to be loaded.
+
+.. note::
+ One can also load ``ssreflect.v`` to get the deprecated ``rewrite``
+ tactic alias for :tacn:`rw` as well as the ``if is isn't then _ else _`` syntax specialised to booleans.
+
Moreover, these tactics come with a methodology
specific to the authors of |SSR| and which requires a few options
to be set in a different way than in their default way. All in all,
@@ -96,7 +101,7 @@ this corresponds to working in the following context:
.. rocqtop:: in
- From Corelib Require Import ssreflect ssrfun ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -105,77 +110,6 @@ this corresponds to working in the following context:
:flag:`Implicit Arguments`, :flag:`Strict Implicit`,
:flag:`Printing Implicit Defensive`
-.. _compatibility_issues_ssr:
-
-
-Compatibility issues
-~~~~~~~~~~~~~~~~~~~~
-
-Requiring the above modules creates an environment that is mostly
-compatible with the rest of Rocq, up to a few discrepancies.
-
-
-+ New keywords (``is``) might clash with variable, constant, tactic or
- tactical names, or with quasi-keywords in tactic or
- notation commands.
-+ New tactic(al)s names (:tacn:`last`, :tacn:`done`, :tacn:`have`, :tacn:`suffices`,
- :tacn:`suff`, :tacn:`without loss`, :tacn:`wlog`, :tacn:`congr`, :tacn:`unlock`)
- might clash with user tactic names.
-+ Identifiers with both leading and trailing ``_``, such as ``_x_``, are
- reserved by |SSR| and cannot appear in scripts.
-+ The extensions to the :tacn:`rewrite` tactic are partly incompatible with those
- available in current versions of Rocq; in particular, ``rewrite .. in
- (type of k)`` or ``rewrite .. in *`` or any other variant of :tacn:`rewrite`
- will not work, and the |SSR| syntax and semantics for occurrence selection
- and rule chaining are different. Use an explicit rewrite direction
- (``rewrite <- …`` or ``rewrite -> …``) to access the Rocq rewrite tactic.
-+ New symbols (``//``, ``/=``, ``//=``) might clash with adjacent
- existing symbols.
- This can be avoided by inserting white spaces.
-+ New constant and theorem names might clash with the user theory.
- This can be avoided by not importing all of |SSR|:
-
- .. rocqtop:: in
-
- From Corelib Require ssreflect.
- Import ssreflect.SsrSyntax.
-
- Note that the full
- syntax of |SSR|’s rewrite and reserved identifiers are enabled
- only if the ssreflect module has been required and if ``SsrSyntax`` has
- been imported. Thus a file that requires (without importing) ``ssreflect``
- and imports ``SsrSyntax`` can be required and imported without
- automatically enabling |SSR|’s extended rewrite syntax and
- reserved identifiers.
-+ Some user notations (in particular, defining an infix ``;``) might
- interfere with the "open term", parenthesis-free syntax of tactics
- such as :tacn:`have`, :tacn:`set (ssreflect)` and :tacn:`pose (ssreflect)`.
-+ The generalization of ``if`` statements to non-Boolean conditions is turned off
- by |SSR|, because it is mostly subsumed by Coercion to ``bool`` of the
- ``sumXXX`` types (declared in ``ssrfun.v``) and the
- :n:`if @term is @pattern then @term else @term` construct
- (see :ref:`pattern_conditional_ssr`). To use the
- generalized form, turn off the |SSR| Boolean ``if`` notation using the command:
- ``Close Scope boolean_if_scope``.
-+ The following flags can be unset to make |SSR| more compatible with
- parts of Rocq.
-
-.. flag:: SsrRewrite
-
- Controls whether the incompatible rewrite syntax is enabled (the default).
- Disabling the :term:`flag` makes the syntax compatible with other parts of Rocq.
-
-.. flag:: SsrIdents
-
- Controls whether tactics can refer to |SSR|-generated variables that are
- in the form _xxx_. Scripts with explicit references to such variables
- are fragile; they are prone to failure if the proof is later modified or
- if the details of variable name generation change in future releases of Rocq.
-
- The default is on, which gives an error message when the user tries to
- create such identifiers. Disabling the :term:`flag` generates a warning instead,
- increasing compatibility with other parts of Rocq.
-
Gallina extensions
--------------------
@@ -217,7 +151,7 @@ construct differs from the latter as follows.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -257,7 +191,8 @@ dependent pattern matching and for aliasing the pattern (see
Pattern conditional
~~~~~~~~~~~~~~~~~~~
-The following construct can be used for a refutable pattern matching,
+When doing ``From Corelib Require Import ssreflect`` (not ``ssreflect_rw``),
+the following construct can be used for a refutable pattern matching,
that is, pattern testing:
.. prodn::
@@ -275,15 +210,16 @@ example, the null and all list function(al)s can be defined as follows:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
- Variable d: Set.
+ From Corelib Require Import ssreflect.
+
+ Section Test.
+ Variable d : Set.
Definition null (s : list d) :=
if s is nil then true else false.
Variable a : d -> bool.
@@ -311,13 +247,15 @@ The latter appears to be marginally shorter, but it is quite
ambiguous, and indeed often requires an explicit annotation
``(term : {_} + {_})`` to type check, which evens the character count.
-Therefore, |SSR| restricts by default the condition of a plain ``if``
+Therefore, ``From Corelib Require Import ssreflect`` restricts by default the condition of a plain ``if``
construct to the standard ``bool`` type; this avoids spurious type
annotations.
.. example::
- .. rocqtop:: all
+ .. rocqtop:: reset all
+
+ From Corelib Require Import ssreflect.
Definition orb b1 b2 := if b1 then true else b2.
@@ -376,7 +314,7 @@ expressions such as
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -401,7 +339,7 @@ each point of use; e.g., the above definition can be written:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -446,16 +384,12 @@ Anonymous arguments
When in a definition, the type of a certain argument is mandatory, but
not its name, one usually uses “arrow” abstractions for prenex
-arguments, or the ``(_ : term)`` syntax for inner arguments. In |SSR|,
-the latter can be replaced by the open syntax ``of term`` or
-(equivalently) ``& term``, which are both syntactically equivalent to a
-``(_ : term)`` expression. This feature almost behaves as the
-following extension of the binder syntax:
-
-.. prodn::
- binder += {| & @term | of @term }
+arguments, or the ``(_ : term)`` syntax for inner arguments.
+The latter can be replaced by the open syntax ``& term``,
+which is syntactically equivalent to a
+``(_ : term)`` expression.
-Caveat: ``& T`` and ``of T`` abbreviations have to appear at the end
+Caveat: ``& T`` abbreviations have to appear at the end
of a binder list. For instance, the usual two-constructor polymorphic
type list, i.e., the one of the standard ``List`` library, can be
defined by the following declaration:
@@ -464,14 +398,13 @@ defined by the following declaration:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
.. rocqtop:: all
- Inductive list (A : Type) : Type := nil | cons of A & list A.
+ Inductive list (A : Type) : Type := nil | cons & A & list A.
Wildcards
@@ -518,7 +451,7 @@ For example, the tactic :tacn:`pose (ssreflect)` supports parameters:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -633,7 +566,7 @@ where:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -681,7 +614,7 @@ conditions.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -702,7 +635,7 @@ conditions.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -723,7 +656,7 @@ Moreover:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -743,7 +676,7 @@ Moreover:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -776,7 +709,7 @@ An *occurrence switch* can be:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -798,7 +731,7 @@ An *occurrence switch* can be:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -819,7 +752,7 @@ An *occurrence switch* can be:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -850,7 +783,7 @@ selection.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -867,7 +800,7 @@ only one occurrence of the selected term.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -898,7 +831,7 @@ context of a goal thanks to the ``in`` tactical.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
.. rocqtop:: all
@@ -914,7 +847,7 @@ context of a goal thanks to the ``in`` tactical.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
.. rocqtop:: all
@@ -1030,7 +963,7 @@ constants to the goal.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1091,7 +1024,7 @@ The ``:`` tactical is used to operate on an element in the context.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1186,7 +1119,7 @@ The move tactic.
.. rocqtop:: reset all
- Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Goal not False.
move.
@@ -1256,7 +1189,7 @@ The elim tactic
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1296,7 +1229,7 @@ existential metavariables of sort :g:`Prop`.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1443,7 +1376,7 @@ If the tactic is ``move`` or ``case`` and an equation :token:`ident` is given, t
(step 3) for :token:`d_item` is suppressed (see Section :ref:`generation_of_equations_ssr`).
Intro patterns (see Section :ref:`introduction_ssr`)
-and the ``rewrite`` tactic (see Section :ref:`rewriting_ssr`)
+and the ``rw`` tactic (see Section :ref:`rewriting_ssr`)
let one place a :token:`clear_switch` in the middle of other items
(namely identifiers, views and rewrite rules). This can trigger the
addition of proof context items to the ones being explicitly
@@ -1476,7 +1409,7 @@ context to interpret wildcards; in particular, it can accommodate the
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1714,7 +1647,7 @@ Intro patterns
(resp. :token:`occ_switch` ``<-``)
pops the top assumption (which should be a rewritable proposition) into an
anonymous fact, rewrites (resp. rewrites right to left) the goal with this
- fact (using the |SSR| ``rewrite`` tactic described in Section
+ fact (using the |SSR| ``rw`` tactic described in Section
:ref:`rewriting_ssr`, and honoring the optional occurrence selector), and
finally deletes the anonymous fact from the context.
``[`` :token:`i_item` * ``| … |`` :token:`i_item` * ``]``
@@ -1768,13 +1701,15 @@ Clears are deferred until the end of the intro pattern.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Lemma test x y : Nat.leb 0 x = true -> (Nat.leb 0 x) && (Nat.leb y 2) = true.
move=> {x} ->.
@@ -1829,7 +1764,7 @@ Block introduction
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1882,7 +1817,7 @@ deal with the possible parameters of the constants introduced.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1901,7 +1836,7 @@ under fresh |SSR| names.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -1968,7 +1903,7 @@ be substituted.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2074,20 +2009,20 @@ of the time more than two levels of indentation.
Here is a fragment of such a structured script::
case E1: (abezoutn _ _) => [[| k1] [| k2]].
- - rewrite !muln0 !gexpn0 mulg1 => H1.
- move/eqP: (sym_equal F0); rewrite -H1 orderg1 eqn_mul1.
+ - rw !muln0 !gexpn0 mulg1 => H1.
+ move/eqP: (sym_equal F0); rw -H1 orderg1 eqn_mul1.
by case/andP; move/eqP.
- - rewrite muln0 gexpn0 mulg1 => H1.
+ - rw muln0 gexpn0 mulg1 => H1.
have F1: t %| t * S k2.+1 - 1.
- apply: (@dvdn_trans (orderg x)); first by rewrite F0; exact: dvdn_mull.
- rewrite orderg_dvd; apply/eqP; apply: (mulgI x).
- rewrite -{1}(gexpn1 x) mulg1 gexpn_add leq_add_sub //.
+ apply: (@dvdn_trans (orderg x)); first by rw F0; exact: dvdn_mull.
+ rw orderg_dvd; apply/eqP; apply: (mulgI x).
+ rw -{1}(gexpn1 x) mulg1 gexpn_add leq_add_sub //.
by move: P1; case t.
- rewrite dvdn_subr in F1; last by exact: dvdn_mulr.
- + rewrite H1 F0 -{2}(muln1 (p ^ l)); congr (_ * _).
- by apply/eqP; rewrite -dvdn1.
+ rw dvdn_subr in F1; last by exact: dvdn_mulr.
+ + rw H1 F0 -{2}(muln1 (p ^ l)); congr (_ * _).
+ by apply/eqP; rw -dvdn1.
+ by move: P1; case: (t) => [| [| s1]].
- - rewrite muln0 gexpn0 mul1g => H1.
+ - rw muln0 gexpn0 mul1g => H1.
...
@@ -2122,7 +2057,7 @@ with a ``by``, like in:
.. rocqdoc::
- by apply/eqP; rewrite -dvdn1.
+ by apply/eqP; rw -dvdn1.
.. tacn:: done
:name: done
@@ -2141,7 +2076,7 @@ with a ``by``, like in:
Ltac done :=
trivial; hnf; intros; solve
- [ do ![solve [trivial | apply: sym_equal; trivial]
+ [ do ![solve [trivial | simple refine (@sym_equal _ _ _ _); trivial]
| discriminate | contradiction | split]
| match goal with H : ~ _ |- _ => solve [case H; trivial] end ].
@@ -2187,19 +2122,19 @@ is equivalent to:
.. rocqdoc::
- by rewrite my_lemma1.
+ by rw my_lemma1.
succeeds, then the tactic:
.. rocqdoc::
- by rewrite my_lemma1; apply my_lemma2.
+ by rw my_lemma1; apply my_lemma2.
usually fails since it is equivalent to:
.. rocqdoc::
- by (rewrite my_lemma1; apply my_lemma2).
+ by (rw my_lemma1; apply my_lemma2).
.. _selectors_ssr:
@@ -2269,7 +2204,7 @@ to the others.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2335,14 +2270,14 @@ For instance, the tactic:
.. rocqdoc::
- tactic; do 1? rewrite mult_comm.
+ tactic; do 1? rw mult_comm.
rewrites at most one time the lemma ``mult_comm`` in all the subgoals
generated by tactic, whereas the tactic:
.. rocqdoc::
- tactic; do 2! rewrite mult_comm.
+ tactic; do 2! rw mult_comm.
rewrites exactly two times the lemma ``mult_comm`` in all the subgoals
generated by ``tactic``, and fails if this rewrite is not possible in some
@@ -2367,7 +2302,7 @@ already presented the *localization* tactical ``in``, whose general syntax is:
where :token:`ident` is a name in the
context. On the left side of ``in``,
-:token:`tactic` can be ``move``, ``case``, ``elim``, ``rewrite``, ``set``,
+:token:`tactic` can be ``move``, ``case``, ``elim``, ``rw``, ``set``,
or any tactic formed with the general iteration tactical ``do`` (see Section
:ref:`iteration_ssr`).
@@ -2388,14 +2323,14 @@ between standard Ltac ``in`` and the |SSR| tactical in.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
.. rocqtop:: all
- Ltac mytac H := rewrite H.
+ Ltac mytac H := rw H.
Lemma test x y (H1 : x = y) (H2 : y = 3) : x + y = 6.
do [mytac H2] in H1 *.
@@ -2406,7 +2341,7 @@ between standard Ltac ``in`` and the |SSR| tactical in.
By default, ``in`` keeps the body of local definitions. To erase the body
of a local definition during the generalization phase, the name of the
local definition must be written between parentheses, like in
-``rewrite H in H1 (def_n) H2.``
+``rw H in H1 (def_n) H2.``
.. tacv:: @tactic in {+ {| @clear_switch | {? @}@ident | ( @ident ) | ( {? @}@ident := @c_pattern ) } } {? * }
@@ -2463,7 +2398,7 @@ the holes are abstracted in term.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2477,7 +2412,7 @@ the holes are abstracted in term.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2495,7 +2430,7 @@ tactic:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2539,7 +2474,7 @@ statement is very short, basically when it fits in one line like in:
.. rocqdoc::
- have H23 : 3 + 2 = 2 + 3 by rewrite addnC.
+ have H23 : 3 + 2 = 2 + 3 by rw addnC.
The possibility of using :token:`i_item` supplies a very concise syntax for
the further use of the intermediate step. For instance,
@@ -2548,7 +2483,7 @@ the further use of the intermediate step. For instance,
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2576,7 +2511,7 @@ destruction of existential assumptions like in the tactic:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2603,7 +2538,7 @@ term for the intermediate lemma, using tactics of the form:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2623,16 +2558,18 @@ The following example requires the mathcomp and mczify libraries.
.. example::
- .. rocqtop:: reset none warn extra-mathcomp extra-mczify
-
- From mathcomp Require Import ssreflect ssrfun ssrbool ssrnat zify.
+ .. rocqtop:: reset none
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
+ Set Warnings "-notation-overridden".
.. rocqtop:: all extra-mathcomp extra-mczify
+ From Corelib Require Import ssreflect_rw.
+ From mathcomp Require Import ssrfun ssrbool ssrnat zify.
+
Lemma test : True.
have H x (y : nat) : 2 * x + y = x + x + y by lia.
@@ -2745,7 +2682,7 @@ typeclass inference.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Axiom ty : Type.
Axiom t : ty.
@@ -2890,16 +2827,19 @@ simplifies a proof. Here is an example showing the beginning of the
proof that quotient and reminder of natural number euclidean division
are unique.
-The following example requires the mathcomp and mczify libraries.
+The following example requires the mathcomp library.
.. example::
- .. rocqtop:: reset none warn extra-mathcomp
+ .. rocqtop:: reset none
- From mathcomp Require Import ssreflect ssrfun ssrbool ssrnat.
+ Set Warnings "-notation-overridden".
.. rocqtop:: all extra-mathcomp
+ From Corelib Require Import ssreflect_rw.
+ From mathcomp Require Import ssrfun ssrbool ssrnat.
+
Lemma quo_rem_unicity d q1 q2 r1 r2 :
q1*d + r1 = q2*d + r2 -> r1 < d -> r2 < d -> (q1, r1) = (q2, r2).
wlog: q1 q2 r1 r2 / q1 <= q2.
@@ -2921,7 +2861,7 @@ pattern will be used to process its instance.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrfun ssrbool.
+ From Corelib Require Import ssreflect_rw ssrfun ssrbool.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2971,7 +2911,7 @@ illustrated in the following example.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -2990,7 +2930,7 @@ illustrated in the following example.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3015,7 +2955,7 @@ intermediate results handled are properties of effectively computable
functions. The most efficient means of establishing such results are
computation and simplification of expressions involving such
functions, i.e., rewriting. |SSR| therefore includes an
-extended ``rewrite`` tactic that unifies and combines most of the
+extended ``rw`` tactic that unifies and combines most of the
rewriting functionalities.
@@ -3034,8 +2974,7 @@ The main features of the rewrite tactic are:
The general form of an |SSR| rewrite tactic is:
-.. tacn:: rewrite {+ @rstep }
- :name: rewrite (ssreflect)
+.. tacn:: rw {+ @rstep }
:undocumented:
The combination of a rewrite tactic with the ``in`` tactical (see Section
@@ -3085,7 +3024,7 @@ operation should be performed.
:token:`r_item` is actually processed and is complemented with the name of
the rewrite rule if and only if it is a simple proof context entry [#10]_.
As a consequence, one can
- write ``rewrite {}H`` to rewrite with ``H`` and dispose ``H`` immediately
+ write ``rw {}H`` to rewrite with ``H`` and dispose ``H`` immediately
afterwards.
This behavior can be avoided by putting parentheses around the rewrite rule.
@@ -3097,16 +3036,16 @@ A :token:`r_item` can be one of the following.
:ref:`introduction_ssr`). Simplification operations are intertwined with the possible
other rewrite operations specified by the list of :token:`r_item`.
+ A *folding/unfolding* :token:`r_item`. The tactic
- ``rewrite /term`` unfolds the
+ ``rw /term`` unfolds the
:term:`head constant` of ``term`` in every occurrence of the first matching of
``term`` in the goal. In particular, if ``my_def`` is a (local or global)
- defined constant, the tactic ``rewrite /my_def.`` is analogous to:
+ defined constant, the tactic ``rw /my_def.`` is analogous to:
``unfold my_def``.
- Conversely, ``rewrite -/my_def.`` is equivalent to ``fold my_def``.
+ Conversely, ``rw -/my_def.`` is equivalent to ``fold my_def``.
When an unfold :token:`r_item` is combined with a
redex pattern, a conversion
operation is performed. A tactic of the form
- ``rewrite -[term1]/term2.``
+ ``rw -[term1]/term2.``
is equivalent to ``change term1 with term2.`` If ``term2`` is a
single constant and ``term1`` head symbol is not ``term2``, then the head
symbol of ``term1`` is repeatedly unfolded until ``term2`` appears.
@@ -3116,15 +3055,15 @@ A :token:`r_item` can be one of the following.
``eq`` is the Leibniz equality or a registered setoid
equality;
+ a list of terms ``(t1 ,…,tn)``, each ``ti`` having a type as above, and
- the tactic ``rewrite r_prefix (t1 ,…,tn ).``
- is equivalent to ``do [rewrite r_prefix t1 | … | rewrite r_prefix tn ].``;
+ the tactic ``rw r_prefix (t1 ,…,tn ).``
+ is equivalent to ``do [rw r_prefix t1 | … | rw r_prefix tn ].``;
+ an anonymous rewrite lemma ``(_ : term)``, where ``term`` has a type as above.
.. example::
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3134,7 +3073,7 @@ A :token:`r_item` can be one of the following.
Definition double x := x + x.
Definition ddouble x := double (double x).
Lemma test x : ddouble x = 4 * x.
- rewrite [ddouble _]/double.
+ rw [ddouble _]/double.
.. warning::
@@ -3148,13 +3087,13 @@ A :token:`r_item` can be one of the following.
.. rocqtop:: all fail
- rewrite -[f y]/(y + _).
+ rw -[f y]/(y + _).
but the following script succeeds
.. rocqtop:: all
- rewrite -[f y x]/(y + _).
+ rw -[f y x]/(y + _).
.. flag:: SsrOldRewriteGoalsOrder
@@ -3185,7 +3124,7 @@ In a rewrite tactic of the form:
.. rocqdoc::
- rewrite occ_switch [term1]term2.
+ rw occ_switch [term1]term2.
``term1`` is the explicit rewrite redex and ``term2`` is the rewrite rule.
This execution of this tactic unfolds as follows.
@@ -3228,7 +3167,7 @@ tactic:
.. rocqdoc::
- rewrite /my_def {2}[f _]/= my_eq //=.
+ rw /my_def {2}[f _]/= my_eq //=.
unfolds ``my_def`` in the goal, simplifies the second occurrence of the
@@ -3243,7 +3182,7 @@ proof of basic results on natural numbers arithmetic.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3255,11 +3194,11 @@ proof of basic results on natural numbers arithmetic.
Axiom addSnnS : forall m n, S m + n = m + S n.
Lemma addnCA m n p : m + (n + p) = n + (m + p).
- by elim: m p => [ | m Hrec] p; rewrite ?addSnnS -?addnS.
+ by elim: m p => [ | m Hrec] p; rw ?addSnnS -?addnS.
Qed.
Lemma addnC n m : m + n = n + m.
- by rewrite -{1}[n]addn0 addnCA addn0.
+ by rw -{1}[n]addn0 addnCA addn0.
Qed.
Note the use of the ``?`` switch for parallel rewrite operations in the
@@ -3279,7 +3218,7 @@ side of the equality the user wants to rewrite.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3287,7 +3226,7 @@ side of the equality the user wants to rewrite.
.. rocqtop:: all
Lemma test (H : forall t u, t + u = u + t) x y : x + y = y + x.
- rewrite [y + _]H.
+ rw [y + _]H.
Note that if this first pattern matching is not compatible with the
:token:`r_item`, the rewrite fails, even if the goal contains a
@@ -3299,7 +3238,7 @@ the equality.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3307,7 +3246,7 @@ the equality.
.. rocqtop:: all
Lemma test (H : forall t u, t + u * 0 = t) x y : x + y * 4 + 2 * 0 = x + 2 * 0.
- Fail rewrite [x + _]H.
+ Fail rw [x + _]H.
Indeed, the left-hand side of ``H`` does not match
the redex identified by the pattern ``x + y * 4``.
@@ -3322,7 +3261,7 @@ Occurrence switches and redex switches
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3330,7 +3269,7 @@ Occurrence switches and redex switches
.. rocqtop:: all
Lemma test x y : x + y + 0 = x + y + y + 0 + 0 + (x + y + 0).
- rewrite {2}[_ + y + 0](_: forall z, z + 0 = z).
+ rw {2}[_ + y + 0](_: forall z, z + 0 = z).
The second subgoal is generated by the use of an anonymous lemma in
the rewrite tactic. The effect of the tactic on the initial goal is to
@@ -3351,7 +3290,7 @@ repetition.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3359,7 +3298,7 @@ repetition.
.. rocqtop:: all
Lemma test x y (z : nat) : x + 1 = x + y + 1.
- rewrite 2!(_ : _ + 1 = z).
+ rw 2!(_ : _ + 1 = z).
This last tactic generates *three* subgoals because
the second rewrite operation specified with the ``2!`` multiplier
@@ -3381,7 +3320,7 @@ rewrite operations prescribed by the rules on the current goal.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3395,7 +3334,7 @@ rewrite operations prescribed by the rules on the current goal.
Hypothesis eqac : a = c.
Lemma test : a = a.
- rewrite (eqab, eqac).
+ rw (eqab, eqac).
Indeed, rule ``eqab`` is the first to apply among the ones
gathered in the tuple passed to the rewrite tactic. This multirule
@@ -3406,8 +3345,8 @@ rewrite operations prescribed by the rules on the current goal.
Definition multi1 := (eqab, eqac).
- In this case, the tactic ``rewrite multi1`` is a synonym for
- ``rewrite (eqab, eqac)``.
+ In this case, the tactic ``rw multi1`` is a synonym for
+ ``rw (eqab, eqac)``.
More precisely, a multirule rewrites the first subterm to which one of
the rules applies in a left-to-right traversal of the goal, with the
@@ -3425,7 +3364,7 @@ literal matches have priority.
Definition multi2 := (eqab, eqd0).
Lemma test : d = b.
- rewrite multi2.
+ rw multi2.
Indeed, rule ``eqd0`` applies without unfolding the
definition of ``d``.
@@ -3443,7 +3382,7 @@ repeated anew.
Definition multi3 := (eq_adda_b, eq_adda_c, eqb0).
Lemma test : 1 + a = 12 + a.
- rewrite 2!multi3.
+ rw 2!multi3.
It uses ``eq_adda_b`` then ``eqb0`` on the left-hand
side only. Without the bound ``2``, one would obtain ``0 = 0``.
@@ -3454,7 +3393,7 @@ to (universally) quantify over the parameters of a subset of rules (as
there is special code that will omit unnecessary quantifiers for rules
that can be syntactically extracted). It is also possible to reverse
the direction of a rule subset, using a special dedicated syntax: the
-tactic rewrite ``(=^~ multi1)`` is equivalent to ``rewrite multi1_rev``.
+tactic rewrite ``(=^~ multi1)`` is equivalent to ``rw multi1_rev``.
.. example::
@@ -3497,7 +3436,7 @@ the efficient operations, we gather all these rules in the definition
Definition trecE := (addE, (doubleE, oddE), (mulE, add_mulE, (expE, mul_expE))).
-The tactic ``rewrite !trecE.``
+The tactic ``rw !trecE.``
restores the naive version of each operation in a goal involving the
efficient ones, e.g., for the purpose of a correctness proof.
@@ -3506,16 +3445,16 @@ Wildcards vs abstractions
`````````````````````````
The rewrite tactic supports :token:`r_item`\s containing holes. For example, in
-the tactic ``rewrite (_ : _ * 0 = 0).``,
+the tactic ``rw (_ : _ * 0 = 0).``,
the term ``_ * 0 = 0`` is interpreted as ``forall n : nat, n * 0 = 0.``
Anyway this tactic is *not* equivalent to
-``rewrite (_ : forall x, x * 0 = 0).``.
+``rw (_ : forall x, x * 0 = 0).``.
.. example::
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3525,13 +3464,13 @@ Anyway this tactic is *not* equivalent to
.. rocqtop:: all
Lemma test y z : y * 0 + y * (z * 0) = 0.
- rewrite (_ : _ * 0 = 0).
+ rw (_ : _ * 0 = 0).
while the other tactic results in
.. rocqtop:: all restart abort
- rewrite (_ : forall x, x * 0 = 0).
+ rw (_ : forall x, x * 0 = 0).
The first tactic requires you to prove the instance of the (missing)
lemma that was used, while the latter requires you prove the quantified
@@ -3565,7 +3504,7 @@ cases.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3580,7 +3519,7 @@ cases.
Lemma test : f 3 + f 3 = f 6.
(* we call the standard rewrite tactic here *)
- rewrite -> H.
+ rewrite H.
This rewriting is not possible in |SSR|, because
there is no occurrence of the head symbol ``f`` of the rewrite rule in the
@@ -3588,23 +3527,23 @@ cases.
.. rocqtop:: all restart fail
- rewrite H.
+ rw H.
Rewriting with ``H`` first requires unfolding the occurrences of
``f``
where the substitution is to be performed (here there is a single such
- occurrence), using tactic ``rewrite /f`` (for a global replacement of
- ``f`` by ``g``) or ``rewrite pattern/f``, for a finer selection.
+ occurrence), using tactic ``rw /f`` (for a global replacement of
+ ``f`` by ``g``) or ``rw pattern/f``, for a finer selection.
.. rocqtop:: all restart
- rewrite /f H.
+ rw /f H.
Alternatively, one can override the pattern inferred from ``H``
.. rocqtop:: all restart
- rewrite [f _]H.
+ rw [f _]H.
Existential metavariables and rewriting
@@ -3623,7 +3562,6 @@ corresponding new goals will be generated.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrfun ssrbool.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3631,6 +3569,8 @@ corresponding new goals will be generated.
.. rocqtop:: all abort
+ From Corelib Require Import ssreflect ssrfun ssrbool.
+
Axiom leq : nat -> nat -> bool.
Notation "m <= n" := (leq m n) : nat_scope.
Notation "m < n" := (S m <= n) : nat_scope.
@@ -3643,11 +3583,11 @@ corresponding new goals will be generated.
Axiom insubT : forall n x Px, insub n x = Some (Sub x Px).
Lemma test (x : 'I_2) y : Some x = insub 2 y.
- rewrite insubT.
+ rw insubT.
Since the argument corresponding to ``Px`` is not supplied by the user, the
resulting goal should be ``Some x = Some (Sub y ?Goal).``
- Instead, |SSR| ``rewrite`` tactic hides the existential variable.
+ Instead, |SSR| ``rw`` tactic hides the existential variable.
As in :ref:`apply_ssr`, the ``ssrautoprop`` tactic is used to try to
solve the existential variable.
@@ -3655,7 +3595,7 @@ corresponding new goals will be generated.
.. rocqtop:: all abort
Lemma test (x : 'I_2) y (H : y < 2) : Some x = insub 2 y.
- rewrite insubT.
+ rw insubT.
As a temporary limitation, this behavior is available only if the
@@ -3680,7 +3620,7 @@ complete terms, as shown by the simple example below.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3703,7 +3643,7 @@ complete terms, as shown by the simple example below.
.. rocqtop:: all fail
- rewrite eq_map.
+ rw eq_map.
as we need to explicitly provide the non-inferable argument ``F2``,
which corresponds here to the term we want to obtain *after* the
@@ -3712,8 +3652,8 @@ complete terms, as shown by the simple example below.
.. rocqtop:: all abort
- rewrite (@eq_map _ (fun _ : nat => 0)).
- by move=> m; rewrite subnn.
+ rw (@eq_map _ (fun _ : nat => 0)).
+ by move=> m; rw subnn.
The :tacn:`under` tactic lets one perform the same operation in a more
convenient way:
@@ -3721,7 +3661,7 @@ complete terms, as shown by the simple example below.
.. rocqtop:: all abort
Lemma example_map l : sumlist (map (fun m => m - m) l) = 0.
- under eq_map => m do rewrite subnn.
+ under eq_map => m do rw subnn.
The under tactic
@@ -3759,7 +3699,7 @@ Let us redo the running example in interactive mode.
Lemma example_map l : sumlist (map (fun m => m - m) l) = 0.
under eq_map => m.
- rewrite subnn.
+ rw subnn.
over.
The execution of the Ltac expression:
@@ -3768,8 +3708,8 @@ The execution of the Ltac expression:
involves the following steps.
-1. It performs a :n:`rewrite @term`
- without failing like in the first example with ``rewrite eq_map.``,
+1. It performs a :n:`rw @term`
+ without failing like in the first example with ``rw eq_map.``,
but creating evars (see :tacn:`evar`). If :n:`term` is prefixed by
a pattern or an occurrence selector, then the modifiers are honoured.
@@ -3787,7 +3727,8 @@ involves the following steps.
registered relations (w.r.t. Class ``RewriteRelation``) between a
term and an evar, e.g., ``m - m = ?F2 m`` in the running example.
(This support for setoid-like relations is enabled as soon as one does
- both ``Require Import ssreflect.`` and ``Require Setoid.``)
+ both ``From Corelib Require Import ssreflect_rw.``
+ and ``From Corelib Require Setoid.``)
5. If so :tacn:`under` protects these n goals against an
accidental instantiation of the evar.
@@ -3871,7 +3812,7 @@ Notes:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -3935,7 +3876,7 @@ Notes:
\sum_(0 <= i < m | prime i) \sum_(0 <= j < n | odd j) (j + i).
under eq_bigr => i prime_i do
under eq_big => [ j | j odd_j ] do
- [ rewrite (muln1 j) | rewrite (addnC i j) ].
+ [ rw (muln1 j) | rw (addnC i j) ].
Remark how the final goal uses the name ``i`` (the name given in the
intro pattern) rather than ``a`` in the binder of the first summation.
@@ -3978,21 +3919,22 @@ selective rewriting, blocking on the fly the reduction in the term ``t``.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrfun ssrbool.
- From Corelib Require Import ListDef.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssreflect ssrfun ssrbool.
+ From Corelib Require Import ListDef.
+ Section Test.
+
Variable A : Type.
Fixpoint has (p : A -> bool) (l : list A) : bool :=
if l is cons x l then p x || (has p l) else false.
Lemma test p x y l (H : p x = true) : has p ( x :: y :: l) = true.
- rewrite {2}[cons]lock /= -lock.
+ rw {2}[cons]lock /= -lock.
It is sometimes desirable to globally prevent a definition from being
expanded by simplification; this is done by adding ``locked`` in the
@@ -4002,7 +3944,7 @@ definition.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4013,7 +3955,7 @@ definition.
Definition lid := locked (fun x : nat => x).
Lemma test : lid 3 = 3.
- rewrite /=.
+ rw /=.
unlock lid.
.. tacn:: unlock {? @occ_switch } @ident
@@ -4073,7 +4015,7 @@ arithmetic operations. We define for instance:
The operation ``addn`` behaves exactly like ``plus``, except that
``(addn (S n) m)`` will not simplify spontaneously to
``(S (addn n m))`` (the two terms, however, are convertible).
-In addition, the unfolding step ``rewrite /addn``
+In addition, the unfolding step ``rw /addn``
will replace ``addn`` directly with ``plus``, so the ``nosimpl`` form is
essentially invisible.
@@ -4115,11 +4057,10 @@ which the function is supplied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
@@ -4142,14 +4083,14 @@ which the function is supplied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssreflect.
+
Definition f n :=
if n is 0 then plus else mult.
Definition g (n m : nat) := plus.
@@ -4165,18 +4106,17 @@ which the function is supplied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
Lemma test n m (Hnm : m <= n) : S m + (S n - S m) = S n.
- congr S; rewrite -/plus.
+ congr S; rw -/plus.
- The tactic ``rewrite -/plus`` folds back the expansion of ``plus``,
+ The tactic ``rw -/plus`` folds back the expansion of ``plus``,
which was necessary for matching both sides of the equality with
an application of ``S``.
@@ -4186,11 +4126,10 @@ which the function is supplied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
@@ -4253,7 +4192,7 @@ in the second column.
The rewrite tactic supports two more patterns obtained prefixing the
first two with ``in``. The intended meaning is that the pattern identifies
-all subterms of the specified context. The ``rewrite`` tactic will infer a
+all subterms of the specified context. The ``rw`` tactic will infer a
pattern for the redex looking at the rule used for rewriting.
.. list-table::
@@ -4287,11 +4226,11 @@ consider the goal ``a = b`` and the tactic
.. rocqdoc::
- rewrite [in X in _ = X]rule.
+ rw [in X in _ = X]rule.
It rewrites all occurrences of the left hand side of ``rule``
inside ``b`` only (``a``, and the hidden type of the equality, are ignored). Note that the
-variant ``rewrite [X in _ = X]rule`` would have rewritten ``b``
+variant ``rw [X in _ = X]rule`` would have rewritten ``b``
exactly (i.e., it would only work if ``b`` and the left-hand side
of rule can be unified).
@@ -4366,17 +4305,16 @@ parentheses are required around more complex patterns.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
Lemma test a b : a + b + 1 = b + (a + 1).
set t := (X in _ = X).
- rewrite {}/t.
+ rw {}/t.
set t := (a + _ in X in _ = X).
@@ -4405,11 +4343,10 @@ Contextual patterns in rewrite
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
@@ -4421,7 +4358,7 @@ Contextual patterns in rewrite
Axiom addnC : forall m n, m + n = n + m.
Lemma test x y z f : (x.+1 + y) + f (x.+1 + y) (z + (x + y).+1) = 0.
- rewrite [in f _ _]addSn.
+ rw [in f _ _]addSn.
Note: the simplification rule ``addSn`` is applied only under the ``f``
symbol.
@@ -4429,7 +4366,7 @@ Contextual patterns in rewrite
.. rocqtop:: all
- rewrite addSn -[X in _ = X]addn0.
+ rw addSn -[X in _ = X]addn0.
Note that the right-hand side of ``addn0`` is undetermined, but the
rewrite pattern specifies the redex explicitly. The right-hand side
@@ -4442,13 +4379,13 @@ Contextual patterns in rewrite
.. rocqtop:: all
- rewrite -{2}[in X in _ = X](addn0 0).
+ rw -{2}[in X in _ = X](addn0 0).
The following tactic is quite tricky:
.. rocqtop:: all
- rewrite [_.+1 in X in f _ X](addnC x.+1).
+ rw [_.+1 in X in f _ X](addnC x.+1).
The explicit redex ``_.+1`` is important, since its :term:`head constant` ``S``
differs from the head constant inferred from
@@ -4468,7 +4405,7 @@ Contextual patterns in rewrite
.. rocqtop:: all
- rewrite [x.+1 + y as X in f X _]addnC.
+ rw [x.+1 + y as X in f X _]addnC.
Patterns for recurrent contexts
@@ -4495,7 +4432,7 @@ Shortcuts defined this way can be freely used in place of the trailing
.. rocqdoc::
set rhs := RHS.
- rewrite [in RHS]rule.
+ rw [in RHS]rule.
case: (a + _ in RHS).
@@ -4569,14 +4506,15 @@ generation (see Section :ref:`generation_of_equations_ssr`).
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ListDef.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssreflect ListDef.
+ Section Test.
+
Variable d : Type.
Fixpoint add_last (s : list d) (z : d) {struct s} : list d :=
if s is cons x s' then cons x (add_last s' z) else z :: nil.
@@ -4644,7 +4582,7 @@ Here is an example of a regular, but nontrivial, eliminator.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4658,10 +4596,10 @@ Here is an example of a regular, but nontrivial, eliminator.
end -> P _x m) -> forall n : nat, P n (plus m n).
Admitted.
- Section Test.
-
.. rocqtop:: all
+ From Corelib Require Import ssreflect.
+
Fixpoint plus (m n : nat) {struct n} : nat :=
if n is S p then S (plus m p) else m.
@@ -4682,10 +4620,10 @@ Here is an example of a regular, but nontrivial, eliminator.
.. rocqtop:: reset none
From Corelib Require Import ssreflect.
+
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
Fixpoint plus (m n : nat) {struct n} : nat :=
if n is S p then S (plus m p) else m.
@@ -4713,6 +4651,7 @@ Here is an example of a regular, but nontrivial, eliminator.
.. rocqtop:: reset none
From Corelib Require Import ssreflect.
+
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4748,11 +4687,10 @@ Here is an example of a truncated eliminator:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqdoc::
@@ -4812,7 +4750,7 @@ disjunction.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4833,7 +4771,7 @@ disjunction.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4868,7 +4806,7 @@ equation-name generation mechanism (see Section :ref:`generation_of_equations_ss
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4901,7 +4839,7 @@ relevant for the current goal.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -4945,11 +4883,10 @@ assumption to some given arguments.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
@@ -4974,14 +4911,16 @@ bookkeeping steps.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+ Section Test.
+
Variables P Q: bool -> Prop.
Hypothesis PQequiv : forall a b, P (a || b) <-> Q a.
@@ -5030,7 +4969,7 @@ analysis:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -5047,14 +4986,15 @@ analysis
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Lemma test b : b || ~~ b = true.
by case: b.
@@ -5137,7 +5077,7 @@ Let us compare the respective behaviors of ``andE`` and ``andP``.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw ssrbool.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
@@ -5178,14 +5118,15 @@ The view mechanism is compatible with reflect predicates.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all abort
+ From Corelib Require Import ssrbool.
+
Lemma test (a b : bool) (Ha : a) (Hb : b) : a /\ b.
apply/andP.
@@ -5296,14 +5237,15 @@ but they also allow complex transformation, involving negations.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Check introN.
.. rocqtop:: all
@@ -5329,16 +5271,17 @@ actually uses its propositional interpretation.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Lemma test (a b : bool) (pab : b && a) : b.
- have /andP [pa ->] : (a && b) by rewrite andbC.
+ have /andP [pa ->] : (a && b) by rw andbC.
Interpreting goals
``````````````````
@@ -5392,14 +5335,15 @@ In this context, the identity view can be used when no view has to be applied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Lemma test (b1 b2 b3 : bool) : ~~ (b1 || b2) = b3.
apply/idP/idP.
@@ -5408,14 +5352,15 @@ In this context, the identity view can be used when no view has to be applied:
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+
Lemma test (b1 b2 b3 : bool) : ~~ (b1 || b2) = b3.
apply/norP/idP.
@@ -5484,15 +5429,17 @@ pass a given hypothesis to a lemma.
.. rocqtop:: reset none
- From Corelib Require Import ssreflect ssrbool.
+ From Corelib Require Import ssreflect_rw.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
- Section Test.
- Variables P Q R : Prop.
.. rocqtop:: all
+ From Corelib Require Import ssrbool.
+ Section Test.
+ Variables P Q R : Prop.
+
Variable P2Q : P -> Q.
Variable Q2R : Q -> R.
@@ -5517,8 +5464,8 @@ The following intro pattern ltac views are provided:
One can call rewrite from an intro pattern, use with parsimony:
-+ ``/[1! rules]`` shortcut for ``rewrite rules``
-+ ``/[! rules]`` shortcut for ``rewrite !rules``
++ ``/[1! rules]`` shortcut for ``rw rules``
++ ``/[! rules]`` shortcut for ``rw !rules``
Synopsis and Index
@@ -5654,7 +5601,7 @@ respectively.
case analysis (see :ref:`the_defective_tactics_ssr`)
-.. tacv:: rewrite {+ @r_step }
+.. tacv:: rw {+ @r_step }
rewrite (see :ref:`rewriting_ssr`)
@@ -5787,3 +5734,54 @@ Commands
Proof`` command of Rocq proof mode.
.. [#10] A simple proof context entry is a naked identifier (i.e., not between
parentheses) designating a context entry that is not a section variable.
+
+.. _compatibility_issues_ssr:
+
+
+Compatibility issues
+~~~~~~~~~~~~~~~~~~~~
+
+Requiring the module `ssreflect_rw` from `Corelib`
+creates an environment that is mostly
+compatible with the rest of Rocq, up to a few discrepancies.
+
++ New tactic(al)s names (:tacn:`last`, :tacn:`done`, :tacn:`have`, :tacn:`suffices`,
+ :tacn:`suff`, :tacn:`without loss`, :tacn:`wlog`, :tacn:`congr`, :tacn:`unlock`)
+ might clash with user tactic names.
++ New symbols (``//``, ``/=``, ``//=``) might clash with adjacent
+ existing symbols.
+ This can be avoided by inserting white spaces.
++ Some user notations (in particular, defining an infix ``;``) might
+ interfere with the "open term", parenthesis-free syntax of tactics
+ such as :tacn:`have`, :tacn:`set (ssreflect)` and :tacn:`pose (ssreflect)`.
+
+In addition, requiring the backward compatibility module `ssreflect` from `Corelib`
+creates an environment that is mostly
+compatible with the rest of Rocq, up to a few discrepancies.
+
++ New keywords (``is``) might clash with variable, constant, tactic or
+ tactical names, or with quasi-keywords in tactic or
+ notation commands.
++ The extensions to the :tacn:`rewrite` tactic are partly incompatible with those
+ available in current versions of Rocq; in particular, ``rewrite .. in
+ (type of k)`` or ``rewrite .. in *`` or any other variant of :tacn:`rewrite`
+ will not work, and the |SSR| syntax and semantics for occurrence selection
+ and rule chaining are different. Use an explicit rewrite direction
+ (``rewrite <- …`` or ``rewrite -> …``) to access the Rocq rewrite tactic.
++ The generalization of ``if`` statements to non-Boolean conditions is turned off
+ by |SSR|, because it is mostly subsumed by Coercion to ``bool`` of the
+ ``sumXXX`` types (declared in ``ssrfun.v``) and the
+ :n:`if @term is @pattern then @term else @term` construct
+ (see :ref:`pattern_conditional_ssr`). To use the
+ generalized form, turn off the |SSR| Boolean ``if`` notation using the command:
+ ``Close Scope boolean_if_scope``.
++ The following flag can be unset to make |SSR| more compatible with
+ parts of Rocq.
+
+.. flag:: SsrRewrite
+
+ Controls whether the incompatible rewrite syntax is enabled (the default).
+ Disabling the :term:`flag` makes the syntax compatible with other parts of Rocq.
+ Note that this ``rewrite`` syntax, now superseded by ``rw``, is
+ only activated when explicitly requiring the backward compatibility
+ module ``From Corelib Require Import ssreflect.``.
diff --git a/lib/deprecation.ml b/lib/deprecation.ml
index 41ed5fd5cf78..ad1c81abc2b7 100644
--- a/lib/deprecation.ml
+++ b/lib/deprecation.ml
@@ -102,6 +102,6 @@ module Version = struct
let v9_3 = get_generic_cat "9.3"
(* When adding a new version here, please also add
#[export] Set Warnings "-deprecated-since-X.Y".
- in theories/Compat/RocqX{Y-1}.v *)
+ in theories/Corelib/Compat/RocqX{Y-1}.v *)
end
diff --git a/plugins/ltac/pptactic.ml b/plugins/ltac/pptactic.ml
index 46a68fa762e7..b3575c44833c 100644
--- a/plugins/ltac/pptactic.ml
+++ b/plugins/ltac/pptactic.ml
@@ -500,10 +500,10 @@ let string_of_genarg_arg (ArgumentType arg) =
(* When the [ssreflect.SsrSynax] module is imported, ssreflect
operates in reduced compatibility mode. During printing, we try to
account for this when this module is imported. *)
-let { Goptions.get = ssr_loaded } =
- Goptions.declare_bool_option_and_ref ~stage:Synterp ~key:["SSR";"Loaded"] ~value:false ()
+let { Goptions.get = ssr_rewrite_loaded } =
+ Goptions.declare_bool_option_and_ref ~stage:Synterp ~key:["SSRRewriteLoaded"] ~value:false ()
- let pr_orient b = if b then if ssr_loaded () then str "-> " else mt () else str "<- "
+ let pr_orient b = if b then if ssr_rewrite_loaded () then str "-> " else mt () else str "<- "
let pr_multi = let open Equality in function
| Precisely 1 -> mt ()
diff --git a/plugins/ltac/pptactic.mli b/plugins/ltac/pptactic.mli
index 0f7602d255bb..5dfe18498fb7 100644
--- a/plugins/ltac/pptactic.mli
+++ b/plugins/ltac/pptactic.mli
@@ -164,7 +164,7 @@ val ltop : entry_relative_level
val make_constr_printer : (env -> Evd.evar_map -> entry_relative_level -> 'a -> Pp.t) ->
'a Genprint.top_printer
-val ssr_loaded : unit -> bool
+val ssr_rewrite_loaded : unit -> bool
module Internal : sig
val pr_tacvalue_ref : (env -> Tacarg.tacvalue -> Pp.t) ref
diff --git a/plugins/ltac/tacinterp.mli b/plugins/ltac/tacinterp.mli
index ff39394f29c8..d9394b101ccb 100644
--- a/plugins/ltac/tacinterp.mli
+++ b/plugins/ltac/tacinterp.mli
@@ -48,6 +48,7 @@ open Genintern
val f_avoid_ids : Id.Set.t TacStore.field
val f_debug : debug_info TacStore.field
+val extract_loc : interp_sign -> Loc.t option
val extract_ltac_constr_values : interp_sign -> Environ.env ->
Ltac_pretype.constr_under_binders Id.Map.t
diff --git a/plugins/ssr/ssrcommon.ml b/plugins/ssr/ssrcommon.ml
index b8f390ca7e57..bfbad25e5cc8 100644
--- a/plugins/ssr/ssrcommon.ml
+++ b/plugins/ssr/ssrcommon.ml
@@ -251,7 +251,7 @@ let add_internal_name pt = internal_names := pt :: !internal_names
let is_internal_name s = List.exists (fun p -> p s) !internal_names
let mk_internal_id s =
- let s' = Printf.sprintf "_%s_" s in
+ let s' = Printf.sprintf "‗%s‗" s in
let s' = String.map (fun c -> if c = ' ' then '_' else c) s' in
add_internal_name ((=) s'); Id.of_string s'
@@ -262,19 +262,22 @@ let skip_digits s =
let n = String.length s in
let rec loop i = if i < n && is_digit s.[i] then loop (i + 1) else i in loop
-let mk_tagged_id t i = Id.of_string (Printf.sprintf "%s%d_" t i)
+let mk_tagged_id t i = Id.of_string (Printf.sprintf "%s%d‗" t i)
+(* [is_dll s n] test if character at pos [n] of [s] is UTF8 double low line '‗'.
+ Assumes [n] <= [String.length n - 3]. *)
+let is_dll s n = s.[n] = '\226' && s.[n+1] = '\128' && s.[n+2] = '\151'
let is_tagged t s =
- let n = String.length s - 1 and m = String.length t in
- m < n && s.[n] = '_' && same_prefix s t m && skip_digits s m = n
+ let n = String.length s and m = String.length t in
+ m < n - 3 && is_dll s (n - 3) && same_prefix s t m && skip_digits s m = n - 3
-let evar_tag = "_evar_"
+let evar_tag = "‗evar_"
let _ = add_internal_name (is_tagged evar_tag)
let mk_evar_name n = Name (mk_tagged_id evar_tag n)
let ssr_anon_hyp = "Hyp"
-let wildcard_tag = "_the_"
-let wildcard_post = "_wildcard_"
+let wildcard_tag = "‗the_"
+let wildcard_post = "_wildcard‗"
let has_wildcard_tag s =
let n = String.length s in let m = String.length wildcard_tag in
let m' = String.length wildcard_post in
@@ -283,19 +286,19 @@ let has_wildcard_tag s =
skip_digits s m = n - m' - 2
let _ = add_internal_name has_wildcard_tag
-let discharged_tag = "_discharged_"
+let discharged_tag = "‗discharged_"
let mk_discharged_id id =
- Id.of_string (Printf.sprintf "%s%s_" discharged_tag (Id.to_string id))
+ Id.of_string (Printf.sprintf "%s%s‗" discharged_tag (Id.to_string id))
let has_discharged_tag s =
- let m = String.length discharged_tag and n = String.length s - 1 in
- m < n && s.[n] = '_' && same_prefix s discharged_tag m
+ let m = String.length discharged_tag and n = String.length s in
+ m < n - 3 && is_dll s (n - 3) && same_prefix s discharged_tag m
let _ = add_internal_name has_discharged_tag
let is_discharged_id id = has_discharged_tag (Id.to_string id)
let max_suffix m (t, j0 as tj0) id =
- let s = Id.to_string id in let n = String.length s - 1 in
- let dn = String.length t - 1 - n in let i0 = j0 - dn in
- if not (i0 >= m && s.[n] = '_' && same_prefix s t m) then tj0 else
+ let s = Id.to_string id in let n = String.length s - 3 in
+ let dn = String.length t - 3 - n in let i0 = j0 - dn in
+ if not (i0 >= m && is_dll s n && same_prefix s t m) then tj0 else
let rec loop i =
if i < i0 && s.[i] = '0' then loop (i + 1) else
if (if i < i0 then skip_digits s i = n else le_s_t i) then s, i else tj0
@@ -309,9 +312,9 @@ let max_suffix m (t, j0 as tj0) id =
let mk_anon_id t gl_ids =
let gl_ids = List.map NamedDecl.get_id (EConstr.named_context_of_val gl_ids) in
let m, si0, id0 =
- let s = ref (Printf.sprintf "_%s_" t) in
- if is_internal_name !s then s := "_" ^ !s;
- let n = String.length !s - 1 in
+ let s = ref (Printf.sprintf "‗%s‗" t) in
+ if is_internal_name !s then s := "‗" ^ !s;
+ let n = String.length !s - 3 in
let rec loop i j =
let d = !s.[i] in if not (is_digit d) then i + 1, j else
loop (i - 1) (if d = '0' then j else i) in
@@ -320,10 +323,12 @@ let mk_anon_id t gl_ids =
let s, i = List.fold_left (max_suffix m) si0 gl_ids in
let open Bytes in
let s = of_string s in
- let n = length s - 1 in
+ let n = length s - 3 in
+ let cat_dll s =
+ set s (n + 1) '\226'; set s (n + 2) '\128'; cat s (of_string "\151") in
let rec loop i =
if get s i = '9' then (set s i '0'; loop (i - 1)) else
- if i < m then (set s n '0'; set s m '1'; cat s (of_string "_")) else
+ if i < m then (set s n '0'; set s m '1'; cat_dll s) else
(set s i (Char.chr (Char.code (get s i) + 1)); s) in
Id.of_string_soft (Bytes.to_string (loop (n - 1)))
@@ -551,7 +556,7 @@ let nb_evar_deps = function
let s = Id.to_string id in
if not (is_tagged evar_tag s) then 0 else
let m = String.length evar_tag in
- (try int_of_string (String.sub s m (String.length s - 1 - m)) with e when CErrors.noncritical e -> 0)
+ (try int_of_string (String.sub s m (String.length s - 3 - m)) with e when CErrors.noncritical e -> 0)
| _ -> 0
let type_id env sigma t = Id.of_string (Namegen.hdchar env sigma t)
diff --git a/plugins/ssr/ssrcommon.mli b/plugins/ssr/ssrcommon.mli
index eb0de8cda3d8..309fd844cd7f 100644
--- a/plugins/ssr/ssrcommon.mli
+++ b/plugins/ssr/ssrcommon.mli
@@ -149,6 +149,9 @@ val mkSsrConst : Environ.env -> Evd.evar_map -> string -> Evd.evar_map * EConstr
val is_discharged_id : Id.t -> bool
val mk_discharged_id : Id.t -> Id.t
+(* [is_dll s n] test if character at pos [n] of [s] is UTF8 double low line '‗'.
+ Assumes [n] < [String.length n - 3]. *)
+val is_dll : string -> int -> bool
val is_tagged : string -> string -> bool
val has_discharged_tag : string -> bool
val ssrqid : string -> Libnames.qualid
diff --git a/plugins/ssr/ssrparser.mlg b/plugins/ssr/ssrparser.mlg
index 57ccbf298144..3ab565e3dd48 100644
--- a/plugins/ssr/ssrparser.mlg
+++ b/plugins/ssr/ssrparser.mlg
@@ -41,19 +41,6 @@ open Ssrequality
open Ssripats
open Libobject
-(** Ssreflect load check. *)
-
-(* To allow ssrcoq to be fully compatible with the "plain" Rocq, we only *)
-(* turn on its incompatible features (the new rewrite syntax, and the *)
-(* reserved identifiers) when the theory library (ssreflect.v) has *)
-(* has actually been required, or is being defined. Because this check *)
-(* needs to be done often (for each identifier lookup), we implement *)
-(* some caching, repeating the test only when the environment changes. *)
-(* We check for protect_term because it is the first constant loaded; *)
-(* ssr_have would ultimately be a better choice. *)
-
-let is_ssr_loaded = Pptactic.ssr_loaded
-
}
DECLARE PLUGIN "rocq-runtime.plugins.ssreflect"
@@ -1583,7 +1570,7 @@ END
{
let sq_brace_tacnames =
- ["first"; "solve"; "do"; "rewrite"; "have"; "suffices"; "wlog"]
+ ["first"; "solve"; "do"; "rewrite"; "rw"; "have"; "suffices"; "wlog"]
(* "by" is a keyword *)
let test_ssrseqvar =
@@ -1626,31 +1613,20 @@ let ltac_expr = Pltac.ltac_expr
(* Since Rocq now does repeated internal checks of its external lexical *)
(* rules, we now need to carve ssreflect reserved identifiers out of *)
-(* out of the user namespace. We use identifiers of the form _id_ for *)
-(* this purpose, e.g., we "anonymize" an identifier id as _id_, adding *)
-(* an extra leading _ if this might clash with an internal identifier. *)
-(* We check for ssreflect identifiers in the ident grammar rule; *)
-(* when the ssreflect Module is present this is normally an error, *)
-(* but we provide a compatibility flag to reduce this to a warning. *)
+(* the user namespace. We use identifiers of the form ‗id‗ for *)
+(* this purpose, e.g., we "anonymize" an identifier id as ‗id‗, adding *)
+(* an extra leading ‗ if this might clash with an internal identifier. *)
+(* We check for ssreflect identifiers in the ident grammar rule. *)
{
-let { Goptions.get = ssr_reserved_ids } =
- Goptions.declare_bool_option_and_ref ~stage:Synterp ~key:["SsrIdents"] ~value:true ()
-
let is_ssr_reserved s =
- let n = String.length s in n > 2 && s.[0] = '_' && s.[n - 1] = '_'
+ let n = String.length s in n > 6 && is_dll s 0 && is_dll s (n - 3)
let ssr_id_of_string loc s =
- if is_ssr_reserved s && is_ssr_loaded () then begin
- if ssr_reserved_ids() then
- CErrors.user_err ~loc (str ("The identifier " ^ s ^ " is reserved."))
- else if is_internal_name s then
- Feedback.msg_warning (str ("Conflict between " ^ s ^ " and ssreflect internal names."))
- else Feedback.msg_warning (str (
- "The name " ^ s ^ " fits the _xxx_ format used for anonymous variables.\n"
- ^ "Scripts with explicit references to anonymous variables are fragile."))
- end; Id.of_string s
+ if is_ssr_reserved s then begin
+ CErrors.user_err ~loc (str ("The identifier " ^ s ^ " is reserved."))
+ end; Id.of_string s
let ssr_null_entry = Procq.Entry.(of_parser "ssr_null" { parser_fun = fun _ _ -> Ok () })
@@ -1663,7 +1639,7 @@ END
{
-let perm_tag = "_perm_Hyp_"
+let perm_tag = "‗perm_Hyp_"
let _ = add_internal_name (is_tagged perm_tag)
}
@@ -1740,7 +1716,6 @@ module Internal = struct
let pr_intros = pr_intros
let pr_view = pr_view
let pr_mult = pr_mult
- let is_ssr_loaded = is_ssr_loaded
let pr_hpats = pr_hpats
let pr_fwd = pr_fwd
let pr_hint = pr_hint
@@ -1752,5 +1727,3 @@ module Internal = struct
end
}
-
-(* vim: set filetype=ocaml foldmethod=marker: *)
diff --git a/plugins/ssr/ssrparser.mli b/plugins/ssr/ssrparser.mli
index a1d177156e4a..04d1096784b5 100644
--- a/plugins/ssr/ssrparser.mli
+++ b/plugins/ssr/ssrparser.mli
@@ -188,8 +188,6 @@ module Internal : sig
val pr_mult : ssrmult -> Pp.t
- val is_ssr_loaded : unit -> bool
-
val pr_hpats : ssrhpats -> Pp.t
val pr_fwd : (Ssrast.ssrfwdkind * Ssrast.ssrbindfmt list) * Ssrast.ast_closure_term -> Pp.t
diff --git a/plugins/ssr/ssrtacs.mlg b/plugins/ssr/ssrtacs.mlg
index eb63b42f655b..64e86faad268 100644
--- a/plugins/ssr/ssrtacs.mlg
+++ b/plugins/ssr/ssrtacs.mlg
@@ -740,41 +740,15 @@ let pr_ssrrwargs _ _ _ rwargs = pr_list spc pr_rwarg rwargs
ARGUMENT EXTEND ssrrwargs TYPED AS ssrrwarg list PRINTED BY { pr_ssrrwargs }
END
-{
-
-let ssr_rw_syntax = Summary.ref ~name:"SSR:rewrite" true
-
-let () =
- Goptions.(declare_bool_option
- { optstage = Summary.Stage.Synterp;
- optkey = ["SsrRewrite"];
- optread = (fun _ -> !ssr_rw_syntax);
- optdepr = None;
- optwrite = (fun b -> ssr_rw_syntax := b) })
-
-let lbrace = Char.chr 123
-(** Workaround to a limitation of coqpp *)
-
-let test_ssr_rw_syntax =
- let test kwstate strm =
- if not !ssr_rw_syntax then Error () else
- if is_ssr_loaded () then Ok () else
- match LStream.peek_nth kwstate 0 strm with
- | Some (Tok.KEYWORD key) when List.mem key.[0] [lbrace; '['; '/'] -> Ok ()
- | _ -> Error () in
- Procq.Entry.(of_parser "test_ssr_rw_syntax" { parser_fun = test })
-
-}
-
GRAMMAR EXTEND Gram
GLOBAL: ssrrwargs;
- ssrrwargs: TOP [[ test_ssr_rw_syntax; a = LIST1 ssrrwarg -> { a } ]];
+ ssrrwargs: TOP [[ a = LIST1 ssrrwarg -> { a } ]];
END
-(** The "rewrite" tactic *)
+(** The "rw" tactic *)
-TACTIC EXTEND ssrrewrite
- | [ "rewrite" ssrrwargs(args) ssrclauses(clauses) ] ->
+TACTIC EXTEND ssrrw
+ | [ "rw" ssrrwargs(args) ssrclauses(clauses) ] ->
{ tclCLAUSES (ssrrewritetac ist args) clauses }
END
@@ -1050,5 +1024,3 @@ TACTIC EXTEND under
Ssrfwd.undertac ~pad_intro:true ist (Some [IPatAnon All]) arg h
}
END
-
-(* vim: set filetype=ocaml foldmethod=marker: *)
diff --git a/plugins/ssr/ssrtacs.mli b/plugins/ssr/ssrtacs.mli
index 4069c40ae277..062f2c1c2d43 100644
--- a/plugins/ssr/ssrtacs.mli
+++ b/plugins/ssr/ssrtacs.mli
@@ -10,6 +10,8 @@ open Ssrparser
val wit_ssrarg : ssrarg Genarg.uniform_genarg_type
val wit_ssrrwarg : ssrrwarg Genarg.uniform_genarg_type
+val ssrrwargs : ssrrwarg list Procq.Entry.t
+val pr_ssrrwargs : 'a -> 'b -> 'c -> ssrrwarg list -> Pp.t
val wit_ssrrwargs : ssrrwarg list Genarg.uniform_genarg_type
val wit_ssrseqdir : ssrdir Genarg.uniform_genarg_type
diff --git a/plugins/ssr/ssrvernac.mlg b/plugins/ssr/ssrvernac.mlg
index d7995bd31af5..ccd46159c1d5 100644
--- a/plugins/ssr/ssrvernac.mlg
+++ b/plugins/ssr/ssrvernac.mlg
@@ -17,7 +17,6 @@ module CoqConstr = Constr
open CoqConstr
open Constrexpr
open Constrexpr_ops
-open Procq
open Procq.Prim
open Procq.Constr
open Pvernac.Vernac_
@@ -47,8 +46,6 @@ IGNORE KEYWORDS
(** Alternative notations for "match" and anonymous arguments. *)(* ************)
(* Syntax: *)
-(* if is then ... else ... *)
-(* if is [in ..] return ... then ... else ... *)
(* let: := in ... *)
(* let: [in ...] := return ... in ... *)
(* The scope of a top-level 'as' in the pattern extends over the *)
@@ -76,7 +73,6 @@ let aliasvar = function
let mk_cnotype mp = aliasvar mp, None
let mk_ctype mp t = aliasvar mp, Some t
let mk_rtype t = Some t
-let mk_dthen ?loc (mp, ct, rt) c = (CAst.make ?loc (mp, c)), ct, rt
let mk_let ?loc rt ct mp c1 =
CAst.make ?loc @@ CCases (LetPatternStyle, rt, ct, [CAst.make ?loc (mp, c1)])
let mk_pat c (na, t) = (c, na, t)
@@ -87,25 +83,8 @@ GRAMMAR EXTEND Gram
GLOBAL: term;
ssr_rtype: [[ "return"; t = term LEVEL "100" -> { mk_rtype t } ]];
ssr_mpat: [[ p = pattern -> { [[p]] } ]];
- ssr_dpat: [
- [ mp = ssr_mpat; "in"; t = pattern; rt = ssr_rtype -> { mp, mk_ctype mp t, rt }
- | mp = ssr_mpat; rt = ssr_rtype -> { mp, mk_cnotype mp, rt }
- | mp = ssr_mpat -> { mp, no_ct, no_rt }
- ] ];
- ssr_dthen: [[ dp = ssr_dpat; "then"; c = lconstr -> { mk_dthen ~loc dp c } ]];
- ssr_elsepat: [[ "else" -> { [[CAst.make ~loc @@ CPatAtom None]] } ]];
- ssr_else: [[ mp = ssr_elsepat; c = lconstr -> { CAst.make ~loc (mp, c) } ]];
term: LEVEL "10" [
- [ "if"; c = term LEVEL "200"; "is"; db1 = ssr_dthen; b2 = ssr_else ->
- { let b1, ct, rt = db1 in CAst.make ~loc @@ CCases (MatchStyle, rt, [mk_pat c ct], [b1; b2]) }
- | "if"; c = term LEVEL "200";"isn't";db1 = ssr_dthen; b2 = ssr_else ->
- { let b1, ct, rt = db1 in
- let b1, b2 = let open CAst in
- let {loc=l1; v=(p1, r1)}, {loc=l2; v=(p2, r2)} = b1, b2 in
- (make ?loc:l1 (p1, r2), make ?loc:l2 (p2, r1))
- in
- CAst.make ~loc @@ CCases (MatchStyle, rt, [mk_pat c ct], [b1; b2]) }
- | "let"; ":"; mp = ssr_mpat; ":="; c = lconstr; "in"; c1 = lconstr ->
+ [ "let"; ":"; mp = ssr_mpat; ":="; c = lconstr; "in"; c1 = lconstr ->
{ mk_let ~loc no_rt [mk_pat c no_ct] mp c1 }
| "let"; ":"; mp = ssr_mpat; ":="; c = lconstr;
rt = ssr_rtype; "in"; c1 = lconstr ->
@@ -291,59 +270,3 @@ VERNAC COMMAND EXTEND HintView CLASSIFIED AS SIDEFF
| Some k ->
Ssrview.AdaptorDb.declare k hints }
END
-
-(** Search compatibility *)
-
-{
-
-open G_vernac
-}
-
-GRAMMAR EXTEND Gram
- GLOBAL: query_command;
-
- query_command: TOP
- [ [ IDENT "Search"; s = search_query; l = search_queries; "." ->
- { let (sl,m) = l in
- fun g ->
- Vernacexpr.VernacSearch (Vernacexpr.Search (s::sl),g, m) }
- ] ]
-;
-END
-
-(** Keyword compatibility fixes. *)
-
-(* Coq v8.1 notation uses "by" and "of" quasi-keywords, i.e., reserved *)
-(* identifiers used as keywords. This is incompatible with ssreflect.v *)
-(* which makes "by" and "of" true keywords, because of technicalities *)
-(* in the internal lexer-parser API of Rocq. We patch this here by *)
-(* adding new parsing rules that recognize the new keywords. *)
-(* To make matters worse, the Rocq grammar for tactics fails to *)
-(* export the non-terminals we need to patch. Fortunately, the CamlP5 *)
-(* API provides a backdoor access (with loads of Obj.magic trickery). *)
-
-(* Coq v8.3 defines "by" as a keyword, some hacks are not needed any *)
-(* longer and thus comment out. Such comments are marked with v8.3 *)
-
-{
-
-open Pltac
-
-}
-
-GRAMMAR EXTEND Gram
- GLOBAL: hypident;
- hypident: TOP [
- [ "("; IDENT "type"; "of"; id = Prim.identref; ")" -> { id, Locus.InHypTypeOnly }
- | "("; IDENT "value"; "of"; id = Prim.identref; ")" -> { id, Locus.InHypValueOnly }
- ] ];
-END
-
-GRAMMAR EXTEND Gram
- GLOBAL: constr_eval;
- constr_eval: TOP [
- [ IDENT "type"; "of"; c = Constr.constr -> { Tacexpr.ConstrTypeOf c }]
- ];
-END
-
-(* vim: set filetype=ocaml foldmethod=marker: *)
diff --git a/plugins/ssrrewrite/dune b/plugins/ssrrewrite/dune
new file mode 100644
index 000000000000..55f94c46ba44
--- /dev/null
+++ b/plugins/ssrrewrite/dune
@@ -0,0 +1,11 @@
+(library
+ (name ssreflect_rewrite_plugin)
+ (public_name rocq-runtime.plugins.ssreflect_rewrite)
+ (synopsis "Rocq's ssreflect plugin for rewrite compatibility")
+ (flags :standard -open Gramlib)
+ (libraries rocq-runtime.plugins.ssrmatching rocq-runtime.plugins.ssreflect))
+
+(rule
+ (targets ssrrewrite.ml)
+ (deps (:mlg ssrrewrite.mlg))
+ (action (chdir %{project_root} (run rocq pp-mlg %{deps}))))
diff --git a/plugins/ssrrewrite/ssrrewrite.mlg b/plugins/ssrrewrite/ssrrewrite.mlg
new file mode 100644
index 000000000000..cf1667041ffa
--- /dev/null
+++ b/plugins/ssrrewrite/ssrrewrite.mlg
@@ -0,0 +1,138 @@
+(************************************************************************)
+(* * The Rocq Prover / The Rocq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* [Quickfix.make ~loc (Pp.str "rw")])
+ (fun () -> Pp.str "The 'rewrite' tactic has been renamed 'rw'.")
+
+}
+
+DECLARE PLUGIN "rocq-runtime.plugins.ssreflect_rewrite"
+
+(* The user is supposed to Require Import ssreflect or Require ssreflect *)
+(* and Import ssreflect.SsrSyntax to obtain these keywords and as a *)
+(* consequence the extended ssreflect grammar. *)
+IGNORE KEYWORDS
+
+(* type ssrrwargs = ssrrwarg list *)
+
+ARGUMENT EXTEND ssrrewriteargs TYPED AS ssrrwarg list PRINTED BY { pr_ssrrwargs }
+END
+
+{
+
+let ssr_rewrite_syntax = Summary.ref ~name:"SSR:rewrite" true
+
+let () =
+ Goptions.(declare_bool_option
+ { optstage = Summary.Stage.Synterp;
+ optkey = ["SsrRewrite"];
+ optread = (fun _ -> !ssr_rewrite_syntax);
+ optdepr = None;
+ optwrite = (fun b -> ssr_rewrite_syntax := b) })
+
+let lbrace = Char.chr 123
+(** Workaround to a limitation of coqpp *)
+
+let test_ssr_rewrite_syntax =
+ let test kwstate strm =
+ if not !ssr_rewrite_syntax then Error () else
+ if Pptactic.ssr_rewrite_loaded () then Ok () else
+ match LStream.peek_nth kwstate 0 strm with
+ | Some (Tok.KEYWORD key) when List.mem key.[0] [lbrace; '['; '/'] -> Ok ()
+ | _ -> Error () in
+ Procq.Entry.(of_parser "test_ssr_rewrite_syntax" { parser_fun = test })
+
+}
+
+GRAMMAR EXTEND Gram
+ GLOBAL: ssrrewriteargs;
+ ssrrewriteargs: TOP [[ test_ssr_rewrite_syntax; a = ssrrwargs -> { a } ]];
+END
+
+(** The "rewrite" tactic *)
+
+TACTIC EXTEND ssrrewrite
+ | [ "rewrite" ssrrewriteargs(args) ssrclauses(clauses) ] ->
+ { let loc = Tacinterp.extract_loc ist
+ |> Option.map (fun l -> Loc.sub l 0 7) in
+ warn_deprecated_rewrite ?loc ();
+ tclCLAUSES (ssrrewritetac ist args) clauses }
+END
+
+{
+
+(* global syntactic changes and vernacular commands *)
+
+(** Alternative notations for "match" and anonymous arguments. *)(* ************)
+
+(* Syntax: *)
+(* if is then ... else ... *)
+(* if is [in ..] return ... then ... else ... *)
+(* The scope of a top-level 'as' in the pattern extends over the *)
+(* 'return' type (dependent if/let). *)
+(* in b (*^--ALTERNATIVE INNER LET--------^ *) *)
+
+(* Caveat : There is no pretty-printing support, since this would *)
+(* require a modification to the Rocq kernel (adding a new match *)
+(* display style -- why aren't these strings?); also, the v8.1 *)
+(* pretty-printer only allows extension hooks for printing *)
+(* integer or string literals. *)
+(* Also note that in the v8 grammar "is" needs to be a keyword; *)
+(* as this can't be done from an ML extension file, the new *)
+(* syntax will only work when ssreflect.v is imported. *)
+
+let no_ct = None, None and no_rt = None
+let aliasvar = function
+ | [[{ CAst.v = CPatAlias (_, na); loc }]] -> Some na
+ | _ -> None
+let mk_cnotype mp = aliasvar mp, None
+let mk_ctype mp t = aliasvar mp, Some t
+let mk_rtype t = Some t
+let mk_dthen ?loc (mp, ct, rt) c = (CAst.make ?loc (mp, c)), ct, rt
+let mk_pat c (na, t) = (c, na, t)
+
+}
+
+GRAMMAR EXTEND Gram
+ GLOBAL: term;
+ ssr_rtype: [[ "return"; t = term LEVEL "100" -> { mk_rtype t } ]];
+ ssr_mpat: [[ p = pattern -> { [[p]] } ]];
+ ssr_dpat: [
+ [ mp = ssr_mpat; "in"; t = pattern; rt = ssr_rtype -> { mp, mk_ctype mp t, rt }
+ | mp = ssr_mpat; rt = ssr_rtype -> { mp, mk_cnotype mp, rt }
+ | mp = ssr_mpat -> { mp, no_ct, no_rt }
+ ] ];
+ ssr_dthen: [[ dp = ssr_dpat; "then"; c = lconstr -> { mk_dthen ~loc dp c } ]];
+ ssr_elsepat: [[ "else" -> { [[CAst.make ~loc @@ CPatAtom None]] } ]];
+ ssr_else: [[ mp = ssr_elsepat; c = lconstr -> { CAst.make ~loc (mp, c) } ]];
+ term: LEVEL "10" [
+ [ "if"; c = term LEVEL "200"; "is"; db1 = ssr_dthen; b2 = ssr_else ->
+ { let b1, ct, rt = db1 in CAst.make ~loc @@ CCases (MatchStyle, rt, [mk_pat c ct], [b1; b2]) }
+ | "if"; c = term LEVEL "200";"isn't";db1 = ssr_dthen; b2 = ssr_else ->
+ { let b1, ct, rt = db1 in
+ let b1, b2 = let open CAst in
+ let {loc=l1; v=(p1, r1)}, {loc=l2; v=(p2, r2)} = b1, b2 in
+ (make ?loc:l1 (p1, r2), make ?loc:l2 (p2, r1))
+ in
+ CAst.make ~loc @@ CCases (MatchStyle, rt, [mk_pat c ct], [b1; b2]) }
+ ] ];
+END
diff --git a/plugins/ssrrewrite/ssrrewrite.mli b/plugins/ssrrewrite/ssrrewrite.mli
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test-suite/bugs/bug_4966.v b/test-suite/bugs/bug_4966.v
index 16dc0d113efc..05e93431c59b 100644
--- a/test-suite/bugs/bug_4966.v
+++ b/test-suite/bugs/bug_4966.v
@@ -1,7 +1,7 @@
(* Interpretation of auto as an argument of an ltac function (i.e. as an ident) was wrongly "auto with *" *)
Axiom proof_admitted : False.
-#[export] Hint Extern 0 => case proof_admitted : unused.
+#[export] Hint Extern 0 => (case proof_admitted) : unused.
Ltac do_tac tac := tac.
Goal False.
diff --git a/test-suite/output/ssr_under.v b/test-suite/output/ssr_under.v
index 5328f35d70fc..d100488d0abb 100644
--- a/test-suite/output/ssr_under.v
+++ b/test-suite/output/ssr_under.v
@@ -10,7 +10,7 @@ Axiom eq_G :
Ltac show := match goal with [|-?g] => idtac g end.
Lemma example_G (n : nat) : G (fun n => n - n) n >= 0.
-under eq_G => m do [show; rewrite subnn].
+under eq_G => m do [show; rw subnn].
show.
Abort.
diff --git a/theories/Corelib/ssr/ssrbool.v b/theories/Corelib/ssr/ssrbool.v
index 514a9b427541..a1d23ba841a8 100644
--- a/theories/Corelib/ssr/ssrbool.v
+++ b/theories/Corelib/ssr/ssrbool.v
@@ -557,7 +557,7 @@ Lemma contraTnot (b : bool) (P : Prop) : (P -> ~~ b) -> (b -> ~ P).
Proof. by case: b; auto. Qed.
Lemma contraNnot (P : Prop) (b : bool) : (P -> b) -> (~~ b -> ~ P).
-Proof. rewrite -{1}[b]negbK; exact: contraTnot. Qed.
+Proof. rw -{1}[b]negbK; exact: contraTnot. Qed.
Lemma contraPT (P : Prop) (b : bool) : (~~ b -> ~ P) -> P -> b.
Proof. by case: b => //= /(_ isT) nP /nP. Qed.
@@ -566,7 +566,7 @@ Lemma contra_notT (P : Prop) (b : bool) : (~~ b -> P) -> ~ P -> b.
Proof. by case: b => //= /(_ isT) HP /(_ HP). Qed.
Lemma contra_notN (P : Prop) (b : bool) : (b -> P) -> ~ P -> ~~ b.
-Proof. rewrite -{1}[b]negbK; exact: contra_notT. Qed.
+Proof. rw -{1}[b]negbK; exact: contra_notT. Qed.
Lemma contraPN (P : Prop) (b : bool) : (b -> ~ P) -> (P -> ~~ b).
Proof. by case: b => //=; move/(_ isT) => HP /HP. Qed.
@@ -620,7 +620,7 @@ Lemma ifP : if_spec (b = false) b (if b then vT else vF).
Proof. by case def_b: b; constructor. Qed.
Lemma ifPn : if_spec (~~ b) b (if b then vT else vF).
-Proof. by case def_b: b; constructor; rewrite ?def_b. Qed.
+Proof. by case def_b: b; constructor; rw ?def_b. Qed.
Lemma ifT : b -> (if b then vT else vF) = vT. Proof. by move->. Qed.
Lemma ifF : b = false -> (if b then vT else vF) = vF. Proof. by move->. Qed.
@@ -686,10 +686,10 @@ Lemma elimTFn : b = c -> if c then ~ P else P.
Proof. by move <-; apply: (elimNTF Hb); case b. Qed.
Lemma equivPifn : (Q -> P) -> (P -> Q) -> if b then ~ Q else Q.
-Proof. by rewrite -if_neg; apply: equivPif. Qed.
+Proof. by rw -if_neg; apply: equivPif. Qed.
Lemma xorPifn : Q \/ P -> ~ (Q /\ P) -> if b then Q else ~ Q.
-Proof. by rewrite -if_neg; apply: xorPif. Qed.
+Proof. by rw -if_neg; apply: xorPif. Qed.
End ReflectNegCore.
@@ -746,7 +746,7 @@ Variant alt_spec : bool -> Type :=
| AltFalse of ~~ b : alt_spec false.
Lemma altP : alt_spec b.
-Proof. by case def_b: b / Pb; constructor; rewrite ?def_b. Qed.
+Proof. by case def_b: b / Pb; constructor; rw ?def_b. Qed.
Lemma eqbLR (b1 b2 : bool) : b1 = b2 -> b1 -> b2.
Proof. by move->. Qed.
@@ -1159,13 +1159,13 @@ Arguments addbP {a b}.
Ltac bool_congr :=
match goal with
| |- (?X1 && ?X2 = ?X3) => first
- [ symmetry; rewrite -1?(andbC X1) -?(andbCA X1); congr 1 (andb X1); symmetry
- | case: (X1); [ rewrite ?andTb ?andbT // | by rewrite ?andbF /= ] ]
+ [ symmetry; rw -1?(andbC X1) -?(andbCA X1); congr 1 (andb X1); symmetry
+ | case: (X1); [ rw ?andTb ?andbT // | by rw ?andbF /= ] ]
| |- (?X1 || ?X2 = ?X3) => first
- [ symmetry; rewrite -1?(orbC X1) -?(orbCA X1); congr 1 (orb X1); symmetry
- | case: (X1); [ by rewrite ?orbT //= | rewrite ?orFb ?orbF ] ]
+ [ symmetry; rw -1?(orbC X1) -?(orbCA X1); congr 1 (orb X1); symmetry
+ | case: (X1); [ by rw ?orbT //= | rw ?orFb ?orbF ] ]
| |- (?X1 (+) ?X2 = ?X3) =>
- symmetry; rewrite -1?(addbC X1) -?(addbCA X1); congr 1 (addb X1); symmetry
+ symmetry; rw -1?(addbC X1) -?(addbCA X1); congr 1 (addb X1); symmetry
| |- (~~ ?X1 = ?X2) => congr 1 negb
end.
@@ -1580,7 +1580,7 @@ Lemma mem_topred pT (pp : pT) : mem (topred pp) = mem pp.
Proof. by case: pT pp. Qed.
Lemma topredE pT x (pp : pT) : topred pp x = (x \in pp).
-Proof. by rewrite -mem_topred. Qed.
+Proof. by rw -mem_topred. Qed.
Lemma app_predE x p (ap : registered_applicative_pred p) : ap x = (x \in p).
Proof. by case: ap => _ /= ->. Qed.
@@ -1776,10 +1776,10 @@ Section PER.
Hypotheses (symR : symmetric) (trR : transitive).
Lemma sym_left_transitive : left_transitive.
-Proof. by move=> x y Rxy z; apply/idP/idP; apply: trR; rewrite // symR. Qed.
+Proof. by move=> x y Rxy z; apply/idP/idP; apply: trR; rw // symR. Qed.
Lemma sym_right_transitive : right_transitive.
-Proof. by move=> x y /sym_left_transitive Rxy z; rewrite !(symR z) Rxy. Qed.
+Proof. by move=> x y /sym_left_transitive Rxy z; rw !(symR z) Rxy. Qed.
End PER.
@@ -1792,7 +1792,7 @@ Definition equivalence_rel := forall x y z, R z z * (R x y -> R x z = R y z).
Lemma equivalence_relP : equivalence_rel <-> reflexive /\ left_transitive.
Proof.
split=> [eqiR | [Rxx trR] x y z]; last by split=> [|/trR->].
-by split=> [x | x y Rxy z]; [rewrite (eqiR x x x) | rewrite (eqiR x y z)].
+by split=> [x | x y Rxy z]; [rw (eqiR x x x) | rw (eqiR x y z)].
Qed.
End RelationProperties.
@@ -1966,19 +1966,19 @@ Lemma can_in_inj : {in D1, cancel f g} -> {in D1 &, injective f}.
Proof. by move=> fK x y /fK{2}<- /fK{2}<- ->. Qed.
Lemma canLR_in x y : {in D1, cancel f g} -> y \in D1 -> x = f y -> g x = y.
-Proof. by move=> fK D1y ->; rewrite fK. Qed.
+Proof. by move=> fK D1y ->; rw fK. Qed.
Lemma canRL_in x y : {in D1, cancel f g} -> x \in D1 -> f x = y -> x = g y.
-Proof. by move=> fK D1x <-; rewrite fK. Qed.
+Proof. by move=> fK D1x <-; rw fK. Qed.
Lemma on_can_inj : {on D2, cancel f & g} -> {on D2 &, injective f}.
Proof. by move=> fK x y /fK{2}<- /fK{2}<- ->. Qed.
Lemma canLR_on x y : {on D2, cancel f & g} -> f y \in D2 -> x = f y -> g x = y.
-Proof. by move=> fK D2fy ->; rewrite fK. Qed.
+Proof. by move=> fK D2fy ->; rw fK. Qed.
Lemma canRL_on x y : {on D2, cancel f & g} -> f x \in D2 -> f x = y -> x = g y.
-Proof. by move=> fK D2fx <-; rewrite fK. Qed.
+Proof. by move=> fK D2fx <-; rw fK. Qed.
Lemma inW_bij : bijective f -> {in D1, bijective f}.
Proof. by case=> g' fK g'K; exists g' => * ? *; auto. Qed.
@@ -2007,21 +2007,21 @@ Qed.
Lemma in_on1P : {in D1, {on D2, allQ1 f}} <->
{in [pred x in D1 | f x \in D2], allQ1 f}.
Proof.
-split => allf x; have := allf x; rewrite inE => Q1f; first by case/andP.
+split => allf x; have := allf x; rw inE => Q1f; first by case/andP.
by move=> ? ?; apply: Q1f; apply/andP.
Qed.
Lemma in_on1lP : {in D1, {on D2, allQ1l f & h}} <->
{in [pred x in D1 | f x \in D2], allQ1l f h}.
Proof.
-split => allf x; have := allf x; rewrite inE => Q1f; first by case/andP.
+split => allf x; have := allf x; rw inE => Q1f; first by case/andP.
by move=> ? ?; apply: Q1f; apply/andP.
Qed.
Lemma in_on2P : {in D1 &, {on D2 &, allQ2 f}} <->
{in [pred x in D1 | f x \in D2] &, allQ2 f}.
Proof.
-split => allf x y; have := allf x y; rewrite !inE => Q2f.
+split => allf x y; have := allf x y; rw !inE => Q2f.
by move=> /andP[? ?] /andP[? ?]; apply: Q2f.
by move=> ? ? ? ?; apply: Q2f; apply/andP.
Qed.
@@ -2098,12 +2098,12 @@ Arguments in_on2S {T1 T2} D2 {f Q2}.
Lemma can_in_pcan [rT aT : Type] (A : {pred aT}) [f : aT -> rT] [g : rT -> aT] :
{in A, cancel f g} -> {in A, pcancel f (fun y : rT => Some (g y))}.
-Proof. by move=> fK x Ax; rewrite fK. Qed.
+Proof. by move=> fK x Ax; rw fK. Qed.
Lemma pcan_in_inj [rT aT : Type] [A : {pred aT}]
[f : aT -> rT] [g : rT -> option aT] :
{in A, pcancel f g} -> {in A &, injective f}.
-Proof. by move=> fK x y Ax Ay /(congr1 g); rewrite !fK// => -[]. Qed.
+Proof. by move=> fK x y Ax Ay /(congr1 g); rw !fK// => -[]. Qed.
Lemma in_inj_comp A B C (f : B -> A) (h : C -> B) (P : pred B) (Q : pred C) :
{in P &, injective f} -> {in Q &, injective h} -> {homo h : x / Q x >-> P x} ->
@@ -2117,14 +2117,14 @@ Lemma can_in_comp [A B C : Type] (D : {pred B}) (D' : {pred C})
{homo h : x / x \in D' >-> x \in D} ->
{in D, cancel f f'} -> {in D', cancel h h'} ->
{in D', cancel (f \o h) (h' \o f')}.
-Proof. by move=> hD fK hK c cD /=; rewrite fK ?hK ?hD. Qed.
+Proof. by move=> hD fK hK c cD /=; rw fK ?hK ?hD. Qed.
Lemma pcan_in_comp [A B C : Type] (D : {pred B}) (D' : {pred C})
[f : B -> A] [h : C -> B] [f' : A -> option B] [h' : B -> option C] :
{homo h : x / x \in D' >-> x \in D} ->
{in D, pcancel f f'} -> {in D', pcancel h h'} ->
{in D', pcancel (f \o h) (obind h' \o f')}.
-Proof. by move=> hD fK hK c cD /=; rewrite fK/= ?hK ?hD. Qed.
+Proof. by move=> hD fK hK c cD /=; rw fK/= ?hK ?hD. Qed.
Definition pred_oapp T (D : {pred T}) : pred (option T) :=
[pred x | oapp (mem D) false x].
@@ -2135,9 +2135,9 @@ Lemma ocan_in_comp [A B C : Type] (D : {pred B}) (D' : {pred C})
{in D, ocancel f f'} -> {in D', ocancel h h'} ->
{in D', ocancel (obind f \o h) (h' \o f')}.
Proof.
-move=> hD fK hK c cD /=; rewrite -[RHS]hK/=; case hcE : (h c) => [b|]//=.
-have bD : b \in D by have := hD _ cD; rewrite hcE inE.
-by rewrite -[b in RHS]fK; case: (f b) => //=; have /hK := cD; rewrite hcE.
+move=> hD fK hK c cD /=; rw -[RHS]hK/=; case hcE : (h c) => [b|]//=.
+have bD : b \in D by have := hD _ cD; rw hcE inE.
+by rw -[b in RHS]fK; case: (f b) => //=; have /hK := cD; rw hcE.
Qed.
Section in_sig.
@@ -2187,7 +2187,7 @@ Lemma equivalence_relP_in T (R : rel T) (A : pred T) :
<-> {in A, reflexive R} /\ {in A &, forall x y, R x y -> {in A, R x =1 R y}}.
Proof.
split=> [eqiR | [Rxx trR] x y z *]; last by split=> [|/trR-> //]; apply: Rxx.
-by split=> [x Ax|x y Ax Ay Rxy z Az]; [rewrite (eqiR x x) | rewrite (eqiR x y)].
+by split=> [x Ax|x y Ax Ay Rxy z Az]; [rw (eqiR x x) | rw (eqiR x y)].
Qed.
Section MonoHomoMorphismTheory.
@@ -2196,41 +2196,41 @@ Variables (aT rT sT : Type) (f : aT -> rT) (g : rT -> aT).
Variables (aP : pred aT) (rP : pred rT) (aR : rel aT) (rR : rel rT).
Lemma monoW : {mono f : x / aP x >-> rP x} -> {homo f : x / aP x >-> rP x}.
-Proof. by move=> hf x ax; rewrite hf. Qed.
+Proof. by move=> hf x ax; rw hf. Qed.
Lemma mono2W :
{mono f : x y / aR x y >-> rR x y} -> {homo f : x y / aR x y >-> rR x y}.
-Proof. by move=> hf x y axy; rewrite hf. Qed.
+Proof. by move=> hf x y axy; rw hf. Qed.
Hypothesis fgK : cancel g f.
Lemma homoRL :
{homo f : x y / aR x y >-> rR x y} -> forall x y, aR (g x) y -> rR x (f y).
-Proof. by move=> Hf x y /Hf; rewrite fgK. Qed.
+Proof. by move=> Hf x y /Hf; rw fgK. Qed.
Lemma homoLR :
{homo f : x y / aR x y >-> rR x y} -> forall x y, aR x (g y) -> rR (f x) y.
-Proof. by move=> Hf x y /Hf; rewrite fgK. Qed.
+Proof. by move=> Hf x y /Hf; rw fgK. Qed.
Lemma homo_mono :
{homo f : x y / aR x y >-> rR x y} -> {homo g : x y / rR x y >-> aR x y} ->
{mono g : x y / rR x y >-> aR x y}.
Proof.
move=> mf mg x y; case: (boolP (rR _ _))=> [/mg //|].
-by apply: contraNF=> /mf; rewrite !fgK.
+by apply: contraNF=> /mf; rw !fgK.
Qed.
Lemma monoLR :
{mono f : x y / aR x y >-> rR x y} -> forall x y, rR (f x) y = aR x (g y).
-Proof. by move=> mf x y; rewrite -{1}[y]fgK mf. Qed.
+Proof. by move=> mf x y; rw -{1}[y]fgK mf. Qed.
Lemma monoRL :
{mono f : x y / aR x y >-> rR x y} -> forall x y, rR x (f y) = aR (g x) y.
-Proof. by move=> mf x y; rewrite -{1}[x]fgK mf. Qed.
+Proof. by move=> mf x y; rw -{1}[x]fgK mf. Qed.
Lemma can_mono :
{mono f : x y / aR x y >-> rR x y} -> {mono g : x y / rR x y >-> aR x y}.
-Proof. by move=> mf x y /=; rewrite -mf !fgK. Qed.
+Proof. by move=> mf x y /=; rw -mf !fgK. Qed.
End MonoHomoMorphismTheory.
@@ -2243,14 +2243,14 @@ Variable (aP : pred aT) (rP : pred rT) (aR : rel aT) (rR : rel rT).
Lemma mono1W_in :
{in aD, {mono f : x / aP x >-> rP x}} ->
{in aD, {homo f : x / aP x >-> rP x}}.
-Proof. by move=> hf x hx ax; rewrite hf. Qed.
+Proof. by move=> hf x hx ax; rw hf. Qed.
#[deprecated(since="Coq 8.16", note="Use mono1W_in instead.")]
Abbreviation mono2W_in := mono1W_in.
Lemma monoW_in :
{in aD &, {mono f : x y / aR x y >-> rR x y}} ->
{in aD &, {homo f : x y / aR x y >-> rR x y}}.
-Proof. by move=> hf x y hx hy axy; rewrite hf. Qed.
+Proof. by move=> hf x y hx hy axy; rw hf. Qed.
Hypothesis fgK : {in rD, {on aD, cancel g & f}}.
Hypothesis mem_g : {homo g : x / x \in rD >-> x \in aD}.
@@ -2258,12 +2258,12 @@ Hypothesis mem_g : {homo g : x / x \in rD >-> x \in aD}.
Lemma homoRL_in :
{in aD &, {homo f : x y / aR x y >-> rR x y}} ->
{in rD & aD, forall x y, aR (g x) y -> rR x (f y)}.
-Proof. by move=> Hf x y hx hy /Hf; rewrite fgK ?mem_g// ?inE; apply. Qed.
+Proof. by move=> Hf x y hx hy /Hf; rw fgK ?mem_g// ?inE; apply. Qed.
Lemma homoLR_in :
{in aD &, {homo f : x y / aR x y >-> rR x y}} ->
{in aD & rD, forall x y, aR x (g y) -> rR (f x) y}.
-Proof. by move=> Hf x y hx hy /Hf; rewrite fgK ?mem_g// ?inE; apply. Qed.
+Proof. by move=> Hf x y hx hy /Hf; rw fgK ?mem_g// ?inE; apply. Qed.
Lemma homo_mono_in :
{in aD &, {homo f : x y / aR x y >-> rR x y}} ->
@@ -2271,23 +2271,23 @@ Lemma homo_mono_in :
{in rD &, {mono g : x y / rR x y >-> aR x y}}.
Proof.
move=> mf mg x y hx hy; case: (boolP (rR _ _))=> [/mg //|]; first exact.
-by apply: contraNF=> /mf; rewrite !fgK ?mem_g//; apply.
+by apply: contraNF=> /mf; rw !fgK ?mem_g//; apply.
Qed.
Lemma monoLR_in :
{in aD &, {mono f : x y / aR x y >-> rR x y}} ->
{in aD & rD, forall x y, rR (f x) y = aR x (g y)}.
-Proof. by move=> mf x y hx hy; rewrite -{1}[y]fgK ?mem_g// mf ?mem_g. Qed.
+Proof. by move=> mf x y hx hy; rw -{1}[y]fgK ?mem_g// mf ?mem_g. Qed.
Lemma monoRL_in :
{in aD &, {mono f : x y / aR x y >-> rR x y}} ->
{in rD & aD, forall x y, rR x (f y) = aR (g x) y}.
-Proof. by move=> mf x y hx hy; rewrite -{1}[x]fgK ?mem_g// mf ?mem_g. Qed.
+Proof. by move=> mf x y hx hy; rw -{1}[x]fgK ?mem_g// mf ?mem_g. Qed.
Lemma can_mono_in :
{in aD &, {mono f : x y / aR x y >-> rR x y}} ->
{in rD &, {mono g : x y / rR x y >-> aR x y}}.
-Proof. by move=> mf x y hx hy; rewrite -mf ?mem_g// !fgK ?mem_g. Qed.
+Proof. by move=> mf x y hx hy; rw -mf ?mem_g// !fgK ?mem_g. Qed.
End MonoHomoMorphismTheory_in.
Arguments homoRL_in {aT rT f g aD rD aR rR}.
@@ -2373,15 +2373,15 @@ Variables (f : aT -> rT) (g : rT -> aT).
Lemma inj_can_sym_in_on :
{homo f : x / x \in aD >-> x \in rD} -> {in aD, {on rD, cancel f & g}} ->
{in rD &, {on aD &, injective g}} -> {in rD, {on aD, cancel g & f}}.
-Proof. by move=> fD fK gI x x_rD gx_aD; apply: gI; rewrite ?inE ?fK ?fD. Qed.
+Proof. by move=> fD fK gI x x_rD gx_aD; apply: gI; rw ?inE ?fK ?fD. Qed.
Lemma inj_can_sym_on : {in aD, cancel f g} ->
{on aD &, injective g} -> {on aD, cancel g & f}.
-Proof. by move=> fK gI x gx_aD; apply: gI; rewrite ?inE ?fK. Qed.
+Proof. by move=> fK gI x gx_aD; apply: gI; rw ?inE ?fK. Qed.
Lemma inj_can_sym_in : {homo f \o g : x / x \in rD} -> {on rD, cancel f & g} ->
{in rD &, injective g} -> {in rD, cancel g f}.
-Proof. by move=> fgD fK gI x x_rD; apply: gI; rewrite ?fK ?fgD. Qed.
+Proof. by move=> fgD fK gI x x_rD; apply: gI; rw ?fK ?fgD. Qed.
End inj_can_sym_in_on.
Arguments inj_can_sym_in_on {aT rT aD rD f g}.
diff --git a/theories/Corelib/ssr/ssreflect.v b/theories/Corelib/ssr/ssreflect.v
index 0b36894e488d..284e34b14631 100644
--- a/theories/Corelib/ssr/ssreflect.v
+++ b/theories/Corelib/ssr/ssreflect.v
@@ -8,103 +8,29 @@
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
-(* This file is (C) Copyright 2006-2015 Microsoft Corporation and Inria. *)
+Require Export ssreflect_rw.
+Declare ML Module "rocq-runtime.plugins.ssreflect_rewrite".
-(** ## **)
+Module SsrIsSyntax.
-Require Import ssrmatching.
-Declare ML Module "rocq-runtime.plugins.ssreflect".
+(** Declare Ssr keywords: "is" "isn't". **)
+Reserved Notation "(******* x 'is' y 'isn't' *******)".
-(**
- This file is the Gallina part of the ssreflect plugin implementation.
- Files that use the ssreflect plugin should always Require ssreflect and
- either Import ssreflect or Import ssreflect.SsrSyntax.
- Part of the contents of this file is technical and will only interest
- advanced developers; in addition the following are defined:
- #[#the str of v by f#]# == the Canonical s : str such that f s = v.
- #[#the str of v#]# == the Canonical s : str that coerces to v.
- argumentType c == the T such that c : forall x : T, P x.
- returnType c == the R such that c : T -> R.
- {type of c for s} == P s where c : forall x : T, P x.
- nonPropType == an interface for non-Prop Types: a nonPropType coerces
- to a Type, and only types that do _not_ have sort
- Prop are canonical nonPropType instances. This is
- useful for applied views (see mid-file comment).
- notProp T == the nonPropType instance for type T.
- phantom T v == singleton type with inhabitant Phantom T v.
- phant T == singleton type with inhabitant Phant v.
- =^~ r == the converse of rewriting rule r (e.g., in a
- rewrite multirule).
- unkeyed t == t, but treated as an unkeyed matching pattern by
- the ssreflect matching algorithm.
- nosimpl t == t, but on the right-hand side of Definition C :=
- nosimpl disables expansion of C by /=.
- locked t == t, but locked t is not convertible to t.
- locked_with k t == t, but not convertible to t or locked_with k' t
- unless k = k' (with k : unit). Rocq type-checking
- will be much more efficient if locked_with with a
- bespoke k is used for sealed definitions.
- unlockable v == interface for sealed constant definitions of v.
- Unlockable def == the unlockable that registers def : C = v.
- #[#unlockable of C#]# == a clone for C of the canonical unlockable for the
- definition of C (e.g., if it uses locked_with).
- #[#unlockable fun C#]# == #[#unlockable of C#]# with the expansion forced to be
- an explicit lambda expression.
- -> The usage pattern for ADT operations is:
- Definition foo_def x1 .. xn := big_foo_expression.
- Fact foo_key : unit. Proof. by #[# #]#. Qed.
- Definition foo := locked_with foo_key foo_def.
- Canonical foo_unlockable := #[#unlockable fun foo#]#.
- This minimizes the comparison overhead for foo, while still allowing
- rewrite unlock to expose big_foo_expression.
-
- #[#elaborate x#]# == triggers Rocq elaboration to fill the holes of the term x
- The main use case is to trigger typeclass inference in
- the body of a ssreflect have := #[#elaborate body#]#.
-
- Additionally we provide default intro pattern ltac views:
- - top of the stack actions:
- => /#[#apply#]# := => hyp {}/hyp
- => /#[#swap#]# := => x y; move: y x
- (also swap and preserves let bindings)
- => /#[#dup#]# := => x; have copy := x; move: copy x
- (also copies and preserves let bindings)
- - calling rewrite from an intro pattern, use with parsimony:
- => /#[#1! rules#]# := rewrite rules
- => /#[#! rules#]# := rewrite !rules
-
- More information about these definitions and their use can be found in the
- ssreflect manual, and in specific comments below. **)
-
-Set Implicit Arguments.
-Unset Strict Implicit.
-Unset Printing Implicit Defensive.
-
-Module SsrSyntax.
-
-(** Declare Ssr keywords: "is" "isn't" "of" "//" "/=" and "//=". **)
-
-Reserved Notation "(* x 'is' y 'of' z 'isn't' // /= //= *)".
+End SsrIsSyntax.
-(** Enable SSR features **)
-#[export] Set SSR Loaded.
+Export SsrIsSyntax.
-Reserved Notation "" (at level 0, n at level 0,
- format "").
-#[warning="-postfix-notation-not-level-1"]
-Reserved Notation "T (* n *)" (at level 200, format "T (* n *)").
-
-End SsrSyntax.
-
-Export SsrMatchingSyntax.
-Export SsrSyntax.
+(** Signal that we have ssreflect version of rewrite (meaning
+ "rewrite a" must be printed "rewrite -> a" for compatibility). **)
+#[export] Set SSRRewriteLoaded.
(** Save primitive notation that will be overloaded. **)
-Local Abbreviation RocqGenericIf c vT vF := (if c then vT else vF) (only parsing).
+Local Abbreviation RocqGenericIf c vT vF :=
+ (if c then vT else vF) (only parsing).
Local Abbreviation RocqGenericDependentIf c x R vT vF :=
(if c as x return R then vT else vF) (only parsing).
-(** Reserve notation that introduced in this file. **)
+(** Reserve notations that are introduced in this file. **)
Reserved Notation "'if' c 'then' vT 'else' vF" (at level 10,
c, vT, vF at level 200).
Reserved Notation "'if' c 'return' R 'then' vT 'else' vF" (at level 10,
@@ -112,28 +38,6 @@ Reserved Notation "'if' c 'return' R 'then' vT 'else' vF" (at level 10,
Reserved Notation "'if' c 'as' x 'return' R 'then' vT 'else' vF" (at level 10,
c, R, vT, vF at level 200, x name).
-Reserved Notation "[ 'the' sT 'of' v 'by' f ]" (at level 0,
- format "[ 'the' sT 'of' v 'by' f ]").
-Reserved Notation "[ 'the' sT 'of' v ]" (at level 0,
- format "[ 'the' sT 'of' v ]").
-Reserved Notation "{ 'type' 'of' c 'for' s }" (at level 0,
- format "{ 'type' 'of' c 'for' s }").
-
-Reserved Notation "=^~ r" (at level 100, format "=^~ r").
-
-Reserved Notation "[ 'unlockable' 'of' C ]" (at level 0,
- format "[ 'unlockable' 'of' C ]").
-Reserved Notation "[ 'unlockable' 'fun' C ]" (at level 0,
- format "[ 'unlockable' 'fun' C ]").
-
-Reserved Notation "[ 'elaborate' x ]" (at level 0).
-
-(**
- To define notations for tactic in intro patterns.
- When "=> /t" is parsed, "t:%ssripat" is actually interpreted. **)
-Declare Scope ssripat_scope.
-Delimit Scope ssripat_scope with ssripat.
-
(**
Make the general "if" into a notation, so that we can override it below.
The notations are "only parsing" because the Rocq decompiler will not
@@ -168,523 +72,10 @@ Notation "'if' c 'as' x 'return' R 'then' vT 'else' vF" :=
Open Scope boolean_if_scope.
-(**
- To allow a wider variety of notations without reserving a large number of
- of identifiers, the ssreflect library systematically uses "forms" to
- enclose complex mixfix syntax. A "form" is simply a mixfix expression
- enclosed in square brackets and introduced by a keyword:
- #[#keyword ... #]#
- Because the keyword follows a bracket it does not need to be reserved.
- Non-ssreflect libraries that do not respect the form syntax (e.g., the Rocq
- Lists library) should be loaded before ssreflect so that their notations
- do not mask all ssreflect forms. **)
-Declare Scope form_scope.
-Delimit Scope form_scope with FORM.
-Open Scope form_scope.
-
-(** Constants for abstract: and #[#: name #]# intro pattern **)
-Definition abstract_lock := unit.
-Definition abstract_key := tt.
-
-Definition abstract (statement : Type) (id : nat) (lock : abstract_lock) :=
- let: tt := lock in statement.
-
-Declare Scope ssr_scope.
-Notation "" := (abstract _ n _) : ssr_scope.
-Notation "T (* n *)" := (abstract T n abstract_key) : ssr_scope.
-Open Scope ssr_scope.
-
-Register abstract_lock as plugins.ssreflect.abstract_lock.
-Register abstract_key as plugins.ssreflect.abstract_key.
-Register abstract as plugins.ssreflect.abstract.
-
-(** Constants for tactic-views **)
-Inductive external_view : Type := tactic_view of Type.
-
-(**
- Syntax for referring to canonical structures:
- #[#the struct_type of proj_val by proj_fun#]#
- This form denotes the Canonical instance s of the Structure type
- struct_type whose proj_fun projection is proj_val, i.e., such that
- proj_fun s = proj_val.
- Typically proj_fun will be A record field accessors of struct_type, but
- this need not be the case; it can be, for instance, a field of a record
- type to which struct_type coerces; proj_val will likewise be coerced to
- the return type of proj_fun. In all but the simplest cases, proj_fun
- should be eta-expanded to allow for the insertion of implicit arguments.
- In the common case where proj_fun itself is a coercion, the "by" part
- can be omitted entirely; in this case it is inferred by casting s to the
- inferred type of proj_val. Obviously the latter can be fixed by using an
- explicit cast on proj_val, and it is highly recommended to do so when the
- return type intended for proj_fun is "Type", as the type inferred for
- proj_val may vary because of sort polymorphism (it could be Set or Prop).
- Note when using the #[#the _ of _ #]# form to generate a substructure from a
- telescopes-style canonical hierarchy (implementing inheritance with
- coercions), one should always project or coerce the value to the BASE
- structure, because Rocq will only find a Canonical derived structure for
- the Canonical base structure -- not for a base structure that is specific
- to proj_value. **)
-
-Module TheCanonical.
-
-Variant put vT sT (v1 v2 : vT) (s : sT) : Prop := Put.
-
-Definition get vT sT v s (p : @put vT sT v v s) := let: Put _ _ _ := p in s.
-
-Definition get_by vT sT & sT -> vT := @get vT sT.
-
-End TheCanonical.
-
-Import TheCanonical. (* Note: no export. *)
-
-Local Arguments get_by _%_type_scope _%_type_scope _ _ _ _.
-
-Notation "[ 'the' sT 'of' v 'by' f ]" :=
- (@get_by _ sT f _ _ ((fun v' (s : sT) => Put v' (f s) s) v _))
- (only parsing) : form_scope.
-
-Notation "[ 'the' sT 'of' v ]" := (get ((fun s : sT => Put v (*coerce*) s s) _))
- (only parsing) : form_scope.
-
-(**
- The following are "format only" versions of the above notations.
- We need to do this to prevent the formatter from being be thrown off by
- application collapsing, coercion insertion and beta reduction in the right
- hand side of the notations above. **)
-
-Notation "[ 'the' sT 'of' v 'by' f ]" := (@get_by _ sT f v _ _)
- (only printing) : form_scope.
-
-Notation "[ 'the' sT 'of' v ]" := (@get _ sT v _ _)
- (only printing) : form_scope.
-
-(**
- We would like to recognize
-Notation " #[# 'the' sT 'of' v : 'Type' #]#" := (@get Type sT v _ _)
- (at level 0, format " #[# 'the' sT 'of' v : 'Type' #]#") : form_scope.
- **)
-
-(**
- Helper notation for canonical structure inheritance support.
- This is a workaround for the poor interaction between delta reduction and
- canonical projections in Rocq's unification algorithm, by which transparent
- definitions hide canonical instances, i.e., in
- Canonical a_type_struct := @Struct a_type ...
- Definition my_type := a_type.
- my_type doesn't effectively inherit the struct structure from a_type. Our
- solution is to redeclare the instance as follows
- Canonical my_type_struct := Eval hnf in #[#struct of my_type#]#.
- The special notation #[#str of _ #]# must be defined for each Structure "str"
- with constructor "Str", typically as follows
- Definition clone_str s :=
- let: Str _ x y ... z := s return {type of Str for s} -> str in
- fun k => k _ x y ... z.
- Notation " #[# 'str' 'of' T 'for' s #]#" := (@clone_str s (@Str T))
- (at level 0, format " #[# 'str' 'of' T 'for' s #]#") : form_scope.
- Notation " #[# 'str' 'of' T #]#" := (repack_str (fun x => @Str T x))
- (at level 0, format " #[# 'str' 'of' T #]#") : form_scope.
- The notation for the match return predicate is defined below; the eta
- expansion in the second form serves both to distinguish it from the first
- and to avoid the delta reduction problem.
- There are several variations on the notation and the definition of the
- the "clone" function, for telescopes, mixin classes, and join (multiple
- inheritance) classes. We describe a different idiom for clones in ssrfun;
- it uses phantom types (see below) and static unification; see fintype and
- ssralg for examples. **)
-
-Definition argumentType T P & forall x : T, P x := T.
-Definition dependentReturnType T P & forall x : T, P x := P.
-Definition returnType aT rT & aT -> rT := rT.
-
-Notation "{ 'type' 'of' c 'for' s }" := (dependentReturnType c s) : type_scope.
-
-(**
- A generic "phantom" type (actually, a unit type with a phantom parameter).
- This type can be used for type definitions that require some Structure
- on one of their parameters, to allow Rocq to infer said structure so it
- does not have to be supplied explicitly or via the " #[#the _ of _ #]#" notation
- (the latter interacts poorly with other Notation).
- The definition of a (co)inductive type with a parameter p : p_type, that
- needs to use the operations of a structure
- Structure p_str : Type := p_Str {p_repr :> p_type; p_op : p_repr -> ...}
- should be given as
- Inductive indt_type (p : p_str) := Indt ... .
- Definition indt_of (p : p_str) & phantom p_type p := indt_type p.
- Notation "{ 'indt' p }" := (indt_of (Phantom p)).
- Definition indt p x y ... z : {indt p} := @Indt p x y ... z.
- Notation " #[# 'indt' x y ... z #]#" := (indt x y ... z).
- That is, the concrete type and its constructor should be shadowed by
- definitions that use a phantom argument to infer and display the true
- value of p (in practice, the "indt" constructor often performs additional
- functions, like "locking" the representation -- see below).
- We also define a simpler version ("phant" / "Phant") of phantom for the
- common case where p_type is Type. **)
-
-Variant phantom T (p : T) : Prop := Phantom.
-Arguments phantom : clear implicits.
-Arguments Phantom : clear implicits.
-Variant phant (p : Type) : Prop := Phant.
-
-(** Internal tagging used by the implementation of the ssreflect elim. **)
-
-Definition protect_term (A : Type) (x : A) : A := x.
-
-Register protect_term as plugins.ssreflect.protect_term.
-
-(**
- The ssreflect idiom for a non-keyed pattern:
- - unkeyed t will match any subterm that unifies with t, regardless of
- whether it displays the same head symbol as t.
- - unkeyed t a b will match any application of a term f unifying with t,
- to two arguments unifying with a and b, respectively, regardless of
- apparent head symbols.
- - unkeyed x where x is a variable will match any subterm with the same
- type as x (when x would raise the 'indeterminate pattern' error). **)
-
+(* This abbreviation is only parsing in Prelude *)
Abbreviation unkeyed x := (let flex := x in flex).
-(** Ssreflect converse rewrite rule rule idiom. **)
-Definition ssr_converse R (r : R) := (Logic.I, r).
-Notation "=^~ r" := (ssr_converse r) : form_scope.
-
-(**
- Term tagging (user-level).
- The ssreflect library uses four strengths of term tagging to restrict
- convertibility during type checking:
- nosimpl t simplifies to t EXCEPT in a definition; more precisely, given
- Definition foo := nosimpl bar, foo (or foo t') will NOT be expanded by
- the /= and //= switches unless it is in a forcing context (e.g., in
- match foo t' with ... end, foo t' will be reduced if this allows the
- match to be reduced). Note that nosimpl bar is simply notation for a
- a term that beta-iota reduces to bar; hence rewrite /foo will replace
- foo by bar, and rewrite -/foo will replace bar by foo.
- CAVEAT: nosimpl should not be used inside a Section, because the end of
- section "cooking" removes the iota redex.
- locked t is provably equal to t, but is not convertible to t; 'locked'
- provides support for selective rewriting, via the lock t : t = locked t
- Lemma, and the ssreflect unlock tactic.
- locked_with k t is equal but not convertible to t, much like locked t,
- but supports explicit tagging with a value k : unit. This is used to
- mitigate a flaw in the term comparison heuristic of the Rocq kernel,
- which treats all terms of the form locked t as equal and compares their
- arguments recursively, leading to an exponential blowup of comparison.
- For this reason locked_with should be used rather than locked when
- defining ADT operations. The unlock tactic does not support locked_with
- but the unlock rewrite rule does, via the unlockable interface.
- we also use Module Type ascription to create truly opaque constants,
- because simple expansion of constants to reveal an unreducible term
- doubles the time complexity of a negative comparison. Such opaque
- constants can be expanded generically with the unlock rewrite rule.
- See the definition of card and subset in fintype for examples of this. **)
-
-Abbreviation nosimpl t := (let: tt := tt in t).
-
-Lemma master_key : unit. Proof. exact tt. Qed.
-Definition locked A := let: tt := master_key in fun x : A => x.
-
-Register master_key as plugins.ssreflect.master_key.
-Register locked as plugins.ssreflect.locked.
-
-Lemma lock A x : x = locked x :> A. Proof. unlock; reflexivity. Qed.
-
-(** The basic closing tactic "done". **)
-Ltac done :=
- trivial; hnf; intros; solve
- [ do ![solve [trivial | simple refine (@sym_equal _ _ _ _); trivial]
- | discriminate | contradiction | split]
- | match goal with H : ~ _ |- _ => solve [case H; trivial] end ].
-
-(** Quicker done tactic not including split, syntax: /0/ **)
-Ltac ssrdone0 :=
- trivial; hnf; intros; solve
- [ do ![solve [trivial | apply: sym_equal; trivial]
- | discriminate | contradiction ]
- | match goal with H : ~ _ |- _ => solve [case H; trivial] end ].
-
-(** To unlock opaque constants. **)
-#[universes(template)]
-Structure unlockable T v := Unlockable {unlocked : T; _ : unlocked = v}.
-Lemma unlock T x C : @unlocked T x C = x. Proof. by case: C. Qed.
-
-Notation "[ 'unlockable' 'of' C ]" :=
- (@Unlockable _ _ C (unlock _)) : form_scope.
-
-Notation "[ 'unlockable' 'fun' C ]" :=
- (@Unlockable _ (fun _ => _) C (unlock _)) : form_scope.
-
-(** Generic keyed constant locking. **)
-
-(** The argument order ensures that k is always compared before T. **)
-Definition locked_with k := let: tt := k in fun T x => x : T.
-
-(**
- This can be used as a cheap alternative to cloning the unlockable instance
- below, but with caution as unkeyed matching can be expensive. **)
-Lemma locked_withE T k x : unkeyed (locked_with k x) = x :> T.
-Proof. by case: k. Qed.
-
-(** Intensionaly, this instance will not apply to locked u. **)
-Canonical locked_with_unlockable T k x :=
- @Unlockable T x (locked_with k x) (locked_withE k x).
-
-(** More accurate variant of unlock, and safer alternative to locked_withE. **)
-Lemma unlock_with T k x : unlocked (locked_with_unlockable k x) = x :> T.
-Proof. exact: unlock. Qed.
-
-(** Abbreviation to trigger Rocq elaboration to fill the holes **)
-Notation "[ 'elaborate' x ]" := (ltac:(refine x)) (only parsing).
-
-(** The internal lemmas for the have tactics. **)
-
-Lemma ssr_have
- (Plemma : Prop) (Pgoal : Prop)
- (step : Plemma) (rest : Plemma -> Pgoal) : Pgoal.
-Proof. exact: rest step. Qed.
-
-Register ssr_have as plugins.ssreflect.ssr_have.
-
-Polymorphic Lemma ssr_have_upoly@{s1 s2;u1 u2}
- (Plemma : Type@{s1;u1}) (Pgoal : Type@{s2;u2})
- (step : Plemma) (rest : Plemma -> Pgoal) : Pgoal.
-Proof. exact: rest step. Qed.
-
-Register ssr_have_upoly as plugins.ssreflect.ssr_have_upoly.
-
-(** Internal N-ary congruence lemmas for the congr tactic. **)
-
-Fixpoint nary_congruence_statement (n : nat)
- : (forall B, (B -> B -> Prop) -> Prop) -> Prop :=
- match n with
- | O => fun k => forall B, k B (fun x1 x2 : B => x1 = x2)
- | S n' =>
- let k' A B e (f1 f2 : A -> B) :=
- forall x1 x2, x1 = x2 -> (e (f1 x1) (f2 x2) : Prop) in
- fun k => forall A, nary_congruence_statement n' (fun B e => k _ (k' A B e))
- end.
-
-Lemma nary_congruence n (k := fun B e => forall y : B, (e y y : Prop)) :
- nary_congruence_statement n k.
-Proof.
-have: k _ _ := _; rewrite {1}/k.
-elim: n k => [|n IHn] k k_P /= A; first exact: k_P.
-by apply: IHn => B e He; apply: k_P => f x1 x2 <-.
-Qed.
-
-Lemma ssr_congr_arrow Plemma Pgoal : Plemma = Pgoal -> Plemma -> Pgoal.
-Proof. by move->. Qed.
-Arguments ssr_congr_arrow : clear implicits.
-
-Register nary_congruence as plugins.ssreflect.nary_congruence.
-Register ssr_congr_arrow as plugins.ssreflect.ssr_congr_arrow.
-
-(** View lemmas that don't use reflection. **)
-
-Section ApplyIff.
-
-Variables P Q : Prop.
-Hypothesis eqPQ : P <-> Q.
-
-Lemma iffLR : P -> Q. Proof. by case: eqPQ. Qed.
-Lemma iffRL : Q -> P. Proof. by case: eqPQ. Qed.
-
-Lemma iffLRn : ~P -> ~Q. Proof. by move=> nP tQ; case: nP; case: eqPQ tQ. Qed.
-Lemma iffRLn : ~Q -> ~P. Proof. by move=> nQ tP; case: nQ; case: eqPQ tP. Qed.
-
-End ApplyIff.
-
-Hint View for move/ iffLRn|2 iffRLn|2 iffLR|2 iffRL|2.
-Hint View for apply/ iffRLn|2 iffLRn|2 iffRL|2 iffLR|2.
-
-(**
- To focus non-ssreflect tactics on a subterm, eg vm_compute.
- Usage:
- elim/abstract_context: (pattern) => G defG.
- vm_compute; rewrite {}defG {G}.
- Note that vm_cast are not stored in the proof term
- for reductions occurring in the context, hence
- set here := pattern; vm_compute in (value of here)
- blows up at Qed time. **)
-Lemma abstract_context T (P : T -> Type) x :
- (forall Q, Q = P -> Q x) -> P x.
-Proof. by move=> /(_ P); apply. Qed.
-
-(*****************************************************************************)
-(* Material for under/over (to rewrite under binders using "context lemmas") *)
-
-Require Export ssrunder.
-
-#[global]
-Hint Extern 0 (@Under_rel.Over_rel _ _ _ _) =>
- solve [ apply: Under_rel.over_rel_done ] : core.
-#[global]
-Hint Resolve Under_rel.over_rel_done : core.
-
-Register Under_rel.Under_rel as plugins.ssreflect.Under_rel.
-Register Under_rel.Under_rel_from_rel as plugins.ssreflect.Under_rel_from_rel.
-
-(** Closing rewrite rule *)
-Definition over := over_rel.
-
-(** Closing tactic *)
-Ltac over :=
- by [ apply: Under_rel.under_rel_done
- | rewrite over
- ].
-
-(** Convenience rewrite rule to unprotect evars, e.g., to instantiate
- them in another way than with reflexivity. *)
-Definition UnderE := Under_relE.
-
-(*****************************************************************************)
-
-(** An interface for non-Prop types; used to avoid improper instantiation
- of polymorphic lemmas with on-demand implicits when they are used as views.
- For example: Some_inj {T} : forall x y : T, Some x = Some y -> x = y.
- Using move/Some_inj on a goal of the form Some n = Some 0 will fail:
- SSReflect will interpret the view as @Some_inj ?T _top_assumption_
- since this is the well-typed application of the view with the minimal
- number of inserted evars (taking ?T := Some n = Some 0), and then will
- later complain that it cannot erase _top_assumption_ after having
- abstracted the viewed assumption. Making x and y maximal implicits
- would avoid this and force the intended @Some_inj nat x y _top_assumption_
- interpretation, but is undesirable as it makes it harder to use Some_inj
- with the many SSReflect and MathComp lemmas that have an injectivity
- premise. Specifying {T : nonPropType} solves this more elegantly, as then
- (?T : Type) no longer unifies with (Some n = Some 0), which has sort Prop.
- **)
-
-Module NonPropType.
-
-(** Implementation notes:
- We rely on three interface Structures:
- - test_of r, the middle structure, performs the actual check: it has two
- canonical instances whose 'condition' projection are maybeProj (?P : Prop)
- and tt, and which set r := true and r := false, respectively. Unifying
- condition (?t : test_of ?r) with maybeProj T will thus set ?r to true if
- T is in Prop as the test_Prop T instance will apply, and otherwise simplify
- maybeProp T to tt and use the test_negative instance and set ?r to false.
- - call_of c r sets up a call to test_of on condition c with expected result r.
- It has a default instance for its 'callee' projection to Type, which
- sets c := maybeProj T and r := false when unifying with a type T.
- - type is a telescope on call_of c r, which checks that unifying test_of ?r1
- with c indeed sets ?r1 := r; the type structure bundles the 'test' instance
- and its 'result' value along with its call_of c r projection. The default
- instance essentially provides eta-expansion for 'type'. This is only
- essential for the first 'result' projection to bool; using the instance
- for other projection merely avoids spurious delta expansions that would
- spoil the notProp T notation.
- In detail, unifying T =~= ?S with ?S : nonPropType, i.e.,
- (1) T =~= @callee (@condition (result ?S) (test ?S)) (result ?S) (frame ?S)
- first uses the default call instance with ?T := T to reduce (1) to
- (2a) @condition (result ?S) (test ?S) =~= maybeProp T
- (3) result ?S =~= false
- (4) frame ?S =~= call T
- along with some trivial universe-related checks which are irrelevant here.
- Then the unification tries to use the test_Prop instance to reduce (2a) to
- (6a) result ?S =~= true
- (7a) ?P =~= T with ?P : Prop
- (8a) test ?S =~= test_Prop ?P
- Now the default 'check' instance with ?result := true resolves (6a) as
- (9a) ?S := @check true ?test ?frame
- Then (7a) can be solved precisely if T has sort at most (hence exactly) Prop,
- and then (8a) is solved by the check instance, yielding ?test := test_Prop T,
- and completing the solution of (2a), and _committing_ to it. But now (3) is
- inconsistent with (9a), and this makes the entire problem (1) fails.
- If on the other hand T does not have sort Prop then (7a) fails and the
- unification resorts to delta expanding (2a), which gives
- (2b) @condition (result ?S) (test ?S) =~= tt
- which is then reduced, using the test_negative instance, to
- (6b) result ?S =~= false
- (8b) test ?S =~= test_negative
- Both are solved using the check default instance, as in the (2a) branch, giving
- (9b) ?S := @check false test_negative ?frame
- Then (3) and (4) are similarly solved using check, giving the final assignment
- (9) ?S := notProp T
- Observe that we _must_ perform the actual test unification on the arguments
- of the initial canonical instance, and not on the instance itself as we do
- in mathcomp/matrix and mathcomp/vector, because we want the unification to
- fail when T has sort Prop. If both the test_of _and_ the result check
- unifications were done as part of the structure telescope then the latter
- would be a sub-problem of the former, and thus failing the check would merely
- make the test_of unification backtrack and delta-expand and we would not get
- failure.
- **)
-
-Structure call_of (condition : unit) (result : bool) := Call {callee : Type}.
-Definition maybeProp (T : Type) := tt.
-Definition call T := Call (maybeProp T) false T.
-
-Structure test_of (result : bool) := Test {condition :> unit}.
-Definition test_Prop (P : Prop) := Test true (maybeProp P).
-Definition test_negative := Test false tt.
-
-Structure type :=
- Check {result : bool; test : test_of result; frame : call_of test result}.
-Definition check result test frame := @Check result test frame.
-
-Module Exports.
-Canonical call.
-Canonical test_Prop.
-Canonical test_negative.
-Canonical check.
-Abbreviation nonPropType := type.
-Coercion callee : call_of >-> Sortclass.
-Coercion frame : type >-> call_of.
-Abbreviation notProp T := (@check false test_negative (call T)).
-End Exports.
-
-End NonPropType.
-Export NonPropType.Exports.
-
-Module Export ipat.
-
-Notation "'[' 'apply' ']'" := (ltac:(let f := fresh "_top_" in move=> f {}/f))
- (at level 0, only parsing) : ssripat_scope.
-
-(* we try to preserve the naming by matching the names from the goal *)
-(* we do move to perform a hnf before trying to match *)
-Notation "'[' 'swap' ']'" := (ltac:(move;
- let x := lazymatch goal with
- | |- forall (x : _), _ => fresh x | |- let x := _ in _ => fresh x | _ => fresh "_top_"
- end in intro x; move;
- let y := lazymatch goal with
- | |- forall (y : _), _ => fresh y | |- let y := _ in _ => fresh y | _ => fresh "_top_"
- end in intro y; revert x; revert y))
- (at level 0, only parsing) : ssripat_scope.
-
-
-(* we try to preserve the naming by matching the names from the goal *)
-(* we do move to perform a hnf before trying to match *)
-Notation "'[' 'dup' ']'" := (ltac:(move;
- lazymatch goal with
- | |- forall (x : _), _ =>
- let x := fresh x in intro x;
- let copy := fresh x in have copy := x; revert x; revert copy
- | |- let x := _ in _ =>
- let x := fresh x in intro x;
- let copy := fresh x in pose copy := x;
- do [unfold x in (value of copy)]; revert x; revert copy
- | |- _ =>
- let x := fresh "_top_" in move=> x;
- let copy := fresh "_top" in have copy := x; revert x; revert copy
- end))
- (at level 0, only parsing) : ssripat_scope.
-
-Notation "'[' '1' '!' rules ']'" := (ltac:(rewrite rules))
- (at level 0, rules at level 200, only parsing) : ssripat_scope.
-Notation "'[' '!' rules ']'" := (ltac:(rewrite !rules))
- (at level 0, rules at level 200, only parsing) : ssripat_scope.
-
-End ipat.
-
-(* A class to trigger reduction by rewriting. *)
-(* Usage: rewrite [pattern]vm_compute. *)
-(* Alternatively one may redefine a lemma as in algebra/rat.v : *)
-(* Lemma rat_vm_compute n (x : rat) : vm_compute_eq n%:Q x -> n%:Q = x. *)
-(* Proof. exact. Qed. *)
-
-Class vm_compute_eq {T : Type} (x y : T) := vm_compute : x = y.
-
-#[global]
-Hint Extern 0 (@vm_compute_eq _ _ _) =>
- vm_compute; reflexivity : typeclass_instances.
+Abbreviation phant := ssreflect_rw.phant.
+Abbreviation Phant := ssreflect_rw.Phant.
+Abbreviation phantom := ssreflect_rw.phantom.
+Abbreviation Phantom := ssreflect_rw.Phantom.
diff --git a/theories/Corelib/ssr/ssreflect_rw.v b/theories/Corelib/ssr/ssreflect_rw.v
new file mode 100644
index 000000000000..810e127f30ce
--- /dev/null
+++ b/theories/Corelib/ssr/ssreflect_rw.v
@@ -0,0 +1,643 @@
+(************************************************************************)
+(* * The Rocq Prover / The Rocq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* .doc { font-family: monospace; white-space: pre; } # **)
+
+Require Import ssrmatching.
+Declare ML Module "rocq-runtime.plugins.ssreflect".
+
+(**
+ This file is the Gallina part of the ssreflect plugin implementation.
+ Files that use the ssreflect plugin should always Require ssreflect and
+ either Import ssreflect or Import ssreflect.SsrSyntax.
+ Part of the contents of this file is technical and will only interest
+ advanced developers; in addition the following are defined:
+ #[#the str of v by f#]# == the Canonical s : str such that f s = v.
+ #[#the str of v#]# == the Canonical s : str that coerces to v.
+ argumentType c == the T such that c : forall x : T, P x.
+ returnType c == the R such that c : T -> R.
+ {type of c for s} == P s where c : forall x : T, P x.
+ nonPropType == an interface for non-Prop Types: a nonPropType coerces
+ to a Type, and only types that do _not_ have sort
+ Prop are canonical nonPropType instances. This is
+ useful for applied views (see mid-file comment).
+ notProp T == the nonPropType instance for type T.
+ phantom T v == singleton type with inhabitant Phantom T v.
+ phant T == singleton type with inhabitant Phant v.
+ =^~ r == the converse of rewriting rule r (e.g., in a
+ rewrite multirule).
+ unkeyed t == t, but treated as an unkeyed matching pattern by
+ the ssreflect matching algorithm.
+ nosimpl t == t, but on the right-hand side of Definition C :=
+ nosimpl disables expansion of C by /=.
+ locked t == t, but locked t is not convertible to t.
+ locked_with k t == t, but not convertible to t or locked_with k' t
+ unless k = k' (with k : unit). Rocq type-checking
+ will be much more efficient if locked_with with a
+ bespoke k is used for sealed definitions.
+ unlockable v == interface for sealed constant definitions of v.
+ Unlockable def == the unlockable that registers def : C = v.
+ #[#unlockable of C#]# == a clone for C of the canonical unlockable for the
+ definition of C (e.g., if it uses locked_with).
+ #[#unlockable fun C#]# == #[#unlockable of C#]# with the expansion forced to be
+ an explicit lambda expression.
+ -> The usage pattern for ADT operations is:
+ Definition foo_def x1 .. xn := big_foo_expression.
+ Fact foo_key : unit. Proof. by #[# #]#. Qed.
+ Definition foo := locked_with foo_key foo_def.
+ Canonical foo_unlockable := #[#unlockable fun foo#]#.
+ This minimizes the comparison overhead for foo, while still allowing
+ rw unlock to expose big_foo_expression.
+
+ #[#elaborate x#]# == triggers Rocq elaboration to fill the holes of the term x
+ The main use case is to trigger typeclass inference in
+ the body of a ssreflect have := #[#elaborate body#]#.
+
+ Additionally we provide default intro pattern ltac views:
+ - top of the stack actions:
+ => /#[#apply#]# := => hyp {}/hyp
+ => /#[#swap#]# := => x y; move: y x
+ (also swap and preserves let bindings)
+ => /#[#dup#]# := => x; have copy := x; move: copy x
+ (also copies and preserves let bindings)
+ - calling rw from an intro pattern, use with parsimony:
+ => /#[#1! rules#]# := rw rules
+ => /#[#! rules#]# := rw !rules
+
+ More information about these definitions and their use can be found in the
+ ssreflect manual, and in specific comments below. **)
+
+Set Implicit Arguments.
+Unset Strict Implicit.
+Unset Printing Implicit Defensive.
+
+Module SsrSyntax.
+
+(** Declare Ssr keywords: "//" "/=" and "//=". **)
+Reserved Notation "(******* // /= //= *******)".
+
+Reserved Notation "" (at level 0, n at level 0, only printing,
+ format "").
+#[warning="-postfix-notation-not-level-1"]
+Reserved Notation "T (* n *)"
+ (at level 200, only printing, format "T (* n *)").
+
+End SsrSyntax.
+
+Export SsrMatchingSyntax.
+Export SsrSyntax.
+
+(** Reserve notations that are introduced in this file. **)
+Reserved Notation "[ 'the' sT 'of' v 'by' f ]" (at level 0,
+ format "[ 'the' sT 'of' v 'by' f ]").
+
+Reserved Notation "[ 'the' sT 'of' v ]" (at level 0,
+ format "[ 'the' sT 'of' v ]").
+Reserved Notation "{ 'type' 'of' c 'for' s }" (at level 0,
+ format "{ 'type' 'of' c 'for' s }").
+
+Reserved Notation "[ 'unlockable' 'of' C ]" (at level 0,
+ format "[ 'unlockable' 'of' C ]").
+
+Reserved Notation "=^~ r" (at level 100, format "=^~ r").
+
+Reserved Notation "[ 'unlockable' 'fun' C ]" (at level 0,
+ format "[ 'unlockable' 'fun' C ]").
+
+Reserved Notation "[ 'elaborate' x ]" (at level 0).
+
+(**
+ To define notations for tactic in intro patterns.
+ When "=> /t" is parsed, "t:%ssripat" is actually interpreted. **)
+Declare Scope ssripat_scope.
+Delimit Scope ssripat_scope with ssripat.
+
+(**
+ To allow a wider variety of notations without reserving a large number
+ of identifiers, the ssreflect library systematically uses "forms" to
+ enclose complex mixfix syntax. A "form" is simply a mixfix expression
+ enclosed in square brackets and introduced by a keyword:
+ #[#keyword ... #]#
+ Because the keyword follows a bracket it does not need to be reserved.
+ Non-ssreflect libraries that do not respect the form syntax (e.g., the Rocq
+ Lists library) should be loaded before ssreflect so that their notations
+ do not mask all ssreflect forms. **)
+Declare Scope form_scope.
+Delimit Scope form_scope with FORM.
+Open Scope form_scope.
+
+(** Constants for abstract: and #[#: name #]# intro pattern **)
+Definition abstract_lock := unit.
+Definition abstract_key := tt.
+
+Definition abstract (statement : Type) (id : nat) (lock : abstract_lock) :=
+ let: tt := lock in statement.
+
+Declare Scope ssr_scope.
+Notation "" := (abstract _ n _) (only printing) : ssr_scope.
+Notation "T (* n *)" := (abstract T n abstract_key) (only printing) : ssr_scope.
+Open Scope ssr_scope.
+
+Register abstract_lock as plugins.ssreflect.abstract_lock.
+Register abstract_key as plugins.ssreflect.abstract_key.
+Register abstract as plugins.ssreflect.abstract.
+
+(** Constants for tactic-views **)
+Inductive external_view : Type := tactic_view of Type.
+
+(**
+ Syntax for referring to canonical structures:
+ #[#the struct_type of proj_val by proj_fun#]#
+ This form denotes the Canonical instance s of the Structure type
+ struct_type whose proj_fun projection is proj_val, i.e., such that
+ proj_fun s = proj_val.
+ Typically proj_fun will be A record field accessors of struct_type, but
+ this need not be the case; it can be, for instance, a field of a record
+ type to which struct_type coerces; proj_val will likewise be coerced to
+ the return type of proj_fun. In all but the simplest cases, proj_fun
+ should be eta-expanded to allow for the insertion of implicit arguments.
+ In the common case where proj_fun itself is a coercion, the "by" part
+ can be omitted entirely; in this case it is inferred by casting s to the
+ inferred type of proj_val. Obviously the latter can be fixed by using an
+ explicit cast on proj_val, and it is highly recommended to do so when the
+ return type intended for proj_fun is "Type", as the type inferred for
+ proj_val may vary because of sort polymorphism (it could be Set or Prop).
+ Note when using the #[#the _ of _ #]# form to generate a substructure from a
+ telescopes-style canonical hierarchy (implementing inheritance with
+ coercions), one should always project or coerce the value to the BASE
+ structure, because Rocq will only find a Canonical derived structure for
+ the Canonical base structure -- not for a base structure that is specific
+ to proj_value. **)
+
+Module TheCanonical.
+
+Variant put vT sT (v1 v2 : vT) (s : sT) : Prop := Put.
+
+Definition get vT sT v s (p : @put vT sT v v s) := let: Put _ _ _ := p in s.
+
+Definition get_by vT sT & sT -> vT := @get vT sT.
+
+End TheCanonical.
+
+Import TheCanonical. (* Note: no export. *)
+
+Local Arguments get_by _%_type_scope _%_type_scope _ _ _ _.
+
+Notation "[ 'the' sT 'of' v 'by' f ]" :=
+ (@get_by _ sT f _ _ ((fun v' (s : sT) => Put v' (f s) s) v _))
+ (only parsing) : form_scope.
+
+Notation "[ 'the' sT 'of' v ]" := (get ((fun s : sT => Put v (*coerce*) s s) _))
+ (only parsing) : form_scope.
+
+(**
+ The following are "format only" versions of the above notations.
+ We need to do this to prevent the formatter from being be thrown off by
+ application collapsing, coercion insertion and beta reduction in the right
+ hand side of the notations above. **)
+
+Notation "[ 'the' sT 'of' v 'by' f ]" := (@get_by _ sT f v _ _)
+ (only printing) : form_scope.
+
+Notation "[ 'the' sT 'of' v ]" := (@get _ sT v _ _)
+ (only printing) : form_scope.
+
+(**
+ We would like to recognize
+Notation " #[# 'the' sT 'of' v : 'Type' #]#" := (@get Type sT v _ _)
+ (at level 0, format " #[# 'the' sT 'of' v : 'Type' #]#") : form_scope.
+ **)
+
+(**
+ Helper notation for canonical structure inheritance support.
+ This is a workaround for the poor interaction between delta reduction and
+ canonical projections in Rocq's unification algorithm, by which transparent
+ definitions hide canonical instances, i.e., in
+ Canonical a_type_struct := @Struct a_type ...
+ Definition my_type := a_type.
+ my_type doesn't effectively inherit the struct structure from a_type. Our
+ solution is to redeclare the instance as follows
+ Canonical my_type_struct := Eval hnf in #[#struct of my_type#]#.
+ The special notation #[#str of _ #]# must be defined for each Structure "str"
+ with constructor "Str", typically as follows
+ Definition clone_str s :=
+ let: Str _ x y ... z := s return {type of Str for s} -> str in
+ fun k => k _ x y ... z.
+ Notation " #[# 'str' 'of' T 'for' s #]#" := (@clone_str s (@Str T))
+ (at level 0, format " #[# 'str' 'of' T 'for' s #]#") : form_scope.
+ Notation " #[# 'str' 'of' T #]#" := (repack_str (fun x => @Str T x))
+ (at level 0, format " #[# 'str' 'of' T #]#") : form_scope.
+ The notation for the match return predicate is defined below; the eta
+ expansion in the second form serves both to distinguish it from the first
+ and to avoid the delta reduction problem.
+ There are several variations on the notation and the definition of the
+ the "clone" function, for telescopes, mixin classes, and join (multiple
+ inheritance) classes. We describe a different idiom for clones in ssrfun;
+ it uses phantom types (see below) and static unification; see fintype and
+ ssralg for examples. **)
+
+Definition argumentType T P & forall x : T, P x := T.
+Definition dependentReturnType T P & forall x : T, P x := P.
+Definition returnType aT rT & aT -> rT := rT.
+
+Notation "{ 'type' 'of' c 'for' s }" := (dependentReturnType c s) : type_scope.
+
+(**
+ A generic "phantom" type (actually, a unit type with a phantom parameter).
+ This type can be used for type definitions that require some Structure
+ on one of their parameters, to allow Rocq to infer said structure so it
+ does not have to be supplied explicitly or via the " #[#the _ of _ #]#" notation
+ (the latter interacts poorly with other Notation).
+ The definition of a (co)inductive type with a parameter p : p_type, that
+ needs to use the operations of a structure
+ Structure p_str : Type := p_Str {p_repr :> p_type; p_op : p_repr -> ...}
+ should be given as
+ Inductive indt_type (p : p_str) := Indt ... .
+ Definition indt_of (p : p_str) & phantom p_type p := indt_type p.
+ Notation "{ 'indt' p }" := (indt_of (Phantom p)).
+ Definition indt p x y ... z : {indt p} := @Indt p x y ... z.
+ Notation " #[# 'indt' x y ... z #]#" := (indt x y ... z).
+ That is, the concrete type and its constructor should be shadowed by
+ definitions that use a phantom argument to infer and display the true
+ value of p (in practice, the "indt" constructor often performs additional
+ functions, like "locking" the representation -- see below).
+ We also define a simpler version ("phant" / "Phant") of phantom for the
+ common case where p_type is Type. **)
+
+Variant phantom T (p : T) : Prop := Phantom.
+Arguments phantom : clear implicits.
+Arguments Phantom : clear implicits.
+Variant phant (p : Type) : Prop := Phant.
+
+(** Internal tagging used by the implementation of the ssreflect elim. **)
+
+Definition protect_term (A : Type) (x : A) : A := x.
+
+Register protect_term as plugins.ssreflect.protect_term.
+
+(**
+ The ssreflect idiom for a non-keyed pattern:
+ - unkeyed t will match any subterm that unifies with t, regardless of
+ whether it displays the same head symbol as t.
+ - unkeyed t a b will match any application of a term f unifying with t,
+ to two arguments unifying with a and b, respectively, regardless of
+ apparent head symbols.
+ - unkeyed x where x is a variable will match any subterm with the same
+ type as x (when x would raise the 'indeterminate pattern' error). **)
+
+Abbreviation unkeyed x := (let flex := x in flex) (only parsing).
+
+(** Ssreflect converse rewrite rule rule idiom. **)
+Definition ssr_converse R (r : R) := (Logic.I, r).
+Notation "=^~ r" := (ssr_converse r) : form_scope.
+
+(**
+ Term tagging (user-level).
+ The ssreflect library uses four strengths of term tagging to restrict
+ convertibility during type checking:
+ nosimpl t simplifies to t EXCEPT in a definition; more precisely, given
+ Definition foo := nosimpl bar, foo (or foo t') will NOT be expanded by
+ the /= and //= switches unless it is in a forcing context (e.g., in
+ match foo t' with ... end, foo t' will be reduced if this allows the
+ match to be reduced). Note that nosimpl bar is simply notation for a
+ a term that beta-iota reduces to bar; hence rw /foo will replace
+ foo by bar, and rw -/foo will replace bar by foo.
+ CAVEAT: nosimpl should not be used inside a Section, because the end of
+ section "cooking" removes the iota redex.
+ locked t is provably equal to t, but is not convertible to t; 'locked'
+ provides support for selective rewriting, via the lock t : t = locked t
+ Lemma, and the ssreflect unlock tactic.
+ locked_with k t is equal but not convertible to t, much like locked t,
+ but supports explicit tagging with a value k : unit. This is used to
+ mitigate a flaw in the term comparison heuristic of the Rocq kernel,
+ which treats all terms of the form locked t as equal and compares their
+ arguments recursively, leading to an exponential blowup of comparison.
+ For this reason locked_with should be used rather than locked when
+ defining ADT operations. The unlock tactic does not support locked_with
+ but the unlock rewrite rule does, via the unlockable interface.
+ we also use Module Type ascription to create truly opaque constants,
+ because simple expansion of constants to reveal an unreducible term
+ doubles the time complexity of a negative comparison. Such opaque
+ constants can be expanded generically with the unlock rewrite rule.
+ See the definition of card and subset in fintype for examples of this. **)
+
+Abbreviation nosimpl t := (let: tt := tt in t).
+
+Lemma master_key : unit. Proof. exact tt. Qed.
+Definition locked A := let: tt := master_key in fun x : A => x.
+
+Register master_key as plugins.ssreflect.master_key.
+Register locked as plugins.ssreflect.locked.
+
+Lemma lock A x : x = locked x :> A. Proof. unlock; reflexivity. Qed.
+
+(** The basic closing tactic "done". **)
+Ltac done :=
+ trivial; hnf; intros; solve
+ [ do ![solve [trivial | simple refine (@sym_equal _ _ _ _); trivial]
+ | discriminate | contradiction | split]
+ | match goal with H : ~ _ |- _ => solve [case H; trivial] end ].
+
+(** Quicker done tactic not including split, syntax: /0/ **)
+Ltac ssrdone0 :=
+ trivial; hnf; intros; solve
+ [ do ![solve [trivial | apply: sym_equal; trivial]
+ | discriminate | contradiction ]
+ | match goal with H : ~ _ |- _ => solve [case H; trivial] end ].
+
+(** To unlock opaque constants. **)
+#[universes(template)]
+Structure unlockable T v := Unlockable {unlocked : T; _ : unlocked = v}.
+Lemma unlock T x C : @unlocked T x C = x. Proof. by case: C. Qed.
+
+Notation "[ 'unlockable' 'of' C ]" :=
+ (@Unlockable _ _ C (unlock _)) : form_scope.
+
+Notation "[ 'unlockable' 'fun' C ]" :=
+ (@Unlockable _ (fun _ => _) C (unlock _)) : form_scope.
+
+(** Generic keyed constant locking. **)
+
+(** The argument order ensures that k is always compared before T. **)
+Definition locked_with k := let: tt := k in fun T x => x : T.
+
+(**
+ This can be used as a cheap alternative to cloning the unlockable instance
+ below, but with caution as unkeyed matching can be expensive. **)
+Lemma locked_withE T k x : unkeyed (locked_with k x) = x :> T.
+Proof. by case: k. Qed.
+
+(** Intensionaly, this instance will not apply to locked u. **)
+Canonical locked_with_unlockable T k x :=
+ @Unlockable T x (locked_with k x) (locked_withE k x).
+
+(** More accurate variant of unlock, and safer alternative to locked_withE. **)
+Lemma unlock_with T k x : unlocked (locked_with_unlockable k x) = x :> T.
+Proof. exact: unlock. Qed.
+
+(** Abbreviation to trigger Rocq elaboration to fill the holes **)
+Notation "[ 'elaborate' x ]" := (ltac:(refine x)) (only parsing).
+
+(** The internal lemmas for the have tactics. **)
+
+Lemma ssr_have
+ (Plemma : Prop) (Pgoal : Prop)
+ (step : Plemma) (rest : Plemma -> Pgoal) : Pgoal.
+Proof. exact: rest step. Qed.
+
+Register ssr_have as plugins.ssreflect.ssr_have.
+
+Polymorphic Lemma ssr_have_upoly@{s1 s2;u1 u2}
+ (Plemma : Type@{s1;u1}) (Pgoal : Type@{s2;u2})
+ (step : Plemma) (rest : Plemma -> Pgoal) : Pgoal.
+Proof. exact: rest step. Qed.
+
+Register ssr_have_upoly as plugins.ssreflect.ssr_have_upoly.
+
+(** Internal N-ary congruence lemmas for the congr tactic. **)
+
+Fixpoint nary_congruence_statement (n : nat)
+ : (forall B, (B -> B -> Prop) -> Prop) -> Prop :=
+ match n with
+ | O => fun k => forall B, k B (fun x1 x2 : B => x1 = x2)
+ | S n' =>
+ let k' A B e (f1 f2 : A -> B) :=
+ forall x1 x2, x1 = x2 -> (e (f1 x1) (f2 x2) : Prop) in
+ fun k => forall A, nary_congruence_statement n' (fun B e => k _ (k' A B e))
+ end.
+
+Lemma nary_congruence n (k := fun B e => forall y : B, (e y y : Prop)) :
+ nary_congruence_statement n k.
+Proof.
+have: k _ _ := _; rw {1}/k.
+elim: n k => [|n IHn] k k_P /= A; first exact: k_P.
+by apply: IHn => B e He; apply: k_P => f x1 x2 <-.
+Qed.
+
+Lemma ssr_congr_arrow Plemma Pgoal : Plemma = Pgoal -> Plemma -> Pgoal.
+Proof. by move->. Qed.
+Arguments ssr_congr_arrow : clear implicits.
+
+Register nary_congruence as plugins.ssreflect.nary_congruence.
+Register ssr_congr_arrow as plugins.ssreflect.ssr_congr_arrow.
+
+(** View lemmas that don't use reflection. **)
+
+Section ApplyIff.
+
+Variables P Q : Prop.
+Hypothesis eqPQ : P <-> Q.
+
+Lemma iffLR : P -> Q. Proof. by case: eqPQ. Qed.
+Lemma iffRL : Q -> P. Proof. by case: eqPQ. Qed.
+
+Lemma iffLRn : ~P -> ~Q. Proof. by move=> nP tQ; case: nP; case: eqPQ tQ. Qed.
+Lemma iffRLn : ~Q -> ~P. Proof. by move=> nQ tP; case: nQ; case: eqPQ tP. Qed.
+
+End ApplyIff.
+
+Hint View for move/ iffLRn|2 iffRLn|2 iffLR|2 iffRL|2.
+Hint View for apply/ iffRLn|2 iffLRn|2 iffRL|2 iffLR|2.
+
+(**
+ To focus non-ssreflect tactics on a subterm, eg vm_compute.
+ Usage:
+ elim/abstract_context: (pattern) => G defG.
+ vm_compute; rw {}defG {G}.
+ Note that vm_cast are not stored in the proof term
+ for reductions occurring in the context, hence
+ set here := pattern; vm_compute in (value of here)
+ blows up at Qed time. **)
+Lemma abstract_context T (P : T -> Type) x :
+ (forall Q, Q = P -> Q x) -> P x.
+Proof. by move=> /(_ P); apply. Qed.
+
+(*****************************************************************************)
+(* Material for under/over (to rewrite under binders using "context lemmas") *)
+
+Require Export ssrunder.
+
+#[global]
+Hint Extern 0 (@Under_rel.Over_rel _ _ _ _) =>
+ solve [ apply: Under_rel.over_rel_done ] : core.
+#[global]
+Hint Resolve Under_rel.over_rel_done : core.
+
+Register Under_rel.Under_rel as plugins.ssreflect.Under_rel.
+Register Under_rel.Under_rel_from_rel as plugins.ssreflect.Under_rel_from_rel.
+
+(** Closing rewrite rule *)
+Definition over := over_rel.
+
+(** Closing tactic *)
+Ltac over :=
+ by [ apply: Under_rel.under_rel_done
+ | rw over
+ ].
+
+(** Convenience rewrite rule to unprotect evars, e.g., to instantiate
+ them in another way than with reflexivity. *)
+Definition UnderE := Under_relE.
+
+(*****************************************************************************)
+
+(** An interface for non-Prop types; used to avoid improper instantiation
+ of polymorphic lemmas with on-demand implicits when they are used as views.
+ For example: Some_inj {T} : forall x y : T, Some x = Some y -> x = y.
+ Using move/Some_inj on a goal of the form Some n = Some 0 will fail:
+ SSReflect will interpret the view as @Some_inj ?T _top_assumption_
+ since this is the well-typed application of the view with the minimal
+ number of inserted evars (taking ?T := Some n = Some 0), and then will
+ later complain that it cannot erase _top_assumption_ after having
+ abstracted the viewed assumption. Making x and y maximal implicits
+ would avoid this and force the intended @Some_inj nat x y _top_assumption_
+ interpretation, but is undesirable as it makes it harder to use Some_inj
+ with the many SSReflect and MathComp lemmas that have an injectivity
+ premise. Specifying {T : nonPropType} solves this more elegantly, as then
+ (?T : Type) no longer unifies with (Some n = Some 0), which has sort Prop.
+ **)
+
+Module NonPropType.
+
+(** Implementation notes:
+ We rely on three interface Structures:
+ - test_of r, the middle structure, performs the actual check: it has two
+ canonical instances whose 'condition' projection are maybeProj (?P : Prop)
+ and tt, and which set r := true and r := false, respectively. Unifying
+ condition (?t : test_of ?r) with maybeProj T will thus set ?r to true if
+ T is in Prop as the test_Prop T instance will apply, and otherwise simplify
+ maybeProp T to tt and use the test_negative instance and set ?r to false.
+ - call_of c r sets up a call to test_of on condition c with expected result r.
+ It has a default instance for its 'callee' projection to Type, which
+ sets c := maybeProj T and r := false when unifying with a type T.
+ - type is a telescope on call_of c r, which checks that unifying test_of ?r1
+ with c indeed sets ?r1 := r; the type structure bundles the 'test' instance
+ and its 'result' value along with its call_of c r projection. The default
+ instance essentially provides eta-expansion for 'type'. This is only
+ essential for the first 'result' projection to bool; using the instance
+ for other projection merely avoids spurious delta expansions that would
+ spoil the notProp T notation.
+ In detail, unifying T =~= ?S with ?S : nonPropType, i.e.,
+ (1) T =~= @callee (@condition (result ?S) (test ?S)) (result ?S) (frame ?S)
+ first uses the default call instance with ?T := T to reduce (1) to
+ (2a) @condition (result ?S) (test ?S) =~= maybeProp T
+ (3) result ?S =~= false
+ (4) frame ?S =~= call T
+ along with some trivial universe-related checks which are irrelevant here.
+ Then the unification tries to use the test_Prop instance to reduce (2a) to
+ (6a) result ?S =~= true
+ (7a) ?P =~= T with ?P : Prop
+ (8a) test ?S =~= test_Prop ?P
+ Now the default 'check' instance with ?result := true resolves (6a) as
+ (9a) ?S := @check true ?test ?frame
+ Then (7a) can be solved precisely if T has sort at most (hence exactly) Prop,
+ and then (8a) is solved by the check instance, yielding ?test := test_Prop T,
+ and completing the solution of (2a), and _committing_ to it. But now (3) is
+ inconsistent with (9a), and this makes the entire problem (1) fails.
+ If on the other hand T does not have sort Prop then (7a) fails and the
+ unification resorts to delta expanding (2a), which gives
+ (2b) @condition (result ?S) (test ?S) =~= tt
+ which is then reduced, using the test_negative instance, to
+ (6b) result ?S =~= false
+ (8b) test ?S =~= test_negative
+ Both are solved using the check default instance, as in the (2a) branch, giving
+ (9b) ?S := @check false test_negative ?frame
+ Then (3) and (4) are similarly solved using check, giving the final assignment
+ (9) ?S := notProp T
+ Observe that we _must_ perform the actual test unification on the arguments
+ of the initial canonical instance, and not on the instance itself as we do
+ in mathcomp/matrix and mathcomp/vector, because we want the unification to
+ fail when T has sort Prop. If both the test_of _and_ the result check
+ unifications were done as part of the structure telescope then the latter
+ would be a sub-problem of the former, and thus failing the check would merely
+ make the test_of unification backtrack and delta-expand and we would not get
+ failure.
+ **)
+
+Structure call_of (condition : unit) (result : bool) := Call {callee : Type}.
+Definition maybeProp (T : Type) := tt.
+Definition call T := Call (maybeProp T) false T.
+
+Structure test_of (result : bool) := Test {condition :> unit}.
+Definition test_Prop (P : Prop) := Test true (maybeProp P).
+Definition test_negative := Test false tt.
+
+Structure type :=
+ Check {result : bool; test : test_of result; frame : call_of test result}.
+Definition check result test frame := @Check result test frame.
+
+Module Exports.
+Canonical call.
+Canonical test_Prop.
+Canonical test_negative.
+Canonical check.
+Abbreviation nonPropType := type.
+Coercion callee : call_of >-> Sortclass.
+Coercion frame : type >-> call_of.
+Abbreviation notProp T := (@check false test_negative (call T)).
+End Exports.
+
+End NonPropType.
+Export NonPropType.Exports.
+
+Module Export ipat.
+
+Notation "'[' 'apply' ']'" := (ltac:(let f := fresh "_top_" in move=> f {}/f))
+ (at level 0, only parsing) : ssripat_scope.
+
+(* we try to preserve the naming by matching the names from the goal *)
+(* we do move to perform a hnf before trying to match *)
+Notation "'[' 'swap' ']'" := (ltac:(move;
+ let x := lazymatch goal with
+ | |- forall (x : _), _ => fresh x | |- let x := _ in _ => fresh x | _ => fresh "_top_"
+ end in intro x; move;
+ let y := lazymatch goal with
+ | |- forall (y : _), _ => fresh y | |- let y := _ in _ => fresh y | _ => fresh "_top_"
+ end in intro y; revert x; revert y))
+ (at level 0, only parsing) : ssripat_scope.
+
+
+(* we try to preserve the naming by matching the names from the goal *)
+(* we do move to perform a hnf before trying to match *)
+Notation "'[' 'dup' ']'" := (ltac:(move;
+ lazymatch goal with
+ | |- forall (x : _), _ =>
+ let x := fresh x in intro x;
+ let copy := fresh x in have copy := x; revert x; revert copy
+ | |- let x := _ in _ =>
+ let x := fresh x in intro x;
+ let copy := fresh x in pose copy := x;
+ do [unfold x in (value of copy)]; revert x; revert copy
+ | |- _ =>
+ let x := fresh "_top_" in move=> x;
+ let copy := fresh "_top" in have copy := x; revert x; revert copy
+ end))
+ (at level 0, only parsing) : ssripat_scope.
+
+Notation "'[' '1' '!' rules ']'" := (ltac:(rw rules))
+ (at level 0, rules at level 200, only parsing) : ssripat_scope.
+Notation "'[' '!' rules ']'" := (ltac:(rw !rules))
+ (at level 0, rules at level 200, only parsing) : ssripat_scope.
+
+End ipat.
+
+(* A class to trigger reduction by rewriting. *)
+(* Usage: rw [pattern]vm_compute. *)
+(* Alternatively one may redefine a lemma as in algebra/rat.v : *)
+(* Lemma rat_vm_compute n (x : rat) : vm_compute_eq n%:Q x -> n%:Q = x. *)
+(* Proof. exact. Qed. *)
+
+Class vm_compute_eq {T : Type} (x y : T) := vm_compute : x = y.
+
+#[global]
+Hint Extern 0 (@vm_compute_eq _ _ _) =>
+ vm_compute; reflexivity : typeclass_instances.
diff --git a/theories/Corelib/ssr/ssrfun.v b/theories/Corelib/ssr/ssrfun.v
index e5e5d1376680..fa714ce2f55c 100644
--- a/theories/Corelib/ssr/ssrfun.v
+++ b/theories/Corelib/ssr/ssrfun.v
@@ -445,7 +445,7 @@ Lemma frefl f : eqfun f f. Proof. by []. Qed.
Lemma fsym f g : eqfun f g -> eqfun g f. Proof. by move=> eq_fg x. Qed.
Lemma ftrans f g h : eqfun f g -> eqfun g h -> eqfun f h.
-Proof. by move=> eq_fg eq_gh x; rewrite eq_fg. Qed.
+Proof. by move=> eq_fg eq_gh x; rw eq_fg. Qed.
Lemma rrefl r : eqrel r r. Proof. by []. Qed.
@@ -470,7 +470,7 @@ Definition catcomp g f := comp f g.
Definition pcomp (f : B -> option A) (g : C -> option B) x := obind f (g x).
Lemma eq_comp f f' g g' : f =1 f' -> g =1 g' -> comp f g =1 comp f' g'.
-Proof. by move=> eq_ff' eq_gg' x; rewrite /comp eq_gg' eq_ff'. Qed.
+Proof. by move=> eq_ff' eq_gg' x; rw /comp eq_gg' eq_ff'. Qed.
End Composition.
@@ -509,7 +509,7 @@ Proof. by []. Qed.
Lemma omap_id (x : option rT) : omap id x = x. Proof. by case: x. Qed.
Lemma eq_omap (h : aT -> rT) : f =1 h -> omap f =1 omap h.
-Proof. by move=> Ef [?|] //=; rewrite Ef. Qed.
+Proof. by move=> Ef [?|] //=; rw Ef. Qed.
Lemma omapEapp : omap f = oapp (olift f) None.
Proof. by []. Qed.
@@ -680,7 +680,7 @@ Lemma can_pcan g : cancel g -> pcancel (fun y => Some (g y)).
Proof. by move=> fK x; congr (Some _). Qed.
Lemma pcan_inj g : pcancel g -> injective.
-Proof. by move=> fK x y /(congr1 g); rewrite !fK => [[]]. Qed.
+Proof. by move=> fK x y /(congr1 g); rw !fK => [[]]. Qed.
Lemma can_inj g : cancel g -> injective.
Proof. by move/can_pcan; apply: pcan_inj. Qed.
@@ -707,7 +707,7 @@ Proof. by move=> injf [?|] [?|] //= [/injf->]. Qed.
Lemma omapK {aT rT : Type} (f : aT -> rT) (g : rT -> aT) :
cancel f g -> cancel (omap f) (omap g).
-Proof. by move=> fK [?|] //=; rewrite fK. Qed.
+Proof. by move=> fK [?|] //=; rw fK. Qed.
Lemma of_voidK T : pcancel (of_void T) [fun _ => None].
Proof. by case. Qed.
@@ -736,28 +736,28 @@ Lemma inj_compr : injective (f \o h) -> injective h.
Proof. by move=> injfh x y /(congr1 f) /injfh. Qed.
Lemma can_comp f' h' : cancel f f' -> cancel h h' -> cancel (f \o h) (h' \o f').
-Proof. by move=> fK hK x; rewrite /= fK hK. Qed.
+Proof. by move=> fK hK x; rw /= fK hK. Qed.
Lemma pcan_pcomp f' h' :
pcancel f f' -> pcancel h h' -> pcancel (f \o h) (pcomp h' f').
-Proof. by move=> fK hK x; rewrite /pcomp fK /= hK. Qed.
+Proof. by move=> fK hK x; rw /pcomp fK /= hK. Qed.
Lemma ocan_comp [fo : B -> option A] [ho : C -> option B]
[f' : A -> B] [h' : B -> C] :
ocancel fo f' -> ocancel ho h' -> ocancel (obind fo \o ho) (h' \o f').
Proof.
-move=> fK hK c /=; rewrite -[RHS]hK/=; case hcE : (ho c) => [b|]//=.
-by rewrite -[b in RHS]fK; case: (fo b) => //=; have := hK c; rewrite hcE.
+move=> fK hK c /=; rw -[RHS]hK/=; case hcE : (ho c) => [b|]//=.
+by rw -[b in RHS]fK; case: (fo b) => //=; have := hK c; rw hcE.
Qed.
Lemma eq_inj : injective f -> f =1 g -> injective g.
-Proof. by move=> injf eqfg x y; rewrite -2!eqfg; apply: injf. Qed.
+Proof. by move=> injf eqfg x y; rw -2!eqfg; apply: injf. Qed.
Lemma eq_can f' g' : cancel f f' -> f =1 g -> f' =1 g' -> cancel g g'.
-Proof. by move=> fK eqfg eqfg' x; rewrite -eqfg -eqfg'. Qed.
+Proof. by move=> fK eqfg eqfg' x; rw -eqfg -eqfg'. Qed.
Lemma inj_can_eq f' : cancel f f' -> injective f' -> cancel g f' -> f =1 g.
-Proof. by move=> fK injf' gK x; apply: injf'; rewrite fK. Qed.
+Proof. by move=> fK injf' gK x; apply: injf'; rw fK. Qed.
End InjectionsTheory.
@@ -775,7 +775,7 @@ Proof. by case: bijf => g fK _; apply: can_inj fK. Qed.
Lemma bij_can_sym f' : cancel f' f <-> cancel f f'.
Proof.
split=> fK; first exact: inj_can_sym fK bij_inj.
-by case: bijf => h _ hK x; rewrite -[x]hK fK.
+by case: bijf => h _ hK x; rw -[x]hK fK.
Qed.
Lemma bij_can_eq f' f'' : cancel f f' -> cancel f f'' -> f' =1 f''.