Set measures generate erroneous constraints when applied to non-polymorphic datatypes
clayrat opened this issue · comments
Typechecking the following program:
{-@ LIQUID "--reflection" @-}
module SngBug where
import Data.Set
data Lst a = Emp | Cons a (Lst a)
{-@ measure lstHd @-}
lstHd :: Ord a => Lst a -> Set a
lstHd Emp = empty
lstHd (Cons x _) = singleton x
lcons :: Lst l -> Lst (Lst l)
{-@ lcons :: p: Lst l -> {v:Lst (Lst l) | v = Cons p Emp } @-}
lcons p = Cons p Emp
crashes with the error:
crash: SMTLIB2 respSat = Error "line 3 column 25217: unknown constant smt_set_sng ((SngBug.Lst Int)) declared: (declare-fun smt_set_sng (Int) (Array Int Bool)) "
The error disappears if lstHd
is declared reflect
instead of measure
. It triggers both with and without PLE.
It looks like the internal Lst l
type doesn't get converted to Int
which is what the encoding of sets as Array Int Bool
expects. We currently think there are two possible solutions for this:
- Only generate set operations for elements whose type can be encoded as
Int
(simpler solution, will turn a crash into a proper typechecking error) - Generate multiple set types for each potential set element type (more complex, but allows for expressing more programs)
hi @clayrat -- i have a new laptop and am still installing stuff, can you remind me what smt_set_sng
is declared as? i.e. there should be a line in the .liquid/foo.hs.smt2
file that says how it is declared?
The problem is that the set elements as declared on SMT as int
so every time the set operations are applied (via measures) to elements that are not encoded as int
(e.g., list of lists) there is an SMT crash.
Also, .liquid/foo.hs.smt2
does not contain the declaration of smt_set_sng
. I assume this is an optimization made by @facundominguez ?
Also, .liquid/foo.hs.smt2 does not contain the declaration of smt_set_sng. I assume this is an optimization made by @facundominguez ?
Not an optimization that I remember doing, but I could still be responsible :)
It looks like this optimization was added in ucsd-progsys/liquid-fixpoint#641
hmm that is mysterious, we have to declare smt_set_sng
somewhere surely...
It is declared by fixpoint and I assume it is sent to the Z3. But, it is not printed at the .smt2 file (after the optimization).
I've created a LF PR to fix the preamble logging: ucsd-progsys/liquid-fixpoint#681
That is indeed a good idea! cvc5 seems to have "polymorphic" arrays that we could use to define sets.
So maybe we should:
- put cvc5 in the benchmark tests (to see if it behaves as well as z3).
- create a minimum z3 test with the feature we want and as in the z3 github if there is a way to support it.
ah ... that's unfortunate, the .smt2 files are supposed to be "standalone" i.e. you can just run
z3 blah.smt2
so it looks like the optimization breaks that?
Maybe we could test that the smt2 files produce no errors in CI. I don't know if there is an easy way to test if the answers provided by z3 match the answers provided by LF.
Looks like CVC5 does have polymorphic sets out of the box though, we should definitely try it out!
https://cvc5.github.io/docs/cvc5-1.0.0/theories/sets-and-relations.html#finite-sets
@nikivazou -- I believe z3 also has polymorphic arrays? the problem if I recall correctly is that we define set
using the z3 map
functionality, but only do it "monomorphically"
https://stackoverflow.com/questions/17706219/defining-a-theory-of-sets-with-z3-smt-lib2
Actually, it occurs to me that the "problem" with our encoding is we try to use the Z3 "function" declaration (e.g. smt_set_sng
) which requires us to give a sort
to that function, which has to be monomorphic (because I think functions can't be polymorphic?)
If instead we just inlined the function definition, then we wouldn't need any sorts :-)