You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Description**
`Copilot.Language.Spec.prop` and `Copilot.Language.Spec.theorem` are both
reified into as a bare stream of booleans, and do not retain information about
whether the `Prop` passed as argument was a `Forall` or an `Exists`. Because
this information is not retained when later using `Copilot.Theorem.Prove.prove`
to check the properties, the results returned by the SMT solvers may be
incorrect.
**Type**
- Bug: Information is lost, leading to unexpected results .
**Additional context**
None.
**Requester**
- Rob Dockins.
**Method to check presence of bug**
The issue can be detected with the following sample programs:
```haskell
{-# LANGUAGE NoImplicitPrelude #-}
module Main (main) where
import Data.Foldable
import Data.Functor
import Copilot.Theorem.What4
import Language.Copilot
trueThenFalses :: Stream Bool
trueThenFalses = [True] ++ constant False
spec :: Spec
spec = do
void $ prop "forAll trueThenFalses (should be invalid)" (forAll trueThenFalses)
void $ prop "exists trueThenFalses (should be valid)" (exists trueThenFalses)
main :: IO ()
main = do
spec' <- reify spec
results <- prove Z3 spec'
forM_ results $ \(nm, res) -> do
putStr $ nm <> ": "
case res of
Valid -> putStrLn "valid"
Invalid -> putStrLn "invalid"
Unknown -> putStrLn "unknown"
```
The following Dockerfile runs the prover on a Copilot spec that proves an
existential, which produces an exception caught by the program (as expected),
after which it prints the message "Success". If an exception is not caught, the
program exits with an error code.
```
--- Dockerfile-verify-254
FROM ubuntu:focal
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install --yes \
libz-dev \
git \
curl \
gcc \
g++ \
make \
libgmp3-dev \
pkg-config \
z3
RUN mkdir -p $HOME/.ghcup/bin
RUN curl https://downloads.haskell.org/~ghcup/0.1.40.0/x86_64-linux-ghcup-0.1.40.0 -o $HOME/.ghcup/bin/ghcup
RUN chmod a+x $HOME/.ghcup/bin/ghcup
ENV PATH=$PATH:/root/.ghcup/bin/
ENV PATH=$PATH:/root/.cabal/bin/
SHELL ["/bin/bash", "-c"]
RUN ghcup install ghc 9.10.1
RUN ghcup install cabal 3.2
RUN ghcup set ghc 9.10.1
RUN cabal update
ADD What4Existential.hs /tmp/What4Existential.hs
SHELL ["/bin/bash", "-c"]
CMD git clone $REPO && cd $NAME && git checkout $COMMIT && cd .. \
&& cabal v1-sandbox init \
&& cabal v1-install alex happy --constraint='happy <= 2' \
&& cabal v1-install $NAME/copilot**/ \
&& cabal v1-exec -- runhaskell /tmp/What4Existential.hs \
&& echo "Success"
--- What4Existential.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main (main) where
import Control.Exception ( SomeException, handle )
import Data.Foldable ( forM_ )
import Data.Functor ( void )
import System.Exit ( exitFailure, exitSuccess )
import Copilot.Theorem.What4
import Language.Copilot
main :: IO ()
main = do
handle (\(_ :: SomeException) -> exitSuccess) $ do
proveSpec specF
proveSpec specE
putStrLn "The What4 backend tried to prove an existential proposition"
exitFailure
proveSpec :: Spec -> IO ()
proveSpec spec = do
spec' <- reify spec
results <- prove Z3 spec'
forM_ results $ \(nm, res) -> do
putStr $ nm <> ": "
case res of
Valid -> putStrLn "valid"
Invalid -> putStrLn "invalid"
Unknown -> putStrLn "unknown"
specF :: Spec
specF = void $
prop "forAll trueThenFalses (should be invalid)" (forAll trueThenFalses)
specE :: Spec
specE = void $
prop
"exists trueThenFalses (shouldn't have a known result)"
(exists trueThenFalses)
trueThenFalses :: Stream Bool
trueThenFalses = [True] ++ constant False
```
Command (substitute variables based on new path after merge):
```
$ docker run -e "REPO=https://github.com/Copilot-Language/copilot" -e "NAME=copilot" -e "COMMIT=<HASH>" -it copilot-verify-254
```
**Expected result**
Running the specs above or a similar variant via What4 should yield `valid`
when the property is indeed valid (the second property above), indicating that
respects the quantifier is being respected.
If the prover is not able to prove a property of that kind, a suitable error
message should be printed.
Running the dockerfile above prints "Success", indicating that copilot-theorem
correctly detected that one of the properties is existential and cannot be
handled by the What4 backend.
**Proposed solution**
Modify `copilot-core` to introduce a type to represent existentially or
universally quantified properties, keeping enough information about the
quantifier.
Modify `copilot-language` to carry enough information about the quantifier
used.
Modify `copilot-theorem` to ensure a proper encoding of the property when
connecting to What4, and refuse to prove the property when the result would be
incorrect by throwing an exception.
Modify `copilot-prettyprinter` to handle the new type of quantified properties.
**Further notes**
None.
0 commit comments