Skip to content

Commit fe9222f

Browse files
authored
Merge pull request #706 from viperproject/meilers_report_early_on_parrBranch
Report errors early with --parallelizeBranches
2 parents 4f642e7 + 223d848 commit fe9222f

4 files changed

Lines changed: 41 additions & 16 deletions

File tree

src/main/scala/interfaces/Verification.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import viper.silver.ast.Program
2626
sealed abstract class VerificationResult {
2727
var previous: Vector[VerificationResult] = Vector() //Sets had problems with equality
2828
val continueVerification: Boolean = true
29+
var isReported: Boolean = false
2930

3031
def isFatal: Boolean
3132
def &&(other: => VerificationResult): VerificationResult

src/main/scala/rules/Brancher.scala

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import java.util.concurrent._
1010
import viper.silicon.common.concurrency._
1111
import viper.silicon.decider.PathConditionStack
1212
import viper.silicon.interfaces.{Unreachable, VerificationResult}
13+
import viper.silicon.reporting.condenseToViperResult
1314
import viper.silicon.state.State
1415
import viper.silicon.state.terms.{FunctionDecl, MacroDecl, Not, Term}
1516
import viper.silicon.verifier.Verifier
1617
import viper.silver.ast
18+
import viper.silver.reporter.{BranchFailureMessage}
19+
import viper.silver.verifier.Failure
1720

1821
trait BranchingRules extends SymbolicExecutionRules {
1922
def branch(s: State,
@@ -151,17 +154,25 @@ object brancher extends BranchingRules {
151154
CompletableFuture.completedFuture(Seq(Unreachable()))
152155
}
153156

154-
val res = (if (executeThenBranch) {
155-
v.symbExLog.markReachable(uidBranchPoint)
156-
executionFlowController.locally(s, v)((s1, v1) => {
157-
v1.decider.prover.comment(s"[then-branch: $cnt | $condition]")
158-
v1.decider.setCurrentBranchCondition(condition, conditionExp)
157+
val res = {
158+
val thenRes = if (executeThenBranch) {
159+
v.symbExLog.markReachable(uidBranchPoint)
160+
executionFlowController.locally(s, v)((s1, v1) => {
161+
v1.decider.prover.comment(s"[then-branch: $cnt | $condition]")
162+
v1.decider.setCurrentBranchCondition(condition, conditionExp)
159163

160-
fThen(v1.stateConsolidator.consolidateIfRetrying(s1, v1), v1)
161-
})
162-
} else {
163-
Unreachable()
164-
}).combine({
164+
fThen(v1.stateConsolidator.consolidateIfRetrying(s1, v1), v1)
165+
})
166+
} else {
167+
Unreachable()
168+
}
169+
if (thenRes.isFatal && !thenRes.isReported && s.parallelizeBranches && s.isLastRetry) {
170+
thenRes.isReported = true
171+
v.reporter.report(BranchFailureMessage("silicon", s.currentMember.get.asInstanceOf[ast.Member with Serializable],
172+
condenseToViperResult(Seq(thenRes)).asInstanceOf[Failure]))
173+
}
174+
thenRes
175+
}.combine({
165176

166177
/* [BRANCH-PARALLELISATION] */
167178
var rs: Seq[VerificationResult] = null
@@ -189,6 +200,11 @@ object brancher extends BranchingRules {
189200
}
190201

191202
assert(rs.length == 1, s"Expected a single verification result but found ${rs.length}")
203+
if (rs.head.isFatal && !rs.head.isReported && s.parallelizeBranches && s.isLastRetry) {
204+
rs.head.isReported = true
205+
v.reporter.report(BranchFailureMessage("silicon", s.currentMember.get.asInstanceOf[ast.Member with Serializable],
206+
condenseToViperResult(Seq(rs.head)).asInstanceOf[Failure]))
207+
}
192208
rs.head
193209

194210
}, alwaysWaitForOther = parallelizeElseBranch)

src/main/scala/state/State.scala

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import viper.silicon.{Map, Stack}
2020
final case class State(g: Store = Store(),
2121
h: Heap = Heap(),
2222
program: ast.Program,
23+
currentMember: Option[ast.Member],
2324
predicateData: Map[ast.Predicate, PredicateData],
2425
functionData: Map[ast.Function, FunctionData],
2526
oldHeaps: OldHeaps = Map.empty,
@@ -64,13 +65,19 @@ final case class State(g: Store = Store(),
6465
/* TODO: Isn't this data stable, i.e. fully known after a preprocessing step? If so, move it to the appropriate supporter. */
6566
predicateSnapMap: Map[ast.Predicate, terms.Sort] = Map.empty,
6667
predicateFormalVarMap: Map[ast.Predicate, Seq[terms.Var]] = Map.empty,
67-
isMethodVerification: Boolean = false,
6868
retryLevel: Int = 0,
6969
/* ast.Field, ast.Predicate, or MagicWandIdentifier */
7070
heapDependentTriggers: InsertionOrderedSet[Any] = InsertionOrderedSet.empty,
7171
moreCompleteExhale: Boolean = false)
7272
extends Mergeable[State] {
7373

74+
val isMethodVerification: Boolean = {
75+
// currentMember being None means we're verifying a CFG; this should behave like verifying a method.
76+
currentMember.isEmpty || currentMember.get.isInstanceOf[ast.Method]
77+
}
78+
79+
val isLastRetry: Boolean = retryLevel == 0
80+
7481
def incCycleCounter(m: ast.Predicate) =
7582
if (recordVisited) copy(visited = m :: visited)
7683
else this
@@ -128,7 +135,7 @@ object State {
128135
def merge(s1: State, s2: State): State = {
129136
s1 match {
130137
/* Decompose state s1 */
131-
case State(g1, h1, program,
138+
case State(g1, h1, program, member,
132139
predicateData,
133140
functionData,
134141
oldHeaps1,
@@ -148,13 +155,13 @@ object State {
148155
reserveHeaps1, reserveCfgs1, conservedPcs1, recordPcs1, exhaleExt1,
149156
ssCache1, hackIssue387DisablePermissionConsumption1,
150157
qpFields1, qpPredicates1, qpMagicWands1, smCache1, pmCache1, smDomainNeeded1,
151-
predicateSnapMap1, predicateFormalVarMap1, hack, retryLevel, useHeapTriggers,
158+
predicateSnapMap1, predicateFormalVarMap1, retryLevel, useHeapTriggers,
152159
moreCompleteExhale) =>
153160

154161
/* Decompose state s2: most values must match those of s1 */
155162
s2 match {
156163
case State(`g1`, `h1`,
157-
`program`,
164+
`program`, `member`,
158165
`predicateData`, `functionData`,
159166
`oldHeaps1`,
160167
`parallelizeBranches1`,
@@ -173,7 +180,7 @@ object State {
173180
`reserveHeaps1`, `reserveCfgs1`, `conservedPcs1`, `recordPcs1`, `exhaleExt1`,
174181
ssCache2, `hackIssue387DisablePermissionConsumption1`,
175182
`qpFields1`, `qpPredicates1`, `qpMagicWands1`, smCache2, pmCache2, `smDomainNeeded1`,
176-
`predicateSnapMap1`, `predicateFormalVarMap1`, `hack`, `retryLevel`, `useHeapTriggers`,
183+
`predicateSnapMap1`, `predicateFormalVarMap1`, `retryLevel`, `useHeapTriggers`,
177184
moreCompleteExhale2) =>
178185

179186
val functionRecorder3 = functionRecorder1.merge(functionRecorder2)

src/main/scala/verifier/DefaultMainVerifier.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class DefaultMainVerifier(config: Config,
311311
qpMagicWands = quantifiedMagicWands,
312312
predicateSnapMap = predSnapGenerator.snapMap,
313313
predicateFormalVarMap = predSnapGenerator.formalVarMap,
314-
isMethodVerification = member.isInstanceOf[ast.Member],
314+
currentMember = Some(member),
315315
heapDependentTriggers = resourceTriggers,
316316
moreCompleteExhale = Verifier.config.exhaleMode == ExhaleMode.MoreComplete)
317317
}
@@ -326,6 +326,7 @@ class DefaultMainVerifier(config: Config,
326326

327327
State(
328328
program = program,
329+
currentMember = None,
329330
functionData = functionData,
330331
predicateData = predicateData,
331332
qpFields = quantifiedFields,

0 commit comments

Comments
 (0)