New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve printing of reverse coercions #17484
Conversation
Fantastic! 🎊 Nitipicking: since |
A constant, x or x', is always either upoly or not. |
@CohenCyril you're right, done. (there was only one |
@gares do you mean that universe monomorphic constants could'nt cause universe issues with a monomorphic |
I think you are right, but then this approach is a bit scary ;-) I wonder if an uglier encoding would be better, eg |
Sounds good except that |
I am very confused by this change but I have no experience with reversible coercions. In any case, instead of changing what is printed this PR seems to change the inferred term instead. Is my understanding correct? In that case this seems like a very dangerous thing to do. Syntactic pattern matching will have to account for the newly introduced term. Another (related) problem that comes to mind immediately is that this will either slow down or break TC search on classes whose arguments are inferred this way. (Again, I haven't really played with reversible coercions so this might not be possible?) Instead of
I am not sure what "of this" refers to exactly. If it refers to reversible coercions I know that they already showed up in unexpected (but not unwelcome) places in the form of terms that typecheck in 8.16 when they hadn't before. So they are definitely used in the wild even if people don't necessarily notice. Sorry if I misunderstood what is going on. I just want to avoid being even more surprised in future coq by what terms really look like compared to what is printed. |
Yes and no. This indeed changes the infered term (to something convertible) in order to improve the printing. That's the behavior of (usual, direct) coercions: when one types |
If I type
I agree it would be unfortunate. And that we have |
Well, that might be a good opportunity to fix many things. (just trying to look at the bright side of it, I perfectly agree with you) |
While I would be very excited to have more concise printing of elaborated code, I think the approach to achieve this needs more discussion. In short, I share the concerns @Janno posted above. More generally, this PR seems to be based on a unknown-to-me vision of how elaboration and tactic programming would interact, so I have a hard time understanding it. Specifically, I don't see what use coercions would be if using them produced different terms than writing out what you meant in painful detail, because I don't expect most tactics to work on the coercion-derived code. I am getting the sense that the PR authors would consider this acceptable and expected, but I would consider any instance where printing (or anything else) depends on whether the term was originally elaborated using coercions or without to be a bug (and considering "the term" to include a constant specific to the coercion mechanism would be deeply dissatisfying). Concretely, would
IIUC, anything like this would be quite costly to support in fiat-cryptography tactics, so if that's the only available behavior, the features affected by this change would be broken as far as I'm concerned. This may not be an immediate practical concern as I am not sure whether we use reversible coercions at all. |
No: reverse coercions are only a way to give a meaning to term that did not typecheck before their introduction. So any tactic will "retain its power" in the sense it should keep handling anything it previously handled in the same way (assuming it is not calling the elaborator and handling its failures in a specific way but most tactic work on already elaborated terms).
Of course, if you start using reverse coercions and feeding this new terms to your own specific tactics, some adptation might be needed to handle the new terms but that's life. Again, this should only be about the new terms, backward compatibility should hold.
Here things are likely to work out of the bow as typeclass search will simply unfold the identity
Basically, if your code compiles with any Coq < 8.16, it means you are not. |
I suspect you allude to this with "likely" but I'd like to make this a bit more concrete for the benefit of people who do not work with typeclasses a lot: This is only true for hint databases that treat constants as transparent by default. Granted, that is often the case because the opposite behavior makes TC search infeasible outside of very specific and restrictive scenarios. However, when performance is a concern, the only way I know to use TC search effectively and efficiently is to use a transparent-by-default database and to make almost all definitions TC opaque explicitly to benefit from the discrimination nets. Failing hint applications can be very, very expensive and even if every individual one is cheap they add up incredibly quickly when hints look too applicable to the discrimination net. In the development I work on a single missed opacity annotation can make a proof 25%, 50%, 100%, or even 500% slower (depending on where the term in question appears in hint patterns and goal terms). Obviously one can make |
@proux01, thank you for the explanation. My concerns are about keeping the effort required to maintain and write reusable tactics low, not backwards compatibility in the strict sense of whether old code will keep compiling. I understand that code from before reversible coercions were released would not be broken by this change. However, it seems that from a tactic-maintainer's perspective, The specific example with Fiat Cryptography is also of this form: Jason Gross, Samuel Gruetter, and I maintain a large library of Ltac&Ltac2 code that is used by less experienced but independent and competent engineers, and our tactics not working with code that they wrote following the Coq reference manual would be unwelcome friction. Examples of this kind of issues that we already are running into include primitive vs nonprimitive projections and unipoly annotations. Porting tactics to handle new features in the elaborator's output language is evidently costly: many standard-library tactics have not been updated for those two cases yet, and even those that have been took a while. Thus, I think we should at least consider alternative strategies to achieve the printing improvements in this PR. |
Right, but its an elaborator think, no need to make it into the kernel.
That's the whole point of having an elaborator.
I'm not sure I understand this? What do you mean by "leaving
What alternative strategies do you offer? |
The question wasn't direct at me but I wonder if one alternative could be a new kind of cast. A lot of tactics already know to deal with casts and even if the current behavior for casts would need to be adapted at least the adaptation would be a in place that would not be surprising at all for developers precisely because casts already need special handling now. |
I've mixed feelings about casts. They are source of bugs in many places, but using them here could solve the universe polymorphism problem. The only problem is that |
@coqbot run full ci |
@coqbot merge now |
What happened here? (Right until the merge I was under the impression that this was blocked on finding a satisfactory story for tactic compatibility, but it looks like it got merged without that?) |
I am equally confused. Was there private discussion that isn't reflected in this MR? It would be nice to understand the reasoning. |
Fixing mathcomp after coq/coq#17484
Seeing #17484 I am now wondering if the new term will result in more difficulties in tactics that construct terms unsafely. It seems that the application of If this is guaranteed, why did HB need changes? Also, given that every inserted |
HB was designed at a time coq-elpi had no support for universe polymorphism so this kind of bug was somewhat expected.
You have your answer, reverse coercions are too recent to get enough use in the CI codebase for a benchmark to be of any interest. |
Since Coq 8.5 a term which is well typed can be rejected by the kernel if it is not accompanied by its universe constraints (even if the kernel is able to infer the missing ones, a bad choice IMO, but that is OT). Tthat explains the bug: In some sense this patch exposed a bug which was already there (w.r.t. the spec of Coq's kernel). |
I am aware of the kernel's requirements. In the kind of automation I write I usually insert strategic calls to typechecking to generate exactly the constraints that are necessary to make the kernel accept the full proof term. In many cases this boils down to typechecking a partial application to which the remaining arguments are then added unsafely. But most of the time we can bypass typechecking entirely since we know exactly that all the constraints are already established by some other mechanism. I was wondering if I should except breakage from schemes like that due to |
Given your code does not use the feature of reverse coercions, I think you should not see any change. |
This reverts commit a7986e6.
Revert "Fixing mathcomp after coq/coq#17484"
This reverts commit a7986e6.
When a a term [x] is elaborated into [x'] through a reverse coercion, return the term [rev_coerce x' x] that is convertible to [x'] but printed [x], thanks to the coercion [rev_coerce]. Previously, the returned term was directly [x'].
Documented any new / changed user messages.Updated documented syntax by runningmake doc_gram_rsts
.