Use the Dolmen identifiers for constructors and ADT names#1098
Conversation
7edf101 to
f53b10e
Compare
bclement-ocp
left a comment
There was a problem hiding this comment.
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.
|
|
||
| type t = | ||
| | Fake of Hstring.t | ||
| | Unique of { name : Hstring.t; index : int } |
There was a problem hiding this comment.
Why use a separate Unique constructor with our own tag rather than directly use the Dolmen identifier?
There was a problem hiding this comment.
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.
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.
I suspect an issue with DE.Id.compare or DE.Id.equal.
There was a problem hiding this comment.
Uhm they seems to be reasonable:
let compare v v' = compare v.index v'.index
let equal v v' = compare v v' = 0very strange ...
There was a problem hiding this comment.
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.
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).
| (* TODO: FIIIIXXX *) | ||
| (* Format.sprintf "%s___%s" record_constr n *) |
There was a problem hiding this comment.
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.
|
|
||
| (* smart constructors *) | ||
| let tunit = Text ([],Hstring.make "unit") | ||
| (* HACK: we should create a unique Dolmen identifier here. *) |
There was a problem hiding this comment.
We should instead use DStd.Ty.Const.unit.
There was a problem hiding this comment.
I don't know Dolmen already contains a unit constant. I'll change it.
| 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.
Why use hstring rather than dolmen IDs here?
There was a problem hiding this comment.
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.
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.
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).
| module DE = DStd.Expr | ||
|
|
||
| type t = | ||
| | Fake of Hstring.t |
There was a problem hiding this comment.
Nit: calling them Fake is confusing; what's fake about them?
There was a problem hiding this comment.
It's fake unique identifier. It's not unique but I can rename it into Hstring.
| type t = int | ||
| let equal = (=) | ||
| let hash = Fun.id | ||
| type id = Id : 'a DE.id -> id |
There was a problem hiding this comment.
| 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 |
bclement-ocp
left a comment
There was a problem hiding this comment.
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.
| HT.find ae_ty_ht (Id id) | ||
|
|
||
| let fresh_ty ?(is_var = true) ?(name = None) () = | ||
| let fresh_ty ?(is_var = true) ?(id = None) () = |
There was a problem hiding this comment.
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)
| 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.
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.
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.
|
|
||
| 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.
Why not DE.Id.print?
b64ecd1 to
0446b52
Compare
|
I rebase this PR on #1117 to remove some polymorphic comparisons again ;) |
bclement-ocp
left a comment
There was a problem hiding this comment.
Still a couple questions but overall I think this is ready to merge once rebased & if the benches are green.
| | 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.
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.
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.
| 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.
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).
| 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.
👍
Do we still need the various string conversion functions with this?
There was a problem hiding this comment.
I don't think so
There was a problem hiding this comment.
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.
| 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.
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.
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.
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.
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.
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 ;) |
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
c1andc2in our second declaration of the typet). AE answersunknownonnextbut it answersunsatif we remove the first declaration oft.This PR fixes the issue for the new frontend only. So we got
unsatwith--frontend dolmenbut we still gotunknownwith--frontend legacy.The solution consists in using the unique identifiers produced by
Dolmenfor 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 withHstringif we use the constructorsof_stringorof_hstringand 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