Skip to content

Commit 2ad913d

Browse files
committed
Factor-out checkRequires and checkEnsures in applyRule
1 parent 95155fc commit 2ad913d

File tree

1 file changed

+76
-52
lines changed

1 file changed

+76
-52
lines changed

booster/library/Booster/Pattern/Rewrite.hs

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import Booster.Pattern.Match (
6363
MatchResult (MatchFailed, MatchIndeterminate, MatchSuccess),
6464
MatchType (Rewrite),
6565
SortError,
66+
Substitution,
6667
matchTerms,
6768
)
6869
import Booster.Pattern.Pretty
@@ -334,61 +335,12 @@ applyRule pat@Pattern{ceilConditions} rule =
334335
pat
335336
rule.computedAttributes.notPreservesDefinednessReasons
336337

337-
-- apply substitution to rule requires constraints and simplify (one by one
338-
-- in isolation). Stop if false, abort rewrite if indeterminate.
339-
let ruleRequires =
340-
concatMap (splitBoolPredicates . coerce . substituteInTerm subst . coerce) rule.requires
341-
notAppliedIfBottom = RewriteRuleAppT $ pure NotApplied
342-
-- filter out any predicates known to be _syntactically_ present in the known prior
343-
let prior = pat.constraints
344-
toCheck <- lift $ filterOutKnownConstraints prior ruleRequires
345-
346-
unclearRequires <-
347-
catMaybes <$> mapM (checkConstraint id notAppliedIfBottom prior) toCheck
348-
349-
-- unclear conditions may have been simplified and
350-
-- could now be syntactically present in the path constraints, filter again
351-
stillUnclear <- lift $ filterOutKnownConstraints prior unclearRequires
352-
353-
-- check unclear requires-clauses in the context of known constraints (prior)
354-
solver <- lift $ RewriteT $ (.smtSolver) <$> ask
355-
356-
let smtUnclear = do
357-
withContext CtxConstraint . withContext CtxAbort . logMessage $
358-
WithJsonMessage (object ["conditions" .= (externaliseTerm . coerce <$> stillUnclear)]) $
359-
renderOneLineText $
360-
"Uncertain about condition(s) in a rule:"
361-
<+> (hsep . punctuate comma . map (pretty' @mods) $ stillUnclear)
362-
failRewrite $
363-
RuleConditionUnclear rule . coerce . foldl1 AndTerm $
364-
map coerce stillUnclear
365-
366-
SMT.checkPredicates solver prior mempty (Set.fromList stillUnclear) >>= \case
367-
SMT.IsUnknown{} ->
368-
smtUnclear -- abort rewrite if a solver result was Unknown
369-
SMT.IsInvalid -> do
370-
-- requires is actually false given the prior
371-
withContext CtxFailure $ logMessage ("Required clauses evaluated to #Bottom." :: Text)
372-
RewriteRuleAppT $ pure NotApplied
373-
SMT.IsValid ->
374-
pure () -- can proceed
338+
-- check required constraints from lhs: Stop if any is false, abort rewrite if indeterminate.
339+
checkRequires subst
375340

376341
-- check ensures constraints (new) from rhs: stop and return `Trivial` if
377342
-- any are false, remove all that are trivially true, return the rest
378-
let ruleEnsures =
379-
concatMap (splitBoolPredicates . coerce . substituteInTerm subst . coerce) $
380-
Set.toList rule.ensures
381-
trivialIfBottom = RewriteRuleAppT $ pure Trivial
382-
newConstraints <-
383-
catMaybes <$> mapM (checkConstraint id trivialIfBottom prior) ruleEnsures
384-
385-
-- check all new constraints together with the known side constraints
386-
(lift $ SMT.checkPredicates solver prior mempty (Set.fromList newConstraints)) >>= \case
387-
SMT.IsInvalid -> do
388-
withContext CtxSuccess $ logMessage ("New constraints evaluated to #Bottom." :: Text)
389-
RewriteRuleAppT $ pure Trivial
390-
_other ->
391-
pure ()
343+
newConstraints <- checkEnsures subst
392344

393345
-- if a new constraint is going to be added, the equation cache is invalid
394346
unless (null newConstraints) $ do
@@ -438,6 +390,12 @@ applyRule pat@Pattern{ceilConditions} rule =
438390
failRewrite :: RewriteFailed "Rewrite" -> RewriteRuleAppT (RewriteT io) a
439391
failRewrite = lift . (throw)
440392

393+
notAppliedIfBottom :: RewriteRuleAppT (RewriteT io) a
394+
notAppliedIfBottom = RewriteRuleAppT $ pure NotApplied
395+
396+
trivialIfBottom :: RewriteRuleAppT (RewriteT io) a
397+
trivialIfBottom = RewriteRuleAppT $ pure Trivial
398+
441399
checkConstraint ::
442400
(Predicate -> a) ->
443401
RewriteRuleAppT (RewriteT io) (Maybe a) ->
@@ -459,6 +417,72 @@ applyRule pat@Pattern{ceilConditions} rule =
459417
Left UndefinedTerm{} -> onBottom
460418
Left _ -> pure $ Just $ onUnclear p
461419

420+
checkRequires ::
421+
Substitution -> RewriteRuleAppT (RewriteT io) ()
422+
checkRequires matchingSubst = do
423+
ModifiersRep (_ :: FromModifiersT mods => Proxy mods) <- getPrettyModifiers
424+
-- apply substitution to rule requires
425+
let ruleRequires =
426+
concatMap (splitBoolPredicates . coerce . substituteInTerm matchingSubst . coerce) rule.requires
427+
428+
-- filter out any predicates known to be _syntactically_ present in the known prior
429+
toCheck <- lift $ filterOutKnownConstraints pat.constraints ruleRequires
430+
431+
-- simplify the constraints (one by one in isolation). Stop if false, abort rewrite if indeterminate.
432+
unclearRequires <-
433+
catMaybes <$> mapM (checkConstraint id notAppliedIfBottom pat.constraints) toCheck
434+
435+
-- unclear conditions may have been simplified and
436+
-- could now be syntactically present in the path constraints, filter again
437+
stillUnclear <- lift $ filterOutKnownConstraints pat.constraints unclearRequires
438+
439+
-- check unclear requires-clauses in the context of known constraints (priorKnowledge)
440+
solver <- lift $ RewriteT $ (.smtSolver) <$> ask
441+
let smtUnclear = do
442+
withContext CtxConstraint . withContext CtxAbort . logMessage $
443+
WithJsonMessage (object ["conditions" .= (externaliseTerm . coerce <$> stillUnclear)]) $
444+
renderOneLineText $
445+
"Uncertain about condition(s) in a rule:"
446+
<+> (hsep . punctuate comma . map (pretty' @mods) $ stillUnclear)
447+
failRewrite $
448+
RuleConditionUnclear rule . coerce . foldl1 AndTerm $
449+
map coerce stillUnclear
450+
SMT.checkPredicates solver pat.constraints mempty (Set.fromList stillUnclear) >>= \case
451+
SMT.IsUnknown{} ->
452+
smtUnclear -- abort rewrite if a solver result was Unknown
453+
SMT.IsInvalid -> do
454+
-- requires is actually false given the prior
455+
withContext CtxFailure $ logMessage ("Required clauses evaluated to #Bottom." :: Text)
456+
RewriteRuleAppT $ pure NotApplied
457+
SMT.IsValid ->
458+
pure () -- can proceed
459+
checkEnsures ::
460+
Substitution -> RewriteRuleAppT (RewriteT io) [Predicate]
461+
checkEnsures matchingSubst = do
462+
-- apply substitution to rule requires
463+
let ruleEnsures =
464+
concatMap (splitBoolPredicates . coerce . substituteInTerm matchingSubst . coerce) $
465+
Set.toList rule.ensures
466+
newConstraints <-
467+
catMaybes <$> mapM (checkConstraint id trivialIfBottom pat.constraints) ruleEnsures
468+
469+
-- check all new constraints together with the known side constraints
470+
solver <- lift $ RewriteT $ (.smtSolver) <$> ask
471+
(lift $ SMT.checkPredicates solver pat.constraints mempty (Set.fromList newConstraints)) >>= \case
472+
SMT.IsInvalid -> do
473+
withContext CtxSuccess $ logMessage ("New constraints evaluated to #Bottom." :: Text)
474+
RewriteRuleAppT $ pure Trivial
475+
_other ->
476+
pure ()
477+
478+
-- if a new constraint is going to be added, the equation cache is invalid
479+
unless (null newConstraints) $ do
480+
withContextFor Equations . logMessage $
481+
("New path condition ensured, invalidating cache" :: Text)
482+
483+
lift . RewriteT . lift . modify $ \s -> s{equations = mempty}
484+
pure newConstraints
485+
462486
{- | Reason why a rewrite did not produce a result. Contains additional
463487
information for logging what happened during the rewrite.
464488
-}

0 commit comments

Comments
 (0)