Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/main/scala/rules/ChunkSupporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,12 @@ object chunkSupporter extends ChunkSupportRules {
case Some(ch) if v.decider.check(IsPositive(ch.perm), Verifier.config.checkTimeout()) =>
Q(s, ch.snap, v)
case _ if v.decider.checkSmoke(true) =>
Success() // TODO: Mark branch as dead?
if (s.isInPackage) {
val snap = v.decider.fresh(v.snapshotSupporter.optimalSnapshotSort(resource, s, v), Option.when(withExp)(PUnknown()))
Q(s, snap, v)
} else {
Success() // TODO: Mark branch as dead?
}
case _ =>
createFailure(ve, v, s, "looking up chunk", true)
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/rules/Executor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ object executor extends ExecutionRules {
consume(s, a, false, pve, v)((s1, _, v1) =>
Q(s1, v1))

case assert @ ast.Assert(a: ast.FalseLit) =>
case assert @ ast.Assert(a: ast.FalseLit) if !s.isInPackage =>
/* "assert false" triggers a smoke check. If successful, we backtrack. */
executionFlowController.tryOrFail0(s.copy(h = magicWandSupporter.getEvalHeap(s)), v)((s1, v1, QS) => {
if (v1.decider.checkSmoke(true))
Expand Down Expand Up @@ -653,7 +653,7 @@ object executor extends ExecutionRules {

case pckg @ ast.Package(wand, proofScript) =>
val pve = PackageFailed(pckg)
magicWandSupporter.packageWand(s, wand, proofScript, pve, v)((s1, chWand, v1) => {
magicWandSupporter.packageWand(s.copy(isInPackage = true), wand, proofScript, pve, v)((s1, chWand, v1) => {

val hOps = s1.reserveHeaps.head + chWand
assert(s.exhaleExt || s1.reserveHeaps.length == 1)
Expand Down Expand Up @@ -692,7 +692,7 @@ object executor extends ExecutionRules {
case _ => s2.smCache
}

continuation(s2.copy(smCache = smCache3), v1)
continuation(s2.copy(smCache = smCache3, isInPackage = s.isInPackage), v1)
})

case apply @ ast.Apply(e) =>
Expand Down
9 changes: 7 additions & 2 deletions src/main/scala/rules/MoreCompleteExhaleSupporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import viper.silicon.utils.ast.{BigAnd, buildMinExp, removeKnownToBeTrueExp, rep
import viper.silicon.verifier.Verifier
import viper.silicon.{MList, MMap}
import viper.silver.ast
import viper.silver.parser.{PKw, PPrimitiv, PReserved}
import viper.silver.parser.PUnknown
import viper.silver.verifier.VerificationError

import scala.collection.mutable.ListBuffer
Expand Down Expand Up @@ -204,7 +204,12 @@ object moreCompleteExhaleSupporter extends SymbolicExecutionRules {

if (relevantChunks.isEmpty) {
if (v.decider.checkSmoke(true)) {
Success() // TODO: Mark branch as dead?
if (s.isInPackage) {
val snap = v.decider.fresh(v.snapshotSupporter.optimalSnapshotSort(resource, s, v), Option.when(withExp)(PUnknown()))
Q(s, snap, v)
} else {
Success() // TODO: Mark branch as dead?
}
} else {
createFailure(ve, v, s, False, "branch is dead")
}
Expand Down
12 changes: 5 additions & 7 deletions src/main/scala/rules/Producer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ object producer extends ProductionRules {
eval(s1, perm, pve, v1)((s2, tPerm, ePermNew, v2) =>
permissionSupporter.assertNotNegative(s2, tPerm, perm, ePermNew, pve, v2)((s2a, v3) => {
val s3 = s2a.copy(constrainableARPs = s.constrainableARPs)
val snap = sf(v3.symbolConverter.toSort(field.typ), v3)
val snap = sf(v3.snapshotSupporter.optimalSnapshotSort(field, s3, v3), v3)
val gain = if (!Verifier.config.unsafeWildcardOptimization() || s2.permLocations.contains(field))
PermTimes(tPerm, s3.permissionScalingFactor)
else
Expand All @@ -350,9 +350,7 @@ object producer extends ProductionRules {
eval(s1, perm, pve, v1)((s1a, tPerm, ePermNew, v1a) =>
permissionSupporter.assertNotNegative(s1a, tPerm, perm, ePermNew, pve, v1a)((s1b, v2) => {
val s2 = s1b.copy(constrainableARPs = s.constrainableARPs)
val snap = sf(
predicate.body.map(v2.snapshotSupporter.optimalSnapshotSort(_, s.program)._1)
.getOrElse(sorts.Snap), v2)
val snap = sf(v2.snapshotSupporter.optimalSnapshotSort(predicate, s2, v2), v2)
val gain = if (!Verifier.config.unsafeWildcardOptimization() || s2.permLocations.contains(predicate))
PermTimes(tPerm, s2.permissionScalingFactor)
else
Expand Down Expand Up @@ -382,7 +380,7 @@ object producer extends ProductionRules {
val formalVarExps = Option.when(withExp)(bodyVars.indices.toList.map(i => ast.LocalVarDecl(s"x$i", bodyVars(i).typ)()))
evals(s, bodyVars, _ => pve, v)((s1, args, bodyVarsNew, v1) => {
val (sm, smValueDef) =
quantifiedChunkSupporter.singletonSnapshotMap(s1, wand, args, sf(sorts.Snap, v1), v1)
quantifiedChunkSupporter.singletonSnapshotMap(s1, wand, args, sf(v1.snapshotSupporter.optimalSnapshotSort(wand, s1, v1), v1), v1)
v1.decider.prover.comment("Definitional axioms for singleton-SM's value")
val definitionalAxiomMark = v1.decider.setPathConditionMark()
val debugExp = Option.when(withExp)(DebugExp.createInstance("Definitional axioms for singleton-SM's value", true))
Expand Down Expand Up @@ -416,7 +414,7 @@ object producer extends ProductionRules {
Q(s2, v1)})

case wand: ast.MagicWand =>
val snap = sf(sorts.MagicWandSnapFunction, v)
val snap = sf(v.snapshotSupporter.optimalSnapshotSort(wand, s, v), v)
magicWandSupporter.createChunk(s, wand, MagicWandSnapshot(snap), pve, v)((s1, chWand, v1) =>
chunkSupporter.produce(s1, s1.h, chWand, v1)((s2, h2, v2) =>
Q(s2.copy(h = h2), v2)))
Expand All @@ -431,7 +429,7 @@ object producer extends ProductionRules {
else Some(forall.triggers)
evalQuantified(s, Forall, forall.variables, Seq(cond), Seq(acc.loc.rcv, acc.perm), optTrigger, qid, pve, v) {
case (s1, qvars, qvarExps, Seq(tCond), eCondNew, Some((Seq(tRcvr, tPerm), rcvrPerm, tTriggers, (auxGlobals, auxNonGlobals), auxExps)), v1) =>
val tSnap = sf(sorts.FieldValueFunction(v1.symbolConverter.toSort(acc.loc.field.typ), acc.loc.field.name), v1)
val tSnap = sf(sorts.FieldValueFunction(v1.snapshotSupporter.optimalSnapshotSort(acc.loc.field, s1, v1), acc.loc.field.name), v1)
val s1a = s1.copy(constrainableARPs = s.constrainableARPs)
quantifiedChunkSupporter.produce(
s1a,
Expand Down
9 changes: 5 additions & 4 deletions src/main/scala/state/State.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ final case class State(g: Store = Store(),
conservedPcs: Stack[Vector[RecordedPathConditions]] = Stack(),
recordPcs: Boolean = false,
exhaleExt: Boolean = false,
isInPackage: Boolean = false,

ssCache: SsCache = Map.empty,
assertReadAccessOnly: Boolean = false,
Expand Down Expand Up @@ -175,7 +176,7 @@ object State {
triggerExp1,
partiallyConsumedHeap1,
permissionScalingFactor1, permissionScalingFactorExp1, isEvalInOld,
reserveHeaps1, reserveCfgs1, conservedPcs1, recordPcs1, exhaleExt1,
reserveHeaps1, reserveCfgs1, conservedPcs1, recordPcs1, exhaleExt1, isInPackage1,
ssCache1, assertReadAccessOnly1,
qpFields1, qpPredicates1, qpMagicWands1, permResources1, smCache1, pmCache1, smDomainNeeded1,
predicateSnapMap1, predicateFormalVarMap1, retryLevel, useHeapTriggers,
Expand All @@ -200,7 +201,7 @@ object State {
triggerExp2,
`partiallyConsumedHeap1`,
`permissionScalingFactor1`, `permissionScalingFactorExp1`, `isEvalInOld`,
`reserveHeaps1`, `reserveCfgs1`, conservedPcs2, `recordPcs1`, `exhaleExt1`,
`reserveHeaps1`, `reserveCfgs1`, conservedPcs2, `recordPcs1`, `exhaleExt1`, `isInPackage1`,
ssCache2, `assertReadAccessOnly1`,
`qpFields1`, `qpPredicates1`, `qpMagicWands1`, `permResources1`, smCache2, pmCache2, `smDomainNeeded1`,
`predicateSnapMap1`, `predicateFormalVarMap1`, `retryLevel`, `useHeapTriggers`,
Expand Down Expand Up @@ -331,7 +332,7 @@ object State {
triggerExp1,
partiallyConsumedHeap1,
permissionScalingFactor1, permissionScalingFactorExp1, isEvalInOld,
reserveHeaps1, reserveCfgs1, conservedPcs1, recordPcs1, exhaleExt1,
reserveHeaps1, reserveCfgs1, conservedPcs1, recordPcs1, exhaleExt1, isInPackage1,
ssCache1, assertReadAccessOnly1,
qpFields1, qpPredicates1, qpMagicWands1, permResources1, smCache1, pmCache1, smDomainNeeded1,
predicateSnapMap1, predicateFormalVarMap1, retryLevel, useHeapTriggers,
Expand All @@ -355,7 +356,7 @@ object State {
triggerExp2,
partiallyConsumedHeap2,
`permissionScalingFactor1`, `permissionScalingFactorExp1`, `isEvalInOld`,
reserveHeaps2, `reserveCfgs1`, conservedPcs2, `recordPcs1`, `exhaleExt1`,
reserveHeaps2, `reserveCfgs1`, conservedPcs2, `recordPcs1`, `exhaleExt1`, `isInPackage1`,
ssCache2, `assertReadAccessOnly1`,
`qpFields1`, `qpPredicates1`, `qpMagicWands1`, `permResources1`, smCache2, pmCache2, smDomainNeeded2,
`predicateSnapMap1`, `predicateFormalVarMap1`, `retryLevel`, `useHeapTriggers`,
Expand Down
16 changes: 15 additions & 1 deletion src/main/scala/supporters/SnapshotSupporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ package viper.silicon.supporters

import viper.silicon.debugger.DebugExp
import viper.silicon.state.terms.{Combine, First, Second, Sort, Term, Unit, sorts}
import viper.silicon.state.{State, SymbolConverter}
import viper.silicon.state.{MagicWandIdentifier, State, SymbolConverter}
import viper.silicon.utils.toSf
import viper.silicon.verifier.Verifier
import viper.silver.ast
import viper.silver.ast.Resource
import viper.silver.ast.utility.QuantifiedPermissions.QuantifiedPermissionAssertion

import scala.annotation.unused

trait SnapshotSupporter {
def optimalSnapshotSort(a: ast.Exp, program: ast.Program): (Sort, Boolean)

def optimalSnapshotSort(r: ast.Resource, s: State, v: Verifier): Sort

def createSnapshotPair(s: State,
sf: (Sort, Verifier) => Term,
a0: ast.Exp,
Expand All @@ -31,6 +34,17 @@ class DefaultSnapshotSupporter(symbolConverter: SymbolConverter) extends Snapsho
def optimalSnapshotSort(a: ast.Exp, program: ast.Program): (Sort, Boolean) =
optimalSnapshotSort(a, program, Nil)

def optimalSnapshotSort(r: Resource, s: State, v: Verifier): Sort = r match {
case f: ast.Field => v.symbolConverter.toSort(f.typ)
case p: ast.Predicate if s.predicateSnapMap.contains(p) => s.predicateSnapMap(p)
case p: ast.Predicate =>
p.body.map(v.snapshotSupporter.optimalSnapshotSort(_, s.program)._1)
.getOrElse(sorts.Snap)
case mw: ast.MagicWand if s.qpMagicWands.contains(MagicWandIdentifier(mw, s.program)) =>
sorts.Snap
case _: ast.MagicWand => sorts.MagicWandSnapFunction
}

private def optimalSnapshotSort(a: ast.Exp, program: ast.Program, visited: Seq[String])
: (Sort, Boolean) =

Expand Down