Liquid haskell creating a new bytestring with PS

70 views Asked by At

I'm making some bindings to C from Haskell, and trying to make it safer with LiquidHaskell. I'm having some trouble with specifying the length of a bytestring in the LH type annotation.

I have an enhanced ByteString type in LiquidHaskell that includes its length:

{-@ type ByteString Blen = {v:B.ByteString | bslen v == Blen} @-}

I am getting the following error when I run Liquidhaskell:

**** RESULT: UNSAFE ************************************************************


 /home/t/liquidproblem/Main.hs:47:3-22: Error: Liquid Type Mismatch

 47 |   Bi.PS foreignPtr 0 l
        ^^^^^^^^^^^^^^^^^^^^

   Inferred type
     VV : {v : Data.ByteString.Internal.ByteString | 0 <= bslen v
                                                     && bslen v == stringlen v}

   not a subtype of Required type
     VV : {VV : Data.ByteString.Internal.ByteString | bslen VV == l}

   In Context
     l : {l : GHC.Types.Int | l >= 0}

Line 47 is:

44 {-@ makeBs :: ForeignPtr Word8 -> l:NonNeg -> ByteString l @-}
45 makeBs :: F.ForeignPtr F.Word8 -> Int -> B.ByteString
46 makeBs foreignPtr l =
47   Bi.PS foreignPtr 0 l

(I know this seems a bit of a silly function, but it got put in because the debugging process was to factor out bits and put LH annotations on them till I found the problem.)

The relevant imports are:

import qualified Data.ByteString.Internal as Bi
import qualified Data.ByteString as B
import qualified Foreign as F

The LH NonNeg type is

{-@ type NonNeg = {i:Int | i >= 0} @-}
1

There are 1 answers

1
user11228628 On

LiquidHaskell doesn't know that the ByteString returned by makeBs has length l, and it can't prove that from the information available to it.

You know it will because you know that the third argument to the PS constructor is the length. So at this point you have two (or possibly one) options:

  1. You can try to tell LH what you know about the PS constructor, and give it an annotation like {-@ Bi.PS :: _ -> _ -> l:NonNeg -> ByteString l @-}. I tried this and it didn't quite work because there are internal GHC types in the signature of PS that LH doesn't seem so good at handling. YMMV. Or, you can:
  2. Forget about annotating PS and mark your own function with assume: {-@ assume makeBs :: ForeignPtr Word8 -> l:NonNeg -> ByteString l @-}. Of course, this gets riskier if the function marked with assume gets any bigger—silly though it may seem, you might want to keep makeBs around if you go this route.