From 2d765f263eab6be638a25bd1a8fb8c386b7d9758 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 3 Feb 2025 20:31:27 +0100 Subject: [PATCH 01/22] Fix Macro Hover + Red beams support --- .../scala/viper/silver/parser/MacroExpander.scala | 7 +++++-- .../viper/silver/verifier/VerificationError.scala | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/scala/viper/silver/parser/MacroExpander.scala b/src/main/scala/viper/silver/parser/MacroExpander.scala index 0a5bcfee9..e6a4e9182 100644 --- a/src/main/scala/viper/silver/parser/MacroExpander.scala +++ b/src/main/scala/viper/silver/parser/MacroExpander.scala @@ -338,8 +338,11 @@ object MacroExpander { var bodyWithReplacedParams = replacer.execute[PNode](bodyWithRenamedVars, context) bodyWithReplacedParams = adaptPositions(bodyWithReplacedParams, pos) - // Return expanded macro's body - bodyWithReplacedParams + // Return expanded macro's body wrapped inside annotation + bodyWithReplacedParams match { + case b: PExp => PAnnotatedExp(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) + case b: PStmt => PAnnotatedStmt(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) + } } def ExpandMacroIfValid(macroCall: PNode, ctx: ContextA[PNode]): PNode = { diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index 4ee3f6d45..f807cdb7a 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -429,6 +429,14 @@ object errors { def PostconditionViolated(offendingNode: Exp, member: Contracted): PartialVerificationError = PartialVerificationError((reason: ErrorReason) => PostconditionViolated(offendingNode, member, reason)) + case class PostconditionViolatedBranch(offendingNode: Exp, reason: ErrorReason, leftIsFatal: Boolean, rightIsFatal: Boolean, override val cached: Boolean = false) extends AbstractVerificationError { + val id = "postcondition.violated.branch" + val text = s"Branch fails." + + def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = PostconditionViolatedBranch(offendingNode.asInstanceOf[Exp], this.reason, leftIsFatal, rightIsFatal, this.cached) + def withReason(r: ErrorReason) = PostconditionViolatedBranch(offendingNode, r, leftIsFatal, rightIsFatal, cached) + } + case class FoldFailed(offendingNode: Fold, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { val id = "fold.failed" val text = s"Folding ${offendingNode.acc.loc} might fail." @@ -625,6 +633,13 @@ object reasons { def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalse(offendingNode.asInstanceOf[Exp]) } + case class AssertionFalseAtBranch(offendingNode: Exp, treeString: String) extends AbstractErrorReason { + val id = "assertion.false.branch" + def readableMessage = "\n" + treeString + + def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalseAtBranch(offendingNode.asInstanceOf[Exp], treeString) + } + // Note: this class should be deprecated/removed - we no longer support epsilon permissions in the language case class EpsilonAsParam(offendingNode: Exp) extends AbstractErrorReason { val id = "epsilon.as.param" From 56bdc1375bba546b635972d1a3c3a028975ba8b9 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 3 Feb 2025 20:40:13 +0100 Subject: [PATCH 02/22] Fix Macro Hover --- .../silver/ast/utility/rewriter/Rewritable.scala | 2 +- .../viper/silver/parser/MacroExpander.scala | 4 ++-- .../scala/viper/silver/parser/ParseAst.scala | 16 ++++++++++++++++ .../scala/viper/silver/parser/Resolver.scala | 5 +++++ .../scala/viper/silver/parser/Translator.scala | 2 ++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala b/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala index 434c2ccf4..6217d4b1b 100644 --- a/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala +++ b/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala @@ -69,7 +69,7 @@ trait Rewritable extends Product { // Call constructor val newNode = try {constructorMirror(firstArgList ++ secondArgList: _*)} catch { - case _: Exception if (this.isInstanceOf[PNode]) => + case e: Exception if (this.isInstanceOf[PNode]) => throw ParseTreeDuplicationError(this.asInstanceOf[PNode], children) } diff --git a/src/main/scala/viper/silver/parser/MacroExpander.scala b/src/main/scala/viper/silver/parser/MacroExpander.scala index e6a4e9182..8402f7e9b 100644 --- a/src/main/scala/viper/silver/parser/MacroExpander.scala +++ b/src/main/scala/viper/silver/parser/MacroExpander.scala @@ -340,8 +340,8 @@ object MacroExpander { // Return expanded macro's body wrapped inside annotation bodyWithReplacedParams match { - case b: PExp => PAnnotatedExp(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) - case b: PStmt => PAnnotatedStmt(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) + case b: PExp => PExpandedMacroExp(b)(pos) + case b: PStmt => PExpandedMacroStmt(b)(pos) } } diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 9f2134825..73adc4cca 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -1440,6 +1440,22 @@ case class PSeqn(ss: PDelimited.Block[PStmt])(val pos: (Position, Position)) ext override def pretty = ss.prettyLines } +trait PExpandedMacro +case class PExpandedMacroExp(exp: PExp)(val pos: (Position, Position)) extends PExp with PExpandedMacro { + override def typeSubstitutions: collection.Seq[PTypeSubstitution] = exp.typeSubstitutions + override def forceSubstitution(ts: PTypeSubstitution): Unit = exp.forceSubstitution(ts) +} +case class PExpandedMacroStmt(stmt: PStmt)(val pos: (Position, Position)) extends PStmt with PExpandedMacro + +/////////////////////////////////////////////////////////////////////////// +// Wrapper for expanded macros +trait PExpandedMacro +case class PExpandedMacroExp(exp: PExp)(val pos: (Position, Position)) extends PExp with PExpandedMacro { + override def typeSubstitutions: collection.Seq[PTypeSubstitution] = exp.typeSubstitutions + override def forceSubstitution(ts: PTypeSubstitution): Unit = exp.forceSubstitution(ts) +} +case class PExpandedMacroStmt(stmt: PStmt)(val pos: (Position, Position)) extends PStmt with PExpandedMacro + /** * PSeqn representing the expanded body of a statement macro. * Unlike a normal PSeqn, it does not represent its own scope. diff --git a/src/main/scala/viper/silver/parser/Resolver.scala b/src/main/scala/viper/silver/parser/Resolver.scala index bc8d402f6..94f4e3f9b 100644 --- a/src/main/scala/viper/silver/parser/Resolver.scala +++ b/src/main/scala/viper/silver/parser/Resolver.scala @@ -210,6 +210,8 @@ case class TypeChecker(names: NameAnalyser) { stmt match { case PAnnotatedStmt(_, s) => check(s) + case PExpandedMacroStmt(s) => + check(s) case s@PSeqn(ss) => checkMember(s) { ss.inner.toSeq foreach check @@ -646,6 +648,9 @@ case class TypeChecker(names: NameAnalyser) { case PAnnotatedExp(_, e) => checkInternal(e) setType(e.typ) + case PExpandedMacroExp(e) => + checkInternal(e) + setType(e.typ) case psl: PSimpleLiteral=> psl match { case r@PResultLit(_) => diff --git a/src/main/scala/viper/silver/parser/Translator.scala b/src/main/scala/viper/silver/parser/Translator.scala index c03893c06..7a45693d0 100644 --- a/src/main/scala/viper/silver/parser/Translator.scala +++ b/src/main/scala/viper/silver/parser/Translator.scala @@ -324,6 +324,7 @@ case class Translator(program: PProgram) { ann.values.inner.toSeq.map(_.str) } (resPexp, innerMap.updated(ann.key.str, combinedValue)) + case PExpandedMacroExp(e) => extractAnnotation(e) case _ => (pexp, Map()) } } @@ -338,6 +339,7 @@ case class Translator(program: PProgram) { ann.values.inner.toSeq.map(_.str) } (resPStmt, innerMap.updated(ann.key.str, combinedValue)) + case PExpandedMacroStmt(s) => extractAnnotationFromStmt(s) case _ => (pStmt, Map()) } } From a53b1ba1284f7acb0418fde57a2984ff2192b8d1 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 3 Feb 2025 20:46:51 +0100 Subject: [PATCH 03/22] Revert irrelevant change --- .../scala/viper/silver/ast/utility/rewriter/Rewritable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala b/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala index 6217d4b1b..434c2ccf4 100644 --- a/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala +++ b/src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala @@ -69,7 +69,7 @@ trait Rewritable extends Product { // Call constructor val newNode = try {constructorMirror(firstArgList ++ secondArgList: _*)} catch { - case e: Exception if (this.isInstanceOf[PNode]) => + case _: Exception if (this.isInstanceOf[PNode]) => throw ParseTreeDuplicationError(this.asInstanceOf[PNode], children) } From 3c04dd60f7476b3cdac8e953cd0e7f852d2cbdfe Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Feb 2025 16:01:51 +0100 Subject: [PATCH 04/22] Add missing change --- src/main/scala/viper/silver/parser/ParseAst.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 73adc4cca..1960bf8f7 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -70,6 +70,10 @@ trait PNode extends Where with Product with Rewritable with HasExtraValList { def deepCollect[A](f: PartialFunction[PNode, A]): Seq[A] = Visitor.deepCollect(Seq(this), PNode.callSubnodes)(f) + /** Same as deep collect except that subnodes are visited only if f1 returns true at the current node */ + def deepCollectOpt[A](f1: PNode => Boolean, f2: PartialFunction[PNode, A]): Seq[A] = + Visitor.deepCollect(Seq(this), (n : PNode) => if (f1(n)) PNode.callSubnodes(n) else Seq.empty)(f2) + /** @see [[Visitor.shallowCollect()]] */ def shallowCollect[R](f: PartialFunction[PNode, R]): Seq[R] = Visitor.shallowCollect(Seq(this), PNode.callSubnodes)(f) From 9979b455bd7635920df7bab426521c6f23c5d492 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Feb 2025 18:00:15 +0100 Subject: [PATCH 05/22] Remove duplicated code --- src/main/scala/viper/silver/parser/ParseAst.scala | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 1960bf8f7..e2d01ad2f 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -1444,13 +1444,6 @@ case class PSeqn(ss: PDelimited.Block[PStmt])(val pos: (Position, Position)) ext override def pretty = ss.prettyLines } -trait PExpandedMacro -case class PExpandedMacroExp(exp: PExp)(val pos: (Position, Position)) extends PExp with PExpandedMacro { - override def typeSubstitutions: collection.Seq[PTypeSubstitution] = exp.typeSubstitutions - override def forceSubstitution(ts: PTypeSubstitution): Unit = exp.forceSubstitution(ts) -} -case class PExpandedMacroStmt(stmt: PStmt)(val pos: (Position, Position)) extends PStmt with PExpandedMacro - /////////////////////////////////////////////////////////////////////////// // Wrapper for expanded macros trait PExpandedMacro From d2a243d4ed0718437f6cdaa8926c3b662125315b Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Feb 2025 21:38:30 +0100 Subject: [PATCH 06/22] Revert changes for hover --- .../scala/viper/silver/ast/pretty/PrettyPrinter.scala | 2 +- src/main/scala/viper/silver/parser/MacroExpander.scala | 4 ++-- src/main/scala/viper/silver/parser/ParseAst.scala | 9 --------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala b/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala index 64e1db3f4..063d14c76 100644 --- a/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala +++ b/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala @@ -750,7 +750,7 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter } else { n.info.getUniqueInfo[AnnotationInfo] match { case Some(ai) if ai.values.nonEmpty => - val docs = ai.values.map(v => char('@') <> v._1 <> parens(ssep(v._2.map(v => text(s"\"${v}\"")), text(", ")))).toSeq + val docs = ai.values.filter(v => v._1 != "expandedMacro").map(v => char('@') <> v._1 <> parens(ssep(v._2.map(v => text(s"\"${v}\"")), text(", ")))).toSeq Some(ssep(docs, if (breakLines) line else space)) case _ => None } diff --git a/src/main/scala/viper/silver/parser/MacroExpander.scala b/src/main/scala/viper/silver/parser/MacroExpander.scala index 8402f7e9b..e6a4e9182 100644 --- a/src/main/scala/viper/silver/parser/MacroExpander.scala +++ b/src/main/scala/viper/silver/parser/MacroExpander.scala @@ -340,8 +340,8 @@ object MacroExpander { // Return expanded macro's body wrapped inside annotation bodyWithReplacedParams match { - case b: PExp => PExpandedMacroExp(b)(pos) - case b: PStmt => PExpandedMacroStmt(b)(pos) + case b: PExp => PAnnotatedExp(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) + case b: PStmt => PAnnotatedStmt(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) } } diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index e2d01ad2f..46c38503b 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -1444,15 +1444,6 @@ case class PSeqn(ss: PDelimited.Block[PStmt])(val pos: (Position, Position)) ext override def pretty = ss.prettyLines } -/////////////////////////////////////////////////////////////////////////// -// Wrapper for expanded macros -trait PExpandedMacro -case class PExpandedMacroExp(exp: PExp)(val pos: (Position, Position)) extends PExp with PExpandedMacro { - override def typeSubstitutions: collection.Seq[PTypeSubstitution] = exp.typeSubstitutions - override def forceSubstitution(ts: PTypeSubstitution): Unit = exp.forceSubstitution(ts) -} -case class PExpandedMacroStmt(stmt: PStmt)(val pos: (Position, Position)) extends PStmt with PExpandedMacro - /** * PSeqn representing the expanded body of a statement macro. * Unlike a normal PSeqn, it does not represent its own scope. From 5a3fc736ecec12a31e30bef6745b0ffba2977de2 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Wed, 5 Feb 2025 15:43:21 +0100 Subject: [PATCH 07/22] Run tests --- src/test/scala/AnnotationBasedTestSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/AnnotationBasedTestSuite.scala b/src/test/scala/AnnotationBasedTestSuite.scala index 58532a1ef..2211920b3 100644 --- a/src/test/scala/AnnotationBasedTestSuite.scala +++ b/src/test/scala/AnnotationBasedTestSuite.scala @@ -41,7 +41,7 @@ abstract class AnnotationBasedTestSuite extends ResourceBasedTestSuite { val parserErrors = input.annotations.errors // Match expected outputs with actual outputs - val actualOutputs = system.run(input) + val actualOutputs = system.run(input).filterNot(_.toString.contains("postcondition.violated.branch")).toSeq val expectedOutputs = input.annotations.outputAnnotations val matcher = OutputMatcher(actualOutputs, expectedOutputs) From b64d9f93720189b0d7c3f0e88c68a2bc37a2a38a Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Wed, 5 Feb 2025 16:20:02 +0100 Subject: [PATCH 08/22] Revert revert changes for hover --- .../scala/viper/silver/ast/pretty/PrettyPrinter.scala | 2 +- src/main/scala/viper/silver/parser/MacroExpander.scala | 4 ++-- src/main/scala/viper/silver/parser/ParseAst.scala | 9 +++++++++ src/main/scala/viper/silver/parser/Translator.scala | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala b/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala index 063d14c76..64e1db3f4 100644 --- a/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala +++ b/src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala @@ -750,7 +750,7 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter } else { n.info.getUniqueInfo[AnnotationInfo] match { case Some(ai) if ai.values.nonEmpty => - val docs = ai.values.filter(v => v._1 != "expandedMacro").map(v => char('@') <> v._1 <> parens(ssep(v._2.map(v => text(s"\"${v}\"")), text(", ")))).toSeq + val docs = ai.values.map(v => char('@') <> v._1 <> parens(ssep(v._2.map(v => text(s"\"${v}\"")), text(", ")))).toSeq Some(ssep(docs, if (breakLines) line else space)) case _ => None } diff --git a/src/main/scala/viper/silver/parser/MacroExpander.scala b/src/main/scala/viper/silver/parser/MacroExpander.scala index e6a4e9182..8402f7e9b 100644 --- a/src/main/scala/viper/silver/parser/MacroExpander.scala +++ b/src/main/scala/viper/silver/parser/MacroExpander.scala @@ -340,8 +340,8 @@ object MacroExpander { // Return expanded macro's body wrapped inside annotation bodyWithReplacedParams match { - case b: PExp => PAnnotatedExp(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) - case b: PStmt => PAnnotatedStmt(PAnnotation(new PSym.At(PSym.At)(pos),PRawString("expandedMacro")(pos),PGrouped.impliedParen(PDelimited.empty))(pos),b)(pos) + case b: PExp => PExpandedMacroExp(b)(pos) + case b: PStmt => PExpandedMacroStmt(b)(pos) } } diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 46c38503b..e2d01ad2f 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -1444,6 +1444,15 @@ case class PSeqn(ss: PDelimited.Block[PStmt])(val pos: (Position, Position)) ext override def pretty = ss.prettyLines } +/////////////////////////////////////////////////////////////////////////// +// Wrapper for expanded macros +trait PExpandedMacro +case class PExpandedMacroExp(exp: PExp)(val pos: (Position, Position)) extends PExp with PExpandedMacro { + override def typeSubstitutions: collection.Seq[PTypeSubstitution] = exp.typeSubstitutions + override def forceSubstitution(ts: PTypeSubstitution): Unit = exp.forceSubstitution(ts) +} +case class PExpandedMacroStmt(stmt: PStmt)(val pos: (Position, Position)) extends PStmt with PExpandedMacro + /** * PSeqn representing the expanded body of a statement macro. * Unlike a normal PSeqn, it does not represent its own scope. diff --git a/src/main/scala/viper/silver/parser/Translator.scala b/src/main/scala/viper/silver/parser/Translator.scala index 7a45693d0..a0e779a72 100644 --- a/src/main/scala/viper/silver/parser/Translator.scala +++ b/src/main/scala/viper/silver/parser/Translator.scala @@ -324,7 +324,7 @@ case class Translator(program: PProgram) { ann.values.inner.toSeq.map(_.str) } (resPexp, innerMap.updated(ann.key.str, combinedValue)) - case PExpandedMacroExp(e) => extractAnnotation(e) + case PExpandedMacroExp(s) => extractAnnotation(s) case _ => (pexp, Map()) } } From adf5c0e47fd4de6009ab33b2f5229a6cddca3f6e Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 10 Feb 2025 12:38:43 +0100 Subject: [PATCH 09/22] Support code actions --- src/main/scala/viper/silver/parser/ParseAst.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index e2d01ad2f..c07275471 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -93,6 +93,10 @@ trait PNode extends Where with Product with Rewritable with HasExtraValList { def deepCopyAll[A <: PNode]: PNode = StrategyBuilder.Slim[PNode]({ case n => n }).forceCopy().execute[PNode](this) + /** @see [[Visitor.find()]] */ + def find[A](f: PartialFunction[PNode, A]): Option[A] = + Visitor.find(this, PNode.callSubnodes)(f) + private val _children = scala.collection.mutable.ListBuffer[PNode]() def getParent: Option[PNode] = parent From cb96d07266c10266a4a01c66038aea04d2dc9e5e Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Sun, 16 Feb 2025 20:31:30 +0100 Subject: [PATCH 10/22] Support code actions --- src/main/scala/viper/silver/ast/Ast.scala | 24 +++++++++++++++---- src/main/scala/viper/silver/ast/Program.scala | 4 +++- .../scala/viper/silver/ast/Statement.scala | 4 ++-- .../viper/silver/frontend/SilFrontend.scala | 5 ++-- .../viper/silver/parser/FastMessage.scala | 12 +++++----- .../scala/viper/silver/parser/Resolver.scala | 12 +++++----- .../silver/verifier/VerificationResult.scala | 3 ++- 7 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/scala/viper/silver/ast/Ast.scala b/src/main/scala/viper/silver/ast/Ast.scala index 304de1bcf..76d492ece 100644 --- a/src/main/scala/viper/silver/ast/Ast.scala +++ b/src/main/scala/viper/silver/ast/Ast.scala @@ -180,6 +180,22 @@ trait Node extends Iterable[Node] with Rewritable { } } + // TODO Duplicated from ParseAst + private var parent: Option[Node] = None + def getParent: Option[Node] = parent + def getAncestor[T](implicit ctag: scala.reflect.ClassTag[T]): Option[T] = { + var p = getParent + while (p.isDefined && !ctag.runtimeClass.isInstance(p.get)) + p = p.get.getParent + p.map(_.asInstanceOf[T]) + } + override def initProperties(): Unit = { + for (c <- this.subnodes) { + c.parent = Some(this) + c.initProperties() + } + } + /* To be overridden in subclasses of Node. */ def isValid: Boolean = true @@ -406,9 +422,9 @@ case object Cached extends Info { } /** An `Info` instance for labelling a node as synthesized. A synthesized node is one that - * was not present in the original program that was passed to a Viper backend, such as nodes that - * originate from an AST transformation. - */ + * was not present in the original program that was passed to a Viper backend, such as nodes that + * originate from an AST transformation. + */ case object Synthesized extends Info { override val comment = Nil override val isCached = false @@ -416,7 +432,7 @@ case object Synthesized extends Info { /** An `Info` instance for labelling an AST node which is expected to fail verification. * This is used by Silicon to avoid stopping verification. -*/ + */ abstract class FailureExpectedInfo extends Info { override val comment = Nil override val isCached = false diff --git a/src/main/scala/viper/silver/ast/Program.scala b/src/main/scala/viper/silver/ast/Program.scala index 733fbee1b..130b64ae1 100644 --- a/src/main/scala/viper/silver/ast/Program.scala +++ b/src/main/scala/viper/silver/ast/Program.scala @@ -392,10 +392,12 @@ case class Predicate(name: String, formalArgs: Seq[LocalVarDecl], body: Option[E } } +trait MemberWithSpec + /** A method declaration. */ case class Method(name: String, formalArgs: Seq[LocalVarDecl], formalReturns: Seq[LocalVarDecl], pres: Seq[Exp], posts: Seq[Exp], body: Option[Seqn]) (val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) - extends Member with Callable with Contracted { + extends Member with MemberWithSpec with Callable with Contracted { /* TODO: Should not have to be a lazy val, see also the comment for method * translateMemberSignature in file parser/Translator.scala diff --git a/src/main/scala/viper/silver/ast/Statement.scala b/src/main/scala/viper/silver/ast/Statement.scala index 4ce312014..edec4293d 100644 --- a/src/main/scala/viper/silver/ast/Statement.scala +++ b/src/main/scala/viper/silver/ast/Statement.scala @@ -170,7 +170,7 @@ case class If(cond: Exp, thn: Seqn, els: Seqn)(val pos: Position = NoPosition, v /** A while loop. */ case class While(cond: Exp, invs: Seq[Exp], body: Seqn) (val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) - extends Stmt { + extends Stmt with MemberWithSpec { override lazy val check : Seq[ConsistencyError] = (if(!Consistency.noResult(this)) Seq(ConsistencyError("Result variables are only allowed in postconditions of functions.", pos)) else Seq()) ++ Consistency.checkPure(cond) ++ @@ -182,7 +182,7 @@ case class While(cond: Exp, invs: Seq[Exp], body: Seqn) /** A named label. Labels can be used by gotos as jump targets, and by labelled old-expressions * to refer to the state as it existed at that label. */ -case class Label(name: String, invs: Seq[Exp])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Stmt with Declaration { +case class Label(name: String, invs: Seq[Exp])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Stmt with MemberWithSpec with Declaration { override lazy val check : Seq[ConsistencyError] = (if(!Consistency.noResult(this)) Seq(ConsistencyError("Result variables are only allowed in postconditions of functions.", pos)) else Seq()) ++ invs.flatMap(i=>{ if(!(i isSubtype Bool)) Seq(ConsistencyError(s"Label invariants must be of type Bool, but found ${i.typ}", i.pos)) else Seq()}) diff --git a/src/main/scala/viper/silver/frontend/SilFrontend.scala b/src/main/scala/viper/silver/frontend/SilFrontend.scala index 5de692857..3b97cd651 100644 --- a/src/main/scala/viper/silver/frontend/SilFrontend.scala +++ b/src/main/scala/viper/silver/frontend/SilFrontend.scala @@ -344,7 +344,7 @@ trait SilFrontend extends DefaultFrontend { Succ(modifiedInput) case None => val errors = for (m <- FastMessaging.sortmessages(r.messages) if m.error) yield { - TypecheckerError(m.label, m.pos) + TypecheckerError(m.label, m.pos, m.node) } Fail(errors) } @@ -361,11 +361,12 @@ trait SilFrontend extends DefaultFrontend { FrontendStateCache.translator = translator translator.translate match { case Some(program) => + program.initProperties() Succ(program) case None => // then there are translation messages Fail(FastMessaging.sortmessages(Consistency.messages) map (m => { - TypecheckerError(m.label, m.pos) + TypecheckerError(m.label, m.pos, m.node) })) } diff --git a/src/main/scala/viper/silver/parser/FastMessage.scala b/src/main/scala/viper/silver/parser/FastMessage.scala index 6b3634fc0..b9e12274b 100644 --- a/src/main/scala/viper/silver/parser/FastMessage.scala +++ b/src/main/scala/viper/silver/parser/FastMessage.scala @@ -12,7 +12,7 @@ import viper.silver.parser.PNode import scala.util.parsing.input.Position -case class FastMessage (label : String, pos : SourcePosition, error: Boolean) { +case class FastMessage (label : String, pos : SourcePosition, error: Boolean, node: Option[PNode] = None) { def line : Int = pos.line def column : Int = pos.column } @@ -50,16 +50,16 @@ object FastMessaging { def aMessage (message : FastMessage) = IndexedSeq (message) - /** - * Makes a message list if cond is true. Stored with the position of the value - */ - def message (value : PNode, msg : String, cond : Boolean = true, error : Boolean = true) : Messages = + /** + * Makes a message list if cond is true. Stored with the position of the value + */ + def message (value : PNode, msg : String, cond : Boolean = true, error : Boolean = true, node: Option[PNode]=None) : Messages = if (cond) { val valuePos = value.errorPosition match { case pos: SourcePosition => pos case other => sys.error(s"Unexpected position type: ${other} (${other.getClass()})") } - aMessage (FastMessage (msg, valuePos, error)) + aMessage (FastMessage (msg, valuePos, error, node)) } else { noMessages } diff --git a/src/main/scala/viper/silver/parser/Resolver.scala b/src/main/scala/viper/silver/parser/Resolver.scala index 94f4e3f9b..f7680d793 100644 --- a/src/main/scala/viper/silver/parser/Resolver.scala +++ b/src/main/scala/viper/silver/parser/Resolver.scala @@ -301,7 +301,7 @@ case class TypeChecker(names: NameAnalyser) { else if (field.decls.length > 1) messages ++= FastMessaging.message(field, s"ambiguous field `${field.name}`") else - messages ++= FastMessaging.message(field, s"undeclared field `${field.name}`") + messages ++= FastMessaging.message(field, s"undeclared field `${field.name}`", node=Some(fa) ) case call: PCall => sys.error(s"Unexpected node $call found") } // Check rhs @@ -329,7 +329,7 @@ case class TypeChecker(names: NameAnalyser) { fields.inner match { case Right(fields) => fields.toSeq foreach (f => { if (f.decls.isEmpty) - messages ++= FastMessaging.message(f, s"undeclared field `${f.name}`") + messages ++= FastMessaging.message(f, s"undeclared field `${f.name}`", node=f.getParent) else if (f.decls.length > 1) messages ++= FastMessaging.message(f, s"ambiguous field `${f.name}`") }) @@ -598,8 +598,8 @@ case class TypeChecker(names: NameAnalyser) { * * TODO: Similar to Consistency.recordIfNot. Combine! */ - def issueError(n: PNode, m: String): Unit = { - messages ++= FastMessaging.message(n, m) + def issueError(n: PNode, m: String, node: Option[PNode]=None): Unit = { + messages ++= FastMessaging.message(n, m, node=node) setErrorType() // suppress further warnings } @@ -732,9 +732,9 @@ case class TypeChecker(names: NameAnalyser) { checkMagicWand(wand) // We checked that the `rcv` is valid above with `poa.args.foreach(checkInternal)` - case PFieldAccess(_, _, idnref) => + case fa@PFieldAccess(_, _, idnref) => if (idnref.decls.isEmpty) - issueError(idnref, s"undeclared field `${idnref.name}`") + issueError(idnref, s"undeclared field `${idnref.name}`", node=Some(fa)) else if (idnref.decl.isEmpty) issueError(idnref, s"ambiguous field `${idnref.name}`") diff --git a/src/main/scala/viper/silver/verifier/VerificationResult.scala b/src/main/scala/viper/silver/verifier/VerificationResult.scala index 95980f6c5..115d6536f 100644 --- a/src/main/scala/viper/silver/verifier/VerificationResult.scala +++ b/src/main/scala/viper/silver/verifier/VerificationResult.scala @@ -7,6 +7,7 @@ package viper.silver.verifier import viper.silver.ast._ +import viper.silver.parser.PNode import scala.annotation.unused @@ -112,7 +113,7 @@ case class ConsistencyError(message: String, pos:Position) extends AbstractError } /** A typechecker error. */ -case class TypecheckerError(message: String, pos: Position) extends AbstractError { +case class TypecheckerError(message: String, pos: Position, node: Option[PNode]) extends AbstractError { def fullId = "typechecker.error" def readableMessage = s"$message ($pos)" } From fd4c51fdd480e0938b5ad02c3c13f3bcb60ec468 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Sun, 2 Mar 2025 23:13:36 +0100 Subject: [PATCH 11/22] Renaming --- .../scala/viper/silver/verifier/VerificationError.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index f807cdb7a..c6e523940 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -633,11 +633,11 @@ object reasons { def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalse(offendingNode.asInstanceOf[Exp]) } - case class AssertionFalseAtBranch(offendingNode: Exp, treeString: String) extends AbstractErrorReason { - val id = "assertion.false.branch" + case class BranchFailure(offendingNode: Exp, treeString: String) extends AbstractErrorReason { + val id = "branch.Failure" def readableMessage = "\n" + treeString - def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalseAtBranch(offendingNode.asInstanceOf[Exp], treeString) + def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFailure(offendingNode.asInstanceOf[Exp], treeString) } // Note: this class should be deprecated/removed - we no longer support epsilon permissions in the language From afbb1500143f3d935621da007f2a70e72e63f6a0 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 3 Mar 2025 22:51:07 +0100 Subject: [PATCH 12/22] Clean up --- src/main/scala/viper/silver/ast/Ast.scala | 16 ---------------- src/main/scala/viper/silver/ast/Program.scala | 4 +--- src/main/scala/viper/silver/ast/Statement.scala | 4 ++-- .../viper/silver/frontend/SilFrontend.scala | 4 +--- .../scala/viper/silver/parser/ParseAst.scala | 6 ++++-- .../scala/viper/silver/reporter/Message.scala | 12 +++++++++++- .../scala/viper/silver/reporter/Reporter.scala | 3 +++ 7 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/main/scala/viper/silver/ast/Ast.scala b/src/main/scala/viper/silver/ast/Ast.scala index 76d492ece..94b15db65 100644 --- a/src/main/scala/viper/silver/ast/Ast.scala +++ b/src/main/scala/viper/silver/ast/Ast.scala @@ -180,22 +180,6 @@ trait Node extends Iterable[Node] with Rewritable { } } - // TODO Duplicated from ParseAst - private var parent: Option[Node] = None - def getParent: Option[Node] = parent - def getAncestor[T](implicit ctag: scala.reflect.ClassTag[T]): Option[T] = { - var p = getParent - while (p.isDefined && !ctag.runtimeClass.isInstance(p.get)) - p = p.get.getParent - p.map(_.asInstanceOf[T]) - } - override def initProperties(): Unit = { - for (c <- this.subnodes) { - c.parent = Some(this) - c.initProperties() - } - } - /* To be overridden in subclasses of Node. */ def isValid: Boolean = true diff --git a/src/main/scala/viper/silver/ast/Program.scala b/src/main/scala/viper/silver/ast/Program.scala index 130b64ae1..733fbee1b 100644 --- a/src/main/scala/viper/silver/ast/Program.scala +++ b/src/main/scala/viper/silver/ast/Program.scala @@ -392,12 +392,10 @@ case class Predicate(name: String, formalArgs: Seq[LocalVarDecl], body: Option[E } } -trait MemberWithSpec - /** A method declaration. */ case class Method(name: String, formalArgs: Seq[LocalVarDecl], formalReturns: Seq[LocalVarDecl], pres: Seq[Exp], posts: Seq[Exp], body: Option[Seqn]) (val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) - extends Member with MemberWithSpec with Callable with Contracted { + extends Member with Callable with Contracted { /* TODO: Should not have to be a lazy val, see also the comment for method * translateMemberSignature in file parser/Translator.scala diff --git a/src/main/scala/viper/silver/ast/Statement.scala b/src/main/scala/viper/silver/ast/Statement.scala index edec4293d..4ce312014 100644 --- a/src/main/scala/viper/silver/ast/Statement.scala +++ b/src/main/scala/viper/silver/ast/Statement.scala @@ -170,7 +170,7 @@ case class If(cond: Exp, thn: Seqn, els: Seqn)(val pos: Position = NoPosition, v /** A while loop. */ case class While(cond: Exp, invs: Seq[Exp], body: Seqn) (val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) - extends Stmt with MemberWithSpec { + extends Stmt { override lazy val check : Seq[ConsistencyError] = (if(!Consistency.noResult(this)) Seq(ConsistencyError("Result variables are only allowed in postconditions of functions.", pos)) else Seq()) ++ Consistency.checkPure(cond) ++ @@ -182,7 +182,7 @@ case class While(cond: Exp, invs: Seq[Exp], body: Seqn) /** A named label. Labels can be used by gotos as jump targets, and by labelled old-expressions * to refer to the state as it existed at that label. */ -case class Label(name: String, invs: Seq[Exp])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Stmt with MemberWithSpec with Declaration { +case class Label(name: String, invs: Seq[Exp])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Stmt with Declaration { override lazy val check : Seq[ConsistencyError] = (if(!Consistency.noResult(this)) Seq(ConsistencyError("Result variables are only allowed in postconditions of functions.", pos)) else Seq()) ++ invs.flatMap(i=>{ if(!(i isSubtype Bool)) Seq(ConsistencyError(s"Label invariants must be of type Bool, but found ${i.typ}", i.pos)) else Seq()}) diff --git a/src/main/scala/viper/silver/frontend/SilFrontend.scala b/src/main/scala/viper/silver/frontend/SilFrontend.scala index 3b97cd651..12711acf6 100644 --- a/src/main/scala/viper/silver/frontend/SilFrontend.scala +++ b/src/main/scala/viper/silver/frontend/SilFrontend.scala @@ -360,9 +360,7 @@ trait SilFrontend extends DefaultFrontend { val translator = Translator(modifiedInputPlugin) FrontendStateCache.translator = translator translator.translate match { - case Some(program) => - program.initProperties() - Succ(program) + case Some(program) => Succ(program) case None => // then there are translation messages Fail(FastMessaging.sortmessages(Consistency.messages) map (m => { diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index c07275471..77b71e465 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -1488,7 +1488,9 @@ sealed trait PIfContinuation extends PStmt case class PIf(keyword: PReserved[PKeywordIf], cond: PGrouped.Paren[PExp], thn: PSeqn, els: Option[PIfContinuation])(val pos: (Position, Position)) extends PStmt with PIfContinuation case class PElse(k: PKw.Else, els: PSeqn)(val pos: (Position, Position)) extends PStmt with PIfContinuation -case class PWhile(keyword: PKw.While, cond: PGrouped.Paren[PExp], invs: PDelimited[PSpecification[PKw.InvSpec], Option[PSym.Semi]], body: PSeqn)(val pos: (Position, Position)) extends PStmt +trait PMemberWithSpec + +case class PWhile(keyword: PKw.While, cond: PGrouped.Paren[PExp], invs: PDelimited[PSpecification[PKw.InvSpec], Option[PSym.Semi]], body: PSeqn)(val pos: (Position, Position)) extends PStmt with PMemberWithSpec case class PVars(keyword: PKw.Var, vars: PDelimited[PLocalVarDecl, PSym.Comma], init: Option[(PSymOp.Assign, PExp)])(val pos: (Position, Position)) extends PStmt { def assign: Option[PAssign] = init map (i => PAssign(vars.update(vars.toSeq.map(_.toIdnUse)), Some(i._1), i._2)(pos)) @@ -1730,7 +1732,7 @@ case class PPredicate(annotations: Seq[PAnnotation], keyword: PKw.Predicate, idn } case class PMethod(annotations: Seq[PAnnotation], keyword: PKw.Method, idndef: PIdnDef, args: PDelimited.Comma[PSym.Paren, PFormalArgDecl], returns: Option[PMethodReturns], pres: PDelimited[PSpecification[PKw.PreSpec], Option[PSym.Semi]], posts: PDelimited[PSpecification[PKw.PostSpec], Option[PSym.Semi]], body: Option[PSeqn]) - (val pos: (Position, Position)) extends PSingleMember with PGlobalCallableNamedArgs with PPrettySubnodes { + (val pos: (Position, Position)) extends PSingleMember with PMemberWithSpec with PGlobalCallableNamedArgs with PPrettySubnodes { def formalReturns: Seq[PFormalReturnDecl] = returns.map(_.formalReturns.inner.toSeq).getOrElse(Nil) override def returnNodes = returns.toSeq } diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 441810eee..5973ab2b9 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -8,7 +8,7 @@ package viper.silver.reporter import viper.silver.reporter.BackendSubProcessStages.BackendSubProcessStage import viper.silver.verifier._ -import viper.silver.ast.{QuantifiedExp, Trigger} +import viper.silver.ast.{Exp, Method, QuantifiedExp, Trigger} import viper.silver.parser.PProgram /** @@ -169,6 +169,16 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } +case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) +case class BranchTreeReport(method: Method, tree : String, beams : Seq[BeamInfo]) + extends Message { + + override lazy val toString: String = s"branch_tree_report(" + + s"method=${method.name}, tree=$tree, beams=$beams" + + override val name = "branch_tree" +} + case class StatisticsReport(nOfMethods: Int, nOfFunctions: Int, nOfPredicates: Int, nOfDomains: Int, nOfFields: Int) extends Message { diff --git a/src/main/scala/viper/silver/reporter/Reporter.scala b/src/main/scala/viper/silver/reporter/Reporter.scala index 0c51bd50d..bd4a8f5b9 100644 --- a/src/main/scala/viper/silver/reporter/Reporter.scala +++ b/src/main/scala/viper/silver/reporter/Reporter.scala @@ -68,6 +68,8 @@ case class CSVReporter(name: String = "csv_reporter", path: String = "report.csv case BranchFailureMessage(_, concerning, _, cached) => csv_file.write(s"BranchFailureMessage,${concerning.name},${cached}\n") + case BranchTreeReport(method, tree, _) => + csv_file.write(s"BranchTreeReport,${method.name},$tree\n") case _: SimpleMessage | _: CopyrightReport | _: MissingDependencyReport | _: BackendSubProcessReport | _: InternalWarningMessage | _: ConfigurationConfirmation=> // Irrelevant for reporting @@ -179,6 +181,7 @@ case class StdIOReporter(name: String = "stdout_reporter", timeInfo: Boolean = t case EntitySuccessMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case EntityFailureMessage(_, _, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case BranchFailureMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. + case BranchTreeReport(_, _, _) => case ConfigurationConfirmation(_) => // TODO use for progress reporting //println( s"Configuration confirmation: $text" ) case InternalWarningMessage(_) => // TODO use for progress reporting From a842d259e8576d0535f958bf746198096b47bc2d Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Mar 2025 13:09:03 +0100 Subject: [PATCH 13/22] Dot representation + report whole tree --- src/main/scala/viper/silver/reporter/Message.scala | 8 ++++++-- src/main/scala/viper/silver/reporter/Reporter.scala | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 5973ab2b9..8ac149492 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -169,12 +169,16 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } +trait BranchTree { + def prettyPrint() : String + def toDotFile() : Unit +} case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) -case class BranchTreeReport(method: Method, tree : String, beams : Seq[BeamInfo]) +case class BranchTreeReport(method: Method, tree : BranchTree, beams : Seq[BeamInfo]) extends Message { override lazy val toString: String = s"branch_tree_report(" + - s"method=${method.name}, tree=$tree, beams=$beams" + s"method=${method.name}, tree=${tree.prettyPrint()}, beams=$beams" override val name = "branch_tree" } diff --git a/src/main/scala/viper/silver/reporter/Reporter.scala b/src/main/scala/viper/silver/reporter/Reporter.scala index bd4a8f5b9..7265c9a06 100644 --- a/src/main/scala/viper/silver/reporter/Reporter.scala +++ b/src/main/scala/viper/silver/reporter/Reporter.scala @@ -69,7 +69,7 @@ case class CSVReporter(name: String = "csv_reporter", path: String = "report.csv case BranchFailureMessage(_, concerning, _, cached) => csv_file.write(s"BranchFailureMessage,${concerning.name},${cached}\n") case BranchTreeReport(method, tree, _) => - csv_file.write(s"BranchTreeReport,${method.name},$tree\n") + csv_file.write(s"BranchTreeReport,${method.name},${tree.prettyPrint()}\n") case _: SimpleMessage | _: CopyrightReport | _: MissingDependencyReport | _: BackendSubProcessReport | _: InternalWarningMessage | _: ConfigurationConfirmation=> // Irrelevant for reporting From 39ea5d01e7837518f4b70e3dd4ef80215a3f933d Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Mar 2025 21:01:14 +0100 Subject: [PATCH 14/22] Clean up --- src/main/scala/viper/silver/ast/Ast.scala | 8 ++++---- .../scala/viper/silver/frontend/SilFrontend.scala | 7 ++++--- src/main/scala/viper/silver/parser/FastMessage.scala | 6 +++--- src/main/scala/viper/silver/parser/ParseAst.scala | 4 ---- src/main/scala/viper/silver/parser/Resolver.scala | 12 ++++++------ .../viper/silver/verifier/VerificationError.scala | 8 -------- .../viper/silver/verifier/VerificationResult.scala | 3 +-- 7 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/main/scala/viper/silver/ast/Ast.scala b/src/main/scala/viper/silver/ast/Ast.scala index 94b15db65..304de1bcf 100644 --- a/src/main/scala/viper/silver/ast/Ast.scala +++ b/src/main/scala/viper/silver/ast/Ast.scala @@ -406,9 +406,9 @@ case object Cached extends Info { } /** An `Info` instance for labelling a node as synthesized. A synthesized node is one that - * was not present in the original program that was passed to a Viper backend, such as nodes that - * originate from an AST transformation. - */ + * was not present in the original program that was passed to a Viper backend, such as nodes that + * originate from an AST transformation. + */ case object Synthesized extends Info { override val comment = Nil override val isCached = false @@ -416,7 +416,7 @@ case object Synthesized extends Info { /** An `Info` instance for labelling an AST node which is expected to fail verification. * This is used by Silicon to avoid stopping verification. - */ +*/ abstract class FailureExpectedInfo extends Info { override val comment = Nil override val isCached = false diff --git a/src/main/scala/viper/silver/frontend/SilFrontend.scala b/src/main/scala/viper/silver/frontend/SilFrontend.scala index 12711acf6..5de692857 100644 --- a/src/main/scala/viper/silver/frontend/SilFrontend.scala +++ b/src/main/scala/viper/silver/frontend/SilFrontend.scala @@ -344,7 +344,7 @@ trait SilFrontend extends DefaultFrontend { Succ(modifiedInput) case None => val errors = for (m <- FastMessaging.sortmessages(r.messages) if m.error) yield { - TypecheckerError(m.label, m.pos, m.node) + TypecheckerError(m.label, m.pos) } Fail(errors) } @@ -360,11 +360,12 @@ trait SilFrontend extends DefaultFrontend { val translator = Translator(modifiedInputPlugin) FrontendStateCache.translator = translator translator.translate match { - case Some(program) => Succ(program) + case Some(program) => + Succ(program) case None => // then there are translation messages Fail(FastMessaging.sortmessages(Consistency.messages) map (m => { - TypecheckerError(m.label, m.pos, m.node) + TypecheckerError(m.label, m.pos) })) } diff --git a/src/main/scala/viper/silver/parser/FastMessage.scala b/src/main/scala/viper/silver/parser/FastMessage.scala index b9e12274b..5d6323001 100644 --- a/src/main/scala/viper/silver/parser/FastMessage.scala +++ b/src/main/scala/viper/silver/parser/FastMessage.scala @@ -12,7 +12,7 @@ import viper.silver.parser.PNode import scala.util.parsing.input.Position -case class FastMessage (label : String, pos : SourcePosition, error: Boolean, node: Option[PNode] = None) { +case class FastMessage (label : String, pos : SourcePosition, error: Boolean) { def line : Int = pos.line def column : Int = pos.column } @@ -53,13 +53,13 @@ object FastMessaging { /** * Makes a message list if cond is true. Stored with the position of the value */ - def message (value : PNode, msg : String, cond : Boolean = true, error : Boolean = true, node: Option[PNode]=None) : Messages = + def message (value : PNode, msg : String, cond : Boolean = true, error : Boolean = true) : Messages = if (cond) { val valuePos = value.errorPosition match { case pos: SourcePosition => pos case other => sys.error(s"Unexpected position type: ${other} (${other.getClass()})") } - aMessage (FastMessage (msg, valuePos, error, node)) + aMessage (FastMessage (msg, valuePos, error)) } else { noMessages } diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 77b71e465..8a4e59594 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -93,10 +93,6 @@ trait PNode extends Where with Product with Rewritable with HasExtraValList { def deepCopyAll[A <: PNode]: PNode = StrategyBuilder.Slim[PNode]({ case n => n }).forceCopy().execute[PNode](this) - /** @see [[Visitor.find()]] */ - def find[A](f: PartialFunction[PNode, A]): Option[A] = - Visitor.find(this, PNode.callSubnodes)(f) - private val _children = scala.collection.mutable.ListBuffer[PNode]() def getParent: Option[PNode] = parent diff --git a/src/main/scala/viper/silver/parser/Resolver.scala b/src/main/scala/viper/silver/parser/Resolver.scala index f7680d793..94f4e3f9b 100644 --- a/src/main/scala/viper/silver/parser/Resolver.scala +++ b/src/main/scala/viper/silver/parser/Resolver.scala @@ -301,7 +301,7 @@ case class TypeChecker(names: NameAnalyser) { else if (field.decls.length > 1) messages ++= FastMessaging.message(field, s"ambiguous field `${field.name}`") else - messages ++= FastMessaging.message(field, s"undeclared field `${field.name}`", node=Some(fa) ) + messages ++= FastMessaging.message(field, s"undeclared field `${field.name}`") case call: PCall => sys.error(s"Unexpected node $call found") } // Check rhs @@ -329,7 +329,7 @@ case class TypeChecker(names: NameAnalyser) { fields.inner match { case Right(fields) => fields.toSeq foreach (f => { if (f.decls.isEmpty) - messages ++= FastMessaging.message(f, s"undeclared field `${f.name}`", node=f.getParent) + messages ++= FastMessaging.message(f, s"undeclared field `${f.name}`") else if (f.decls.length > 1) messages ++= FastMessaging.message(f, s"ambiguous field `${f.name}`") }) @@ -598,8 +598,8 @@ case class TypeChecker(names: NameAnalyser) { * * TODO: Similar to Consistency.recordIfNot. Combine! */ - def issueError(n: PNode, m: String, node: Option[PNode]=None): Unit = { - messages ++= FastMessaging.message(n, m, node=node) + def issueError(n: PNode, m: String): Unit = { + messages ++= FastMessaging.message(n, m) setErrorType() // suppress further warnings } @@ -732,9 +732,9 @@ case class TypeChecker(names: NameAnalyser) { checkMagicWand(wand) // We checked that the `rcv` is valid above with `poa.args.foreach(checkInternal)` - case fa@PFieldAccess(_, _, idnref) => + case PFieldAccess(_, _, idnref) => if (idnref.decls.isEmpty) - issueError(idnref, s"undeclared field `${idnref.name}`", node=Some(fa)) + issueError(idnref, s"undeclared field `${idnref.name}`") else if (idnref.decl.isEmpty) issueError(idnref, s"ambiguous field `${idnref.name}`") diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index c6e523940..11c062c0c 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -429,14 +429,6 @@ object errors { def PostconditionViolated(offendingNode: Exp, member: Contracted): PartialVerificationError = PartialVerificationError((reason: ErrorReason) => PostconditionViolated(offendingNode, member, reason)) - case class PostconditionViolatedBranch(offendingNode: Exp, reason: ErrorReason, leftIsFatal: Boolean, rightIsFatal: Boolean, override val cached: Boolean = false) extends AbstractVerificationError { - val id = "postcondition.violated.branch" - val text = s"Branch fails." - - def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = PostconditionViolatedBranch(offendingNode.asInstanceOf[Exp], this.reason, leftIsFatal, rightIsFatal, this.cached) - def withReason(r: ErrorReason) = PostconditionViolatedBranch(offendingNode, r, leftIsFatal, rightIsFatal, cached) - } - case class FoldFailed(offendingNode: Fold, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { val id = "fold.failed" val text = s"Folding ${offendingNode.acc.loc} might fail." diff --git a/src/main/scala/viper/silver/verifier/VerificationResult.scala b/src/main/scala/viper/silver/verifier/VerificationResult.scala index 115d6536f..95980f6c5 100644 --- a/src/main/scala/viper/silver/verifier/VerificationResult.scala +++ b/src/main/scala/viper/silver/verifier/VerificationResult.scala @@ -7,7 +7,6 @@ package viper.silver.verifier import viper.silver.ast._ -import viper.silver.parser.PNode import scala.annotation.unused @@ -113,7 +112,7 @@ case class ConsistencyError(message: String, pos:Position) extends AbstractError } /** A typechecker error. */ -case class TypecheckerError(message: String, pos: Position, node: Option[PNode]) extends AbstractError { +case class TypecheckerError(message: String, pos: Position) extends AbstractError { def fullId = "typechecker.error" def readableMessage = s"$message ($pos)" } From f8d4551293bb616e090cba51b8c81617a2be24e6 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Mar 2025 21:04:55 +0100 Subject: [PATCH 15/22] Clean up --- src/main/scala/viper/silver/parser/FastMessage.scala | 6 +++--- .../scala/viper/silver/verifier/VerificationError.scala | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/scala/viper/silver/parser/FastMessage.scala b/src/main/scala/viper/silver/parser/FastMessage.scala index 5d6323001..6b3634fc0 100644 --- a/src/main/scala/viper/silver/parser/FastMessage.scala +++ b/src/main/scala/viper/silver/parser/FastMessage.scala @@ -50,9 +50,9 @@ object FastMessaging { def aMessage (message : FastMessage) = IndexedSeq (message) - /** - * Makes a message list if cond is true. Stored with the position of the value - */ + /** + * Makes a message list if cond is true. Stored with the position of the value + */ def message (value : PNode, msg : String, cond : Boolean = true, error : Boolean = true) : Messages = if (cond) { val valuePos = value.errorPosition match { diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index 11c062c0c..4ee3f6d45 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -625,13 +625,6 @@ object reasons { def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalse(offendingNode.asInstanceOf[Exp]) } - case class BranchFailure(offendingNode: Exp, treeString: String) extends AbstractErrorReason { - val id = "branch.Failure" - def readableMessage = "\n" + treeString - - def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFailure(offendingNode.asInstanceOf[Exp], treeString) - } - // Note: this class should be deprecated/removed - we no longer support epsilon permissions in the language case class EpsilonAsParam(offendingNode: Exp) extends AbstractErrorReason { val id = "epsilon.as.param" From a6ed486ec7ce7b10e07c02a99cc95f28c8e63d2a Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 4 Mar 2025 21:32:25 +0100 Subject: [PATCH 16/22] Readd lost function --- src/main/scala/viper/silver/parser/ParseAst.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/viper/silver/parser/ParseAst.scala b/src/main/scala/viper/silver/parser/ParseAst.scala index 8a4e59594..77b71e465 100644 --- a/src/main/scala/viper/silver/parser/ParseAst.scala +++ b/src/main/scala/viper/silver/parser/ParseAst.scala @@ -93,6 +93,10 @@ trait PNode extends Where with Product with Rewritable with HasExtraValList { def deepCopyAll[A <: PNode]: PNode = StrategyBuilder.Slim[PNode]({ case n => n }).forceCopy().execute[PNode](this) + /** @see [[Visitor.find()]] */ + def find[A](f: PartialFunction[PNode, A]): Option[A] = + Visitor.find(this, PNode.callSubnodes)(f) + private val _children = scala.collection.mutable.ListBuffer[PNode]() def getParent: Option[PNode] = parent From bb940282c9981d097e352dbdb0ad41063100f6da Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Fri, 7 Mar 2025 22:53:20 +0100 Subject: [PATCH 17/22] Change back from reporting to errors --- .../scala/viper/silver/reporter/Message.scala | 16 +------------- .../viper/silver/reporter/Reporter.scala | 3 --- .../silver/verifier/VerificationError.scala | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 8ac149492..441810eee 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -8,7 +8,7 @@ package viper.silver.reporter import viper.silver.reporter.BackendSubProcessStages.BackendSubProcessStage import viper.silver.verifier._ -import viper.silver.ast.{Exp, Method, QuantifiedExp, Trigger} +import viper.silver.ast.{QuantifiedExp, Trigger} import viper.silver.parser.PProgram /** @@ -169,20 +169,6 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } -trait BranchTree { - def prettyPrint() : String - def toDotFile() : Unit -} -case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) -case class BranchTreeReport(method: Method, tree : BranchTree, beams : Seq[BeamInfo]) - extends Message { - - override lazy val toString: String = s"branch_tree_report(" + - s"method=${method.name}, tree=${tree.prettyPrint()}, beams=$beams" - - override val name = "branch_tree" -} - case class StatisticsReport(nOfMethods: Int, nOfFunctions: Int, nOfPredicates: Int, nOfDomains: Int, nOfFields: Int) extends Message { diff --git a/src/main/scala/viper/silver/reporter/Reporter.scala b/src/main/scala/viper/silver/reporter/Reporter.scala index 7265c9a06..0c51bd50d 100644 --- a/src/main/scala/viper/silver/reporter/Reporter.scala +++ b/src/main/scala/viper/silver/reporter/Reporter.scala @@ -68,8 +68,6 @@ case class CSVReporter(name: String = "csv_reporter", path: String = "report.csv case BranchFailureMessage(_, concerning, _, cached) => csv_file.write(s"BranchFailureMessage,${concerning.name},${cached}\n") - case BranchTreeReport(method, tree, _) => - csv_file.write(s"BranchTreeReport,${method.name},${tree.prettyPrint()}\n") case _: SimpleMessage | _: CopyrightReport | _: MissingDependencyReport | _: BackendSubProcessReport | _: InternalWarningMessage | _: ConfigurationConfirmation=> // Irrelevant for reporting @@ -181,7 +179,6 @@ case class StdIOReporter(name: String = "stdout_reporter", timeInfo: Boolean = t case EntitySuccessMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case EntityFailureMessage(_, _, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case BranchFailureMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. - case BranchTreeReport(_, _, _) => case ConfigurationConfirmation(_) => // TODO use for progress reporting //println( s"Configuration confirmation: $text" ) case InternalWarningMessage(_) => // TODO use for progress reporting diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index 4ee3f6d45..f08df3779 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -9,6 +9,7 @@ package viper.silver.verifier import fastparse.Parsed import viper.silver.ast._ import viper.silver.ast.utility.rewriter.Rewritable +import viper.silver.verifier.errors.{BeamInfo, BranchTree} /********************************************************************************** @@ -429,6 +430,19 @@ object errors { def PostconditionViolated(offendingNode: Exp, member: Contracted): PartialVerificationError = PartialVerificationError((reason: ErrorReason) => PostconditionViolated(offendingNode, member, reason)) + trait BranchTree { + def prettyPrint() : String + def toDotFile() : Unit + } + case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) + case class BranchFailed(offendingNode: Method, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { + val id = "branch.failed" + val text = s"Branch fails." + + def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFailed(offendingNode.asInstanceOf[Method], this.reason, this.cached) + def withReason(r: ErrorReason) = BranchFailed(offendingNode, r, cached) + } + case class FoldFailed(offendingNode: Fold, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { val id = "fold.failed" val text = s"Folding ${offendingNode.acc.loc} might fail." @@ -625,6 +639,13 @@ object reasons { def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalse(offendingNode.asInstanceOf[Exp]) } + case class BranchFails(offendingNode: Method, tree: BranchTree, beamInfos: Seq[BeamInfo]) extends AbstractErrorReason { + val id = "branch.fails" + def readableMessage = s"\n${tree.prettyPrint()}" + + def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFails(offendingNode.asInstanceOf[Method],tree,beamInfos) + } + // Note: this class should be deprecated/removed - we no longer support epsilon permissions in the language case class EpsilonAsParam(offendingNode: Exp) extends AbstractErrorReason { val id = "epsilon.as.param" From 311593a4561ba81e422570ad45c65ded1e7fd5ea Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Mon, 10 Mar 2025 10:46:51 +0100 Subject: [PATCH 18/22] Change back to reporting --- .../viper/silver/frontend/SilFrontend.scala | 6 ++--- .../PredicateInstancePlugin.scala | 4 ++-- .../plugin/standard/refute/RefutePlugin.scala | 10 +++++---- .../termination/TerminationPlugin.scala | 4 ++-- .../scala/viper/silver/reporter/Message.scala | 22 +++++++++++++++++-- .../viper/silver/reporter/Reporter.scala | 15 ++++++++----- .../silver/testing/BackendTypeTest.scala | 12 +++++----- .../silver/verifier/VerificationError.scala | 21 ------------------ .../silver/verifier/VerificationResult.scala | 11 +++++----- src/test/scala/PluginTests.scala | 8 +++---- src/test/scala/SilSuite.scala | 2 +- src/test/scala/StatisticalTestSuite.scala | 2 +- 12 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/main/scala/viper/silver/frontend/SilFrontend.scala b/src/main/scala/viper/silver/frontend/SilFrontend.scala index 5de692857..417e946ac 100644 --- a/src/main/scala/viper/silver/frontend/SilFrontend.scala +++ b/src/main/scala/viper/silver/frontend/SilFrontend.scala @@ -54,7 +54,7 @@ trait SilFrontend extends DefaultFrontend { if (_state >= DefaultStates.Verification) { _appExitReason = result match { case Success => ApplicationExitReason.VERIFICATION_SUCCEEDED - case Failure(_) => ApplicationExitReason.VERIFICATION_FAILED + case Failure(_,_) => ApplicationExitReason.VERIFICATION_FAILED } } } @@ -283,9 +283,9 @@ trait SilFrontend extends DefaultFrontend { val res = plugins.beforeFinish(tRes) val filteredRes = res match { case Success => res - case Failure(errors) => + case Failure(errors,branchTree) => // Remove duplicate errors - Failure(errors.distinctBy(failureFilterAndGroupingCriterion)) + Failure(errors.distinctBy(failureFilterAndGroupingCriterion),branchTree) } _verificationResult = Some(filteredRes) filteredRes match { diff --git a/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala b/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala index 450f72ff5..871c52584 100644 --- a/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala @@ -103,11 +103,11 @@ class PredicateInstancePlugin(@unused reporter: viper.silver.reporter.Reporter, private def translateVerificationResult(input: VerificationResult): VerificationResult = { input match { case Success => input - case Failure(errors) => + case Failure(errors,branchTree) => Failure(errors.map { case e@PreconditionInAppFalse(_, _, _) => e.transformedError() case e => e - }) + },branchTree) } } diff --git a/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala b/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala index 63f4c3070..f952f97c9 100644 --- a/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala @@ -74,12 +74,14 @@ class RefutePlugin(@unused reporter: viper.silver.reporter.Reporter, mapVerificationResultsForNode(program, input) private def mapVerificationResultsForNode(n: Node, input: VerificationResult): VerificationResult = { - val (refutesForWhichErrorOccurred, otherErrors) = input match { - case Success => (Seq.empty, Seq.empty) - case Failure(errors) => errors.partitionMap { + val (refutesForWhichErrorOccurred, otherErrors, branchTree_) = input match { + case Success => (Seq.empty, Seq.empty,None) + case Failure(errors,branchTree) => + val partErrs = errors.partitionMap { case AssertFailed(NodeWithRefuteInfo(RefuteInfo(r)), _, _) => Left((r, r.pos)) case err => Right(err) } + (partErrs._1, partErrs._2, branchTree) } val refutesContainedInNode = n.collect { case NodeWithRefuteInfo(RefuteInfo(r)) => (r, r.pos) @@ -93,7 +95,7 @@ class RefutePlugin(@unused reporter: viper.silver.reporter.Reporter, val errors = otherErrors ++ missingErrorsInNode if (errors.isEmpty) Success - else Failure(errors) + else Failure(errors, branchTree_) } } diff --git a/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala b/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala index a77b9ff91..149d44bc5 100644 --- a/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala @@ -297,10 +297,10 @@ class TerminationPlugin(@unused reporter: viper.silver.reporter.Reporter, input match { case Success => input - case Failure(errors) => Failure(errors.map({ + case Failure(errors,branchTree) => Failure(errors.map({ case a@AssertFailed(Assert(_), _, _) => a.transformedError() case e => e - })) + }),branchTree) } } diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 441810eee..0a52946d4 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -8,7 +8,7 @@ package viper.silver.reporter import viper.silver.reporter.BackendSubProcessStages.BackendSubProcessStage import viper.silver.verifier._ -import viper.silver.ast.{QuantifiedExp, Trigger} +import viper.silver.ast.{Exp, Method, QuantifiedExp, Trigger} import viper.silver.parser.PProgram /** @@ -169,7 +169,25 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } -case class StatisticsReport(nOfMethods: Int, nOfFunctions: Int, nOfPredicates: Int, +trait BranchTree { + val DotFilePath : String + var cached: Boolean = false + def getMethod() : Method + def getBeams() : Seq[BeamInfo] + def prettyPrint() : String + def toDotFile() : Unit +} +case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) +case class BranchTreeReport(tree : BranchTree) + extends Message { + + override lazy val toString: String = s"branch_tree_report(" + + s"method=${tree.getMethod().name}, tree=${tree.prettyPrint()}, beams=${tree.getBeams()}" + + override val name = "branch_tree" +} + +case class StatisticsReport(nOfMethods: Int, nOfFunctions: Int, nOfPredicates: Int, nOfDomains: Int, nOfFields: Int) extends Message { diff --git a/src/main/scala/viper/silver/reporter/Reporter.scala b/src/main/scala/viper/silver/reporter/Reporter.scala index 0c51bd50d..ac1f484a6 100644 --- a/src/main/scala/viper/silver/reporter/Reporter.scala +++ b/src/main/scala/viper/silver/reporter/Reporter.scala @@ -68,6 +68,8 @@ case class CSVReporter(name: String = "csv_reporter", path: String = "report.csv case BranchFailureMessage(_, concerning, _, cached) => csv_file.write(s"BranchFailureMessage,${concerning.name},${cached}\n") + case BranchTreeReport(tree) => + csv_file.write(s"BranchTreeReport,${tree.getMethod().name},${tree.prettyPrint()}\n") case _: SimpleMessage | _: CopyrightReport | _: MissingDependencyReport | _: BackendSubProcessReport | _: InternalWarningMessage | _: ConfigurationConfirmation=> // Irrelevant for reporting @@ -125,15 +127,15 @@ case class StdIOReporter(name: String = "stdout_reporter", timeInfo: Boolean = t case ExceptionReport(e) => /** Theoretically, we may encounter an exceptional message that has - * not yet been reported via AbortedExceptionally. This can happen - * if we encounter exeptions in e.g. the parser. */ + * not yet been reported via AbortedExceptionally. This can happen + * if we encounter exeptions in e.g. the parser. */ println( s"Verification aborted exceptionally: ${e.toString}" ) e.printStackTrace(System.out); Option(e.getCause) match { case Some(cause) => println( s" Cause: ${cause.toString}" ) case None => } - //println( s" See log file for more details: ..." ) + //println( s" See log file for more details: ..." ) case ExternalDependenciesReport(deps) => val s: String = (deps map (dep => { @@ -179,12 +181,13 @@ case class StdIOReporter(name: String = "stdout_reporter", timeInfo: Boolean = t case EntitySuccessMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case EntityFailureMessage(_, _, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case BranchFailureMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. + case BranchTreeReport(_) => case ConfigurationConfirmation(_) => // TODO use for progress reporting - //println( s"Configuration confirmation: $text" ) + //println( s"Configuration confirmation: $text" ) case InternalWarningMessage(_) => // TODO use for progress reporting - //println( s"Internal warning: $text" ) + //println( s"Internal warning: $text" ) case _: SimpleMessage => - //println( sm.text ) + //println( sm.text ) case _: QuantifierInstantiationsMessage => // too verbose, do not print case _: QuantifierChosenTriggersMessage => // too verbose, do not print case _: VerificationTerminationMessage => diff --git a/src/main/scala/viper/silver/testing/BackendTypeTest.scala b/src/main/scala/viper/silver/testing/BackendTypeTest.scala index 3b070fe09..736e2ce40 100644 --- a/src/main/scala/viper/silver/testing/BackendTypeTest.scala +++ b/src/main/scala/viper/silver/testing/BackendTypeTest.scala @@ -265,7 +265,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, assertNode) = generateTypeCombinationTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(AssertFailed(a, _, _))) if a == assertNode => true + case Failure(Seq(AssertFailed(a, _, _)),_) if a == assertNode => true case _ => false }) } @@ -286,7 +286,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, assertNode) = generateFieldTypeTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(AssertFailed(a, _, _))) if a == assertNode => true + case Failure(Seq(AssertFailed(a, _, _)),_) if a == assertNode => true case _ => false }) } @@ -301,7 +301,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, assertNode) = generateBvOpTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(AssertFailed(a, _, _))) if a == assertNode => true + case Failure(Seq(AssertFailed(a, _, _)),_) if a == assertNode => true case _ => false }) } @@ -322,7 +322,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, assertNode) = generateFloatOpTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(AssertFailed(a, _, _))) if a == assertNode => true + case Failure(Seq(AssertFailed(a, _, _)),_) if a == assertNode => true case _ => false }) } @@ -337,7 +337,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, assertNode) = generateFloatMinMaxTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(AssertFailed(a, _, _))) if a == assertNode => true + case Failure(Seq(AssertFailed(a, _, _)),_) if a == assertNode => true case _ => false }) } @@ -352,7 +352,7 @@ trait BackendTypeTest extends AnyFunSuite with Matchers with BeforeAndAfterAllCo val (prog, fun, exp) = generateFloatOpFunctionTest(false) val res = verifier.verify(prog) assert(res match { - case Failure(Seq(PostconditionViolated(e, f, _, _))) if e == exp && fun == f => true + case Failure(Seq(PostconditionViolated(e, f, _, _)),_) if e == exp && fun == f => true case _ => false }) } diff --git a/src/main/scala/viper/silver/verifier/VerificationError.scala b/src/main/scala/viper/silver/verifier/VerificationError.scala index f08df3779..4ee3f6d45 100644 --- a/src/main/scala/viper/silver/verifier/VerificationError.scala +++ b/src/main/scala/viper/silver/verifier/VerificationError.scala @@ -9,7 +9,6 @@ package viper.silver.verifier import fastparse.Parsed import viper.silver.ast._ import viper.silver.ast.utility.rewriter.Rewritable -import viper.silver.verifier.errors.{BeamInfo, BranchTree} /********************************************************************************** @@ -430,19 +429,6 @@ object errors { def PostconditionViolated(offendingNode: Exp, member: Contracted): PartialVerificationError = PartialVerificationError((reason: ErrorReason) => PostconditionViolated(offendingNode, member, reason)) - trait BranchTree { - def prettyPrint() : String - def toDotFile() : Unit - } - case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) - case class BranchFailed(offendingNode: Method, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { - val id = "branch.failed" - val text = s"Branch fails." - - def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFailed(offendingNode.asInstanceOf[Method], this.reason, this.cached) - def withReason(r: ErrorReason) = BranchFailed(offendingNode, r, cached) - } - case class FoldFailed(offendingNode: Fold, reason: ErrorReason, override val cached: Boolean = false) extends AbstractVerificationError { val id = "fold.failed" val text = s"Folding ${offendingNode.acc.loc} might fail." @@ -639,13 +625,6 @@ object reasons { def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = AssertionFalse(offendingNode.asInstanceOf[Exp]) } - case class BranchFails(offendingNode: Method, tree: BranchTree, beamInfos: Seq[BeamInfo]) extends AbstractErrorReason { - val id = "branch.fails" - def readableMessage = s"\n${tree.prettyPrint()}" - - def withNode(offendingNode: errors.ErrorNode = this.offendingNode) = BranchFails(offendingNode.asInstanceOf[Method],tree,beamInfos) - } - // Note: this class should be deprecated/removed - we no longer support epsilon permissions in the language case class EpsilonAsParam(offendingNode: Exp) extends AbstractErrorReason { val id = "epsilon.as.param" diff --git a/src/main/scala/viper/silver/verifier/VerificationResult.scala b/src/main/scala/viper/silver/verifier/VerificationResult.scala index 95980f6c5..4f4cb9fdf 100644 --- a/src/main/scala/viper/silver/verifier/VerificationResult.scala +++ b/src/main/scala/viper/silver/verifier/VerificationResult.scala @@ -7,6 +7,7 @@ package viper.silver.verifier import viper.silver.ast._ +import viper.silver.reporter.BranchTree import scala.annotation.unused @@ -24,15 +25,15 @@ object Success extends VerificationResult { } /** A non-successful verification. - * - * @param errors The errors encountered during parsing, translation or verification. - */ -case class Failure(errors: Seq[AbstractError]) extends VerificationResult { + * + * @param errors The errors encountered during parsing, translation or verification. + */ +case class Failure(errors: Seq[AbstractError], branchTree : Option[BranchTree] = None) extends VerificationResult { override def toString = { s"Verification failed with ${errors.size} errors:\n " + (errors map (e => "[" + e.fullId + "] " + e.readableMessage)).mkString("\n ") } - override def transformedResult(): VerificationResult = Failure(errors.map(_.transformedError())) + override def transformedResult(): VerificationResult = Failure(errors.map(_.transformedError()), branchTree) } /** diff --git a/src/test/scala/PluginTests.scala b/src/test/scala/PluginTests.scala index 1f34f2ef3..8f4717e54 100644 --- a/src/test/scala/PluginTests.scala +++ b/src/test/scala/PluginTests.scala @@ -61,7 +61,7 @@ class TestPluginReportError extends SilverPlugin { override def beforeFinish(input: VerificationResult): VerificationResult = { input match { case Success => assert(false) - case Failure(errs) => assert(errs.contains(error)) + case Failure(errs,_) => assert(errs.contains(error)) } input } @@ -148,7 +148,7 @@ class TestPluginMapErrors extends SilverPlugin with TestPlugin with FakeResult { // println(">>> detected VerificationResult is Success") assert(false) input - case Failure(errors) => + case Failure(errors,_) => // println(s">>> detected VerificationResult is Failure: ${errors.toString()}") assert(errors.contains(error1)) Failure(Seq(error2)) @@ -161,7 +161,7 @@ class TestPluginMapErrors extends SilverPlugin with TestPlugin with FakeResult { case Success => // println("]]] detected VerificationResult is Success") assert(false) - case Failure(errors) => + case Failure(errors,_) => // println(s"]]] detected VerificationResult is Failure: ${errors.toString()}") assert(!errors.contains(error1)) assert(errors.contains(error2)) @@ -200,7 +200,7 @@ class TestPluginMapVsFinish extends SilverPlugin with TestPlugin { finish = true input match { case Success => assert(false) - case Failure(errors) => + case Failure(errors,_) => assert(errors.contains(error)) } input diff --git a/src/test/scala/SilSuite.scala b/src/test/scala/SilSuite.scala index a0d87ba3f..84cd8f7fd 100644 --- a/src/test/scala/SilSuite.scala +++ b/src/test/scala/SilSuite.scala @@ -109,7 +109,7 @@ abstract class SilSuite extends AnnotationBasedTestSuite with BeforeAndAfterAllC info(s"Time required: $tPhases.") val actualErrors = fe.result match { case Success => Nil - case Failure(es) => es collect { + case Failure(es,_) => es collect { case e: AbstractVerificationError => e.transformedError() case rest: AbstractError => rest diff --git a/src/test/scala/StatisticalTestSuite.scala b/src/test/scala/StatisticalTestSuite.scala index bbca77076..5d3f3e080 100644 --- a/src/test/scala/StatisticalTestSuite.scala +++ b/src/test/scala/StatisticalTestSuite.scala @@ -142,7 +142,7 @@ trait StatisticalTestSuite extends SilSuite { val actualErrors: Seq[AbstractError] = fe.result match { case Success => Nil - case Failure(es) => es collect { + case Failure(es,_) => es collect { case e: AbstractVerificationError => e.transformedError() case rest: AbstractError => rest From b0e5553251b652a8c1e311d74683576d4698e262 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Fri, 14 Mar 2025 16:05:50 +0100 Subject: [PATCH 19/22] Generate ASCII / DOT file client side --- .../viper/silver/frontend/SilFrontend.scala | 4 ++-- .../PredicateInstancePlugin.scala | 4 ++-- .../plugin/standard/refute/RefutePlugin.scala | 8 ++++---- .../termination/TerminationPlugin.scala | 4 ++-- .../scala/viper/silver/reporter/Message.scala | 20 ++++++------------- .../viper/silver/reporter/Reporter.scala | 6 +++--- .../silver/verifier/VerificationResult.scala | 7 ++++--- 7 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/main/scala/viper/silver/frontend/SilFrontend.scala b/src/main/scala/viper/silver/frontend/SilFrontend.scala index 417e946ac..fca9da74d 100644 --- a/src/main/scala/viper/silver/frontend/SilFrontend.scala +++ b/src/main/scala/viper/silver/frontend/SilFrontend.scala @@ -283,9 +283,9 @@ trait SilFrontend extends DefaultFrontend { val res = plugins.beforeFinish(tRes) val filteredRes = res match { case Success => res - case Failure(errors,branchTree) => + case Failure(errors,exploredBranches) => // Remove duplicate errors - Failure(errors.distinctBy(failureFilterAndGroupingCriterion),branchTree) + Failure(errors.distinctBy(failureFilterAndGroupingCriterion),exploredBranches) } _verificationResult = Some(filteredRes) filteredRes match { diff --git a/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala b/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala index 871c52584..3b2152562 100644 --- a/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/predicateinstance/PredicateInstancePlugin.scala @@ -103,11 +103,11 @@ class PredicateInstancePlugin(@unused reporter: viper.silver.reporter.Reporter, private def translateVerificationResult(input: VerificationResult): VerificationResult = { input match { case Success => input - case Failure(errors,branchTree) => + case Failure(errors,exploredBranches) => Failure(errors.map { case e@PreconditionInAppFalse(_, _, _) => e.transformedError() case e => e - },branchTree) + },exploredBranches) } } diff --git a/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala b/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala index f952f97c9..90e549d96 100644 --- a/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala @@ -74,14 +74,14 @@ class RefutePlugin(@unused reporter: viper.silver.reporter.Reporter, mapVerificationResultsForNode(program, input) private def mapVerificationResultsForNode(n: Node, input: VerificationResult): VerificationResult = { - val (refutesForWhichErrorOccurred, otherErrors, branchTree_) = input match { + val (refutesForWhichErrorOccurred, otherErrors, exploredBranches_) = input match { case Success => (Seq.empty, Seq.empty,None) - case Failure(errors,branchTree) => + case Failure(errors,exploredBranches) => val partErrs = errors.partitionMap { case AssertFailed(NodeWithRefuteInfo(RefuteInfo(r)), _, _) => Left((r, r.pos)) case err => Right(err) } - (partErrs._1, partErrs._2, branchTree) + (partErrs._1, partErrs._2, exploredBranches) } val refutesContainedInNode = n.collect { case NodeWithRefuteInfo(RefuteInfo(r)) => (r, r.pos) @@ -95,7 +95,7 @@ class RefutePlugin(@unused reporter: viper.silver.reporter.Reporter, val errors = otherErrors ++ missingErrorsInNode if (errors.isEmpty) Success - else Failure(errors, branchTree_) + else Failure(errors, exploredBranches_) } } diff --git a/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala b/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala index 149d44bc5..119a0f198 100644 --- a/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala +++ b/src/main/scala/viper/silver/plugin/standard/termination/TerminationPlugin.scala @@ -297,10 +297,10 @@ class TerminationPlugin(@unused reporter: viper.silver.reporter.Reporter, input match { case Success => input - case Failure(errors,branchTree) => Failure(errors.map({ + case Failure(errors,exploredBranches) => Failure(errors.map({ case a@AssertFailed(Assert(_), _, _) => a.transformedError() case e => e - }),branchTree) + }),exploredBranches) } } diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 0a52946d4..0a371215e 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -8,7 +8,7 @@ package viper.silver.reporter import viper.silver.reporter.BackendSubProcessStages.BackendSubProcessStage import viper.silver.verifier._ -import viper.silver.ast.{Exp, Method, QuantifiedExp, Trigger} +import viper.silver.ast.{Method, QuantifiedExp, Trigger} import viper.silver.parser.PProgram /** @@ -169,22 +169,14 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } -trait BranchTree { - val DotFilePath : String - var cached: Boolean = false - def getMethod() : Method - def getBeams() : Seq[BeamInfo] - def prettyPrint() : String - def toDotFile() : Unit -} -case class BeamInfo(e: Exp, isLeftFatal : Boolean, isRightFatal : Boolean) -case class BranchTreeReport(tree : BranchTree) +case class ExploredBranches(method: Method, paths: Vector[(Seq[Exp], Boolean)], var cached : Boolean = false) +case class ExploredBranchesReport(exploredBranches : ExploredBranches) extends Message { - override lazy val toString: String = s"branch_tree_report(" + - s"method=${tree.getMethod().name}, tree=${tree.prettyPrint()}, beams=${tree.getBeams()}" + override lazy val toString: String = s"explored_branches_report(" + + s"method=${exploredBranches.method.name}, paths=${exploredBranches.paths}" - override val name = "branch_tree" + override val name = "explored_branches" } case class StatisticsReport(nOfMethods: Int, nOfFunctions: Int, nOfPredicates: Int, diff --git a/src/main/scala/viper/silver/reporter/Reporter.scala b/src/main/scala/viper/silver/reporter/Reporter.scala index ac1f484a6..ad0c106d2 100644 --- a/src/main/scala/viper/silver/reporter/Reporter.scala +++ b/src/main/scala/viper/silver/reporter/Reporter.scala @@ -68,8 +68,8 @@ case class CSVReporter(name: String = "csv_reporter", path: String = "report.csv case BranchFailureMessage(_, concerning, _, cached) => csv_file.write(s"BranchFailureMessage,${concerning.name},${cached}\n") - case BranchTreeReport(tree) => - csv_file.write(s"BranchTreeReport,${tree.getMethod().name},${tree.prettyPrint()}\n") + case ExploredBranchesReport(eb) => + csv_file.write(s"ExploredBranchesReport,${eb.method.name},${eb.paths}, ${eb.cached}\n") case _: SimpleMessage | _: CopyrightReport | _: MissingDependencyReport | _: BackendSubProcessReport | _: InternalWarningMessage | _: ConfigurationConfirmation=> // Irrelevant for reporting @@ -181,7 +181,7 @@ case class StdIOReporter(name: String = "stdout_reporter", timeInfo: Boolean = t case EntitySuccessMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case EntityFailureMessage(_, _, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. case BranchFailureMessage(_, _, _, _) => // FIXME Currently, we only print overall verification results to STDOUT. - case BranchTreeReport(_) => + case ExploredBranchesReport(_) => case ConfigurationConfirmation(_) => // TODO use for progress reporting //println( s"Configuration confirmation: $text" ) case InternalWarningMessage(_) => // TODO use for progress reporting diff --git a/src/main/scala/viper/silver/verifier/VerificationResult.scala b/src/main/scala/viper/silver/verifier/VerificationResult.scala index 4f4cb9fdf..93045ed24 100644 --- a/src/main/scala/viper/silver/verifier/VerificationResult.scala +++ b/src/main/scala/viper/silver/verifier/VerificationResult.scala @@ -7,9 +7,10 @@ package viper.silver.verifier import viper.silver.ast._ -import viper.silver.reporter.BranchTree +import viper.silver.reporter.ExploredBranches import scala.annotation.unused +import viper.silver.reporter.ExploredBranches /** Describes the outcome of a verification attempt of a Viper program. @@ -28,12 +29,12 @@ object Success extends VerificationResult { * * @param errors The errors encountered during parsing, translation or verification. */ -case class Failure(errors: Seq[AbstractError], branchTree : Option[BranchTree] = None) extends VerificationResult { +case class Failure(errors: Seq[AbstractError], exploredBranches : Option[ExploredBranches] = None) extends VerificationResult { override def toString = { s"Verification failed with ${errors.size} errors:\n " + (errors map (e => "[" + e.fullId + "] " + e.readableMessage)).mkString("\n ") } - override def transformedResult(): VerificationResult = Failure(errors.map(_.transformedError()), branchTree) + override def transformedResult(): VerificationResult = Failure(errors.map(_.transformedError()), exploredBranches) } /** From 16ae2d17e0c50f019b159177b578f5c6ea2da203 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 25 Mar 2025 07:11:11 +0100 Subject: [PATCH 20/22] Undo unnecessary change --- src/test/scala/AnnotationBasedTestSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/AnnotationBasedTestSuite.scala b/src/test/scala/AnnotationBasedTestSuite.scala index 2211920b3..58532a1ef 100644 --- a/src/test/scala/AnnotationBasedTestSuite.scala +++ b/src/test/scala/AnnotationBasedTestSuite.scala @@ -41,7 +41,7 @@ abstract class AnnotationBasedTestSuite extends ResourceBasedTestSuite { val parserErrors = input.annotations.errors // Match expected outputs with actual outputs - val actualOutputs = system.run(input).filterNot(_.toString.contains("postcondition.violated.branch")).toSeq + val actualOutputs = system.run(input) val expectedOutputs = input.annotations.outputAnnotations val matcher = OutputMatcher(actualOutputs, expectedOutputs) From 64beeb538b976bb316318c460d14da9846b7d555 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 25 Mar 2025 08:38:24 +0100 Subject: [PATCH 21/22] Remove duplicate import --- src/main/scala/viper/silver/verifier/VerificationResult.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/viper/silver/verifier/VerificationResult.scala b/src/main/scala/viper/silver/verifier/VerificationResult.scala index 93045ed24..d4542a8bb 100644 --- a/src/main/scala/viper/silver/verifier/VerificationResult.scala +++ b/src/main/scala/viper/silver/verifier/VerificationResult.scala @@ -10,7 +10,6 @@ import viper.silver.ast._ import viper.silver.reporter.ExploredBranches import scala.annotation.unused -import viper.silver.reporter.ExploredBranches /** Describes the outcome of a verification attempt of a Viper program. From f610f5c6a0cfa75f13ea6b8e036655b799d2d4a3 Mon Sep 17 00:00:00 2001 From: 7i6ht Date: Tue, 25 Mar 2025 08:45:29 +0100 Subject: [PATCH 22/22] Fix datatype --- src/main/scala/viper/silver/reporter/Message.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/viper/silver/reporter/Message.scala b/src/main/scala/viper/silver/reporter/Message.scala index 0a371215e..5e96b1131 100644 --- a/src/main/scala/viper/silver/reporter/Message.scala +++ b/src/main/scala/viper/silver/reporter/Message.scala @@ -169,7 +169,7 @@ case class BranchFailureMessage(verifier: String, concerning: Entity, s"result=${result.toString}, cached=$cached)" } -case class ExploredBranches(method: Method, paths: Vector[(Seq[Exp], Boolean)], var cached : Boolean = false) +case class ExploredBranches(method: Method, paths: Vector[(Vector[(String, Boolean)], Boolean)], var cached : Boolean = false) case class ExploredBranchesReport(exploredBranches : ExploredBranches) extends Message {