Skip to content

Commit e09f9e0

Browse files
committed
Recognize and reject quantified input cases if queries are present
Addresses #407
1 parent 5cb1ded commit e09f9e0

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

CHANGES.md

+6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
of this function. Also add extra checks to warn the user if optimization
5454
constraints are present in a regular sat/prove call.
5555

56+
* SBV now rejects queries if universally quantified inputs are present. Previously
57+
these were allowed to go through, but in general skolemization makes the corresponding
58+
variables unusable in the query context. See http://github.com/LeventErkok/sbv/issues/407
59+
for details. If you have an actual use case for such a feature, please get in
60+
touch. Thanks to Brian Schroeder for reporting this anomaly.
61+
5662
### Version 7.9, 2018-06-15
5763

5864
* Add support for bit-vector arithmetic underflow/overflow detection. The new

Data/SBV/Control/Utils.hs

+50-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module Data.SBV.Control.Utils (
3636
) where
3737

3838
import Data.Maybe (isJust)
39-
import Data.List (sortBy, sortOn, elemIndex, partition, groupBy, tails)
39+
import Data.List (sortBy, sortOn, elemIndex, partition, groupBy, tails, intercalate)
4040

4141
import Data.Char (isPunctuation, isSpace, chr)
4242
import Data.Function (on)
@@ -740,9 +740,57 @@ runProofOn rm comments res@(Result ki _qcInfo _observables _codeSegs is consts t
740740

741741
-- | Execute a query
742742
executeQuery :: QueryContext -> Query a -> Symbolic a
743-
executeQuery _queryContext (Query userQuery) = do
743+
executeQuery queryContext (Query userQuery) = do
744744
st <- R.ask
745745
rm <- liftIO $ readIORef (runMode st)
746+
747+
-- If we're doing an external query, then we cannot allow quantifiers to be present. Why?
748+
-- Consider:
749+
--
750+
-- issue = do x :: SBool <- forall_
751+
-- y :: SBool <- exists_
752+
-- constrain y
753+
-- query $ do checkSat
754+
-- (,) <$> getValue x <*> getValue y
755+
--
756+
-- This is the (simplified/annotated SMTLib we would generate:)
757+
--
758+
-- (declare-fun s1 (Bool) Bool) ; s1 is the function that corresponds to the skolemized 'y'
759+
-- (assert (forall ((s0 Bool)) ; s0 is 'x'
760+
-- (s1 s0))) ; s1 applied to s0 is the actual 'y'
761+
-- (check-sat)
762+
-- (get-value (s0)) ; s0 simply not visible here
763+
-- (get-value (s1)) ; s1 is visible, but only via 's1 s0', so it is also not available.
764+
--
765+
-- And that would be terrible! The scoping rules of our "quantified" variables and how they map to
766+
-- SMTLib is just not compatible. This is a historical design issue, but too late at this point. (We
767+
-- should've never allowed general quantification like this, but only in limited contexts.)
768+
--
769+
-- So, we check if this is an external-query, and if there are quantified variables. If so, we
770+
-- cowardly refuse to continue. For details, see: <http://github.com/LeventErkok/sbv/issues/407>
771+
772+
() <- liftIO $ case queryContext of
773+
QueryInternal -> return () -- we're good, internal usages don't mess with scopes
774+
QueryExternal -> do
775+
(userInps, _) <- readIORef (rinps st)
776+
let badInps = reverse [n | (ALL, (_, n)) <- userInps]
777+
case badInps of
778+
[] -> return ()
779+
_ -> let plu | length badInps > 1 = "s require"
780+
| True = " requires"
781+
in error $ unlines [ ""
782+
, "*** Data.SBV: Unsupported query call in the presence of quantified inputs."
783+
, "***"
784+
, "*** The following variable" ++ plu ++ " explicit quantification: "
785+
, "***"
786+
, "*** " ++ intercalate ", " badInps
787+
, "***"
788+
, "*** While quantification and queries can co-exist in principle, SBV currently"
789+
, "*** does not support this scenario. Avoid using quantifiers with user queries"
790+
, "*** if possible. Please do get in touch if your use case does require such"
791+
, "*** a feature to see how we can accommodate such scenarios."
792+
]
793+
746794
case rm of
747795
-- Transitioning from setup
748796
SMTMode stage isSAT cfg | not (isRunIStage stage) -> liftIO $ do

0 commit comments

Comments
 (0)