Prune indeterminate-match rules using the matcher's partial substitution#4148
Merged
Conversation
ba599b1 to
22409db
Compare
…pile},test-escalate-partial-match}, scripts/booster-integration-tests.sh: add regression test for partial-substitution pruning of indeterminate match
Tiny self-contained K definition pinning the booster-dev behaviour fixed
by the partial-substitution pruning in 'applyRule's MatchIndeterminate
branch. The shape mirrors the motivating KEVM '#addr [OP] / wordStack'
case but uses a Bool-sorted rule variable so the partial substitution
binds directly to FalseBool without needing the LLVM backend to evaluate
a domain-specific function.
* Module 'ESCALATE-PARTIAL-MATCH' (resources/escalate-partial-match.k):
'Two' (priority 50) matches 'step(B, cons(_, cons(_, _)))' with
'requires B'; 'Catch' (priority 60) is the unconditional catch-all.
* Subject 'step(false, S:MyList)': matching the wordstack-shaped
second slot against the symbolic 'S' goes MatchIndeterminate, but
the first slot binds 'B -> false' cleanly into the partial sub.
* Post-fix behaviour (state-000.execute / response-000.json): booster
prunes 'Two' via 'returnNotApplied' (the substituted 'requires
false' is FalseBool) and fires 'Catch' on its own, leaving the
rewrite at depth=1 with a single success log entry for the catch-all
(rule-id f297177533fd...). Pre-fix booster-dev aborts at depth=0
with two 'Uncertain about unification of rule' log entries for
'Two' (rule-id d0d3cc8f09ad...).
* Wired into 'scripts/booster-integration-tests.sh' alongside the
other booster-dev-only tests ('compute-ceil', 'simplify', etc.) —
the test demonstrates booster-only progress and is not meaningful
under 'kore-rpc-booster', whose Kore fallback would mask the
difference.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…tests/Pattern/Match{Eval,Implies,Rewrite}: thread partial substitution through MatchIndeterminate
The matcher already accumulates a substitution as it processes pairs, even
when some pairs end up indeterminate. Expose that partial substitution on
the 'MatchIndeterminate' result so callers (next commit will exercise this
from 'applyRule') can attempt to falsify a rule's side conditions before
treating the match as unrecoverably indeterminate.
* 'MatchResult.MatchIndeterminate' now carries the partial 'Substitution'
in addition to the remainder pairs. 'checkIndeterminate' threads
'mSubstitution' through.
* All existing consumers (Rewrite.hs:407 applyRule, ApplyEquations.hs
equation application, Implies.hs predicate matching) ignore the new
field — no behavioural change yet.
* Test helpers ('remainder' defaults to empty partial sub; new
'remainderWith' helper for the non-empty case).
* Existing matcher test "Matching the same variable in a constructor
(indeterminate)" now asserts the bind-then-conflict partial sub the
matcher always produced but the API was previously discarding.
* New matcher test "Structured/var pattern with mixed-determinacy
subject" pins the shape that mirrors the downstream '#addr [OP]'
case: one slot resolves cleanly into the partial sub while another
is indeterminate via a subject-side variable.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…artial-substitution pruning of indeterminate match
Scaffolding for the next commit's prune behaviour. After this commit
857 of 858 unit tests still pass; the prune-on-false case fails on
purpose and flips to PASS once 'applyRule' starts using the partial
substitution to falsify the rule.
* New 'conBoolPair' constructor in the test fixture so a rule LHS
can bind a Bool-sorted variable through matching and drive a
'requires' clause to syntactic 'FalseBool' under substitution.
* 'ruleBoolGuarded' (priority 42) matches
'conBoolPair("trigger", P:SortBool)' with 'requires = [P]', sitting
above an unconditional 'ruleBoolCatchAll' (priority 50).
* Subject 'conBoolPair(VSub:SomeSort, b)' with VSub a subject-side
variable forces 'MatchIndeterminate' against the guarded rule but
cleanly binds 'P ↦ b' in the partial substitution. Three
scenarios:
- b = FalseBool: rule should prune, catch-all fires.
(today: aborts → FAIL; impl in the next commit flips it)
- b = TrueBool: rule still aborts (the match is still
indeterminate even though 'requires' is trivially true) —
locks in that the impl does not accidentally treat a
true-under-partial-sub rule as applicable.
* A third "free Bool variable" case is noted as deferred to the
rpc-integration test because it exercises the SMT-discharge
branch of 'checkRequires' and the unit harness uses 'noSolver'.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…uates to false under partial substitution In 'applyRule' (MatchIndeterminate branch), invoke 'checkRequires' with the matcher's partial substitution before the existing 'RuleApplicationUnclear' abort. The matcher accumulates bindings for every pair it resolves cleanly, independently of the indeterminate pairs; any successful extension of the match must extend that substitution. So if any 'requires' clause evaluates to bottom under the partial substitution alone (via 'returnNotApplied' from 'checkConstraint's onBottom), no extension can rescue the rule and we prune it. The next-applicable rule in the priority group is then tried. If 'checkRequires' returns successfully (clauses true or trivially dropped) or aborts via 'smtUnclear' (RuleConditionUnclear), control falls through to the unchanged 'RuleApplicationUnclear' abort — the match itself is still indeterminate, so the rule is not safe to apply even if its conditions look satisfied under the partial sub. This reuses 'checkRequires' directly so the prune path picks up the standard LLVM-discharge / equation-evaluator / SMT-discharge chain automatically. Flips the previously-failing "Indeterminate match is pruned when requires under partial sub is FalseBool" test to PASS; all 858 unit tests now green. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
22409db to
35a6746
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
applyRulehits aMatchIndeterminateresult, it currently aborts immediately withRuleApplicationUnclearand hands off to Kore — even when the rule'srequiresclause is already unsatisfiable under the bindings the matcher did resolve. The matcher accumulates a partial substitution while processing pairs, so any successful extension of the indeterminate match must extend that substitution; if arequiresclause already evaluates toFalseBoolunder it, no extension can rescue the rule and it can be pruned in favour of the next-priority alternative.This PR exposes that partial substitution on the
MatchIndeterminateresult and uses it inapplyRuleto invokecheckRequiresbefore the existing abort. OnreturnNotAppliedfromcheckConstraint'sonBottom, the rule is pruned; onsmtUnclearor successful clauses, control falls through to the unchangedRuleApplicationUnclearabort (the match itself is still indeterminate, so we cannot apply the rule). The standard LLVM-discharge / equation-evaluator / SMT-discharge chain is reused viacheckRequiresdirectly.The motivating case is the KEVM
#addr [OP:OpCode], where the earlier rules in the priority chain haverequiresthat are falsified by the partial sub but booster was bailing to Kore instead. See here for the rules, basically whenever the workstack was symbolic, the booster would fail on every opcode because it could not tell if there were sufficient items to fire the rule. But it does partially match the<k>cell, which frequently (usually) produces an opcode that fails the#isAddr1Opand#isAddr2Opside-conditions, so it can definitely throw out the rule and fall-through to theowisecase.Changes:
Pattern/Match:MatchIndeterminatecarries the partialSubstitutionalongside the remainder pairs;checkIndeterminatethreads it through.Pattern/Rewrite:applyRule'sMatchIndeterminatebranch invokescheckRequireswith the partial sub; onreturnNotApplied, prunes the rule and continues with the next-priority alternative.Pattern/ApplyEquations,Pattern/Implies: pattern-match the new field as_partialSubst— no behavioural change in the equation evaluator or implies handler.MatchRewrite: new "structured/var pattern with mixed-determinacy subject" case that mirrors the#addr [OP]shape and asserts the partial sub the matcher always produced but the API was previously discarding.Pattern/Rewrite+Fixture.conBoolPair: rewrite tests covering prune-on-FalseBool(catch-all fires), prune-not-fired-on-TrueBool(still aborts — match is still indeterminate), and a deferred free-SortBool-variable SMT case noted for the rpc-integration suite.test-escalate-partial-match(booster-dev only): minimal K module pinning the end-to-end behaviour — pre-fix booster aborts at depth=0 with twoUncertain about unification of rulelog entries; post-fix booster prunes the higher-priority rule and fires the catch-all in a single step.Validation:
test-escalate-partial-matchfails at the test-only commit (first in the chain) and passes at the tip.booster-devmode (mostly blocked by implication checking).executefallbacks that this was designed to address, it does address.