Skip to content

Commit b976bec

Browse files
Merge PR #22283: Add Printing Reversible flags: check printed terms reparse to equal terms, escalating printing options when not
Reviewed-by: SkySkimmer Co-authored-by: SkySkimmer <SkySkimmer@users.noreply.github.com>
2 parents 5f7f494 + a448f0c commit b976bec

7 files changed

Lines changed: 613 additions & 5 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
- **Added:**
2+
flags ``Printing Reversible Up To Unification``,
3+
``Printing Reversible Up To Conversion Modulo Sorts And Universes``,
4+
``Printing Reversible Up To Conversion Modulo Universes``,
5+
``Printing Reversible Up To Conversion Modulo Universe Unification`` and
6+
``Printing Reversible Up To Conversion``, which check, each time a term
7+
is printed, that the printed form can be parsed and elaborated back to
8+
a term equal to the original one up to the selected equivalence, and
9+
progressively turn more printing options on until this is the case
10+
(`#22283 <https://github.com/rocq-prover/rocq/pull/22283>`_,
11+
written by Claude (Anthropic), for Jason Gross).

doc/sphinx/proof-engine/vernacular-commands.rst

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,101 @@ Printing constructions in full
11641164

11651165
This flag is off by default.
11661166

1167+
.. _reversible-printing:
1168+
1169+
Checking that printed terms can be parsed back (reversible printing)
1170+
--------------------------------------------------------------------
1171+
1172+
Because notations, hidden implicit arguments, hidden coercions or hidden
1173+
universe instances can make different terms print alike, the printed form
1174+
of a term cannot always be parsed and elaborated back to the term it
1175+
stands for. Rather than unconditionally making printing fully explicit as
1176+
:flag:`Printing All` does, the following flags keep the current printing
1177+
options, but check, each time a term is printed, that its printed form
1178+
can be parsed and elaborated back to a term equal to the original one, up
1179+
to the equivalence selected by the flag; when the check fails, printing
1180+
options are progressively turned on — first :flag:`Printing Coercions`,
1181+
then :flag:`Printing Implicit`, then unsetting :flag:`Printing Notations`,
1182+
then :flag:`Printing Universes` (first with, then without notations),
1183+
then :flag:`Printing Parentheses` and finally all the options implied by
1184+
:flag:`Printing All` — until the printed form passes the check.
1185+
1186+
These five flags are mutually exclusive: setting one of them unsets the
1187+
others, and unsetting the currently set one turns the checks off
1188+
entirely. All are off by default. Since every displayed term is re-parsed
1189+
and re-elaborated (possibly several times), printing can become
1190+
noticeably more expensive when one of these flags is set.
1191+
1192+
.. flag:: Printing Reversible Up To Unification
1193+
1194+
The re-parsed form must unify with the original term: holes standing
1195+
for arguments that are not printed and universes introduced by the
1196+
re-elaboration may be instantiated by unifying against the original
1197+
term. This is the most permissive of the five checks; it accepts any
1198+
printed form that can denote the original term, even if only in a
1199+
context where the expected type is known.
1200+
1201+
.. warn:: The printed form of this term could not be re-parsed and re-elaborated to an equal term (up to ...), even with all printing options turned on.
1202+
1203+
If no printed form, however explicit, passes the check, the most
1204+
explicit one is printed anyway and this warning is emitted. This
1205+
happens for instance for terms mentioning universes that cannot be
1206+
referred to by name, such as the sort of ``Check Type``.
1207+
1208+
.. flag:: Printing Reversible Up To Conversion Modulo Sorts And Universes
1209+
1210+
The printed form must re-elaborate on its own (without help from the
1211+
original term) to a term with no unresolved holes, and that term must
1212+
be convertible to the original one when sorts and universes are
1213+
ignored entirely: sort qualities (``SProp``, ``Prop``, ``Type``),
1214+
universe levels and universe instances may all differ. This is the
1215+
laxest of the conversion-based checks; in particular, unlike
1216+
:flag:`Printing Reversible Up To Conversion Modulo Universes` below,
1217+
it accepts a printed form whose re-elaboration lives at a different
1218+
sort quality than the original term.
1219+
1220+
.. flag:: Printing Reversible Up To Conversion Modulo Universes
1221+
1222+
The printed form must re-elaborate on its own (without help from the
1223+
original term) to a term with no unresolved holes, and that term must
1224+
be convertible to the original one when universe levels (and the level
1225+
components of universe instances) are ignored, but *sort qualities
1226+
must agree*: ``Set`` and ``Type@{u}`` are accepted, but ``Prop``,
1227+
``SProp`` and ``Type`` are pairwise distinguished. With this flag,
1228+
implicit arguments that can only be inferred from the type of the
1229+
original term get printed, and the universe levels of sorts (such as
1230+
the sort of ``Check Type``) generally do not, but the *sort quality*
1231+
part of a polymorphic instance is kept when it would otherwise
1232+
re-elaborate to a different quality.
1233+
1234+
.. flag:: Printing Reversible Up To Conversion Modulo Universe Unification
1235+
1236+
Like :flag:`Printing Reversible Up To Conversion Modulo Universes`,
1237+
but instead of ignoring universe levels it lets the universes (and
1238+
sort qualities) introduced by the re-elaboration be unified against
1239+
the original ones, enforcing new universe (in)equalities as needed.
1240+
This is stricter than
1241+
:flag:`Printing Reversible Up To Conversion Modulo Universes` on
1242+
universe levels — a universe level cannot be unified with an
1243+
algebraic universe, so the sort of ``Check Type`` is printed
1244+
explicitly — but laxer on sort qualities, which get unified rather
1245+
than required to match syntactically.
1246+
1247+
.. flag:: Printing Reversible Up To Conversion
1248+
1249+
Like :flag:`Printing Reversible Up To Conversion Modulo Universe
1250+
Unification`, but no new universe constraints are enforced: the
1251+
universe (in)equalities needed for convertibility must already be
1252+
valid in the current universe graph. With this flag, universe
1253+
instances of polymorphic constants generally need to be printed
1254+
(turning on :flag:`Printing Universes` for the terms where they
1255+
matter).
1256+
1257+
For all five flags, when the printed expression stands for a term (as
1258+
opposed to a type), the types of the original and re-elaborated terms
1259+
are compared as well, so that, e.g., a printed form whose re-elaboration
1260+
lives at a different universe instance is not considered reversible.
1261+
11671262
.. _controlling-typing-flags:
11681263

