-
Notifications
You must be signed in to change notification settings - Fork 33
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
Use the Dolmen identifiers for constructors and ADT names #1098
Conversation
7edf101
to
f53b10e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not look thoroughly through the minutiæ of all mechanical changes from Hstring
→ Uid
but the change looks correct overall. I do have some minor questions, and something needs to be done for record constructors which I think are broken in the legacy typechecker by this PR.
src/lib/structures/uid.ml
Outdated
|
||
type t = | ||
| Fake of Hstring.t | ||
| Unique of { name : Hstring.t; index : int } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use a separate Unique
constructor with our own tag rather than directly use the Dolmen identifier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course I tried to use the Dolmen identifier
directly but I got a regression in our non-regression test suite. I should investigate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I tried again with the original index produced by Dolmen. Now I got five regressions and it seems that Alt-Ergo ignores the timeout for them (make runtest
never returns). Actually, if I run dune exec -- alt-ergo tests/adts/match_in_terms.ae
, I cannot kill the processus with CTRL+C
. I have to type pkill alt-ergo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect an issue with DE.Id.compare
or DE.Id.equal
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm they seems to be reasonable:
let compare v v' = compare v.index v'.index
let equal v v' = compare v v' = 0
very strange ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to Vincent, I got the bug with gdb
. The issue comes from the fact that Dolmen
identifiers can be infinite values and the polymorphic equality loops infinitely on them. I wrote another PR to remove as much as possible polymorphic comparison in lists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, dolmen identifiers should never be compared using the polymorphic identity: besides being slow (compared to the comparison defined by dolmen), it may loop forever (because the Type
identifiers loops on itself), or may fail at runtime (because ids contain tags that can contain arbitrary data such as functions).
src/lib/structures/ty.ml
Outdated
(* TODO: FIIIIXXX *) | ||
(* Format.sprintf "%s___%s" record_constr n *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is required for the legacy typechecker not to confuse constructors for distinct record types ; it should be moved to the legacy typechecker.ml rather than removed entirely.
src/lib/structures/ty.ml
Outdated
@@ -514,19 +514,20 @@ let type_body name args = Decls.body name args | |||
|
|||
|
|||
(* smart constructors *) | |||
let tunit = Text ([],Hstring.make "unit") | |||
(* HACK: we should create a unique Dolmen identifier here. *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should instead use DStd.Ty.Const.unit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know Dolmen
already contains a unit constant. I'll change it.
src/lib/structures/fpa_rounding.ml
Outdated
let fake_reprs = List.map Uid.of_hstring hstring_smt_reprs in | ||
Ty.Tsum (Uid.of_string "RoundingMode", fake_reprs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use hstring rather than dolmen IDs here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I wrote this PR I didn't do it because I didn't want to have to manage unique identifiers in the legacy typechecker. Basically, if we use real unique identifiers and hstring identifiers, we have to ensure that the legacy typechecker won't recreate ADTs' constructors for builtin enums (and it does...).
Finally I found another way to use dolmen
identifiers here. I modified the comparison functions of Uid
. Now if we compare a Hstring
and a Dolmen
identifiers, we transform the Dolmen
identifier into string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the legacy typechecker won't recreate ADTs' constructors for builtin enums (and it does...).
Ah, I guess this is the issue of having different names for the AE and SMT enums, got it.
Now if we compare a Hstring and a Dolmen identifiers, we transform the Dolmen identifier into string.
Is this not re-introducing the dependency on string values that this PR is trying to eliminate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the Dolmen
frontend doesn't produce Uid.t
of type Hstring
anymore (but for abstract types, I'll change that). It means we always compare Dolmen
identifiers here (for constructors, destructors and ADTs' names).
src/lib/structures/uid.ml
Outdated
module DE = DStd.Expr | ||
|
||
type t = | ||
| Fake of Hstring.t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: calling them Fake
is confusing; what's fake about them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fake unique identifier. It's not unique but I can rename it into Hstring
.
src/lib/frontend/d_cnf.ml
Outdated
type t = int | ||
let equal = (=) | ||
let hash = Fun.id | ||
type id = Id : 'a DE.id -> id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type id = Id : 'a DE.id -> id | |
type id = Id : 'a DE.id -> id[@@unboxed] |
4105dbf
to
6a81272
Compare
The PR is ready for a second pass. I think we should test the legacy frontend with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah on paper the changes look correct but we definitely should check that there are no regressions. I am a bit lost by the many small changes now; I will take a deeper look after the weekend. I think there are many unneeded string/Hstring conversions now but we can clean that up later.
src/lib/frontend/d_cnf.ml
Outdated
|
||
let fresh_ty ?(is_var = true) ?(name = None) () = | ||
let fresh_ty ?(is_var = true) ?(id = None) () = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want ?id
here and ~id
when fresh_ty
is called.
(Currently fresh_ty
has a ?id:Uid.t option
optional argument, simply using ?id
would make it a ?id:Uid.t
argument)
src/lib/frontend/d_cnf.ml
Outdated
DStd.Expr.Id.mk ~builtin:B.Base | ||
(DStd.Path.global (Hstring.view name)) | ||
(DStd.Path.global (Uid.show name)) | ||
DStd.Expr.{ arity = 0; alias = No_alias } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a bit weird; aren't we building a second Dolmen identifier with the same name as an existing one here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, I thought it was correct but we duplicate the identifiers here. I fixed the issue by creating the constructors and the Dolmen type in Fpa_rounding
.
src/lib/structures/uid.ml
Outdated
|
||
let pp ppf = function | ||
| Hstring hs -> Hstring.print ppf hs | ||
| Dolmen { path; _ } -> Fmt.string ppf @@ get_basename path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not DE.Id.print
?
b64ecd1
to
0446b52
Compare
I rebase this PR on #1117 to remove some polymorphic comparisons again ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a couple questions but overall I think this is ready to merge once rebased & if the benches are green.
src/lib/structures/uid.ml
Outdated
| Hstring hs1, Hstring hs2 -> Hstring.equal hs1 hs2 | ||
| Dolmen id1, Dolmen id2 -> DE.Id.equal id1 id2 | ||
| _ -> | ||
Hstring.equal (Hstring.make @@ show u1) (Hstring.make @@ show u2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a complicated way of writing String.equal (show u1) (show u2)
? The complexity should be the same since Hstring.make
requires a linear scan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it was a little bit faster because we compare integers if these Hstring
already exist but we have to compute the hash of the strings, which may be linear in the length of them.
src/lib/structures/uid.ml
Outdated
match u1, u2 with | ||
| Hstring hs1, Hstring hs2 -> Hstring.compare hs1 hs2 | ||
| Dolmen id1, Dolmen id2 -> DE.Id.compare id1 id2 | ||
| _ -> Hstring.compare (Hstring.make @@ show u1) (Hstring.make @@ show u2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the Hstring
comparison here? Otherwise String.compare (show u1) (show u2)
might be sufficient (complexity should be the same since Hstring.make
requires a linear scan).
|
||
(** Equal to ["RoundingMode"], the SMT2 type of rounding modes. *) | ||
val fpa_rounding_mode_type_name : string | ||
|
||
(** Equal to ["fpa_rounding_mode"], the Alt-Ergo native rounding mode type. *) | ||
val fpa_rounding_mode_ae_type_name : string | ||
|
||
(** The Dolmen rounding mode type. *) | ||
val fpa_rounding_mode_dty : Dolmen.Std.Expr.Ty.t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Do we still need the various string conversion functions with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still need them in both legacy and new frontend. In the new frontend, we use these functions in the typechecker to inject the AE identifiers into SMT-LIB identifiers.
We also use them in Expr
because we need to convert a Hstring
identifier into Fpa_rounding.rounding_mode
.
I'm sure we can remove some of them after getting rid of the legacy frontend.
src/lib/structures/fpa_rounding.ml
Outdated
let module DStd = Dolmen.Std in | ||
let ty_cst = DE.Ty.Const.mk (DStd.Path.global "RoundingMode") 0 in | ||
let cstrs = | ||
List.map (fun c -> DStd.Path.global @@ to_smt_string c, []) cstrs | ||
in | ||
let _, cstrs = DE.Term.define_adt ty_cst [] cstrs in | ||
DE.Ty.apply ty_cst [], cstrs, | ||
Ty.Tsum (Uid.of_dolmen ty_cst, List.map (fun (c, _) -> Uid.of_dolmen c) cstrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I think this could be replaced with DStd.Expr.Ty.roundingMode
. I don't think it is entirely trivial to do so, but might be worth a note in a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't the enum type is shipped with Dolmen
. We can replace it easily. It's exactly the same code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm actually roundingMode
is the SMT-LIB roundingMode, so it's not so obvious. I add a note.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RoundingMode
type from AE (SMT-LIB flavor) should be identical to the SMT-LIB RoundingMode, we made sure with @Stevendeo that the constructors are the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put a note and I will do it in another PR, maybe after the release.
818f88b
to
c838a68
Compare
No regression with the following combinations:
So this PR is ready for I hope a last check ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
We don't manage correctly incremental type declarations. For instance the following input is accepted by the SMT-LIB standard:
(Notice that we switch the constructors
c1
andc2
in our second declaration of the typet
). AE answersunknown
onnext
but it answersunsat
if we remove the first declaration oft
.This PR fixes the issue for the new frontend only. So we got
unsat
with--frontend dolmen
but we still gotunknown
with--frontend legacy
.The solution consists in using the unique identifiers produced by
Dolmen
for the constructors, destructors and names of ADTs. To reduce as much as possible the amount of modification done in the legacy typechecker, I wrapped Dolmen's identifiers in a new moduleUid
. This module agrees withHstring
if we use the constructorsof_string
orof_hstring
and it uses Dolmen's identifiers if we use the constructorof_dolmen
. Of course, we'll get rid of this module as soon as we remove the legacy frontend.I didn't use a unique identifier for the constructor of builtin enumeration types. This case will be fixed after removing the legacy frontend.
This PR is supposed to be merged before #1093