ucsd-progsys / liquidhaskell

Liquid Types For Haskell

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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:

  1. Only generate set operations for elements whose type can be encoded as Int (simpler solution, will turn a crash into a proper typechecking error)
  2. 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:

  1. put cvc5 in the benchmark tests (to see if it behaves as well as z3).
  2. 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 :-)