@@ -75,6 +75,7 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
7575 private val resultName = Identifier (" Result" )
7676 private val insidePredicateName = Identifier (" InsidePredicate" )
7777
78+ private val qpCondPostfix = " #condqp"
7879 private var qpPrecondId = 0
7980 private var qpCondFuncs : ListBuffer [(Func ,sil.Forall )] = new ListBuffer [(Func , sil.Forall )]();
8081
@@ -539,7 +540,7 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
539540 case QuantifiedPermissionAssertion (forall, _, _ : sil.AccessPredicate ) => // works the same for fields and predicates
540541 qpPrecondId = qpPrecondId+ 1
541542 val heap = heapModule.staticStateContributions(true , true )
542- val condName = Identifier (name + " #condqp " + qpPrecondId.toString)
543+ val condName = Identifier (name + qpCondPostfix + qpPrecondId.toString)
543544 val condFunc = Func (condName, heap++ args,Int )
544545 val res = (condFunc, forall)
545546 qpCondFuncs += res
@@ -599,16 +600,35 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
599600
600601 val funApp2 = FuncApp (condFunc.name, (heap2++ origArgs) map (_.l), condFunc.typ)
601602
602- val triggers = if (locationAccess.exists(lvds.toSet)) Seq (Trigger (Seq (locationAccess1,locationAccess2))) else Seq () // TODO: we could (also in general) raise an error/warning if the tools fail to find triggers
603+ // Pair each quantified variable with a Skolem function on condFunc applications (rather than all condFunc params)
604+ // This shares witness variables for term equalities, resulting in fewer evaluated heap accesses in framing proofs
605+ val lvsToSkFunctions : Seq [(LocalVar , Func )] = vsFresh.map(vFresh => {
606+ val lvd = translateLocalVarDecl(vFresh)
607+ (lvd.l,
608+ Func (Identifier (env.uniqueName(" sk_" + condFunc.name.name)),
609+ Seq (LocalVarDecl (Identifier (env.uniqueName(" fnAppH1" )), condFunc.typ),
610+ LocalVarDecl (Identifier (env.uniqueName(" fnAppH2" )), condFunc.typ)),
611+ lvd.typ))
612+ })
613+ val skSubs = lvsToSkFunctions.map(lvSkPair =>
614+ (lvSkPair._1, FuncApp (lvSkPair._2.name, Seq (funApp1, funApp2), lvSkPair._2.typ)))
615+
616+ // Replace quantified index variables with Skolem functions in extensional equality on heap locations
617+ val extEq = (translatedCond1 <==> translatedCond2) && (translatedCond1 ==> (locationAccess1 === locationAccess2))
618+ val skExtEq = skSubs.foldLeft(extEq)((body, skSub) => body.replace(skSub._1, skSub._2))
603619
604620 val res = CommentedDecl (" Function used for framing of quantified permission " + qp.toString + " in " + originalName,
605621 condFunc ++
606- Axiom (
607- Forall (heap1 ++ heap2 ++ origArgs, Seq (Trigger (Seq (funApp1, funApp2, heapModule.successorHeapState(heap1,heap2)))),
608- (Forall (vsFresh.map(vFresh => translateLocalVarDecl(vFresh)), triggers,
609- (translatedCond1 <==> translatedCond2) && (translatedCond1 ==> (locationAccess1 === locationAccess2))) ==> (funApp1 === funApp2))
610- ))
611- );
622+ lvsToSkFunctions.map(_._2) ++
623+ Axiom (
624+ Forall (
625+ heap1 ++ heap2 ++ origArgs,
626+ Seq (Trigger (Seq (funApp1, funApp2, heapModule.successorHeapState(heap1,heap2)))),
627+ skExtEq ==> (funApp1 === funApp2)
628+ )
629+ )
630+ )
631+
612632 vsFresh.foreach(vFresh => env.undefine(vFresh.localVar))
613633 stateModule.replaceState(curState)
614634 res
0 commit comments