11691264
Controlling Typing Flags

printing/printer.ml

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,32 @@ let current_extern = PrintingFlags.Extern.current
4545
and only names of goal/section variables and rel names that do
4646
_not_ occur in the scope of the binder to be printed are avoided. *)
4747

48+
(* When a [Printing Reversible] flag is set, the externalization is
49+
checked for reparsability and the printing flags are possibly made
50+
more explicit accordingly, hence rendering uses the flags returned
51+
by [ReversiblePrinting.checked_extern]. *)
52+
let checked_extern_constr ?inctx ?scope ~flags env sigma t =
53+
ReversiblePrinting.checked_extern ~flags
54+
~extern:(fun ~flags -> extern_constr ?inctx ?scope ~flags env sigma t)
55+
~kind:ReversiblePrinting.Term env sigma t
56+
57+
let checked_extern_type ?goal_concl_style ?impargs ~flags env sigma t =
58+
ReversiblePrinting.checked_extern ~flags
59+
~extern:(fun ~flags -> extern_type ?goal_concl_style ~flags env sigma ?impargs t)
60+
~kind:ReversiblePrinting.Type env sigma t
61+
4862
let pr_econstr_n_env ?inctx ?scope ?(flags=current_combined()) env sigma n t =
63+
let flags, c = checked_extern_constr ?inctx ?scope ~flags env sigma t in
4964
let ppflags = Ppconstr.of_printing_flags flags in
50-
pr_constr_expr_n ~flags:ppflags env sigma n (extern_constr ?inctx ?scope ~flags env sigma t)
65+
pr_constr_expr_n ~flags:ppflags env sigma n c
5166
let pr_econstr_env ?inctx ?scope ?(flags=current_combined()) env sigma t =
67+
let flags, c = checked_extern_constr ?inctx ?scope ~flags env sigma t in
5268
let ppflags = Ppconstr.of_printing_flags flags in
53-
pr_constr_expr ~flags:ppflags env sigma (extern_constr ?inctx ?scope ~flags env sigma t)
69+
pr_constr_expr ~flags:ppflags env sigma c
5470
let pr_leconstr_env ?inctx ?scope ?(flags=current_combined()) env sigma t =
71+
let flags, c = checked_extern_constr ?inctx ?scope ~flags env sigma t in
5572
let ppflags = Ppconstr.of_printing_flags flags in
56-
Ppconstr.pr_lconstr_expr ~flags:ppflags env sigma (extern_constr ?inctx ?scope ~flags env sigma t)
73+
Ppconstr.pr_lconstr_expr ~flags:ppflags env sigma c
5774

5875
let pr_constr_n_env ?inctx ?scope ?flags env sigma n c =
5976
pr_econstr_n_env ?inctx ?scope ?flags env sigma n (EConstr.of_constr c)
@@ -73,11 +90,13 @@ let pr_constr_under_binders_env = pr_constr_under_binders_env_gen pr_econstr_env
7390
let pr_lconstr_under_binders_env = pr_constr_under_binders_env_gen pr_leconstr_env
7491

7592
let pr_etype_env ?goal_concl_style ?(flags=current_combined()) env sigma t =
93+
let flags, c = checked_extern_type ?goal_concl_style ~flags env sigma t in
7694
let ppflags = Ppconstr.of_printing_flags flags in
77-
pr_constr_expr ~flags:ppflags env sigma (extern_type ?goal_concl_style ~flags env sigma t)
95+
pr_constr_expr ~flags:ppflags env sigma c
7896
let pr_letype_env ?goal_concl_style ?(flags=current_combined()) env sigma ?impargs t =
97+
let flags, c = checked_extern_type ?goal_concl_style ?impargs ~flags env sigma t in
7998
let ppflags = Ppconstr.of_printing_flags flags in
80-
pr_lconstr_expr ~flags:ppflags env sigma (extern_type ?goal_concl_style ~flags env sigma ?impargs t)
99+
pr_lconstr_expr ~flags:ppflags env sigma c
81100

82101
let pr_type_env ?goal_concl_style ?flags env sigma c =
83102
pr_etype_env ?goal_concl_style ?flags env sigma (EConstr.of_constr c)

0 commit comments

Comments
 (0)