@@ -26,6 +26,7 @@ module Booster.Pattern.ApplyEquations (
2626 evaluateConstraints ,
2727) where
2828
29+ import Control.Exception qualified as Exception (throw )
2930import Control.Monad
3031import Control.Monad.Extra (fromMaybeM , whenJust )
3132import Control.Monad.IO.Class (MonadIO (.. ))
@@ -39,7 +40,7 @@ import Data.ByteString.Char8 qualified as BS
3940import Data.Coerce (coerce )
4041import Data.Data (Data , Proxy )
4142import Data.Foldable (toList , traverse_ )
42- import Data.List (intersperse , partition )
43+ import Data.List (foldl1' , intersperse , partition )
4344import Data.List.NonEmpty qualified as NonEmpty
4445import Data.Map (Map )
4546import Data.Map qualified as Map
@@ -817,17 +818,45 @@ applyEquation term rule =
817818 -- could now be syntactically present in the path constraints, filter again
818819 stillUnclear <- lift $ filterOutKnownConstraints knownPredicates unclearConditions
819820
820- -- abort if any of the conditions is still unclear at that point
821+ mbSolver :: Maybe SMT. SMTContext <- (. smtSolver) <$> lift getConfig
822+
823+ -- check any conditions that are still unclear with the SMT solver
824+ -- (or abort if no solver is being used), abort if still unclear after
821825 unless (null stillUnclear) $
822- throwE
823- ( \ ctxt ->
824- ctxt $
825- logMessage $
826- renderOneLineText $
827- " Uncertain about a condition(s) in rule:"
828- <+> hsep (intersperse " ," $ map (pretty' @ mods ) unclearConditions)
829- , IndeterminateCondition unclearConditions
830- )
826+ let checkWithSmt :: SMT. SMTContext -> EquationT io (Maybe Bool )
827+ checkWithSmt smt =
828+ SMT. checkPredicates smt knownPredicates mempty (Set. fromList stillUnclear) >>= \ case
829+ Left SMT. SMTSolverUnknown {} -> do
830+ pure Nothing
831+ Left other ->
832+ liftIO $ Exception. throw other
833+ Right result ->
834+ pure result
835+ in maybe (pure Nothing ) (lift . checkWithSmt) mbSolver >>= \ case
836+ Nothing -> do
837+ -- no solver or still unclear: abort
838+ throwE
839+ ( \ ctx ->
840+ ctx . logMessage $
841+ WithJsonMessage (object [" conditions" .= map (externaliseTerm . coerce) stillUnclear]) $
842+ renderOneLineText
843+ ( " Uncertain about conditions in rule: " <+> hsep (intersperse " ," $ map (pretty' @ mods ) stillUnclear)
844+ )
845+ , IndeterminateCondition stillUnclear
846+ )
847+ Just False -> do
848+ -- actually false given path condition: fail
849+ let failedP = Predicate $ foldl1' AndTerm $ map coerce stillUnclear
850+ throwE
851+ ( \ ctx ->
852+ ctx . logMessage $
853+ WithJsonMessage (object [" conditions" .= map (externaliseTerm . coerce) stillUnclear]) $
854+ renderOneLineText (" Required condition found to be false: " <> pretty' @ mods failedP)
855+ , ConditionFalse failedP
856+ )
857+ Just True -> do
858+ -- can proceed
859+ pure ()
831860
832861 -- check ensured conditions, filter any
833862 -- true ones, prune if any is false
@@ -842,6 +871,24 @@ applyEquation term rule =
842871 ( checkConstraint $ \ p -> (\ ctxt -> ctxt $ logMessage (" Ensures clause simplified to #Bottom." :: Text ), EnsuresFalse p)
843872 )
844873 ensured
874+ -- check all ensured conditions together with the path condition
875+ whenJust mbSolver $ \ solver -> do
876+ lift (SMT. checkPredicates solver knownPredicates mempty $ Set. fromList ensuredConditions) >>= \ case
877+ Right (Just False ) -> do
878+ let falseEnsures = Predicate $ foldl1' AndTerm $ map coerce ensuredConditions
879+ throwE
880+ ( \ ctx ->
881+ ctx . logMessage $
882+ WithJsonMessage (object [" conditions" .= map (externaliseTerm . coerce) ensuredConditions]) $
883+ renderOneLineText (" Ensured conditions found to be false: " <> pretty' @ mods falseEnsures)
884+ , EnsuresFalse falseEnsures
885+ )
886+ Right _other ->
887+ pure ()
888+ Left SMT. SMTSolverUnknown {} ->
889+ pure ()
890+ Left other ->
891+ liftIO $ Exception. throw other
845892 lift $ pushConstraints $ Set. fromList ensuredConditions
846893 pure $ substituteInTerm subst rule. rhs
847894 where
0 commit comments