summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore3
-rw-r--r--BCT/BytecodeTranslator/Heap.cs3
-rw-r--r--BCT/BytecodeTranslator/Sink.cs3
-rw-r--r--BCT/BytecodeTranslator/StatementTraverser.cs1
-rw-r--r--Chalice/chalice.bat8
-rw-r--r--Chalice/src/main/scala/Ast.scala163
-rw-r--r--Chalice/src/main/scala/Chalice.scala179
-rw-r--r--Chalice/src/main/scala/Prelude.scala43
-rw-r--r--Chalice/src/main/scala/PrettyPrinter.scala1
-rw-r--r--Chalice/src/main/scala/Resolver.scala12
-rw-r--r--Chalice/src/main/scala/Translator.scala1047
-rw-r--r--Chalice/tests/examples/AssociationList.output.txt10
-rw-r--r--Chalice/tests/general-tests/counter.chalice3
-rw-r--r--Chalice/tests/general-tests/counter.output.txt22
-rw-r--r--Chalice/tests/general-tests/prog2.chalice1
-rw-r--r--Chalice/tests/general-tests/prog2.output.txt9
-rw-r--r--Chalice/tests/predicates/FoldUnfoldExperiments.chalice32
-rw-r--r--Chalice/tests/predicates/FoldUnfoldExperiments.output.txt4
-rw-r--r--Chalice/tests/predicates/aux-info.chalice33
-rw-r--r--Chalice/tests/predicates/aux-info.output.txt5
-rw-r--r--Chalice/tests/predicates/generate_reference.bat2
-rw-r--r--Chalice/tests/predicates/generate_reference_all.bat2
-rw-r--r--Chalice/tests/predicates/mutual-dependence.chalice24
-rw-r--r--Chalice/tests/predicates/mutual-dependence.output.txt5
-rw-r--r--Chalice/tests/predicates/reg_test.bat2
-rw-r--r--Chalice/tests/predicates/reg_test_all.bat2
-rw-r--r--Chalice/tests/predicates/test.bat2
-rw-r--r--Chalice/tests/predicates/test.chalice38
-rw-r--r--Chalice/tests/predicates/test.output.txt5
-rw-r--r--Chalice/tests/predicates/test1.chalice50
-rw-r--r--Chalice/tests/predicates/test1.output.txt4
-rw-r--r--Chalice/tests/predicates/test10.chalice18
-rw-r--r--Chalice/tests/predicates/test10.output.txt4
-rw-r--r--Chalice/tests/predicates/test2.chalice55
-rw-r--r--Chalice/tests/predicates/test2.output.txt4
-rw-r--r--Chalice/tests/predicates/test3.chalice29
-rw-r--r--Chalice/tests/predicates/test3.output.txt4
-rw-r--r--Chalice/tests/predicates/test4.chalice56
-rw-r--r--Chalice/tests/predicates/test4.output.txt5
-rw-r--r--Chalice/tests/predicates/test7.chalice109
-rw-r--r--Chalice/tests/predicates/test7.output.txt16
-rw-r--r--Chalice/tests/predicates/test8.chalice55
-rw-r--r--Chalice/tests/predicates/test8.output.txt4
-rw-r--r--Chalice/tests/regressions/internal-bug-1.chalice16
-rw-r--r--Chalice/tests/regressions/internal-bug-1.output.txt4
-rw-r--r--Chalice/tests/regressions/workitem-10194.output.txt3
-rw-r--r--Chalice/tests/runalltests.bat2
-rw-r--r--Source/BoogieDriver/BoogieDriver.cs364
-rw-r--r--Source/Core/BoogiePL.atg32
-rw-r--r--Source/Core/CommandLineOptions.cs15
-rw-r--r--Source/Core/Parser.cs33
-rw-r--r--Source/Dafny/Compiler.cs6
-rw-r--r--Source/Dafny/Dafny.atg77
-rw-r--r--Source/Dafny/DafnyAst.cs217
-rw-r--r--Source/Dafny/DafnyPipeline.csproj1
-rw-r--r--Source/Dafny/Parser.cs344
-rw-r--r--Source/Dafny/Printer.cs8
-rw-r--r--Source/Dafny/RefinementTransformer.cs246
-rw-r--r--Source/Dafny/Resolver.cs13
-rw-r--r--Source/Dafny/Rewriter.cs321
-rw-r--r--Source/Dafny/Scanner.cs10
-rw-r--r--Source/Dafny/Translator.cs21
-rw-r--r--Source/DafnyDriver/DafnyDriver.cs2
-rw-r--r--Source/GPUVerify.sln110
-rw-r--r--Source/GPUVerify/AccessInvariantProcessor.cs107
-rw-r--r--Source/GPUVerify/AsymmetricExpressionFinder.cs29
-rw-r--r--Source/GPUVerify/CrossThreadInvariantProcessor.cs53
-rw-r--r--Source/GPUVerify/ElementEncodingRaceInstrumenter.cs26
-rw-r--r--Source/GPUVerify/EnabledToPredicateVisitor.cs39
-rw-r--r--Source/GPUVerify/GPUVerifier.cs511
-rw-r--r--Source/GPUVerify/GPUVerify.csproj5
-rw-r--r--Source/GPUVerify/IRaceInstrumenter.cs6
-rw-r--r--Source/GPUVerify/NullRaceInstrumenter.cs15
-rw-r--r--Source/GPUVerify/Predicator.cs262
-rw-r--r--Source/GPUVerify/RaceInstrumenterBase.cs72
-rw-r--r--Source/GPUVerify/SetEncodingRaceInstrumenter.cs16
-rw-r--r--Source/GPUVerify/StructuredProgramVisitor.cs152
-rw-r--r--Source/GPUVerify/VariableDualiser.cs23
-rw-r--r--Source/Houdini/Checker.cs46
-rw-r--r--Source/Houdini/Houdini.cs464
-rw-r--r--Source/Provers/SMTLib/ProverInterface.cs203
-rw-r--r--Source/Provers/Z3api/ProverLayer.cs153
-rw-r--r--Source/VCGeneration/Check.cs57
-rw-r--r--Source/VCGeneration/StratifiedVC.cs471
-rw-r--r--Source/VCGeneration/VC.cs99
-rw-r--r--Source/VCGeneration/Wlp.cs12
-rw-r--r--Test/dafny0/Answer20
-rw-r--r--Test/dafny0/LetExpr.dfy40
-rw-r--r--Test/dafny0/Skeletons.dfy63
-rw-r--r--Test/dafny0/runtest.bat2
-rw-r--r--Test/dafny1/Answer4
-rw-r--r--Test/dafny1/ExtensibleArrayAuto.dfy113
-rw-r--r--Test/dafny1/runtest.bat3
-rw-r--r--Test/houdini/Answer14
-rw-r--r--Test/houdini/runtest.bat4
-rw-r--r--Test/vstte2012/Answer4
-rw-r--r--Test/vstte2012/RingBufferAuto.dfy75
-rw-r--r--Test/vstte2012/runtest.bat2
-rw-r--r--_admin/Boogie/aste/summary.log28
99 files changed, 4887 insertions, 2228 deletions
diff --git a/.hgignore b/.hgignore
index 06649311..2df022a3 100644
--- a/.hgignore
+++ b/.hgignore
@@ -7,8 +7,7 @@ syntax: regexp
^.*(bin|obj)/([^/]*/)?(Debug|Release|Checked|Debug All|DEBUG ALL)/.*$
^Binaries/BytecodeTranslator$
^BCT/Binaries/.*$
-^Chalice/bin
-^Chalice/tests/(examples|permission-model|refinements|general-tests|regressions)/.*\.bpl
+^Chalice/tests/(examples|permission-model|refinements|general-tests|regressions|predicates)/.*\.bpl
Test/([^/]*)/Output
Test/([^/]*)/([^/]*)\.sx
Test/(dafny0|dafny1|dafny2|VSI-Benchmarks|vacid0|VSComp2010|vstte2012)/(out\.cs|.*\.dll|.*\.pdb|.*\.exe|.*\.tmp.*)
diff --git a/BCT/BytecodeTranslator/Heap.cs b/BCT/BytecodeTranslator/Heap.cs
index aaed79e4..731d5e66 100644
--- a/BCT/BytecodeTranslator/Heap.cs
+++ b/BCT/BytecodeTranslator/Heap.cs
@@ -314,8 +314,7 @@ namespace BytecodeTranslator {
#endregion
#region Parse the declarations
- var ms = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(preludeText.ToString()));
- int errorCount = Bpl.Parser.Parse(ms, "foo", new List<string>(), out prelude);
+ int errorCount = Bpl.Parser.Parse(preludeText.ToString(), "foo", out prelude);
if (prelude == null || errorCount > 0) {
prelude = null;
return false;
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index 916a6485..d89f1bfd 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -330,6 +330,9 @@ namespace BytecodeTranslator {
var name = "$string_literal_" + TranslationHelper.TurnStringIntoValidIdentifier(str) + "_" + declaredStringConstants.Count;
var tident = new Bpl.TypedIdent(tok, name, t);
c = new Bpl.Constant(tok, tident, true);
+ str = str.Replace("\n", "\\n");
+ str = str.Replace("\r", "\\r");
+ str = str.Replace("\"", "\u0022");
var attrib = new Bpl.QKeyValue(Bpl.Token.NoToken, "value", new List<object> { str, }, null);
c.Attributes = attrib;
this.declaredStringConstants.Add(str, c);
diff --git a/BCT/BytecodeTranslator/StatementTraverser.cs b/BCT/BytecodeTranslator/StatementTraverser.cs
index 1e618bf2..9005b43a 100644
--- a/BCT/BytecodeTranslator/StatementTraverser.cs
+++ b/BCT/BytecodeTranslator/StatementTraverser.cs
@@ -88,6 +88,7 @@ namespace BytecodeTranslator
var remover = new AnonymousDelegateRemover(this.sink.host, this.PdbReader);
newTypes = remover.RemoveAnonymousDelegates(methodBody.MethodDefinition, block);
}
+ StmtBuilder.Add(new Bpl.AssumeCmd(Bpl.Token.NoToken, Bpl.Expr.True, new Bpl.QKeyValue(Bpl.Token.NoToken, "breadcrumb", new List<object> { Bpl.Expr.Literal(this.NextUniqueNumber()) }, null)));
this.Traverse(methodBody);
return newTypes;
}
diff --git a/Chalice/chalice.bat b/Chalice/chalice.bat
index e4bbf5da..d5991326 100644
--- a/Chalice/chalice.bat
+++ b/Chalice/chalice.bat
@@ -11,12 +11,12 @@ if not %ERRORLEVEL%==0 (
goto :exit_with_error
)
-REM Get the Scala version, or rather, a string such as "scala-2.8.1"
-for /f "delims=" %%A in ('dir /b %ROOT_DIR%\project\boot\scala-*') do @set SCALA_DIR=%%A
+
+set SCALA_DIR=scala-2.8.1
REM Set classpath elements
-set __CP.SCALA_LIB=%ROOT_DIR%\project\boot\%SCALA_DIR%\lib\scala-library.jar
-set __CP.CHALICE=%ROOT_DIR%\target\%SCALA_DIR%.final\classes
+set __CP.SCALA_LIB="%ROOT_DIR%project\boot\%SCALA_DIR%\lib\scala-library.jar"
+set __CP.CHALICE="%ROOT_DIR%target\%SCALA_DIR%.final\classes"
REM Assemble classpath and check if all classpath elements exist
set CP=
diff --git a/Chalice/src/main/scala/Ast.scala b/Chalice/src/main/scala/Ast.scala
index cd4a6cd8..1cfd173e 100644
--- a/Chalice/src/main/scala/Ast.scala
+++ b/Chalice/src/main/scala/Ast.scala
@@ -188,6 +188,21 @@ case class Predicate(id: String, private val rawDefinition: Expression) extends
}
}
case class Function(id: String, ins: List[Variable], out: Type, spec: List[Specification], definition: Option[Expression]) extends NamedMember(id) {
+ // list of predicates that this function possibly depends on (that is, predicates
+ // that are mentioned in the functions precondition)
+ def dependentPredicates: List[Predicate] = {
+ var predicates: List[Predicate] = List()
+ spec foreach {
+ case Precondition(e) =>
+ e visit {_ match {
+ case pred@MemberAccess(e, p) if pred.isPredicate =>
+ predicates = pred.predicate :: predicates
+ case _ =>}
+ }
+ case _ =>
+ }
+ predicates
+ }
def apply(rec: Expression, args: List[Expression]): FunctionApplication = {
val result = FunctionApplication(rec, id, args);
result.f = this;
@@ -398,6 +413,7 @@ case class Init(id: String, e: Expression) extends ASTNode {
sealed abstract class Expression extends RValue {
def transform(f: Expression => Option[Expression]) = AST.transform(this, f)
def visit(f: RValue => Unit) = AST.visit(this, f)
+ def visitOpt(f: RValue => Boolean) = AST.visitOpt(this, f)
}
sealed abstract class Literal extends Expression
case class IntLiteral(n: Int) extends Literal
@@ -411,6 +427,10 @@ case class VariableExpr(id: String) extends Expression {
def this(vr: Variable) = { this(vr.id); v = vr; typ = vr.t.typ }
def Resolve(vr: Variable) = { v = vr; typ = vr.t.typ }
}
+// hack to allow boogie expressions in the Chalice AST during transformation
+case class BoogieExpr(expr: Boogie.Expr) extends Expression {
+ override def toString = "BoogieExpr("+expr+")"
+}
case class Result() extends Expression
sealed abstract class ThisExpr extends Expression
case class ExplicitThisExpr() extends ThisExpr {
@@ -757,6 +777,7 @@ object AST {
case _:ThisExpr => expr
case _:Result => expr
case _:VariableExpr => expr
+ case _:BoogieExpr => expr
case ma@MemberAccess(e, id) =>
val g = MemberAccess(func(e), id);
g.f = ma.f;
@@ -848,75 +869,79 @@ object AST {
}
// Applies recursively the function f first to the expression and then to its subexpressions (that is members of type RValue)
- def visit(expr: RValue, f: RValue => Unit) {
- f(expr);
- expr match {
- case _:Literal => ;
- case _:ThisExpr => ;
- case _:Result => ;
- case _:VariableExpr => ;
- case MemberAccess(e, _) =>
- visit(e, f);
-
- case Frac(p) => visit(p, f);
- case Epsilons(p) => visit(p, f);
- case Full | Epsilon | Star | MethodEpsilon =>;
- case ChannelEpsilon(None) | PredicateEpsilon(None) | MonitorEpsilon(None) =>;
- case ChannelEpsilon(Some(e)) => visit(e, f);
- case PredicateEpsilon(Some(e)) => visit(e, f);
- case MonitorEpsilon(Some(e)) => visit(e, f);
- case ForkEpsilon(tk) => visit(tk, f);
- case IntPermTimes(n, p) =>
- visit(n, f); visit(p, f);
- case PermTimes(e0, e1) =>
- visit(e0, f); visit(e1, f);
- case PermPlus(e0, e1) =>
- visit(e0, f); visit(e1, f);
- case PermMinus(e0, e1) =>
- visit(e0, f); visit(e1, f);
- case Access(e, perm) =>
- visit(e, f); visit(perm, f);
- case AccessAll(obj, perm) =>
- visit(obj, f); visit(perm, f);
- case AccessSeq(s, _, perm) =>
- visit(s, f); visit(perm, f);
-
- case Credit(e, n) =>
- visit(e, f); n match { case Some(n) => visit(n, f); case _ => }
- case Holds(e) => visit(e, f);
- case RdHolds(e) => visit(e, f);
-
- case e: BinaryExpr =>
- visit(e.E0, f); visit(e.E1, f);
- case Range(min, max) =>
- visit(min, f); visit(max, f);
- case e: Assigned => e
- case Old(e) => visit(e, f);
- case IfThenElse(con, then, els) => visit(con, f); visit(then, f); visit(els, f);
- case Not(e) => visit(e, f);
- case funapp@FunctionApplication(obj, id, args) =>
- visit(obj, f); args foreach { arg => visit(arg, f) };
- case Unfolding(pred, e) =>
- visit(pred, f); visit(e, f);
-
- case SeqQuantification(_, _, seq, e) => visit(seq, f); visit(e, f);
- case TypeQuantification(_, _, _, e, (min,max)) => visit(e, f); visit(min, f); visit(max, f);
- case TypeQuantification(_, _, _, e, _) => visit(e, f);
- case ExplicitSeq(es) =>
- es foreach { e => visit(e, f) }
- case Length(e) =>
- visit(e, f)
- case Eval(h, e) =>
- h match {
- case AcquireState(obj) => visit(obj, f);
- case ReleaseState(obj) => visit(obj, f);
- case CallState(token, obj, id, args) =>
- visit(token, f); visit(obj, f); args foreach {a : Expression => visit(a, f)};
- }
- visit(e, f);
- case NewRhs(_, init, lowerBounds, upperBounds) =>
- lowerBounds foreach { e => visit(e, f)};
- upperBounds foreach { e => visit(e, f)};
+ def visit(expr: RValue, f: RValue => Unit) = visitOpt(expr, r => {f(r); true})
+ // Applies recursively the function f first to the expression and, if f returns true, then to its subexpressions
+ def visitOpt(expr: RValue, f: RValue => Boolean) {
+ if (f(expr)) {
+ expr match {
+ case _:Literal => ;
+ case _:ThisExpr => ;
+ case _:Result => ;
+ case _:VariableExpr => ;
+ case _:BoogieExpr => ;
+ case MemberAccess(e, _) =>
+ visitOpt(e, f);
+
+ case Frac(p) => visitOpt(p, f);
+ case Epsilons(p) => visitOpt(p, f);
+ case Full | Epsilon | Star | MethodEpsilon =>;
+ case ChannelEpsilon(None) | PredicateEpsilon(None) | MonitorEpsilon(None) =>;
+ case ChannelEpsilon(Some(e)) => visitOpt(e, f);
+ case PredicateEpsilon(Some(e)) => visitOpt(e, f);
+ case MonitorEpsilon(Some(e)) => visitOpt(e, f);
+ case ForkEpsilon(tk) => visitOpt(tk, f);
+ case IntPermTimes(n, p) =>
+ visitOpt(n, f); visitOpt(p, f);
+ case PermTimes(e0, e1) =>
+ visitOpt(e0, f); visitOpt(e1, f);
+ case PermPlus(e0, e1) =>
+ visitOpt(e0, f); visitOpt(e1, f);
+ case PermMinus(e0, e1) =>
+ visitOpt(e0, f); visitOpt(e1, f);
+ case Access(e, perm) =>
+ visitOpt(e, f); visitOpt(perm, f);
+ case AccessAll(obj, perm) =>
+ visitOpt(obj, f); visitOpt(perm, f);
+ case AccessSeq(s, _, perm) =>
+ visitOpt(s, f); visitOpt(perm, f);
+
+ case Credit(e, n) =>
+ visitOpt(e, f); n match { case Some(n) => visitOpt(n, f); case _ => }
+ case Holds(e) => visitOpt(e, f);
+ case RdHolds(e) => visitOpt(e, f);
+
+ case e: BinaryExpr =>
+ visitOpt(e.E0, f); visitOpt(e.E1, f);
+ case Range(min, max) =>
+ visitOpt(min, f); visitOpt(max, f);
+ case e: Assigned => e
+ case Old(e) => visitOpt(e, f);
+ case IfThenElse(con, then, els) => visitOpt(con, f); visitOpt(then, f); visitOpt(els, f);
+ case Not(e) => visitOpt(e, f);
+ case funapp@FunctionApplication(obj, id, args) =>
+ visitOpt(obj, f); args foreach { arg => visitOpt(arg, f) };
+ case Unfolding(pred, e) =>
+ visitOpt(pred, f); visitOpt(e, f);
+
+ case SeqQuantification(_, _, seq, e) => visitOpt(seq, f); visitOpt(e, f);
+ case TypeQuantification(_, _, _, e, (min,max)) => visitOpt(e, f); visitOpt(min, f); visitOpt(max, f);
+ case TypeQuantification(_, _, _, e, _) => visitOpt(e, f);
+ case ExplicitSeq(es) =>
+ es foreach { e => visitOpt(e, f) }
+ case Length(e) =>
+ visitOpt(e, f)
+ case Eval(h, e) =>
+ h match {
+ case AcquireState(obj) => visitOpt(obj, f);
+ case ReleaseState(obj) => visitOpt(obj, f);
+ case CallState(token, obj, id, args) =>
+ visitOpt(token, f); visitOpt(obj, f); args foreach {a : Expression => visitOpt(a, f)};
+ }
+ visitOpt(e, f);
+ case NewRhs(_, init, lowerBounds, upperBounds) =>
+ lowerBounds foreach { e => visitOpt(e, f)};
+ upperBounds foreach { e => visitOpt(e, f)};
+ }
}
}
}
diff --git a/Chalice/src/main/scala/Chalice.scala b/Chalice/src/main/scala/Chalice.scala
index cc06ad7b..5cdb470b 100644
--- a/Chalice/src/main/scala/Chalice.scala
+++ b/Chalice/src/main/scala/Chalice.scala
@@ -55,6 +55,7 @@ object Chalice {
val boogieArgs: String
val gen: Boolean
val showFullStackTrace: Boolean
+ val noBplFile: Boolean
def getHelp(): String
}
@@ -68,6 +69,7 @@ object Chalice {
var aPrintProgram = false
var aDoTypecheck = true
var aDoTranslate = true
+ var aNoBplFile = false
var aBoogieArgs = " ";
var aGen = false;
var aShowFullStackTrace = false
@@ -92,6 +94,9 @@ object Chalice {
"checkLeaks" -> (
{() => checkLeaks = true},
"(no description available)"),
+ "noBplFile" -> (
+ {() => aNoBplFile = true},
+ "Do not generate a .bpl file, but pass the intermediate program directly to Boogie."),
"noDeadlockChecks" -> (
{() => skipDeadlockChecks = true},
"skip all lock ordering checks"),
@@ -216,6 +221,7 @@ object Chalice {
val boogieArgs = aBoogieArgs
val gen = aGen
val showFullStackTrace = aShowFullStackTrace
+ val noBplFile = aNoBplFile
def getHelp(): String = help
})
}
@@ -274,43 +280,96 @@ object Chalice {
case Some(p) => p
case None => return //invalid arguments, help has been displayed
}
-
- val program = parsePrograms(params) match {
- case Some(p) => p
- case None => return //illegal program, errors have already been displayed
- }
-
- if(!params.doTypecheck || !typecheckProgram(params, program))
- return ;
-
- if (params.printProgram) {
- Console.out.println("Program after type checking: ");
- PrintProgram.P(program)
- }
-
- if(!params.doTranslate)
- return;
-
- // checking if Boogie.exe exists (on non-Linux machine)
- val boogieFile = new File(params.boogiePath);
- if(! boogieFile.exists() || ! boogieFile.isFile()
- && (System.getProperty("os.name") != "Linux")) {
- CommandLineError("Boogie.exe not found at " + params.boogiePath, params.getHelp());
- return;
- }
- val showFullStackTrace = params.showFullStackTrace
- val boogiePath = params.boogiePath
- val boogieArgs = params.boogieArgs
-
- // translate program to Boogie
- val translator = new Translator();
- var bplProg: List[Boogie.Decl] = Nil
try {
+
+ val program = parsePrograms(params) match {
+ case Some(p) => p
+ case None => return //illegal program, errors have already been displayed
+ }
+
+ if(!params.doTypecheck || !typecheckProgram(params, program))
+ return ;
+
+ if (params.printProgram) {
+ Console.out.println("Program after type checking: ");
+ PrintProgram.P(program)
+ }
+
+ if(!params.doTranslate)
+ return;
+
+ // checking if Boogie.exe exists (on non-Linux machine)
+ val boogieFile = new File(params.boogiePath);
+ if(! boogieFile.exists() || ! boogieFile.isFile()
+ && (System.getProperty("os.name") != "Linux")) {
+ CommandLineError("Boogie.exe not found at " + params.boogiePath, params.getHelp());
+ return;
+ }
+
+ val boogiePath = params.boogiePath
+ val boogieArgs = params.boogieArgs
+
+ // translate program to Boogie
+ val translator = new Translator();
+ var bplProg: List[Boogie.Decl] = Nil
bplProg = translator.translateProgram(program);
+
+ // write to out.bpl
+ val bplText = TranslatorPrelude.P + (bplProg map Boogie.Print).foldLeft(""){ (a, b) => a + b };
+ val bplFilename = if (vsMode) "c:\\tmp\\out.bpl" else (if (params.noBplFile) "stdin.bpl" else "out.bpl")
+ if (!params.noBplFile) writeFile(bplFilename, bplText);
+ // run Boogie.exe on out.bpl
+ val boogie = Runtime.getRuntime.exec(boogiePath + " /errorTrace:0 " + boogieArgs + bplFilename);
+ if (params.noBplFile) {
+ val output = boogie.getOutputStream()
+ output.write(bplText.getBytes)
+ output.close
+ }
+ // terminate boogie if interrupted
+ Runtime.getRuntime.addShutdownHook(new Thread(new Runnable() {
+ def run {
+ boogie.destroy
+ }
+ }))
+ // the process blocks until we exhaust input and error streams
+ new Thread(new Runnable() {
+ def run {
+ val err = new BufferedReader(new InputStreamReader(boogie.getErrorStream));
+ var line = err.readLine;
+ while(line!=null) {Console.err.println(line); Console.err.flush}
+ }
+ }).start;
+ val input = new BufferedReader(new InputStreamReader(boogie.getInputStream));
+ var line = input.readLine();
+ var previous_line = null: String;
+ val boogieOutput: ListBuffer[String] = new ListBuffer()
+ while (line!=null){
+ if (!smoke) {
+ Console.out.println(line);
+ Console.out.flush;
+ }
+ boogieOutput += line
+ previous_line = line;
+ line = input.readLine();
+ }
+ boogie.waitFor;
+ input.close;
+
+ // smoke test output
+ if (smoke) {
+ val output = SmokeTest.processBoogieOutput(boogieOutput.toList)
+ Console.out.println(output);
+ Console.out.flush;
+ }
+
+ // generate code
+ if(params.gen && (previous_line != null) && previous_line.endsWith(" 0 errors")) { // hack
+ generateCSharpCode(params, program)
+ }
} catch {
case e:InternalErrorException => {
- if (showFullStackTrace) {
+ if (params.showFullStackTrace) {
e.printStackTrace()
Console.err.println()
Console.err.println()
@@ -319,7 +378,7 @@ object Chalice {
return
}
case e:NotSupportedException => {
- if (showFullStackTrace) {
+ if (params.showFullStackTrace) {
e.printStackTrace()
Console.err.println()
Console.err.println()
@@ -328,60 +387,6 @@ object Chalice {
return
}
}
-
-
- // write to out.bpl
- val bplText = TranslatorPrelude.P + (bplProg map Boogie.Print).foldLeft(""){ (a, b) => a + b };
- val bplFilename = if (vsMode) "c:\\tmp\\out.bpl" else "out.bpl"
- writeFile(bplFilename, bplText);
- // run Boogie.exe on out.bpl
- val boogie = Runtime.getRuntime.exec(boogiePath + " /errorTrace:0 " + boogieArgs + bplFilename);
- // terminate boogie if interrupted
- Runtime.getRuntime.addShutdownHook(new Thread(new Runnable() {
- def run {
- try {
- val kill = Runtime.getRuntime.exec("taskkill /T /F /IM Boogie.exe");
- kill.waitFor;
- } catch {case _ => }
- // just to be sure
- boogie.destroy
- }
- }))
- // the process blocks until we exhaust input and error streams
- new Thread(new Runnable() {
- def run {
- val err = new BufferedReader(new InputStreamReader(boogie.getErrorStream));
- var line = err.readLine;
- while(line!=null) {Console.err.println(line); Console.err.flush}
- }
- }).start;
- val input = new BufferedReader(new InputStreamReader(boogie.getInputStream));
- var line = input.readLine();
- var previous_line = null: String;
- val boogieOutput: ListBuffer[String] = new ListBuffer()
- while (line!=null){
- if (!smoke) {
- Console.out.println(line);
- Console.out.flush;
- }
- boogieOutput += line
- previous_line = line;
- line = input.readLine();
- }
- boogie.waitFor;
- input.close;
-
- // smoke test output
- if (smoke) {
- val output = SmokeTest.processBoogieOutput(boogieOutput.toList)
- Console.out.println(output);
- Console.out.flush;
- }
-
- // generate code
- if(params.gen && (previous_line != null) && previous_line.endsWith(" 0 errors")) { // hack
- generateCSharpCode(params, program)
- }
}
def generateCSharpCode(params: CommandLineParameters, program: List[TopLevelDecl]): Unit = {
diff --git a/Chalice/src/main/scala/Prelude.scala b/Chalice/src/main/scala/Prelude.scala
index 3c24d8b2..721b0131 100644
--- a/Chalice/src/main/scala/Prelude.scala
+++ b/Chalice/src/main/scala/Prelude.scala
@@ -73,6 +73,7 @@ type PermissionComponent;
const unique perm$R: PermissionComponent;
const unique perm$N: PermissionComponent;
var Mask: MaskType where IsGoodMask(Mask);
+var SecMask: MaskType where IsGoodMask(SecMask);
const Permission$denominator: int;
axiom Permission$denominator > 0;
const Permission$FullFraction: int;
@@ -136,12 +137,14 @@ object CreditsAndMuPL extends PreludeComponent {
val text = """
var Credits: CreditsType;
-function IsGoodState<T>(T) returns (bool);
-function combine<T,U>(T, U) returns (T);
-const nostate: HeapType;
+function IsGoodState(PartialHeapType) returns (bool);
+function combine(PartialHeapType, PartialHeapType) returns (PartialHeapType);
+function heapFragment<T>(T) returns (PartialHeapType);
+type PartialHeapType;
+const emptyPartialHeap: PartialHeapType;
-axiom (forall<T,U> a: T, b: U :: {IsGoodState(combine(a, b))} IsGoodState(combine(a, b)) <==> IsGoodState(a) && IsGoodState(b));
-axiom IsGoodState(nostate);
+axiom (forall a: PartialHeapType, b: PartialHeapType :: {IsGoodState(combine(a, b))} IsGoodState(combine(a, b)) <==> IsGoodState(a) && IsGoodState(b));
+axiom IsGoodState(emptyPartialHeap);
type ModuleName;
const CurrentModule: ModuleName;
@@ -165,25 +168,39 @@ axiom (forall m, n: Mu :: MuBelow(m, n) ==> n != $LockBottom);
const unique held: Field int;
function Acquire$Heap(int) returns (HeapType);
function Acquire$Mask(int) returns (MaskType);
+function Acquire$SecMask(int) returns (MaskType);
function Acquire$Credits(int) returns (CreditsType);
axiom NonPredicateField(held);
function LastSeen$Heap(Mu, int) returns (HeapType);
function LastSeen$Mask(Mu, int) returns (MaskType);
+function LastSeen$SecMask(Mu, int) returns (MaskType);
function LastSeen$Credits(Mu, int) returns (CreditsType);
const unique rdheld: Field bool;
axiom NonPredicateField(rdheld);
-function wf(h: HeapType, m: MaskType) returns (bool);
+function wf(h: HeapType, m: MaskType, sm: MaskType) returns (bool);
function IsGoodInhaleState(ih: HeapType, h: HeapType,
- m: MaskType) returns (bool)
+ m: MaskType, sm: MaskType) returns (bool)
{
- (forall<T> o: ref, f: Field T :: { ih[o, f] } CanRead(m, o, f) ==> ih[o, f] == h[o, f]) &&
+ (forall<T> o: ref, f: Field T :: { ih[o, f] } CanRead(m, sm, o, f) ==> ih[o, f] == h[o, f]) &&
(forall o: ref :: { ih[o, held] } (0<ih[o, held]) == (0<h[o, held])) &&
(forall o: ref :: { ih[o, rdheld] } ih[o, rdheld] == h[o, rdheld]) &&
(forall o: ref :: { h[o, held] } (0<h[o, held]) ==> ih[o, mu] == h[o, mu]) &&
(forall o: ref :: { h[o, rdheld] } h[o, rdheld] ==> ih[o, mu] == h[o, mu])
+}
+function IsGoodExhaleState(eh: HeapType, h: HeapType,
+ m: MaskType, sm: MaskType) returns (bool)
+{
+ (forall<T> o: ref, f: Field T :: { eh[o, f] } CanRead(m, sm, o, f) ==> eh[o, f] == h[o, f]) &&
+ (forall o: ref :: { eh[o, held] } (0<eh[o, held]) == (0<h[o, held])) &&
+ (forall o: ref :: { eh[o, rdheld] } eh[o, rdheld] == h[o, rdheld]) &&
+ (forall o: ref :: { h[o, held] } (0<h[o, held]) ==> eh[o, mu] == h[o, mu]) &&
+ (forall o: ref :: { h[o, rdheld] } h[o, rdheld] ==> eh[o, mu] == h[o, mu]) &&
+ (forall o: ref :: { h[o, forkK] } { eh[o, forkK] } h[o, forkK] == eh[o, forkK]) &&
+ (forall o: ref :: { h[o, held] } { eh[o, held] } h[o, held] == eh[o, held]) &&
+ (forall o: ref, f: Field int :: { eh[o, f], PredicateField(f) } PredicateField(f) ==> h[o, f] <= eh[o, f])
}"""
}
object PermissionFunctionsAndAxiomsPL extends PreludeComponent {
@@ -192,7 +209,12 @@ object PermissionFunctionsAndAxiomsPL extends PreludeComponent {
// -- Permissions ------------------------------------------------
// ---------------------------------------------------------------
-function {:expand false} CanRead<T>(m: MaskType, obj: ref, f: Field T) returns (bool)
+function {:expand false} CanRead<T>(m: MaskType, sm: MaskType, obj: ref, f: Field T) returns (bool)
+{
+ 0 < m[obj,f][perm$R] || 0 < m[obj,f][perm$N] ||
+ 0 < sm[obj,f][perm$R] || 0 < sm[obj,f][perm$N]
+}
+function {:expand false} CanReadForSure<T>(m: MaskType, obj: ref, f: Field T) returns (bool)
{
0 < m[obj,f][perm$R] || 0 < m[obj,f][perm$N]
}
@@ -210,7 +232,7 @@ function {:expand true} IsGoodMask(m: MaskType) returns (bool)
(m[o,f][perm$N] < 0 ==> 0 < m[o,f][perm$R]))
}
-axiom (forall h: HeapType, m: MaskType, o: ref, q: ref :: {wf(h, m), h[o, mu], h[q, mu]} wf(h, m) && o!=q && (0 < h[o, held] || h[o, rdheld]) && (0 < h[q, held] || h[q, rdheld]) ==> h[o, mu] != h[q, mu]);
+axiom (forall h: HeapType, m, sm: MaskType, o: ref, q: ref :: {wf(h, m, sm), h[o, mu], h[q, mu]} wf(h, m, sm) && o!=q && (0 < h[o, held] || h[o, rdheld]) && (0 < h[q, held] || h[q, rdheld]) ==> h[o, mu] != h[q, mu]);
function DecPerm<T>(m: MaskType, o: ref, f: Field T, howMuch: int) returns (MaskType);
@@ -244,6 +266,7 @@ axiom (forall<T,U> h: HeapType, o: ref, f: Field T, newValue: U, q: ref, g: Fiel
function Call$Heap(int) returns (HeapType);
function Call$Mask(int) returns (MaskType);
+function Call$SecMask(int) returns (MaskType);
function Call$Credits(int) returns (CreditsType);
function Call$Args(int) returns (ArgSeq);
type ArgSeq = <T>[int]T;
diff --git a/Chalice/src/main/scala/PrettyPrinter.scala b/Chalice/src/main/scala/PrettyPrinter.scala
index ac9ebd2f..18557b99 100644
--- a/Chalice/src/main/scala/PrettyPrinter.scala
+++ b/Chalice/src/main/scala/PrettyPrinter.scala
@@ -258,6 +258,7 @@ object PrintProgram {
}
def Expr(e: Expression): Unit = Expr(e, 0, false)
def Expr(e: Expression, contextBindingPower: Int, fragileContext: Boolean): Unit = e match {
+ case BoogieExpr(_) => throw new InternalErrorException("unexpected in pretty printer")
case IntLiteral(n) => print(n)
case BoolLiteral(b) => print(b)
case NullLiteral() => print("null")
diff --git a/Chalice/src/main/scala/Resolver.scala b/Chalice/src/main/scala/Resolver.scala
index dee231c8..7f5b3ecf 100644
--- a/Chalice/src/main/scala/Resolver.scala
+++ b/Chalice/src/main/scala/Resolver.scala
@@ -54,6 +54,15 @@ object Resolver {
}
def Resolve(prog: List[TopLevelDecl]): ResolverOutcome = {
+
+ // check for deprecates and/or unsupported constructs
+ var refinements = false
+ prog map (_ match {
+ case c: Class => if (c.IsRefinement) refinements = true
+ case _ => }
+ )
+ if (refinements) throw new NotSupportedException("stepwise refinements are currently not supported")
+
// register the channels as well as the classes and their members
var decls = Map[String,TopLevelDecl]()
for (decl <- BoolClass :: IntClass :: RootClass :: NullClass :: StringClass :: MuClass :: prog) {
@@ -900,6 +909,8 @@ object Resolver {
mx.typ = MuClass
case mx:LockBottomLiteral =>
mx.typ = MuClass
+ case _:BoogieExpr =>
+ throw new InternalErrorException("boogie expression unexpected here")
case r:Result =>
assert(context.currentMember!=null);
r.typ = IntClass
@@ -1237,6 +1248,7 @@ object Resolver {
case _:VariableExpr =>
case _:ThisExpr =>
case _:Result =>
+ case _:BoogieExpr =>
case MemberAccess(e, id) =>
CheckRunSpecification(e, context, false)
case Frac(perm) => CheckRunSpecification(perm, context, false)
diff --git a/Chalice/src/main/scala/Translator.scala b/Chalice/src/main/scala/Translator.scala
index b2dd9fa0..95996ee9 100644
--- a/Chalice/src/main/scala/Translator.scala
+++ b/Chalice/src/main/scala/Translator.scala
@@ -19,7 +19,7 @@ class Translator {
var currentClass = null: Class;
var modules = Nil: List[String]
var etran = new ExpressionTranslator(null);
-
+
def translateProgram(decls: List[TopLevelDecl]): List[Decl] = {
decls flatMap {
case cl: Class => translateClass(cl)
@@ -45,6 +45,7 @@ class Translator {
declarations = declarations ::: translateMonitorInvariant(cl.MonitorInvariants, cl.pos);
// translate each member
for(member <- cl.members) {
+ etran.fpi.reset
declarations = declarations ::: translateMember(member);
}
declarations
@@ -99,9 +100,13 @@ class Translator {
}
def translateMonitorInvariant(invs: List[MonitorInvariant], pos: Position): List[Decl] = {
- val (h0V, h0) = NewBVar("h0", theap, true); val (m0V, m0) = NewBVar("m0", tmask, true);
+ val (h0V, h0) = NewBVar("h0", theap, true);
+ val (m0V, m0) = NewBVar("m0", tmask, true);
+ val (sm0V, sm0) = NewBVar("sm0", tmask, true);
val (c0V, c0) = NewBVar("c0", tcredits, true);
- val (h1V, h1) = NewBVar("h1", theap, true); val (m1V, m1) = NewBVar("m1", tmask, true);
+ val (h1V, h1) = NewBVar("h1", theap, true);
+ val (m1V, m1) = NewBVar("m1", tmask, true);
+ val (sm1V, sm1) = NewBVar("sm1", tmask, true);
val (c1V, c1) = NewBVar("c1", tcredits, true);
val (lkV, lk) = NewBVar("lk", tref, true);
@@ -109,21 +114,20 @@ class Translator {
val (methodKV, methodK) = Boogie.NewBVar("methodK", tint, true)
val methodKStmts = BLocal(methodKV) :: bassume(0 < methodK && 1000*methodK < permissionOnePercent)
- val oldTranslator = new ExpressionTranslator(List(h1, m1, c1), List(h0, m0, c0), currentClass);
+ val oldTranslator = new ExpressionTranslator(Globals(h1, m1, sm1, c1), Globals(h0, m0, sm0, c0), currentClass);
Proc(currentClass.id + "$monitorinvariant$checkDefinedness",
List(NewBVarWhere("this", new Type(currentClass))),
Nil,
GlobalNames,
DefaultPrecondition(),
methodKStmts :::
- BLocal(h0V) :: BLocal(m0V) :: BLocal(c0V) :: BLocal(h1V) :: BLocal(m1V) :: BLocal(c1V) :: BLocal(lkV) ::
- bassume(wf(h0, m0)) :: bassume(wf(h1, m1)) ::
- (oldTranslator.Mask := ZeroMask) :: (oldTranslator.Credits := ZeroCredits) ::
+ BLocal(h0V) :: BLocal(m0V) :: BLocal(sm0V) :: BLocal(c0V) :: BLocal(h1V) :: BLocal(m1V) :: BLocal(sm1V) :: BLocal(c1V) :: BLocal(lkV) ::
+ bassume(wf(h0, m0, sm0)) :: bassume(wf(h1, m1, sm1)) ::
+ resetState(oldTranslator) :::
oldTranslator.Inhale(invs map { mi => mi.e}, "monitor invariant", false, methodK) :::
- (etran.Mask := ZeroMask) :: (etran.Credits := ZeroCredits) ::
- Havoc(etran.Heap) ::
+ resetState(etran) :::
// check that invariant is well-defined
- etran.WhereOldIs(h1, m1, c1).Inhale(invs map { mi => mi.e}, "monitor invariant", true, methodK) :::
+ etran.WhereOldIs(h1, m1, sm1, c1).Inhale(invs map { mi => mi.e}, "monitor invariant", true, methodK) :::
// smoke test: is the monitor invariant equivalent to false?
(if (Chalice.smoke) {
val a = SmokeTest.initSmokeAssert(pos, "Monitor invariant is equivalent to false.")
@@ -164,7 +168,7 @@ class Translator {
val functionKStmts = BLocal(functionKV) :: bassume(0 < functionK && 1000*functionK < permissionOnePercent)
// Boogie function that represents the Chalice function
- Boogie.Function(functionName(f), BVar("heap", theap) :: BVar("mask", tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar), BVar("$myresult", f.out.typ)) ::
+ Boogie.Function(functionName(f), BVar("heap", theap) :: BVar("this", tref) :: (f.ins map Variable2BVar), BVar("$myresult", f.out.typ)) ::
// check definedness of the function's precondition and body
Proc(f.FullName + "$checkDefinedness",
NewBVarWhere("this", new Type(currentClass)) :: (f.ins map {i => Variable2BVarWhere(i)}),
@@ -198,12 +202,19 @@ class Translator {
// postcondition axiom(s)
postconditionAxiom(f)
}
-
+
def definitionAxiom(f: Function, definition: Expression): List[Decl] = {
- val inArgs = (f.ins map {i => Boogie.VarExpr(i.UniqueName)});
- val args = VarExpr("this") :: inArgs;
- val formals = BVar(HeapName, theap) :: BVar(MaskName, tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar);
- val applyF = FunctionApp(functionName(f), List(etran.Heap, etran.Mask) ::: args);
+ val inArgs = (f.ins map {i => Boogie.VarExpr(i.UniqueName)})
+ val thisArg = VarExpr("this")
+ val args = thisArg :: inArgs;
+
+ val formalsNoMask = BVar(HeapName, theap) :: BVar("this", tref) :: (f.ins map Variable2BVar)
+ val formals = BVar(MaskName, tmask) :: BVar(SecMaskName, tmask) :: formalsNoMask
+ val applyF = FunctionApp(functionName(f), List(etran.Heap) ::: args);
+ val limitedApplyF = FunctionApp(functionName(f) + "#limited", List(etran.Heap) ::: args)
+ val pre = Preconditions(f.spec).foldLeft(BoolLiteral(true): Expression)({ (a, b) => And(a, b) });
+ val wellformed = wf(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName))
+ val triggers = f.dependentPredicates map (p => new Trigger(List(limitedApplyF, wellformed, FunctionApp("#" + p.FullName+"#trigger", thisArg :: Nil))))
/** Limit application of the function by introducing a second (limited) function */
val body = etran.Tr(
@@ -226,23 +237,23 @@ class Translator {
}
);
- /* axiom (forall h: HeapType, m: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
- wf(h, m) && CurrentModule == module#C ==> #C.f(h, m, this, x_1, ..., x_n) == tr(body))
- */
- Axiom(new Boogie.Forall(
- formals, new Trigger(applyF),
- (wf(VarExpr(HeapName), VarExpr(MaskName)) && (CurrentModule ==@ ModuleName(currentClass)))
+ /* axiom (forall h: HeapType, m, sm: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
+ wf(h, m, sm) && CurrentModule == module#C ==> #C.f(h, m, this, x_1, ..., x_n) == tr(body))
+ */
+ Axiom(new Boogie.Forall(Nil,
+ formals, List(new Trigger(List(applyF,wellformed))),
+ (wellformed && (CurrentModule ==@ ModuleName(currentClass)) && etran.TrAll(pre))
==>
(applyF ==@ body))) ::
(if (f.isRecursive)
// define the limited function (even for unlimited function since its SCC might have limited functions)
- Boogie.Function(functionName(f) + "#limited", formals, BVar("$myresult", f.out.typ)) ::
- Axiom(new Boogie.Forall(
- formals, new Trigger(applyF),
- applyF ==@ FunctionApp(functionName(f) + "#limited", List(etran.Heap, etran.Mask) ::: args))) ::
+ Boogie.Function(functionName(f) + "#limited", formalsNoMask, BVar("$myresult", f.out.typ)) ::
+ Axiom(new Boogie.Forall(Nil, formals,
+ new Trigger(List(applyF,wellformed)) :: triggers,
+ (wellformed ==> (applyF ==@ limitedApplyF)))) ::
Nil
else
- Nil)
+ Nil)
}
def framingAxiom(f: Function): List[Decl] = {
@@ -251,67 +262,72 @@ class Translator {
pre visit {_ match {case _: AccessSeq => hasAccessSeq = true; case _ => }}
if (!hasAccessSeq) {
- // Encoding with nostate and combine
+ // Encoding with heapFragment and combine
/* function ##C.f(state, ref, t_1, ..., t_n) returns (t);
- axiom (forall h: HeapType, m: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
- wf(h, m) && IsGoodState(version) ==> #C.f(h, m, this, x_1, ..., x_n) == ##C.f(version, this, x_1, ..., x_n))
+ axiom (forall h: HeapType, m, sm: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
+ wf(h, m, sm) && IsGoodState(partialHeap) ==> #C.f(h, m, sm, this, x_1, ..., x_n) == ##C.f(partialHeap, this, x_1, ..., x_n))
*/
- // make sure version is of HeapType
- val version = Boogie.FunctionApp("combine", List("nostate", Version(pre, etran)));
+ val partialHeap = functionDependencies(pre, etran);
val inArgs = (f.ins map {i => Boogie.VarExpr(i.UniqueName)});
val frameFunctionName = "#" + functionName(f);
val args = VarExpr("this") :: inArgs;
- val applyF = FunctionApp(functionName(f) + (if (f.isRecursive) "#limited" else ""), List(etran.Heap, etran.Mask) ::: args);
- val applyFrameFunction = FunctionApp(frameFunctionName, version :: args);
- Boogie.Function(frameFunctionName, Boogie.BVar("state", theap) :: Boogie.BVar("this", tref) :: (f.ins map Variable2BVar), new BVar("$myresult", f.out.typ)) ::
+ val applyF = FunctionApp(functionName(f) + (if (f.isRecursive) "#limited" else ""), List(etran.Heap) ::: args);
+ val applyFrameFunction = FunctionApp(frameFunctionName, partialHeap :: args)
+ val wellformed = wf(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName))
+
+ Boogie.Function(frameFunctionName, Boogie.BVar("state", tpartialheap) :: Boogie.BVar("this", tref) :: (f.ins map Variable2BVar), new BVar("$myresult", f.out.typ)) ::
Axiom(new Boogie.Forall(
- BVar(HeapName, theap) :: BVar(MaskName, tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar),
- new Trigger(applyF),
- (wf(VarExpr(HeapName), VarExpr(MaskName)) && IsGoodState(version) && CanAssumeFunctionDefs)
+ BVar(HeapName, theap) :: BVar(MaskName, tmask) :: BVar(SecMaskName, tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar),
+ new Trigger(List(applyF, wellformed)),
+ (wellformed && IsGoodState(partialHeap) && CanAssumeFunctionDefs)
==>
(applyF ==@ applyFrameFunction))
)
} else {
// Encoding with universal quantification over two heaps
- /* axiom (forall h1, h2: HeapType, m1, m2: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
- wf(h1,m1) && wf(h2,m2) && version(h1, h2, #C.f) ==>
- #C.f(h1, m1, this, x_1, ..., x_n) == #C.f(h2, m2, this, x_1, ..., x_n)
+ /* axiom (forall h1, h2: HeapType, m1, m2, sm1, sm2: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
+ wf(h1,m1,sm1) && wf(h2,m2,sm1) && functionDependenciesEqual(h1, h2, #C.f) ==>
+ #C.f(h1, m1, sm1, this, x_1, ..., x_n) == #C.f(h2, m2, sm2, this, x_1, ..., x_n)
*/
var args = VarExpr("this") :: (f.ins map {i => Boogie.VarExpr(i.UniqueName)});
// create two heaps
- val globals1 = etran.FreshGlobals("a"); val etran1 = new ExpressionTranslator(globals1 map {v => new Boogie.VarExpr(v)}, currentClass);
- val globals2 = etran.FreshGlobals("b"); val etran2 = new ExpressionTranslator(globals2 map {v => new Boogie.VarExpr(v)}, currentClass);
- val List(heap1, mask1, _) = globals1;
- val List(heap2, mask2, _) = globals2;
- val apply1 = FunctionApp(functionName(f), etran1.Heap :: etran1.Mask :: args);
- val apply2 = FunctionApp(functionName(f), etran2.Heap :: etran2.Mask :: args);
+ val (globals1V, globals1) = etran.FreshGlobals("a"); val etran1 = new ExpressionTranslator(globals1, currentClass);
+ val (globals2V, globals2) = etran.FreshGlobals("b"); val etran2 = new ExpressionTranslator(globals2, currentClass);
+ val List(heap1, mask1, secmask1, _) = globals1V;
+ val List(heap2, mask2, secmask2, _) = globals2V;
+ val apply1 = FunctionApp(functionName(f), etran1.Heap :: args)
+ val apply2 = FunctionApp(functionName(f), etran2.Heap :: args)
+ val wellformed1 = wf(etran1.Heap, etran1.Mask, etran1.SecMask)
+ val wellformed2 = wf(etran2.Heap, etran2.Mask, etran2.SecMask)
Axiom(new Boogie.Forall(
- heap1 :: heap2 :: mask1 :: mask2 :: BVar("this", tref) :: (f.ins map Variable2BVar),
- new Trigger(List(apply1, apply2)),
- ((wf(etran1.Heap, etran1.Mask) && wf(etran2.Heap, etran2.Mask) && Version(pre, etran1, etran2) && CanAssumeFunctionDefs)
+ heap1 :: heap2 :: mask1 :: mask2 :: secmask1 :: secmask2 :: BVar("this", tref) :: (f.ins map Variable2BVar),
+ new Trigger(List(apply1, apply2, wellformed1, wellformed2)),
+ (wellformed1 && wellformed2 && functionDependenciesEqual(pre, etran1, etran2) && CanAssumeFunctionDefs)
==>
- (apply1 ==@ apply2))
+ (apply1 ==@ apply2)
))
}
}
-
+
def postconditionAxiom(f: Function): List[Decl] = {
- /* axiom (forall h: HeapType, m: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
- wf(h, m) && CanAssumeFunctionDefs ==> Q[#C.f(h, m, this, x_1, ..., x_n)/result]
+ /* axiom (forall h: HeapType, m, sm: MaskType, this: ref, x_1: t_1, ..., x_n: t_n ::
+ wf(h, m, sm) && CanAssumeFunctionDefs ==> Q[#C.f(h, m, this, x_1, ..., x_n)/result]
*/
val inArgs = (f.ins map {i => Boogie.VarExpr(i.UniqueName)});
val myresult = Boogie.BVar("result", f.out.typ);
val args = VarExpr("this") :: inArgs;
- val applyF = FunctionApp(functionName(f), List(VarExpr(HeapName), VarExpr(MaskName)) ::: args)
+ val applyF = FunctionApp(functionName(f), List(VarExpr(HeapName)) ::: args)
+ val wellformed = wf(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName))
+
//postcondition axioms
(Postconditions(f.spec) map { post : Expression =>
Axiom(new Boogie.Forall(
- BVar(HeapName, theap) :: BVar(MaskName, tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar),
- new Trigger(applyF),
- (wf(VarExpr(HeapName), VarExpr(MaskName)) && CanAssumeFunctionDefs)
+ BVar(HeapName, theap) :: BVar(MaskName, tmask) :: BVar(SecMaskName, tmask) :: BVar("this", tref) :: (f.ins map Variable2BVar),
+ new Trigger(List(applyF, wellformed)),
+ (wellformed && CanAssumeFunctionDefs)
==>
etran.Tr(SubstResult(post, f.apply(ExplicitThisExpr(), f.ins map { arg => new VariableExpr(arg) })))
))
@@ -325,9 +341,11 @@ class Translator {
val predicateKStmts = BLocal(predicateKV) :: bassume(0 < predicateK && 1000*predicateK < permissionOnePercent)
// const unique class.name: HeapType;
- Const(pred.FullName, true, FieldType(theap)) ::
+ Const(pred.FullName, true, FieldType(tint)) ::
// axiom PredicateField(f);
Axiom(PredicateField(pred.FullName)) ::
+ // trigger function to unfold function definitions
+ Boogie.Function("#" + pred.FullName + "#trigger", BVar("this", tref) :: Nil, BVar("$myresult", tbool)) ::
// check definedness of predicate body
Proc(pred.FullName + "$checkDefinedness",
List(NewBVarWhere("this", new Type(currentClass))),
@@ -346,6 +364,7 @@ class Translator {
}
def translateMethod(method: Method): List[Decl] = {
+
// pick new k for this method, that represents the fraction for read permissions
val (methodKV, methodK) = Boogie.NewBVar("methodK", tint, true)
val methodKStmts = BLocal(methodKV) :: bassume(0 < methodK && 1000*methodK < permissionOnePercent)
@@ -362,12 +381,13 @@ class Translator {
// check precondition
InhaleWithChecking(Preconditions(method.spec), "precondition", methodK) :::
DefineInitialState :::
- (etran.Mask := ZeroMask) :: (etran.Credits := ZeroCredits) ::
- Havoc(etran.Heap) ::
+ resetState(etran) :::
// check postcondition
InhaleWithChecking(Postconditions(method.spec), "postcondition", methodK) :::
// check lockchange
(LockChanges(method.spec) flatMap { lc => isDefined(lc)})) ::
+ {
+ etran.fpi.reset
// check that method body satisfies the method contract
Proc(method.FullName,
NewBVarWhere("this", new Type(currentClass)) :: (method.ins map {i => Variable2BVarWhere(i)}),
@@ -385,6 +405,7 @@ class Translator {
(if(Chalice.checkLeaks) isLeaking(method.pos, "Method " + method.FullName + " might leak references.") else Nil) :::
bassert(LockFrame(LockChanges(method.spec), etran), method.pos, "Method might lock/unlock more than allowed.") :::
bassert(DebtCheck, method.pos, "Method body is not allowed to leave any debt."))
+ }
}
def translateMethodTransform(mt: MethodTransform): List[Decl] = {
@@ -421,8 +442,7 @@ class Translator {
// check precondition
InhaleWithChecking(Preconditions(mt.Spec) ::: preCI, "precondition", methodK) :::
DefineInitialState :::
- (etran.Mask := ZeroMask) :: (etran.Credits := ZeroCredits) ::
- Havoc(etran.Heap) ::
+ resetState(etran) :::
// check postcondition
InhaleWithChecking(Postconditions(mt.refines.Spec), "postcondition", methodK) :::
tag(InhaleWithChecking(postCI ::: Postconditions(mt.spec), "postcondition", methodK), keepTag)
@@ -458,18 +478,19 @@ class Translator {
def DefaultPrecondition() = {
"requires this!=null;" ::
- "free requires wf(Heap, Mask);" ::
+ "free requires wf(Heap, Mask, SecMask);" ::
Nil
}
def DefinePreInitialState = {
Comment("define pre-initial state") ::
- (etran.Mask := ZeroMask) :: (etran.Credits := ZeroCredits)
+ (etran.Mask := ZeroMask) :: (etran.SecMask := ZeroMask) :: (etran.Credits := ZeroCredits)
}
def DefineInitialState = {
Comment("define initial state") ::
bassume(etran.Heap ==@ Boogie.Old(etran.Heap)) ::
bassume(etran.Mask ==@ Boogie.Old(etran.Mask)) ::
+ bassume(etran.SecMask ==@ Boogie.Old(etran.SecMask)) ::
bassume(etran.Credits ==@ Boogie.Old(etran.Credits))
}
@@ -483,16 +504,12 @@ class Translator {
case a@Assert(e) =>
a.smokeErrorNr match {
case None =>
- val newGlobals = etran.FreshGlobals("assert");
- val tmpHeap = Boogie.NewBVar(HeapName, theap, true);
- val tmpMask = Boogie.NewBVar(MaskName, tmask, true);
- val tmpCredits = Boogie.NewBVar(CreditsName, tcredits, true);
- val tmpTranslator = new ExpressionTranslator(List(tmpHeap._1.id, tmpMask._1.id, tmpCredits._1.id), List(etran.ChooseEtran(true).Heap, etran.ChooseEtran(true).Mask, etran.ChooseEtran(true).Credits), currentClass);
+ val (tmpGlobalsV, tmpGlobals) = etran.FreshGlobals("assert");
+ val tmpTranslator = new ExpressionTranslator(tmpGlobals, etran.oldEtran.globals, currentClass);
Comment("assert") ::
// exhale e in a copy of the heap/mask/credits
- BLocal(tmpHeap._1) :: (tmpHeap._2 := etran.Heap) ::
- BLocal(tmpMask._1) :: (tmpMask._2 := etran.Mask) ::
- BLocal(tmpCredits._1) :: (tmpCredits._2 := etran.Credits) ::
+ BLocals(tmpGlobalsV) :::
+ copyState(tmpGlobals, etran) :::
tmpTranslator.Exhale(List((e, ErrorMessage(s.pos, "Assertion might not hold."))), "assert", true, methodK, true)
case Some(err) =>
bassert(e, a.pos, "SMOKE-TEST-" + err + ". ("+SmokeTest.smokeWarningMessage(err)+")", 0) :: Nil
@@ -504,13 +521,22 @@ class Translator {
case BlockStmt(ss) =>
translateStatements(ss, methodK)
case IfStmt(guard, then, els) =>
+ val (condV, cond) = Boogie.NewBVar("cond", tbool, true)
+ val oldConditions = etran.fpi.currentConditions
+ etran.fpi.currentConditions += ((cond, true))
val tt = translateStatement(then, methodK)
val et = els match {
case None => Nil
- case Some(els) => translateStatement(els, methodK) }
+ case Some(els) =>
+ etran.fpi.currentConditions = oldConditions
+ etran.fpi.currentConditions += ((cond, false))
+ translateStatement(els, methodK)
+ }
Comment("if") ::
+ BLocal(condV) ::
+ (cond := etran.Tr(guard)) ::
isDefined(guard) :::
- Boogie.If(guard, tt, et)
+ Boogie.If(cond, tt, et)
case w: WhileStmt =>
translateWhile(w, methodK)
case Assign(lhs, rhs) =>
@@ -547,7 +573,7 @@ class Translator {
Comment("update field " + f) ::
isDefined(target) :::
bassert(CanWrite(target, lhs.f), s.pos, "Location might not be writable") ::
- statements ::: etran.Heap.store(target, lhs.f, toStore) :: bassume(wf(VarExpr(HeapName), VarExpr(MaskName)))
+ statements ::: etran.Heap.store(target, lhs.f, toStore) :: bassume(wf(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName)))
case lv : LocalVar =>
translateLocalVarDecl(lv.v, false) :::
{ lv.rhs match {
@@ -572,12 +598,12 @@ class Translator {
bassert(nonNull(obj), s.pos, "The target of the share statement might be null.") ::
UpdateMu(obj, true, false, lowerBounds, upperBounds, ErrorMessage(s.pos, "Share might fail.")) :::
bassume(!isHeld(obj) && ! isRdHeld(obj)) :: // follows from o.mu==lockbottom
- // exhale the monitor invariant (using the current state as the old state)
- ExhaleInvariants(obj, false, ErrorMessage(s.pos, "Monitor invariant might not hold."), etran.UseCurrentAsOld(), methodK) :::
// assume a seen state is the one right before the share
bassume(LastSeenHeap(etran.Heap.select(obj, "mu"), etran.Heap.select(obj, "held")) ==@ etran.Heap) ::
bassume(LastSeenMask(etran.Heap.select(obj, "mu"), etran.Heap.select(obj, "held")) ==@ preShareMask) ::
- bassume(LastSeenCredits(etran.Heap.select(obj, "mu"), etran.Heap.select(obj, "held")) ==@ etran.Credits)
+ bassume(LastSeenCredits(etran.Heap.select(obj, "mu"), etran.Heap.select(obj, "held")) ==@ etran.Credits) ::
+ // exhale the monitor invariant (using the current state as the old state)
+ ExhaleInvariants(obj, false, ErrorMessage(s.pos, "Monitor invariant might not hold."), etran.UseCurrentAsOld(), methodK)
case Unshare(obj) =>
val (heldV, held) = Boogie.NewBVar("held", Boogie.NamedType("int"), true)
val o = TrExpr(obj)
@@ -657,19 +683,30 @@ class Translator {
case fold@Fold(acc@Access(pred@MemberAccess(e, f), perm)) =>
val o = TrExpr(e);
var definition = scaleExpressionByPermission(SubstThis(DefinitionOf(pred.predicate), e), perm, fold.pos)
+ val (receiverV, receiver) = Boogie.NewBVar("predRec", tref, true)
+ val (versionV, version) = Boogie.NewBVar("predVer", tint, true)
+ val (flagV, flag) = Boogie.NewBVar("predFlag", tbool, true)
// pick new k
val (foldKV, foldK) = Boogie.NewBVar("foldK", tint, true)
- Comment("fold") ::
+ val stmts = Comment("fold") ::
+ functionTrigger(o, pred.predicate) ::
BLocal(foldKV) :: bassume(0 < foldK && 1000*foldK < percentPermission(1) && 1000*foldK < methodK) ::
isDefined(e) :::
isDefined(perm) :::
bassert(nonNull(o), s.pos, "The target of the fold statement might be null.") ::
// remove the definition from the current state, and replace by predicate itself
- Exhale(List((definition, ErrorMessage(s.pos, "Fold might fail because the definition of " + pred.predicate.FullName + " does not hold."))), "fold", foldK, false) :::
+ etran.ExhaleAndTransferToSecMask(List((definition, ErrorMessage(s.pos, "Fold might fail because the definition of " + pred.predicate.FullName + " does not hold."))), "fold", foldK, false) :::
Inhale(List(acc), "fold", foldK) :::
- etran.Heap.store(o, pred.predicate.FullName, etran.Heap) :: // Is this necessary?
- bassume(wf(etran.Heap, etran.Mask))
+ BLocal(receiverV) :: (receiver := o) ::
+ BLocal(versionV) :: (version := etran.Heap.select(o, pred.predicate.FullName)) ::
+ BLocal(flagV) :: (flag := true) ::
+ bassume(wf(etran.Heap, etran.Mask, etran.SecMask))
+
+ // record folded predicate
+ etran.fpi.addFoldedPredicate(FoldedPredicate(pred.predicate, receiver, version, etran.fpi.currentConditions, flag))
+
+ stmts
case unfld@Unfold(acc@Access(pred@MemberAccess(e, f), perm:Permission)) =>
val o = TrExpr(e);
val definition = scaleExpressionByPermission(SubstThis(DefinitionOf(pred.predicate), e), perm, unfld.pos)
@@ -677,12 +714,13 @@ class Translator {
// pick new k
val (unfoldKV, unfoldK) = Boogie.NewBVar("unfoldK", tint, true)
Comment("unfold") ::
+ functionTrigger(o, pred.predicate) ::
BLocal(unfoldKV) :: bassume(0 < unfoldK && unfoldK < percentPermission(1) && 1000*unfoldK < methodK) ::
isDefined(e) :::
bassert(nonNull(o), s.pos, "The target of the fold statement might be null.") ::
isDefined(perm) :::
- Exhale(List((acc, ErrorMessage(s.pos, "unfold might fail because the predicate " + pred.predicate.FullName + " does not hold."))), "unfold", unfoldK, false) :::
- etran.InhaleFrom(List(definition), "unfold", false, etran.Heap.select(o, pred.predicate.FullName), unfoldK)
+ ExhaleDuringUnfold(List((acc, ErrorMessage(s.pos, "unfold might fail because the predicate " + pred.predicate.FullName + " does not hold."))), "unfold", unfoldK, false) :::
+ etran.Inhale(List(definition), "unfold", false, unfoldK)
case c@CallAsync(declaresLocal, token, obj, id, args) =>
val formalThisV = new Variable("this", new Type(c.m.Parent))
val formalThis = new VariableExpr(formalThisV)
@@ -693,6 +731,7 @@ class Translator {
val (asyncStateV,asyncState) = NewBVar("asyncstate", tint, true)
val (preCallHeapV, preCallHeap) = NewBVar("preCallHeap", theap, true)
val (preCallMaskV, preCallMask) = NewBVar("preCallMask", tmask, true)
+ val (preCallSecMaskV, preCallSecMask) = NewBVar("preCallSecMask", tmask, true)
val (preCallCreditsV, preCallCredits) = NewBVar("preCallCredits", tcredits, true)
val (argsSeqV, argsSeq) = NewBVar("argsSeq", tArgSeq, true)
val argsSeqLength = 1 + args.length;
@@ -710,6 +749,7 @@ class Translator {
// remember the value of the heap/mask/credits
BLocal(preCallHeapV) :: (preCallHeap := etran.Heap) ::
BLocal(preCallMaskV) :: (preCallMask := etran.Mask) ::
+ BLocal(preCallSecMaskV) :: (preCallSecMask := etran.SecMask) ::
BLocal(preCallCreditsV) :: (preCallCredits := etran.Credits) ::
BLocal(argsSeqV) ::
// introduce formal parameters and pre-state globals
@@ -744,11 +784,12 @@ class Translator {
// assume the pre call state for the token is the state before inhaling the precondition
bassume(CallHeap(asyncState) ==@ preCallHeap) ::
bassume(CallMask(asyncState) ==@ preCallMask) ::
+ bassume(CallSecMask(asyncState) ==@ preCallSecMask) ::
bassume(CallCredits(asyncState) ==@ preCallCredits) ::
bassume(CallArgs(asyncState) ==@ argsSeq) :::
// assign the returned token to the variable
{ if (token != null) List(token := tokenId) else List() } :::
- bassume(wf(VarExpr(HeapName), VarExpr(MaskName))) :: Nil
+ bassume(wf(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName))) :: Nil
case jn@JoinAsync(lhs, token) =>
val formalThisV = new Variable("this", new Type(jn.m.Parent))
val formalThis = new VariableExpr(formalThisV)
@@ -760,9 +801,9 @@ class Translator {
val (argsSeqV, argsSeq) = NewBVar("argsSeq", tArgSeq, true)
val (preCallHeapV, preCallHeap) = NewBVar("preCallHeap", theap, true);
val (preCallMaskV, preCallMask) = NewBVar("preCallMask", tmask, true);
+ val (preCallSecMaskV, preCallSecMask) = NewBVar("preCallSecMask", tmask, true);
val (preCallCreditsV, preCallCredits) = NewBVar("preCallCredits", tcredits, true);
- val preGlobals = List(preCallHeap, preCallMask, preCallCredits);
- val postEtran = new ExpressionTranslator(List(etran.Heap, etran.Mask, etran.Credits), preGlobals, currentClass);
+ val postEtran = new ExpressionTranslator(etran.globals, Globals(preCallHeap, preCallMask, preCallSecMask, preCallCredits), currentClass);
val (asyncJoinKV, asyncJoinK) = Boogie.NewBVar("asyncJoinK", tint, true)
Comment("join async") ::
@@ -781,6 +822,7 @@ class Translator {
// retrieve the call's pre-state from token.joinable
BLocal(preCallHeapV) :: (preCallHeap := CallHeap(etran.Heap.select(token, "joinable"))) ::
BLocal(preCallMaskV) :: (preCallMask := CallMask(etran.Heap.select(token, "joinable"))) ::
+ BLocal(preCallSecMaskV) :: (preCallSecMask := CallSecMask(etran.Heap.select(token, "joinable"))) ::
BLocal(preCallCreditsV) :: (preCallCredits := CallCredits(etran.Heap.select(token, "joinable"))) ::
// introduce locals for the out parameters
(for (v <- formalThisV :: formalInsV ::: formalOutsV) yield BLocal(Variable2BVarWhere(v))) :::
@@ -917,10 +959,12 @@ class Translator {
InhaleInvariants(nonNullObj, false, etran.WhereOldIs(
LastSeenHeap(lastSeenMu, lastSeenHeld),
LastSeenMask(lastSeenMu, lastSeenHeld),
+ LastSeenSecMask(lastSeenMu, lastSeenHeld),
LastSeenCredits(lastSeenMu, lastSeenHeld)), currentK) :::
// remember values of Heap/Mask/Credits globals (for proving history constraint at release)
bassume(AcquireHeap(lastAcquire) ==@ etran.Heap) ::
bassume(AcquireMask(lastAcquire) ==@ etran.Mask) ::
+ bassume(AcquireSecMask(lastAcquire) ==@ etran.SecMask) ::
bassume(AcquireCredits(lastAcquire) ==@ etran.Credits)
}
def TrRelease(s: Statement, nonNullObj: Expression, currentK: Expr) = {
@@ -928,16 +972,19 @@ class Translator {
val (prevLmV, prevLm) = Boogie.NewBVar("prevLM", tref, true)
val (preReleaseHeapV, preReleaseHeap) = NewBVar("preReleaseHeap", theap, true)
val (preReleaseMaskV, preReleaseMask) = NewBVar("preReleaseMask", tmask, true)
+ val (preReleaseSecMaskV, preReleaseSecMask) = NewBVar("preReleaseSecMask", tmask, true)
val (preReleaseCreditsV, preReleaseCredits) = NewBVar("preReleaseCredits", tcredits, true)
val o = TrExpr(nonNullObj);
BLocal(preReleaseHeapV) :: (preReleaseHeap := etran.Heap) ::
BLocal(preReleaseMaskV) :: (preReleaseMask := etran.Mask) ::
+ BLocal(preReleaseSecMaskV) :: (preReleaseSecMask := etran.SecMask) ::
BLocal(preReleaseCreditsV) :: (preReleaseCredits := etran.Credits) ::
bassert(isHeld(o), s.pos, "The target of the release statement might not be locked by the current thread.") ::
bassert(!isRdHeld(o), s.pos, "Release might fail because the current thread might hold the read lock.") ::
ExhaleInvariants(nonNullObj, false, ErrorMessage(s.pos, "Monitor invariant might hot hold."), etran.WhereOldIs(
AcquireHeap(etran.Heap.select(o, "held")),
AcquireMask(etran.Heap.select(o, "held")),
+ AcquireSecMask(etran.Heap.select(o, "held")),
AcquireCredits(etran.Heap.select(o, "held"))), currentK) :::
// havoc o.held where 0<=o.held
BLocal(heldV) :: Havoc(held) :: bassume(held <= 0) ::
@@ -945,6 +992,7 @@ class Translator {
// assume a seen state is the one right before the share
bassume(LastSeenHeap(etran.Heap.select(o, "mu"), held) ==@ preReleaseHeap) ::
bassume(LastSeenMask(etran.Heap.select(o, "mu"), held) ==@ preReleaseMask) ::
+ bassume(LastSeenSecMask(etran.Heap.select(o, "mu"), held) ==@ preReleaseSecMask) ::
bassume(LastSeenCredits(etran.Heap.select(o, "mu"), held) ==@ preReleaseCredits)
}
def TrRdAcquire(s: Statement, nonNullObj: Expression, currentK: Expr) = {
@@ -970,7 +1018,7 @@ class Translator {
}
def translateSpecStmt(s: SpecStmt, methodK: Expr): List[Stmt] = {
- val preGlobals = etran.FreshGlobals("pre")
+ val (preGlobalsV, preGlobals) = etran.FreshGlobals("pre")
// pick new k for the spec stmt
val (specKV, specK) = Boogie.NewBVar("specStmtK", tint, true)
@@ -980,9 +1028,9 @@ class Translator {
// declare new local variables
s.locals.flatMap(v => translateLocalVarDecl(v, true)) :::
Comment("spec statement") ::
- (for (v <- preGlobals) yield BLocal(v)) :::
+ BLocals(preGlobalsV) :::
// remember values of globals
- (for ((o,g) <- preGlobals zip etran.Globals) yield (new Boogie.VarExpr(o) := g)) :::
+ copyState(preGlobals, etran) :::
// exhale preconditions
etran.Exhale(List((s.pre, ErrorMessage(s.pos, "The specification statement precondition at " + s.pos + " might not hold."))), "spec stmt precondition", true, specK, false) :::
// havoc locals
@@ -1002,7 +1050,7 @@ class Translator {
val formalIns = for (v <- formalInsV) yield new VariableExpr(v)
val formalOutsV = for (p <- c.m.Outs) yield new Variable(p.id, p.t)
val formalOuts = for (v <- formalOutsV) yield new VariableExpr(v)
- val preGlobals = etran.FreshGlobals("call")
+ val (preGlobalsV, preGlobals) = etran.FreshGlobals("call")
val postEtran = etran.FromPreGlobals(preGlobals)
// pick new k for this method call
@@ -1012,9 +1060,9 @@ class Translator {
Comment("call " + id) ::
// introduce formal parameters and pre-state globals
(for (v <- formalThisV :: formalInsV ::: formalOutsV) yield BLocal(Variable2BVarWhere(v))) :::
- (for (v <- preGlobals) yield BLocal(v)) :::
+ BLocals(preGlobalsV) :::
// remember values of globals
- (for ((o,g) <- preGlobals zip etran.Globals) yield (new Boogie.VarExpr(o) := g)) :::
+ copyState(preGlobals, etran) :::
// check definedness of arguments
isDefined(obj) :::
bassert(nonNull(obj), c.pos, "The target of the method call might be null.") ::
@@ -1043,9 +1091,9 @@ class Translator {
val lkch = w.lkch;
val body = w.body;
- val preLoopGlobals = etran.FreshGlobals("while")
+ val (preLoopGlobalsV, preLoopGlobals) = etran.FreshGlobals("while")
val loopEtran = etran.FromPreGlobals(preLoopGlobals)
- val iterStartGlobals = etran.FreshGlobals("iterStart")
+ val (iterStartGlobalsV, iterStartGlobals) = etran.FreshGlobals("iterStart")
val iterStartEtran = etran.FromPreGlobals(iterStartGlobals)
val saveLocalsV = for (v <- w.LoopTargets) yield new Variable(v.id, v.t)
val iterStartLocalsV = for (v <- w.LoopTargets) yield new Variable(v.id, v.t)
@@ -1057,16 +1105,15 @@ class Translator {
val iterStartLocks = lkchIterStart map (e => iterStartEtran.oldEtran.Tr(e))
val newLocks = lkch map (e => loopEtran.Tr(e));
val (whileKV, whileK) = Boogie.NewBVar("whileK", tint, true)
+ val previousEtran = etran // save etran
Comment("while") ::
// pick new k for this method call
BLocal(whileKV) ::
bassume(0 < whileK && 1000*whileK < percentPermission(1) && 1000*whileK < methodK) ::
// save globals
- (for (v <- preLoopGlobals) yield BLocal(v)) :::
- (loopEtran.oldEtran.Heap := loopEtran.Heap) ::
- (loopEtran.oldEtran.Mask := loopEtran.Mask) :: // oldMask is not actually used below
- (loopEtran.oldEtran.Credits := loopEtran.Credits) :: // is oldCredits?
+ BLocals(preLoopGlobalsV) :::
+ copyState(preLoopGlobals, loopEtran) :::
// check invariant on entry to the loop
Exhale(w.oldInvs map { inv => (inv, ErrorMessage(inv.pos, "The loop invariant might not hold on entry to the loop."))}, "loop invariant, initially", whileK, false) :::
tag(Exhale(w.newInvs map { inv => (inv, ErrorMessage(inv.pos, "The loop invariant might not hold on entry to the loop."))}, "loop invariant, initially", whileK, false), keepTag) :::
@@ -1083,26 +1130,26 @@ class Translator {
case _ => Boogie.Havoc(Boogie.VarExpr(v.UniqueName)) }) :: vars) :::
Boogie.If(null,
// 1. CHECK DEFINEDNESS OF INVARIANT
+ { etran = etran.resetFpi
Comment("check loop invariant definedness") ::
//(w.LoopTargets.toList map { v: Variable => Boogie.Havoc(Boogie.VarExpr(v.id)) }) :::
- Boogie.Havoc(etran.Heap) :: Boogie.Assign(etran.Mask, ZeroMask) :: Boogie.Assign(etran.Credits, ZeroCredits) ::
+ resetState(etran) :::
InhaleWithChecking(w.oldInvs, "loop invariant definedness", whileK) :::
tag(InhaleWithChecking(w.newInvs, "loop invariant definedness", whileK), keepTag) :::
- bassume(false)
+ bassume(false) }
, Boogie.If(null,
// 2. CHECK LOOP BODY
// Renew state: set Mask to ZeroMask and Credits to ZeroCredits, and havoc Heap everywhere except
// at {old(local),local}.{held,rdheld}
- Havoc(etran.Heap) :: (etran.Mask := ZeroMask) :: (etran.Credits := ZeroCredits) ::
+ { etran = etran.resetFpi
+ resetState(etran) :::
Inhale(w.Invs, "loop invariant, body", whileK) :::
// assume lockchange at the beginning of the loop iteration
Comment("assume lockchange at the beginning of the loop iteration") ::
(bassume(LockFrame(lkch, etran))) ::
// this is the state at the beginning of the loop iteration; save these values
- (for (v <- iterStartGlobals) yield BLocal(v)) :::
- (iterStartEtran.oldEtran.Heap := iterStartEtran.Heap) ::
- (iterStartEtran.oldEtran.Mask := iterStartEtran.Mask) :: // oldMask is not actually used below
- (iterStartEtran.oldEtran.Credits := iterStartEtran.Credits) :: // is oldCredits?
+ BLocals(iterStartGlobalsV) :::
+ copyState(iterStartGlobals, iterStartEtran) :::
(for (isv <- iterStartLocalsV) yield BLocal(Variable2BVarWhere(isv))) :::
(for ((v,isv) <- w.LoopTargets zip iterStartLocalsV) yield
(new VariableExpr(isv) := new VariableExpr(v))) :::
@@ -1118,22 +1165,23 @@ class Translator {
(bassert(LockFrame(lkch, etran), w.pos, "The loop might lock/unlock more than the lockchange clause allows.")) ::
// perform debt check
bassert(DebtCheck, w.pos, "Loop body is not allowed to leave any debt.") :::
- bassume(false),
+ bassume(false)},
// 3. AFTER LOOP
+ { etran = previousEtran
LockHavoc(oldLocks ++ newLocks, loopEtran) :::
// assume lockchange after the loop
Comment("assume lockchange after the loop") ::
(bassume(LockFrame(lkch, etran))) ::
Inhale(w.Invs, "loop invariant, after loop", whileK) :::
- bassume(!guard)))
+ bassume(!guard)}))
}
def translateRefinement(r: RefinementBlock, methodK: Expr): List[Stmt] = {
// abstract expression translator
val absTran = etran;
// concrete expression translate
- val conGlobals = etran.FreshGlobals("concrete")
- val conTran = new ExpressionTranslator(conGlobals map {v => new VarExpr(v)}, etran.oldEtran.Globals, currentClass);
+ val (conGlobalsV, conGlobals) = etran.FreshGlobals("concrete")
+ val conTran = new ExpressionTranslator(conGlobals, etran.oldEtran.globals, currentClass); // TODO: what about FoldedPredicateInfo?
// shared locals existing before the block (excluding immutable)
val before = for (v <- r.before; if (! v.isImmutable)) yield v;
// shared locals declared in the block
@@ -1145,8 +1193,8 @@ class Translator {
Comment("refinement block") ::
// save heap
- (for (c <- conGlobals) yield BLocal(c)) :::
- (for ((c, a) <- conGlobals zip etran.Globals) yield (new VarExpr(c) := a)) :::
+ BLocals(conGlobalsV) :::
+ copyState(conGlobals, etran) :::
// save shared local variables
(for (v <- beforeV) yield BLocal(Variable2BVarWhere(v))) :::
(for ((v, w) <- beforeV zip before) yield (new VariableExpr(v) := new VariableExpr(w))) :::
@@ -1162,14 +1210,14 @@ class Translator {
r.abs match {
case List(s: SpecStmt) =>
var (m, me) = NewBVar("specMask", tmask, true)
-
+ var (sm, sme) = NewBVar("specSecMask", tmask, true)
tag(
Comment("give witnesses to the declared local variables") ::
(for (v <- duringA) yield BLocal(Variable2BVarWhere(v))) :::
(for ((v, w) <- duringA zip duringC) yield (new VariableExpr(v) := new VariableExpr(w))) :::
- BLocal(m) ::
- (me := absTran.Mask) ::
- absTran.Exhale(s.post, me, absTran.Heap, ErrorMessage(r.pos, "Refinement may fail to satisfy the specification statement post-condition."), false, methodK, false, false) :::
+ BLocal(m) :: BLocal(sm) ::
+ (me := absTran.Mask) :: (sme := absTran.SecMask) ::
+ absTran.Exhale(me, sme, List((s.post,ErrorMessage(r.pos, "Refinement may fail to satisfy specification statement post-condition."))), "SpecStmt", false, methodK, false) :::
(for ((v, w) <- beforeV zip before; if (! s.lhs.exists(ve => ve.v == w))) yield
bassert(new VariableExpr(v) ==@ new VariableExpr(w), r.pos, "Refinement may change a variable outside of the frame of the specification statement: " + v.id)),
keepTag)
@@ -1388,6 +1436,7 @@ class Translator {
def Inhale(predicates: List[Expression], occasion: String, currentK: Expr): List[Boogie.Stmt] = etran.Inhale(predicates, occasion, false, currentK)
def Exhale(predicates: List[(Expression, ErrorMessage)], occasion: String, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = etran.Exhale(predicates, occasion, false, currentK, exactchecking)
+ def ExhaleDuringUnfold(predicates: List[(Expression, ErrorMessage)], occasion: String, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = etran.ExhaleDuringUnfold(predicates, occasion, false, currentK, exactchecking)
def InhaleWithChecking(predicates: List[Expression], occasion: String, currentK: Expr): List[Boogie.Stmt] = etran.Inhale(predicates, occasion, true, currentK)
def ExhaleWithChecking(predicates: List[(Expression, ErrorMessage)], occasion: String, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = etran.Exhale(predicates, occasion, true, currentK, exactchecking)
@@ -1399,60 +1448,98 @@ class Translator {
***************** EXPRESSIONS *****************
**********************************************************************/
-object ExpressionTranslator {
- val Globals = {
- ("Heap", theap) ::
- ("Mask", tmask) ::
- ("Credits", tcredits) ::
- Nil
+/** Represents a predicate that has been folded by ourselfs, or that we have peeked
+ * at using unfolding.
+ */
+case class FoldedPredicate(predicate: Predicate, receiver: Expr, version: Expr, conditions: Set[(VarExpr,Boolean)], flag: Expr)
+
+/** All information that we need to keep track of about folded predicates. */
+class FoldedPredicatesInfo {
+
+ private var foldedPredicates: List[FoldedPredicate] = List()
+ var currentConditions: Set[(VarExpr,Boolean)] = Set()
+
+ /** Add a predicate that we have folded */
+ def addFoldedPredicate(predicate: FoldedPredicate) {
+ foldedPredicates ::= predicate
}
+
+ /** Start again with the empty information about folded predicates. */
+ def reset {
+ foldedPredicates = List()
+ currentConditions = Set()
+ }
+
+ /** return a list of folded predicates that might match for predicate */
+ def getFoldedPredicates(predicate: Predicate): List[FoldedPredicate] = {
+ foldedPredicates filter (fp => fp.predicate.FullName == predicate.FullName)
+ }
+
+ /** get an upper bound on the recursion depth when updating the secondary mask */
+ def getRecursionBound(predicate: Predicate): Int = {
+ foldedPredicates length
+ }
+
+}
+object FoldedPredicatesInfo {
+ def apply() = new FoldedPredicatesInfo()
+}
+
+case class Globals(heap: Expr, mask: Expr, secmask: Expr, credits: Expr) {
+ def list: List[Expr] = List(heap, mask, secmask, credits)
}
-class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.Expr], currentClass: Class, checkTermination: Boolean) {
- assert(globals.size == 3)
- assert(preGlobals.size == 3)
+class ExpressionTranslator(val globals: Globals, preGlobals: Globals, val fpi: FoldedPredicatesInfo, currentClass: Class, checkTermination: Boolean) {
import TranslationHelper._
- val Heap = globals(0);
- val Mask = globals(1);
- val Credits = globals(2);
- lazy val oldEtran = new ExpressionTranslator(preGlobals, preGlobals, currentClass, checkTermination)
+ val Heap = globals.heap;
+ val Mask = globals.mask;
+ val SecMask = globals.secmask;
+ val Credits = globals.credits;
+ lazy val oldEtran = new ExpressionTranslator(preGlobals, preGlobals, fpi, currentClass, checkTermination)
- def this(globals: List[Boogie.Expr], preGlobals: List[Boogie.Expr], currentClass: Class) = this(globals, preGlobals, currentClass, false)
- def this(globals: List[Boogie.Expr], cl: Class) = this(globals, globals map (g => Boogie.Old(g)), cl)
- def this(cl: Class) = this(for ((id,t) <- ExpressionTranslator.Globals) yield Boogie.VarExpr(id), cl)
+ def this(globals: Globals, preGlobals: Globals, fpi: FoldedPredicatesInfo, currentClass: Class) = this(globals, preGlobals, fpi, currentClass, false)
+ def this(globals: Globals, preGlobals: Globals, currentClass: Class) = this(globals, preGlobals, FoldedPredicatesInfo(), currentClass, false)
+ def this(globals: Globals, cl: Class) = this(globals, Globals(Boogie.Old(globals.heap), Boogie.Old(globals.mask), Boogie.Old(globals.secmask), Boogie.Old(globals.credits)), cl)
+ def this(cl: Class) = this(Globals(VarExpr(HeapName), VarExpr(MaskName), VarExpr(SecMaskName), VarExpr(CreditsName)), cl)
- def Globals = List(Heap, Mask, Credits)
def ChooseEtran(chooseOld: Boolean) = if (chooseOld) oldEtran else this
+
+ /** return a new etran which is identical, expect for the fpi */
+ def resetFpi = {
+ new ExpressionTranslator(globals, preGlobals, new FoldedPredicatesInfo, currentClass, checkTermination)
+ }
/**
* Create a list of fresh global variables
*/
- def FreshGlobals(prefix: String):List[Boogie.BVar] = {
- new Boogie.BVar(prefix + HeapName, theap, true) ::
+ def FreshGlobals(prefix: String): (List[Boogie.BVar], Globals) = {
+ val vs = new Boogie.BVar(prefix + HeapName, theap, true) ::
new Boogie.BVar(prefix + MaskName, tmask, true) ::
+ new Boogie.BVar(prefix + SecMaskName, tmask, true) ::
new Boogie.BVar(prefix + CreditsName, tcredits, true) ::
Nil
+ val es = vs map {v => new Boogie.VarExpr(v)}
+ (vs, Globals(es(0), es(1), es(2), es(3)))
}
- def FromPreGlobals(preGlobals: List[Boogie.BVar]) = {
- val pg = preGlobals map (g => new VarExpr(g))
- new ExpressionTranslator(globals, pg, currentClass, checkTermination)
+ def FromPreGlobals(pg: Globals) = {
+ new ExpressionTranslator(globals, pg, fpi, currentClass, checkTermination)
}
def UseCurrentAsOld() = {
- new ExpressionTranslator(globals, globals, currentClass, checkTermination);
+ new ExpressionTranslator(globals, globals, fpi, currentClass, checkTermination);
}
- def WhereOldIs(h: Boogie.Expr, m: Boogie.Expr, c: Boogie.Expr) = {
- new ExpressionTranslator(globals, List(h, m, c), currentClass, checkTermination);
+ def WhereOldIs(h: Boogie.Expr, m: Boogie.Expr, sm: Boogie.Expr, c: Boogie.Expr) = {
+ new ExpressionTranslator(globals, Globals(h, m, sm, c), fpi, currentClass, checkTermination);
}
def CheckTermination(check: Boolean) = {
- new ExpressionTranslator(globals, preGlobals, currentClass, check);
+ new ExpressionTranslator(globals, preGlobals, fpi, currentClass, check);
}
-
+
/**********************************************************************
***************** TR/DF *****************
**********************************************************************/
@@ -1470,6 +1557,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case LockBottomLiteral() => Nil
case _:ThisExpr => Nil
case _:Result => Nil
+ case _:BoogieExpr => Nil
case _:VariableExpr => Nil
case fs @ MemberAccess(e, f) =>
assert(!fs.isPredicate);
@@ -1504,11 +1592,8 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case Not(e) =>
isDefined(e)
case func@FunctionApplication(obj, id, args) =>
- val newGlobals = FreshGlobals("checkPre");
- val (tmpHeapV, tmpHeap) = Boogie.NewBVar("Heap", theap, true);
- val (tmpMaskV, tmpMask) = Boogie.NewBVar("Mask", tmask, true);
- val (tmpCreditsV, tmpCredits) = Boogie.NewBVar("Credits", tcredits, true);
- val tmpTranslator = new ExpressionTranslator(List(tmpHeap,tmpMask,tmpCredits), etran.oldEtran.Globals, currentClass);
+ val (tmpGlobalsV, tmpGlobals) = this.FreshGlobals("fapp")
+ val tmpTranslator = new ExpressionTranslator(tmpGlobals, this.oldEtran.globals, currentClass);
// pick new k
val (funcappKV, funcappK) = Boogie.NewBVar("funcappK", tint, true)
@@ -1521,20 +1606,16 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
Comment("check precondition of call") ::
BLocal(funcappKV) :: bassume(0 < funcappK && 1000*funcappK < percentPermission(1)) ::
bassume(assumption) ::
- BLocal(tmpHeapV) :: (tmpHeap := Heap) ::
- BLocal(tmpMaskV) :: (tmpMask := Mask) :::
- BLocal(tmpCreditsV) :: (tmpCredits := Credits) :::
+ BLocals(tmpGlobalsV) :::
+ copyState(tmpGlobals, this) :::
tmpTranslator.Exhale(Preconditions(func.f.spec) map { pre=> (SubstVars(pre, obj, func.f.ins, args), ErrorMessage(func.pos, "Precondition at " + pre.pos + " might not hold."))},
"function call",
false, funcappK, false) :::
// size of the heap of callee must be strictly smaller than size of the heap of the caller
- (if(checkTermination) { List(prove(NonEmptyMask(tmpMask), func.pos, "The heap of the callee might not be strictly smaller than the heap of the caller.")) } else Nil)
+ (if(checkTermination) { List(prove(NonEmptyMask(tmpGlobals.mask), func.pos, "The heap of the callee might not be strictly smaller than the heap of the caller.")) } else Nil)
case unfolding@Unfolding(acc@Access(pred@MemberAccess(obj, f), perm), e) =>
- val newGlobals = FreshGlobals("checkPre");
- val (tmpHeapV, tmpHeap) = Boogie.NewBVar("Heap", theap, true);
- val (tmpMaskV, tmpMask) = Boogie.NewBVar("Mask", tmask, true);
- val (tmpCreditsV, tmpCredits) = Boogie.NewBVar("Credits", tcredits, true);
- val tmpTranslator = new ExpressionTranslator(List(tmpHeap, tmpMask, tmpCredits), etran.oldEtran.Globals, currentClass);
+ val (tmpGlobalsV, tmpGlobals) = this.FreshGlobals("unfolding")
+ val tmpTranslator = new ExpressionTranslator(tmpGlobals, this.oldEtran.globals, currentClass);
val receiverOk = isDefined(obj) ::: prove(nonNull(Tr(obj)), obj.pos, "Receiver might be null.");
val definition = scaleExpressionByPermission(SubstThis(DefinitionOf(pred.predicate), obj), perm, unfolding.pos)
@@ -1547,13 +1628,12 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
// check definedness
receiverOk ::: isDefined(perm) :::
// copy state into temporary variables
- BLocal(tmpHeapV) :: Boogie.Assign(tmpHeap, Heap) ::
- BLocal(tmpMaskV) :: Boogie.Assign(tmpMask, Mask) ::
- BLocal(tmpCreditsV) :: Boogie.Assign(tmpCredits, Credits) ::
+ BLocals(tmpGlobalsV) :::
+ copyState(tmpGlobals, this) :::
// exhale the predicate
- tmpTranslator.Exhale(List((acc, ErrorMessage(unfolding.pos, "Unfolding might fail."))), "unfolding", false, unfoldingK, false) :::
+ tmpTranslator.ExhaleDuringUnfold(List((acc, ErrorMessage(unfolding.pos, "Unfolding might fail."))), "unfolding", false, unfoldingK, false) :::
// inhale the definition of the predicate
- tmpTranslator.InhaleFrom(List(definition), "unfolding", false, Heap.select(Tr(obj), pred.predicate.FullName), unfoldingK) :::
+ tmpTranslator.Inhale(List(definition), "unfolding", false, unfoldingK) :::
// check definedness of e in state where the predicate is unfolded
tmpTranslator.isDefined(e)
case Iff(e0,e1) =>
@@ -1607,8 +1687,8 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case Contains(e0, e1) =>
isDefined(e0) ::: isDefined(e1)
case Eval(h, e) =>
- val (evalHeap, evalMask, evalCredits, checks, assumptions) = fromEvalState(h);
- val evalEtran = new ExpressionTranslator(List(evalHeap, evalMask, evalCredits), etran.oldEtran.Globals, currentClass);
+ val (evalHeap, evalMask, evalSecMask, evalCredits, checks, assumptions) = fromEvalState(h);
+ val evalEtran = new ExpressionTranslator(Globals(evalHeap, evalMask, evalSecMask, evalCredits), this.oldEtran.globals, currentClass);
evalEtran.isDefined(e)
case _ : SeqQuantification => throw new InternalErrorException("should be desugared")
case tq @ TypeQuantification(_, _, _, e, (min, max)) =>
@@ -1625,7 +1705,14 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
}
}
- def Tr(e: Expression): Boogie.Expr = desugar(e) match {
+ /** Translate an expression, using 'trrec' in the recursive calls (which takes
+ * the expression and an expression translator as argument). The default
+ * behaviour is to translate only pure assertions (and throw and error otherwise).
+ */
+ def Tr(e: Expression): Boogie.Expr = Tr(e, (ee,et) => et.Tr(ee))
+ def Tr(e: Expression, trrec: (Expression, ExpressionTranslator) => Expr): Boogie.Expr = {
+ def trrecursive(e: Expression): Expr = trrec(e, this)
+ desugar(e) match {
case IntLiteral(n) => n
case BoolLiteral(b) => b
case NullLiteral() => bnull
@@ -1633,6 +1720,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
// since there currently are no operations defined on string, except == and !=, just translate
// each string to a unique number
s.hashCode()
+ case BoogieExpr(b) => b
case MaxLockLiteral() => throw new InternalErrorException("waitlevel case should be handled in << and == and !=")
case LockBottomLiteral() => bLockBottom
case _:ThisExpr => VarExpr("this")
@@ -1640,7 +1728,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case ve : VariableExpr => VarExpr(ve.v.UniqueName)
case fs @ MemberAccess(e,_) =>
assert(! fs.isPredicate);
- var r = Heap.select(Tr(e), fs.f.FullName);
+ var r = Heap.select(trrecursive(e), fs.f.FullName);
if (fs.f.isInstanceOf[SpecialField] && fs.f.id == "joinable")
r !=@ 0 // joinable is encoded as an integer
else
@@ -1649,30 +1737,31 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case _:PermissionExpr => throw new InternalErrorException("permission expression unexpected here: " + e.pos)
case _:Credit => throw new InternalErrorException("credit expression unexpected here")
case Holds(e) =>
- (0 < Heap.select(Tr(e), "held")) &&
- !Heap.select(Tr(e), "rdheld")
+ var ee = trrecursive(e)
+ (0 < Heap.select(ee, "held")) &&
+ !Heap.select(ee, "rdheld")
case RdHolds(e) =>
- Heap.select(Tr(e), "rdheld")
+ Heap.select(trrecursive(e), "rdheld")
case a: Assigned =>
VarExpr("assigned$" + a.v.UniqueName)
case Old(e) =>
- oldEtran.Tr(e)
+ trrec(e, oldEtran)
case IfThenElse(con, then, els) =>
- Boogie.Ite(Tr(con), Tr(then), Tr(els)) // of type: VarExpr(TrClass(then.typ))
+ Boogie.Ite(trrecursive(con), trrecursive(then), trrecursive(els)) // of type: VarExpr(TrClass(then.typ))
case Not(e) =>
- ! Tr(e)
+ ! trrecursive(e)
case func@FunctionApplication(obj, id, args) =>
- FunctionApp(functionName(func.f), Heap :: Mask :: (obj :: args map { arg => Tr(arg)}))
+ FunctionApp(functionName(func.f), Heap :: (obj :: args map { arg => trrecursive(arg)}))
case uf@Unfolding(_, e) =>
- Tr(e)
+ trrecursive(e)
case Iff(e0,e1) =>
- Tr(e0) <==> Tr(e1)
+ trrecursive(e0) <==> trrecursive(e1)
case Implies(e0,e1) =>
- Tr(e0) ==> Tr(e1)
+ trrecursive(e0) ==> trrecursive(e1)
case And(e0,e1) =>
- Tr(e0) && Tr(e1)
+ trrecursive(e0) && trrecursive(e1)
case Or(e0,e1) =>
- Tr(e0) || Tr(e1)
+ trrecursive(e0) || trrecursive(e1)
case Eq(e0,e1) =>
(ShaveOffOld(e0), ShaveOffOld(e1)) match {
case ((MaxLockLiteral(),o0), (MaxLockLiteral(),o1)) =>
@@ -1680,23 +1769,23 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
true
else
MaxLockPreserved
- case ((MaxLockLiteral(),o), _) => ChooseEtran(o).IsHighestLock(Tr(e1))
- case (_, (MaxLockLiteral(),o)) => ChooseEtran(o).IsHighestLock(Tr(e0))
- case _ => if(e0.typ.IsSeq) FunctionApp("Seq#Equal", List(Tr(e0), Tr(e1))) else (Tr(e0) ==@ Tr(e1))
+ case ((MaxLockLiteral(),o), _) => ChooseEtran(o).IsHighestLock(trrecursive(e1))
+ case (_, (MaxLockLiteral(),o)) => ChooseEtran(o).IsHighestLock(trrecursive(e0))
+ case _ => if(e0.typ.IsSeq) FunctionApp("Seq#Equal", List(trrecursive(e0), trrecursive(e1))) else (trrecursive(e0) ==@ trrecursive(e1))
}
case Neq(e0,e1) =>
- Tr(Not(Eq(e0,e1)))
+ trrecursive(Not(Eq(e0,e1)))
case Less(e0,e1) =>
- Tr(e0) < Tr(e1)
+ trrecursive(e0) < trrecursive(e1)
case AtMost(e0,e1) =>
- Tr(e0) <= Tr(e1)
+ trrecursive(e0) <= trrecursive(e1)
case AtLeast(e0,e1) =>
- Tr(e0) >= Tr(e1)
+ trrecursive(e0) >= trrecursive(e1)
case Greater(e0,e1) =>
- Tr(e0) > Tr(e1)
+ trrecursive(e0) > trrecursive(e1)
case LockBelow(e0,e1) => {
def MuValue(b: Expression): Boogie.Expr =
- if (b.typ.IsRef) new Boogie.MapSelect(Heap, Tr(b), "mu") else Tr(b)
+ if (b.typ.IsRef) new Boogie.MapSelect(Heap, trrecursive(b), "mu") else trrecursive(b)
(ShaveOffOld(e0), ShaveOffOld(e1)) match {
case ((MaxLockLiteral(),o0), (MaxLockLiteral(),o1)) =>
if (o0 == o1)
@@ -1708,48 +1797,68 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case _ => new FunctionApp("MuBelow", MuValue(e0), MuValue(e1)) }
}
case Plus(e0,e1) =>
- Tr(e0) + Tr(e1)
+ trrecursive(e0) + trrecursive(e1)
case Minus(e0,e1) =>
- Tr(e0) - Tr(e1)
+ trrecursive(e0) - trrecursive(e1)
case Times(e0,e1) =>
- Tr(e0) * Tr(e1)
+ trrecursive(e0) * trrecursive(e1)
case Div(e0,e1) =>
- Tr(e0) / Tr(e1)
+ trrecursive(e0) / trrecursive(e1)
case Mod(e0,e1) =>
- Tr(e0) % Tr(e1)
+ trrecursive(e0) % trrecursive(e1)
case EmptySeq(t) =>
createEmptySeq
case ExplicitSeq(es) =>
es match {
case Nil => createEmptySeq
- case h :: Nil => createSingletonSeq(Tr(h))
- case h :: t => createAppendSeq(createSingletonSeq(Tr(h)), Tr(ExplicitSeq(t)))
+ case h :: Nil => createSingletonSeq(trrecursive(h))
+ case h :: t => createAppendSeq(createSingletonSeq(trrecursive(h)), trrecursive(ExplicitSeq(t)))
}
case Range(min, max) =>
- createRange(Tr(min), Tr(max))
+ createRange(trrecursive(min), trrecursive(max))
case Append(e0, e1) =>
- createAppendSeq(Tr(e0), Tr(e1))
- case at@At(e0, e1) =>SeqIndex(Tr(e0), Tr(e1))
+ createAppendSeq(trrecursive(e0), trrecursive(e1))
+ case at@At(e0, e1) =>SeqIndex(trrecursive(e0), trrecursive(e1))
case Drop(e0, e1) =>
e1 match {
case IntLiteral(0) =>
- Tr(e0)
+ trrecursive(e0)
case _ =>
- Boogie.FunctionApp("Seq#Drop", List(Tr(e0), Tr(e1)))
+ Boogie.FunctionApp("Seq#Drop", List(trrecursive(e0), trrecursive(e1)))
}
case Take(e0, e1) =>
- Boogie.FunctionApp("Seq#Take", List(Tr(e0), Tr(e1)))
- case Length(e) => SeqLength(Tr(e))
- case Contains(e0, e1) => SeqContains(Tr(e1), Tr(e0))
+ Boogie.FunctionApp("Seq#Take", List(trrecursive(e0), trrecursive(e1)))
+ case Length(e) => SeqLength(trrecursive(e))
+ case Contains(e0, e1) => SeqContains(trrecursive(e1), trrecursive(e0))
case Eval(h, e) =>
- val (evalHeap, evalMask, evalCredits, checks, assumptions) = fromEvalState(h);
- val evalEtran = new ExpressionTranslator(List(evalHeap, evalMask, evalCredits), etran.oldEtran.Globals, currentClass);
- evalEtran.Tr(e)
+ val (evalHeap, evalMask, evalSecMask, evalCredits, checks, assumptions) = fromEvalState(h);
+ val evalEtran = new ExpressionTranslator(Globals(evalHeap, evalMask, evalSecMask, evalCredits), oldEtran.globals, currentClass);
+ trrec(e, evalEtran)
case _:SeqQuantification => throw new InternalErrorException("should be desugared")
case tq @ TypeQuantification(Forall, _, _, e, _) =>
- Boogie.Forall(Nil, tq.variables map { v => Variable2BVar(v)}, Nil, Tr(e))
+ Boogie.Forall(Nil, tq.variables map { v => Variable2BVar(v)}, Nil, trrecursive(e))
case tq @ TypeQuantification(Exists, _, _, e, _) =>
- Boogie.Exists(Nil, tq.variables map { v => Variable2BVar(v)}, Nil, Tr(e))
+ Boogie.Exists(Nil, tq.variables map { v => Variable2BVar(v)}, Nil, trrecursive(e))
+ }
+ }
+
+ /** translate everything, including permissions and credit expressions */
+ def TrAll(e: Expression): Expr = {
+ def TrAllHelper(e: Expression, etran: ExpressionTranslator): Expr = e match {
+ case pred@MemberAccess(e, p) if pred.isPredicate =>
+ val tmp = Access(pred, Full); tmp.pos = pred.pos
+ TrAll(tmp)
+ case acc@Access(e,perm) =>
+ val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
+ CanRead(Tr(e.e), memberName)
+ case acc @ AccessSeq(s, Some(member), perm) =>
+ if (member.isPredicate) throw new NotSupportedException("not yet implemented");
+ val memberName = member.f.FullName;
+ val (refV, ref) = Boogie.NewBVar("ref", tref, true);
+ (SeqContains(Tr(s), ref) ==> CanRead(ref, memberName)).forall(refV)
+ case _ => etran.Tr(e, TrAllHelper)
+ }
+ TrAllHelper(e, this)
}
def ShaveOffOld(e: Expression): (Expression, Boolean) = e match {
@@ -1770,30 +1879,17 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
def Inhale(predicates: List[Expression], occasion: String, check: Boolean, currentK: Expr): List[Boogie.Stmt] = {
if (predicates.size == 0) return Nil;
- val (ihV, ih) = Boogie.NewBVar("inhaleHeap", theap, true)
- Comment("inhale (" + occasion + ")") ::
- BLocal(ihV) :: Boogie.Havoc(ih) ::
- bassume(IsGoodInhaleState(ih, Heap, Mask)) ::
- (for (p <- predicates) yield Inhale(p, ih, check, currentK)).flatten :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- Comment("end inhale")
- }
-
- def InhaleFrom(predicates: List[Expression], occasion: String, check: Boolean, useHeap: Boogie.Expr, currentK: Expr): List[Boogie.Stmt] = {
- if (predicates.size == 0) return Nil;
-
- val (ihV, ih) = Boogie.NewBVar("inhaleHeap", theap, true)
+ //val (ihV, ih) = Boogie.NewBVar("inhaleHeap", theap, true)
Comment("inhale (" + occasion + ")") ::
- BLocal(ihV) :: Boogie.Assign(ih, useHeap) ::
- bassume(IsGoodInhaleState(ih, Heap, Mask)) ::
- (for (p <- predicates) yield Inhale(p,ih, check, currentK)).flatten :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
+ //BLocal(ihV) :: Boogie.Havoc(ih) ::
+ //bassume(IsGoodInhaleState(ih, Heap, Mask, SecMask)) ::
+ (for (p <- predicates) yield Inhale(p, Heap, check, currentK)).flatten :::
+ bassume(AreGoodMasks(Mask, SecMask)) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
Comment("end inhale")
}
- def InhalePermission(perm: Permission, obj: Expr, memberName: String, currentK: Expr): List[Boogie.Stmt] = {
+ def InhalePermission(perm: Permission, obj: Expr, memberName: String, currentK: Expr, m: Expr = Mask): List[Boogie.Stmt] = {
val (f, stmts) = extractKFromPermission(perm, currentK)
val n = extractEpsilonsFromPermission(perm);
@@ -1802,18 +1898,24 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
(perm.permissionType match {
case PermissionType.Mixed =>
bassume(f > 0 || (f == 0 && n > 0)) ::
- IncPermission(obj, memberName, f) :::
- IncPermissionEpsilon(obj, memberName, n)
+ IncPermission(obj, memberName, f, m) :::
+ IncPermissionEpsilon(obj, memberName, n, m)
case PermissionType.Epsilons =>
bassume(n > 0) ::
- IncPermissionEpsilon(obj, memberName, n)
+ IncPermissionEpsilon(obj, memberName, n, m)
case PermissionType.Fraction =>
bassume(f > 0) ::
- IncPermission(obj, memberName, f)
+ IncPermission(obj, memberName, f, m)
})
}
+
+ def Inhale(p: Expression, ih: Boogie.Expr, check: Boolean, currentK: Expr): List[Boogie.Stmt] =
+ InhaleImplementation(p, ih, check, currentK, false)
+
+ def InhaleToSecMask(p: Expression): List[Boogie.Stmt] =
+ InhaleImplementation(p, Heap /* it should not matter what we pass here */, false /* check */, -1 /* it should not matter what we pass here */, true)
- def Inhale(p: Expression, ih: Boogie.Expr, check: Boolean, currentK: Expr): List[Boogie.Stmt] = desugar(p) match {
+ def InhaleImplementation(p: Expression, ih: Boogie.Expr, check: Boolean, currentK: Expr, transferToSecMask: Boolean): List[Boogie.Stmt] = desugar(p) match {
case pred@MemberAccess(e, p) if pred.isPredicate =>
val chk = (if (check) {
isDefined(e)(true) :::
@@ -1821,7 +1923,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
} else Nil)
val tmp = Access(pred, Full);
tmp.pos = pred.pos;
- chk ::: Inhale(tmp, ih, check, currentK)
+ chk ::: InhaleImplementation(tmp, ih, check, currentK, transferToSecMask)
case AccessAll(obj, perm) => throw new InternalErrorException("should be desugared")
case AccessSeq(s, None, perm) => throw new InternalErrorException("should be desugared")
case acc@Access(e,perm) =>
@@ -1833,16 +1935,15 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
(if(check) isDefined(e.e)(true) ::: isDefined(perm)(true)
else Nil) :::
bassume(nonNull(trE)) ::
- new MapUpdate(Heap, trE, VarExpr(memberName), new Boogie.MapSelect(ih, trE, memberName)) ::
- bassume(wf(Heap, Mask)) ::
- (if(e.isPredicate && e.predicate.Parent.module.equals(currentClass.module)) List(bassume(new Boogie.MapSelect(ih, trE, memberName) ==@ Heap)) else Nil) :::
+ bassume(wf(Heap, Mask, SecMask)) ::
(if(e.isPredicate) Nil else List(bassume(TypeInformation(new Boogie.MapSelect(Heap, trE, memberName), e.f.typ.typ)))) :::
- InhalePermission(perm, trE, memberName, currentK) :::
- bassume(IsGoodMask(Mask)) ::
- bassume(IsGoodState(new Boogie.MapSelect(ih, trE, memberName))) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(ih, Mask))
+ InhalePermission(perm, trE, memberName, currentK, (if (transferToSecMask) SecMask else Mask)) :::
+ bassume(AreGoodMasks(Mask, SecMask)) ::
+ bassume(IsGoodState(heapFragment(new Boogie.MapSelect(ih, trE, memberName)))) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
+ bassume(wf(ih, Mask, SecMask))
case acc @ AccessSeq(s, Some(member), perm) =>
+ if (transferToSecMask) throw new NotSupportedException("not yet implemented")
if (member.isPredicate) throw new NotSupportedException("not yet implemented");
val e = Tr(s);
val memberName = member.f.FullName;
@@ -1869,7 +1970,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
(ih(ref, f), Heap(ref, f)))) ::
bassume((SeqContains(e, ref) ==> TypeInformation(Heap(ref, memberName), member.f.typ.typ)).forall(refV))
} :::
- bassume(wf(Heap, Mask)) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
// update the map
{
val (aV,a) = Boogie.NewTVar("alpha");
@@ -1883,9 +1984,9 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
Mask(ref, f)("perm$N") + n)),
Mask(ref, f)))
} :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(ih, Mask))
+ bassume(AreGoodMasks(Mask, SecMask)) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
+ bassume(wf(ih, Mask, SecMask))
case cr@Credit(ch, n) =>
val trCh = Tr(ch)
(if (check)
@@ -1897,37 +1998,40 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
new Boogie.MapUpdate(Credits, trCh, new Boogie.MapSelect(Credits, trCh) + Tr(cr.N))
case Implies(e0,e1) =>
(if(check) isDefined(e0)(true) else Nil) :::
- Boogie.If(Tr(e0), Inhale(e1, ih, check, currentK), Nil)
+ Boogie.If(Tr(e0), InhaleImplementation(e1, ih, check, currentK, transferToSecMask), Nil)
case IfThenElse(con, then, els) =>
(if(check) isDefined(con)(true) else Nil) :::
- Boogie.If(Tr(con), Inhale(then, ih, check, currentK), Inhale(els, ih, check, currentK))
+ Boogie.If(Tr(con), InhaleImplementation(then, ih, check, currentK, transferToSecMask), InhaleImplementation(els, ih, check, currentK, transferToSecMask))
case And(e0,e1) =>
- Inhale(e0, ih, check, currentK) ::: Inhale(e1, ih, check, currentK)
+ InhaleImplementation(e0, ih, check, currentK, transferToSecMask) ::: InhaleImplementation(e1, ih, check, currentK, transferToSecMask)
case holds@Holds(e) =>
val trE = Tr(e);
(if(check)
isDefined(e)(true) :::
bassert(nonNull(trE), holds.pos, "The target of the holds predicate might be null.")
else Nil) :::
- bassume(IsGoodMask(Mask)) ::
- bassume(IsGoodState(new Boogie.MapSelect(ih, trE, "held"))) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(ih, Mask)) ::
+ bassume(AreGoodMasks(Mask, SecMask)) ::
+ bassume(IsGoodState(heapFragment(new Boogie.MapSelect(ih, trE, "held")))) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
+ bassume(wf(ih, Mask, SecMask)) ::
new Boogie.MapUpdate(Heap, trE, VarExpr("held"),
new Boogie.MapSelect(ih, trE, "held")) ::
bassume(0 < new Boogie.MapSelect(ih, trE, "held")) ::
bassume(! new Boogie.MapSelect(ih, trE, "rdheld")) ::
- bassume(wf(Heap, Mask)) ::
- bassume(IsGoodMask(Mask)) ::
- bassume(IsGoodState(new Boogie.MapSelect(ih, trE, "held"))) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(ih, Mask))
+ bassume(new Boogie.MapSelect(ih, trE, "mu") !=@ bLockBottom) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
+ bassume(AreGoodMasks(Mask, SecMask)) ::
+ bassume(IsGoodState(heapFragment(new Boogie.MapSelect(ih, trE, "held")))) ::
+ bassume(wf(Heap, Mask, SecMask)) ::
+ bassume(wf(ih, Mask, SecMask))
case Eval(h, e) =>
- val (evalHeap, evalMask, evalCredits, checks, proofOrAssume) = fromEvalState(h);
- val preGlobals = etran.FreshGlobals("eval")
- val preEtran = new ExpressionTranslator(preGlobals map (v => new Boogie.VarExpr(v)), currentClass)
- BLocal(preGlobals(0)) :: BLocal(preGlobals(1)) :: BLocal(preGlobals(2)) ::
- (new VarExpr(preGlobals(1)) := ZeroMask) ::
+ if (transferToSecMask) throw new NotSupportedException("not yet implemented")
+ val (evalHeap, evalMask, evalSecMask, evalCredits, checks, proofOrAssume) = fromEvalState(h);
+ val (preGlobalsV, preGlobals) = etran.FreshGlobals("eval")
+ val preEtran = new ExpressionTranslator(preGlobals, currentClass)
+ BLocals(preGlobalsV) :::
+ (preGlobals.mask := ZeroMask) ::
+ (preGlobals.secmask := ZeroMask) ::
// Should we start from ZeroMask instead of an arbitrary mask? In that case, assume submask(preEtran.Mask, evalMask); at the end!
(if(check) checks else Nil) :::
// havoc the held field when inhaling eval(o.release, ...)
@@ -1936,32 +2040,169 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
val obj = Tr(h.target());
List(BLocal(freshHeldV), bassume((0<Heap.select(obj, "held")) <==> (0<freshHeld)), (Heap.select(obj, "held") := freshHeld))
} else Nil) :::
- bassume(IsGoodMask(preEtran.Mask)) ::
- bassume(wf(preEtran.Heap, preEtran.Mask)) ::
+ bassume(AreGoodMasks(preEtran.Mask, preEtran.SecMask)) ::
+ bassume(wf(preEtran.Heap, preEtran.Mask, preEtran.SecMask)) ::
bassume(proofOrAssume) ::
- preEtran.Inhale(e, ih, check, currentK) :::
+ preEtran.InhaleImplementation(e, ih, check, currentK, transferToSecMask) :::
bassume(preEtran.Heap ==@ evalHeap) ::
bassume(submask(preEtran.Mask, evalMask))
- case e => (if(check) isDefined(e)(true) else Nil) ::: bassume(Tr(e))
+ case uf@Unfolding(acc@Access(pred@MemberAccess(obj, f), perm), ufexpr) =>
+ if (transferToSecMask) throw new NotSupportedException("not yet implemented")
+ // handle unfolding like the next case, but also record permissions of the predicate
+ // in the secondary mask and track the predicate in the auxilary information
+ val (receiverV, receiver) = Boogie.NewBVar("predRec", tref, true)
+ val (versionV, version) = Boogie.NewBVar("predVer", tint, true)
+ val (flagV, flag) = Boogie.NewBVar("predFlag", tbool, true)
+ val o = TrExpr(obj);
+
+ val stmts = BLocal(receiverV) :: (receiver := o) ::
+ BLocal(flagV) :: (flag := true) ::
+ functionTrigger(o, pred.predicate) ::
+ BLocal(versionV) :: (version := etran.Heap.select(o, pred.predicate.FullName)) ::
+ (if(check) isDefined(uf)(true) else Nil) :::
+ TransferPermissionToSecMask(pred.predicate, BoogieExpr(receiver), perm, uf.pos) :::
+ bassume(Tr(uf))
+
+ // record folded predicate
+ etran.fpi.addFoldedPredicate(FoldedPredicate(pred.predicate, receiver, version, etran.fpi.currentConditions, flag))
+
+ stmts
+ case e =>
+ (if(check) isDefined(e)(true) else Nil) :::
+ bassume(Tr(e))
+ }
+
+ /** Transfer the permissions mentioned in the body of the predicate to the
+ * secondary mask.
+ */
+ def TransferPermissionToSecMask(pred: Predicate, obj: Expression, perm: Permission, pos: Position): List[Stmt] = {
+ var definition = scaleExpressionByPermission(SubstThis(DefinitionOf(pred), obj), perm, pos)
+ // go through definition and handle all permisions correctly
+ InhaleToSecMask(definition)
}
- def Exhale(predicates: List[(Expression, ErrorMessage)], occasion: String, check: Boolean, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = {
+ // Exhale is done in two passes: In the first run, everything except permissions
+ // which need exact checking are exhaled. Then, in the second run, those
+ // permissions are exhaled. The behaviour is controlled with the parameter
+ // onlyExactCheckingPermissions.
+ // The reason for this behaviour is that we want to support preconditions like
+ // "acc(o.f,100-rd) && acc(o.f,rd)", which should be equivalent to a full
+ // permission to o.f. However, when we exhale in the given order, we cannot
+ // use inexact checking for the abstract read permission ("acc(o.f,rd)"), as
+ // this would introduce the (unsound) assumption that "methodcallk < mask[o.f]".
+ // To avoid detecting this, we exhale all abstract read permissions first (or,
+ // more precisely, we exhale all permissions with exact checking later).
+
+ /** Regular exhale */
+ def Exhale(predicates: List[(Expression, ErrorMessage)], occasion: String, check: Boolean, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] =
+ Exhale(Mask, SecMask, predicates, occasion, check, currentK, exactchecking)
+ /** Exhale as part of a unfold statement (just like a regular exhale, but no heap havocing) */
+ def ExhaleDuringUnfold(predicates: List[(Expression, ErrorMessage)], occasion: String, check: Boolean, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] =
+ Exhale(Mask, SecMask, predicates, occasion, check, currentK, exactchecking, false, -1, false, null, true)
+ /** Regular exhale with specific mask/secmask */
+ def Exhale(m: Expr, sm: Expr, predicates: List[(Expression, ErrorMessage)], occasion: String, check: Boolean, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = {
+ Exhale(m, sm, predicates, occasion, check, currentK, exactchecking, false, -1, false, null, false)
+ }
+ /** Exhale that transfers permission to the secondary mask */
+ def ExhaleAndTransferToSecMask(predicates: List[(Expression, ErrorMessage)], occasion: String, currentK: Expr, exactchecking: Boolean): List[Boogie.Stmt] = {
+ Exhale(Mask, SecMask, predicates, occasion, false, currentK, exactchecking, true /* transfer to SecMask */, -1, false, null, false)
+ }
+ /** Remove permission from the secondary mask, and assume all assertions that
+ * would get generated. Recursion is bouded by the parameter depth.
+ */
+ def UpdateSecMask(predicate: Predicate, receiver: Expr, version: Expr, perm: Permission, currentK: Expr): List[Stmt] = {
+ val depth = etran.fpi.getRecursionBound(predicate)
+ UpdateSecMask(predicate, receiver, version, perm, currentK, depth, Map())
+ }
+ def UpdateSecMaskDuringUnfold(predicate: Predicate, receiver: Expr, version: Expr, perm: Permission, currentK: Expr): List[Stmt] = {
+ UpdateSecMask(predicate, receiver, version, perm, currentK, 1, Map())
+ }
+ def UpdateSecMask(predicate: Predicate, receiver: Expr, version: Expr, perm: Permission, currentK: Expr, depth: Int, previousReceivers: Map[String,List[Expr]]): List[Stmt] = {
+ assert (depth >= 0)
+ if (depth <= 0) return Nil
+
+ val definition = scaleExpressionByPermission(SubstThis(DefinitionOf(predicate), BoogieExpr(receiver)), perm, NoPosition)
+ val occasion = "update SecMask"
+
+ // condition: if any folded predicate matches (both receiver and version), update the secondary map
+ val disj = (for (fp <- etran.fpi.getFoldedPredicates(predicate)) yield {
+ val conditions = (fp.conditions map (c => if (c._2) c._1 else !c._1)).foldLeft(true: Expr){ (a: Expr, b: Expr) => a && b }
+ val b = fp.version ==@ version && fp.receiver ==@ receiver && conditions && fp.flag
+ (b, fp.flag)
+ })
+ val b = (disj map (a => a._1)).foldLeft(false: Expr){ (a: Expr, b: Expr) => a || b }
+
+ // add receiver to list of previous receivers
+ val newPreviousReceivers = previousReceivers + (predicate.FullName -> (receiver :: previousReceivers.getOrElse(predicate.FullName, Nil)))
+
+ // assumption that the current receiver is different from all previous ones
+ (for (r <- previousReceivers.getOrElse(predicate.FullName, Nil)) yield {
+ bassume(receiver !=@ r)
+ }) :::
+ // actually update the secondary mask
+ Boogie.If(b,
+ // remove correct predicate from the auxiliary information by setting
+ // its flag to false
+ (disj.foldLeft(Nil: List[Stmt]){ (a: List[Stmt], b: (Expr, Expr)) => Boogie.If(b._1,/*(b._2 := false) :: */Nil,a) :: Nil }) :::
+ // asserts are converted to assumes, so error messages do not matter
+ assert2assume(Exhale(SecMask, SecMask, List((definition, ErrorMessage(NoPosition, ""))), occasion, false, currentK, false /* it should not important what we pass here */, false, depth-1, true, newPreviousReceivers, false)),
+ Nil) :: Nil
+ }
+ /** Most general form of exhale; implements all the specific versions above */
+ // Note: If isUpdatingSecMask, then m is actually a secondary mask, and at the
+ // moment we do not want an assumption IsGoodMask(SecMask). Therefore, we omit
+ // those if isUpdatingSecMask.
+ // Furthermore, we do not want to generate assumptions that we have enough
+ // permission available (something like "assume 50% >= SecMask[obj,f]"; note
+ // that these assumption come from the assertions that check that the necessary
+ // permissions are available, and are then turned into assumptions by
+ // assertion2assumption.
+ //
+ // Assumption 1: if isUpdatingSecMask==true, then the exhale heap is not used at
+ // all, and the regular heap is not changed.
+ // Assumption 2: If isUpdatingSecMask is false, then recurseOnPredicatesDepth
+ // is meaningless (and should be -1 by convention). Only if isUpdatingSecMask
+ // is true, then the depth is important. It is initially set in the method
+ // UpdateSecMask (because only there we have precise knowledge of what upper
+ // bound we want to use).
+ // Assumption 3: Similarly, if isUpdatingSecMask is false, then the list
+ // previousReceivers is not needed, and thus null.
+ // Assumption 4+5: duringUnfold can only be true if transferPermissionToSecMask
+ // and isUpdatingSecMask are not.
+ def Exhale(m: Expr, sm: Expr, predicates: List[(Expression, ErrorMessage)], occasion: String, check: Boolean, currentK: Expr, exactchecking: Boolean, transferPermissionToSecMask: Boolean, recurseOnPredicatesDepth: Int, isUpdatingSecMask: Boolean, previousReceivers: Map[String,List[Expr]], duringUnfold: Boolean): List[Boogie.Stmt] = {
+ assert ((isUpdatingSecMask && recurseOnPredicatesDepth >= 0) || (!isUpdatingSecMask && recurseOnPredicatesDepth == -1)) // check assumption 2
+ assert (isUpdatingSecMask || (previousReceivers == null))
+ assert (!(isUpdatingSecMask && duringUnfold))
+ assert (!(transferPermissionToSecMask && duringUnfold))
if (predicates.size == 0) return Nil;
- val (emV, em) = NewBVar("exhaleMask", tmask, true)
+ val (ehV, eh) = Boogie.NewBVar("exhaleHeap", theap, true)
+ var (emV, em: Expr) = Boogie.NewBVar("exhaleMask", tmask, true)
Comment("begin exhale (" + occasion + ")") ::
- BLocal(emV) :: (em := Mask) ::
- (for (p <- predicates) yield Exhale(p._1, em, null, p._2, check, currentK, exactchecking, false)).flatten :::
- (for (p <- predicates) yield Exhale(p._1, em, null, p._2, check, currentK, exactchecking, true)).flatten :::
- (Mask := em) ::
- bassume(wf(Heap, Mask)) ::
+ (if (!isUpdatingSecMask && !duringUnfold)
+ BLocal(emV) :: (em := m) ::
+ BLocal(ehV) :: Boogie.Havoc(eh) :: Nil
+ else {
+ em = m
+ Nil
+ }) :::
+ (for (p <- predicates) yield ExhaleHelper(p._1, em, sm, eh, p._2, check, currentK, exactchecking, false, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold)).flatten :::
+ (for (p <- predicates) yield ExhaleHelper(p._1, em, sm, eh, p._2, check, currentK, exactchecking, true, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold)).flatten :::
+ (if (!isUpdatingSecMask && !duringUnfold)
+ (m := em) ::
+ bassume(IsGoodExhaleState(eh, Heap, m, sm)) ::
+ (Heap := eh) :: Nil
+ else Nil) :::
+ (if (isUpdatingSecMask) Nil else bassume(AreGoodMasks(m, sm)) :: Nil) :::
+ bassume(wf(Heap, m, sm)) ::
Comment("end exhale")
}
- def ExhalePermission(perm: Permission, obj: Expr, memberName: String, currentK: Expr, pos: Position, error: ErrorMessage, em: Boogie.Expr, exactchecking: Boolean): List[Boogie.Stmt] = {
+ // see comment in front of method exhale about parameter isUpdatingSecMask
+ def ExhalePermission(perm: Permission, obj: Expr, memberName: String, currentK: Expr, pos: Position, error: ErrorMessage, em: Boogie.Expr, exactchecking: Boolean, isUpdatingSecMask: Boolean): List[Boogie.Stmt] = {
val (f, stmts) = extractKFromPermission(perm, currentK)
val n = extractEpsilonsFromPermission(perm);
- stmts :::
+ val res = stmts :::
(perm.permissionType match {
case PermissionType.Mixed =>
bassert(f > 0 || (f == 0 && n > 0), error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
@@ -1973,6 +2214,10 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
bassert(f > 0, error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
DecPermission(obj, memberName, f, em, error, pos, exactchecking)
})
+
+ if (isUpdatingSecMask)
+ res filter (a => !a.isInstanceOf[Boogie.Assert]) // we do not want "insufficient permission checks" at the moment, as they will be turned into (possibly wrong) assumptions
+ else res
}
// does this permission require exact checking, or is it enough to check that we have any permission > 0?
@@ -2004,22 +2249,11 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
}
}
- // Exhale is done in two passes: In the first run, everything except permissions
- // which need exact checking are exhaled. Then, in the second run, those
- // permissions are exhaled. The behaviour is controlled with the parameter
- // onlyExactCheckingPermissions.
- // The reason for this behaviour is that we want to support preconditions like
- // "acc(o.f,100-rd) && acc(o.f,rd)", which should be equivalent to a full
- // permission to o.f. However, when we exhale in the given order, we cannot
- // use inexact checking for the abstract read permission ("acc(o.f,rd)"), as
- // this would introduce the (unsound) assumption that "methodcallk < mask[o.f]".
- // To avoid detecting this, we exhale all abstract read permissions first (or,
- // more precisely, we exhale all permissions with exact checking later).
- def Exhale(p: Expression, em: Boogie.Expr, eh: Boogie.Expr, error: ErrorMessage, check: Boolean, currentK: Expr, exactchecking: Boolean, onlyExactCheckingPermissions: Boolean): List[Boogie.Stmt] = desugar(p) match {
+ def ExhaleHelper(p: Expression, m: Boogie.Expr, sm: Boogie.Expr, eh: Boogie.Expr, error: ErrorMessage, check: Boolean, currentK: Expr, exactchecking: Boolean, onlyExactCheckingPermissions: Boolean, transferPermissionToSecMask: Boolean, recurseOnPredicatesDepth: Int, isUpdatingSecMask: Boolean, previousReceivers: Map[String,List[Expr]], duringUnfold: Boolean): List[Boogie.Stmt] = desugar(p) match {
case pred@MemberAccess(e, p) if pred.isPredicate =>
val tmp = Access(pred, Full);
tmp.pos = pred.pos;
- Exhale(tmp, em , eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions)
+ ExhaleHelper(tmp, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold)
case AccessAll(obj, perm) => throw new InternalErrorException("should be desugared")
case AccessSeq(s, None, perm) => throw new InternalErrorException("should be desugared")
case acc@Access(e,perm) =>
@@ -2027,6 +2261,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
if (ec != onlyExactCheckingPermissions) Nil else {
val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
val (starKV, starK) = NewBVar("starK", tint, true);
+ val trE = Tr(e.e)
// check definedness
(if(check) isDefined(e.e)(true) :::
@@ -2034,10 +2269,38 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
// if the mask does not contain sufficient permissions, try folding acc(e, fraction)
// TODO: include automagic again
// check that the necessary permissions are there and remove them from the mask
- ExhalePermission(perm, Tr(e.e), memberName, currentK, acc.pos, error, em, ec) :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(Heap, em))
+ ExhalePermission(perm, trE, memberName, currentK, acc.pos, error, m, ec, isUpdatingSecMask) :::
+ // transfer permission to secondary mask if necessary
+ (if (transferPermissionToSecMask) InhalePermission(perm, trE, memberName, currentK, sm)
+ else Nil) :::
+ // give up secondary permission to locations of the body of the predicate (also recursively)
+ (if (e.isPredicate && !transferPermissionToSecMask)
+ (if (isUpdatingSecMask)
+ UpdateSecMask(e.predicate, trE, Heap.select(trE, memberName), perm, currentK, recurseOnPredicatesDepth, previousReceivers)
+ else
+ (if (duringUnfold)
+ UpdateSecMaskDuringUnfold(e.predicate, trE, Heap.select(trE, memberName), perm, currentK)
+ else
+ UpdateSecMask(e.predicate, trE, Heap.select(trE, memberName), perm, currentK)
+ )
+ )
+ else Nil) :::
+ // update version number (if necessary)
+ (if (e.isPredicate && !isUpdatingSecMask)
+ Boogie.If(!CanRead(trE, memberName, m, sm), // if we cannot access the predicate anymore, then its version will be havoced
+ (if (!duringUnfold) bassume(Heap.select(trE, memberName) < eh.select(trE, memberName)) :: Nil // assume that the predicate's version grows monotonically
+ else { // duringUnfold -> the heap is not havoced, thus we need to locally havoc the version
+ val (oldVersV, oldVers) = Boogie.NewBVar("oldVers", tint, true)
+ val (newVersV, newVers) = Boogie.NewBVar("newVers", tint, true)
+ BLocal(oldVersV) :: (oldVers := Heap.select(trE, memberName)) ::
+ BLocal(newVersV) :: Boogie.Havoc(newVers) :: (Heap.select(trE, memberName) := newVers) ::
+ bassume(oldVers < Heap.select(trE, memberName)) :: Nil
+ }),
+ Nil) :: Nil
+ else Nil) :::
+ (if (isUpdatingSecMask) Nil else bassume(AreGoodMasks(m, sm)) :: Nil) :::
+ bassume(wf(Heap, m, sm)) :::
+ (if (m != Mask || sm != SecMask) bassume(wf(Heap, Mask, SecMask)) :: Nil else Nil)
}
case acc @ AccessSeq(s, Some(member), perm) =>
if (member.isPredicate) throw new NotSupportedException("not yet implemented");
@@ -2056,8 +2319,8 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
val (refV, ref) = Boogie.NewBVar("ref", tref, true);
val (fV, f) = Boogie.NewBVar("f", FieldType(a), true);
val (pcV,pc) = Boogie.NewBVar("p", tperm, true);
- val mr = em(ref, memberName)("perm$R");
- val mn = em(ref, memberName)("perm$N");
+ val mr = m(ref, memberName)("perm$R");
+ val mn = m(ref, memberName)("perm$N");
// assert that the permission is positive
bassert((SeqContains(e, ref) ==>
@@ -2067,14 +2330,15 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case PermissionType.Epsilons => n > 0
})).forall(refV), error.pos, error.message + " The permission at " + acc.pos + " might not be positive.") ::
// make sure enough permission is available
- bassert((SeqContains(e, ref) ==>
+ // (see comment in front of method exhale for explanation of isUpdatingSecMask)
+ (if (!isUpdatingSecMask) bassert((SeqContains(e, ref) ==>
((perm,perm.permissionType) match {
case _ if !ec => mr > 0
case (Star,_) => mr > 0
case (_,PermissionType.Fraction) => r <= mr && (r ==@ mr ==> 0 <= mn)
case (_,PermissionType.Mixed) => r <= mr && (r ==@ mr ==> n <= mn)
case (_,PermissionType.Epsilons) => mr ==@ 0 ==> n <= mn
- })).forall(refV), error.pos, error.message + " Insufficient permission at " + acc.pos + " for " + member.f.FullName) ::
+ })).forall(refV), error.pos, error.message + " Insufficient permission at " + acc.pos + " for " + member.f.FullName) :: Nil else Nil) :::
// additional assumption on k if we have a star permission or use inexact checking
( perm match {
case _ if !ec => bassume((SeqContains(e, ref) ==> (r < mr)).forall(refV)) :: Nil
@@ -2082,14 +2346,14 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
case _ => Nil
}) :::
// update the map
- (em := Lambda(List(aV), List(refV, fV),
+ (m := Lambda(List(aV), List(refV, fV),
(SeqContains(e, ref) && f ==@ memberName).thenElse(
Lambda(List(), List(pcV), (pc ==@ "perm$R").thenElse(mr - r, mn - n)),
- em(ref, f))))
+ m(ref, f))))
} :::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(Heap, em))
+ (if (isUpdatingSecMask) Nil else bassume(AreGoodMasks(m, sm)) :: Nil) :::
+ bassume(wf(Heap, m, sm)) :::
+ (if (m != Mask || sm != SecMask) bassume(wf(Heap, Mask, SecMask)) :: Nil else Nil)
}
case cr@Credit(ch, n) if !onlyExactCheckingPermissions =>
val trCh = Tr(ch)
@@ -2099,33 +2363,34 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
isDefined(cr.N)(true)
else
Nil) :::
- new Boogie.MapUpdate(Credits, trCh, new Boogie.MapSelect(Credits, trCh) - Tr(cr.N))
+ // only update the heap if we are not updating the secondary mask
+ (if (!isUpdatingSecMask)
+ new Boogie.MapUpdate(Credits, trCh, new Boogie.MapSelect(Credits, trCh) - Tr(cr.N)) :: Nil
+ else Nil)
case Implies(e0,e1) =>
(if(check && !onlyExactCheckingPermissions) isDefined(e0)(true) else Nil) :::
- Boogie.If(Tr(e0), Exhale(e1, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions), Nil)
+ Boogie.If(Tr(e0), ExhaleHelper(e1, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold), Nil)
case IfThenElse(con, then, els) =>
(if(check) isDefined(con)(true) else Nil) :::
- Boogie.If(Tr(con), Exhale(then, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions), Exhale(els, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions))
+ Boogie.If(Tr(con), ExhaleHelper(then, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold), ExhaleHelper(els, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold))
case And(e0,e1) =>
- Exhale(e0, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions) ::: Exhale(e1, em, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions)
+ ExhaleHelper(e0, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold) ::: ExhaleHelper(e1, m, sm, eh, error, check, currentK, exactchecking, onlyExactCheckingPermissions, transferPermissionToSecMask, recurseOnPredicatesDepth, isUpdatingSecMask, previousReceivers, duringUnfold)
case holds@Holds(e) if !onlyExactCheckingPermissions =>
(if(check) isDefined(e)(true) :::
bassert(nonNull(Tr(e)), error.pos, error.message + " The target of the holds predicate at " + holds.pos + " might be null.") :: Nil else Nil) :::
bassert(0 < new Boogie.MapSelect(Heap, Tr(e), "held"), error.pos, error.message + " The current thread might not hold lock at " + holds.pos + ".") ::
bassert(! new Boogie.MapSelect(Heap, Tr(e), "rdheld"), error.pos, error.message + " The current thread might hold the read lock at " + holds.pos + ".") ::
- bassume(IsGoodMask(Mask)) ::
- bassume(wf(Heap, Mask)) ::
- bassume(wf(Heap, em))
+ (if (isUpdatingSecMask) Nil else bassume(AreGoodMasks(m, sm)) :: Nil) :::
+ bassume(wf(Heap, m, sm))
case Eval(h, e) if !onlyExactCheckingPermissions =>
- val (evalHeap, evalMask, evalCredits, checks, proofOrAssume) = fromEvalState(h);
- val preGlobals = etran.FreshGlobals("eval")
- val preEtran = new ExpressionTranslator(List(Boogie.VarExpr(preGlobals(0).id), Boogie.VarExpr(preGlobals(1).id), Boogie.VarExpr(preGlobals(2).id)), currentClass);
- BLocal(preGlobals(0)) :: (VarExpr(preGlobals(0).id) := evalHeap) ::
- BLocal(preGlobals(1)) :: (VarExpr(preGlobals(1).id) := evalMask) ::
- BLocal(preGlobals(2)) :: (VarExpr(preGlobals(2).id) := evalCredits) ::
+ val (evalHeap, evalMask, evalSecMask, evalCredits, checks, proofOrAssume) = fromEvalState(h);
+ val (preGlobalsV, preGlobals) = etran.FreshGlobals("eval")
+ val preEtran = new ExpressionTranslator(preGlobals, currentClass);
+ BLocals(preGlobalsV) :::
+ copyState(preGlobals, Globals(evalHeap, evalMask, evalSecMask, evalCredits)) :::
(if(check) checks else Nil) :::
- bassume(IsGoodMask(preEtran.Mask)) ::
- bassume(wf(preEtran.Heap, preEtran.Mask)) ::
+ (if (isUpdatingSecMask) Nil else bassume(AreGoodMasks(preEtran.Mask, preEtran.SecMask)) :: Nil) :::
+ bassume(wf(preEtran.Heap, preEtran.Mask, preEtran.SecMask)) ::
bassert(proofOrAssume, p.pos, "Arguments for joinable might not match up.") ::
preEtran.Exhale(List((e, error)), "eval", check, currentK, exactchecking)
case e if !onlyExactCheckingPermissions => (if(check) isDefined(e)(true) else Nil) ::: List(bassert(Tr(e), error.pos, error.message + " The expression at " + e.pos + " might not evaluate to true."))
@@ -2186,16 +2451,18 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
}
}
- def fromEvalState(h: EvalState): (Expr, Expr, Expr, List[Stmt], Expr) = {
+ def fromEvalState(h: EvalState): (Expr, Expr, Expr, Expr, List[Stmt], Expr) = {
h match {
case AcquireState(obj) =>
(AcquireHeap(Heap.select(Tr(obj), "held")),
AcquireMask(Heap.select(Tr(obj), "held")),
+ AcquireSecMask(Heap.select(Tr(obj), "held")),
AcquireCredits(Heap.select(Tr(obj), "held")),
isDefined(obj)(true), true)
case ReleaseState(obj) =>
(LastSeenHeap(Heap.select(Tr(obj), "mu"), Heap.select(Tr(obj), "held")),
LastSeenMask(Heap.select(Tr(obj), "mu"), Heap.select(Tr(obj), "held")),
+ LastSeenSecMask(Heap.select(Tr(obj), "mu"), Heap.select(Tr(obj), "held")),
LastSeenCredits(Heap.select(Tr(obj), "mu"), Heap.select(Tr(obj), "held")),
isDefined(obj)(true), true)
case CallState(token, obj, id, args) =>
@@ -2212,6 +2479,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
var i = 0;
(CallHeap(Heap.select(Tr(token), "joinable")),
CallMask(Heap.select(Tr(token), "joinable")),
+ CallSecMask(Heap.select(Tr(token), "joinable")),
CallCredits(Heap.select(Tr(token), "joinable")),
isDefined(token)(true) :::
isDefined(obj)(true) :::
@@ -2230,8 +2498,12 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
***************** PERMISSIONS *****************
**********************************************************************/
- def CanRead(obj: Boogie.Expr, field: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanRead", Mask, obj, field)
+ def CanRead(obj: Boogie.Expr, field: Boogie.Expr, m: Boogie.Expr, sm: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanRead", List(m, sm, obj, field))
+ def CanRead(obj: Boogie.Expr, field: String, m: Boogie.Expr, sm: Boogie.Expr): Boogie.Expr = CanRead(obj, new Boogie.VarExpr(field), m, sm)
+ def CanRead(obj: Boogie.Expr, field: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanRead", List(Mask, SecMask, obj, field))
def CanRead(obj: Boogie.Expr, field: String): Boogie.Expr = CanRead(obj, new Boogie.VarExpr(field))
+ def CanReadForSure(obj: Boogie.Expr, field: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanReadForSure", List(Mask, obj, field))
+ def CanReadForSure(obj: Boogie.Expr, field: String): Boogie.Expr = CanReadForSure(obj, new Boogie.VarExpr(field))
def CanWrite(obj: Boogie.Expr, field: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanWrite", Mask, obj, field)
def CanWrite(obj: Boogie.Expr, field: String): Boogie.Expr = CanWrite(obj, new Boogie.VarExpr(field))
def HasNoPermission(obj: Boogie.Expr, field: String) =
@@ -2245,12 +2517,12 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
def SetFullPermission(obj: Boogie.Expr, field: String) =
Boogie.Assign(new Boogie.MapSelect(Mask, obj, field), Boogie.VarExpr("Permission$Full"))
- def IncPermission(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr): List[Boogie.Stmt] = {
- MapUpdate3(Mask, obj, field, "perm$R", new Boogie.MapSelect(Mask, obj, field, "perm$R") + howMuch) :: Nil
+ def IncPermission(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr, m: Expr = Mask): List[Boogie.Stmt] = {
+ MapUpdate3(m, obj, field, "perm$R", new Boogie.MapSelect(m, obj, field, "perm$R") + howMuch) :: Nil
}
- def IncPermissionEpsilon(obj: Boogie.Expr, field: String, epsilons: Boogie.Expr): List[Boogie.Stmt] = {
- MapUpdate3(Mask, obj, field, "perm$N", new Boogie.MapSelect(Mask, obj, field, "perm$N") + epsilons) ::
- bassume(Boogie.FunctionApp("wf", List(Heap, Mask))) :: Nil
+ def IncPermissionEpsilon(obj: Boogie.Expr, field: String, epsilons: Boogie.Expr, m: Expr = Mask): List[Boogie.Stmt] = {
+ MapUpdate3(m, obj, field, "perm$N", new Boogie.MapSelect(m, obj, field, "perm$N") + epsilons) ::
+ bassume(wf(Heap, m, SecMask)) :: Nil
}
def DecPermission(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr, mask: Boogie.Expr, error: ErrorMessage, pos: Position, exactchecking: Boolean): List[Boogie.Stmt] = {
val fP: Boogie.Expr = new Boogie.MapSelect(mask, obj, field, "perm$R")
@@ -2263,7 +2535,7 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
val xyz = new Boogie.MapSelect(mask, obj, field, "perm$N")
bassert((new Boogie.MapSelect(mask, obj, field, "perm$R") ==@ Boogie.IntLiteral(0)) ==> (epsilons <= xyz), error.pos, error.message + " Insufficient epsilons at " + pos + " for " + field + ".") ::
MapUpdate3(mask, obj, field, "perm$N", new Boogie.MapSelect(mask, obj, field, "perm$N") - epsilons) ::
- bassume(Boogie.FunctionApp("wf", List(Heap, Mask))) :: Nil
+ bassume(wf(Heap, Mask, SecMask)) :: Nil
}
def DecPermissionBoth(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr, epsilons: Boogie.Expr, mask: Boogie.Expr, error: ErrorMessage, pos: Position, exactchecking: Boolean): List[Boogie.Stmt] = {
val fP: Boogie.Expr = new Boogie.MapSelect(mask, obj, field, "perm$R")
@@ -2272,8 +2544,8 @@ class ExpressionTranslator(globals: List[Boogie.Expr], preGlobals: List[Boogie.E
(if (exactchecking) bassert(howMuch <= fP && (howMuch ==@ fP ==> epsilons <= fC), error.pos, error.message + " Insufficient permission at " + pos + " for " + field + ".") :: Nil
else bassert(fP > 0, error.pos, error.message + " Insufficient permission at " + pos + " for " + field + ".") :: bassume(howMuch < fP)) :::
MapUpdate3(mask, obj, field, "perm$N", fC - epsilons) ::
- bassume(Boogie.FunctionApp("wf", List(Heap, Mask))) ::
- MapUpdate3(mask, obj, field, "perm$R", fP - howMuch) :: Nil
+ MapUpdate3(mask, obj, field, "perm$R", fP - howMuch) ::
+ bassume(wf(Heap, Mask, SecMask)) :: Nil
}
def MapUpdate3(m: Boogie.Expr, arg0: Boogie.Expr, arg1: String, arg2: String, rhs: Boogie.Expr) = {
@@ -2406,6 +2678,7 @@ object TranslationHelper {
def bassume(e: Expr) = Boogie.Assume(e)
def BLocal(id: String, tp: BType) = new Boogie.LocalVar(id, tp)
def BLocal(x: Boogie.BVar) = Boogie.LocalVar(x)
+ def BLocals(xs: List[Boogie.BVar]) = xs map BLocal
def tArgSeq = NamedType("ArgSeq");
def tref = NamedType("ref");
def tbool = NamedType("bool");
@@ -2421,8 +2694,9 @@ object TranslationHelper {
def ZeroCredits = VarExpr("ZeroCredits");
def HeapName = "Heap";
def MaskName = "Mask";
+ def SecMaskName = "SecMask";
def CreditsName = "Credits";
- def GlobalNames = List(HeapName, MaskName, CreditsName);
+ def GlobalNames = List(HeapName, MaskName, SecMaskName, CreditsName);
def CanAssumeFunctionDefs = VarExpr("CanAssumeFunctionDefs");
def permissionFull = percentPermission(100);
def permissionOnePercent = percentPermission(1);
@@ -2446,26 +2720,64 @@ object TranslationHelper {
def nonNull(e: Expr): Expr = e !=@ bnull
def LastSeenHeap(sharedBit: Expr, heldBit: Expr) = FunctionApp("LastSeen$Heap", List(sharedBit, heldBit))
def LastSeenMask(sharedBit: Expr, heldBit: Expr) = FunctionApp("LastSeen$Mask", List(sharedBit, heldBit))
+ def LastSeenSecMask(sharedBit: Expr, heldBit: Expr) = FunctionApp("LastSeen$SecMask", List(sharedBit, heldBit))
def LastSeenCredits(sharedBit: Expr, heldBit: Expr) = FunctionApp("LastSeen$Credits", List(sharedBit, heldBit))
def AcquireHeap(heldBit: Expr) = FunctionApp("Acquire$Heap", List(heldBit))
def AcquireMask(heldBit: Expr) = FunctionApp("Acquire$Mask", List(heldBit))
+ def AcquireSecMask(heldBit: Expr) = FunctionApp("Acquire$SecMask", List(heldBit))
def AcquireCredits(heldBit: Expr) = FunctionApp("Acquire$Credits", List(heldBit))
def CallHeap(joinableBit: Expr) = FunctionApp("Call$Heap", List(joinableBit))
def CallMask(joinableBit: Expr) = FunctionApp("Call$Mask", List(joinableBit))
+ def CallSecMask(joinableBit: Expr) = FunctionApp("Call$SecMask", List(joinableBit))
def CallCredits(joinableBit: Expr) = FunctionApp("Call$Credits", List(joinableBit))
def CallArgs(joinableBit: Expr) = FunctionApp("Call$Args", List(joinableBit))
def submask(m0: Expr, m1: Expr) = FunctionApp("submask", List(m0, m1))
- def wf(h: Expr, m: Expr) = FunctionApp("wf", List(h, m));
+ def wf(g: Globals) = FunctionApp("wf", List(g.heap, g.mask, g.secmask));
+ def wf(h: Expr, m: Expr, sm: Expr) = FunctionApp("wf", List(h, m, sm));
def IsGoodMask(m: Expr) = FunctionApp("IsGoodMask", List(m))
- def IsGoodInhaleState(a: Expr, b: Expr, c: Expr) = FunctionApp("IsGoodInhaleState", List(a, b, c))
+ def AreGoodMasks(m: Expr, sm: Expr) = IsGoodMask(m) // && IsGoodMask(sm) /** The second mask does currently not necessarily contain positive permissions, which means that we cannot assume IsGoodMask(sm). This might change in the future if we see a need for it */
+ def IsGoodInhaleState(ih: Expr, h: Expr, m: Expr, sm: Expr) = FunctionApp("IsGoodInhaleState", List(ih,h,m,sm))
+ def IsGoodExhaleState(eh: Expr, h: Expr, m: Expr, sm: Expr) = FunctionApp("IsGoodExhaleState", List(eh,h,m,sm))
def contributesToWaitLevel(e: Expr, h: Expr, c: Expr) =
(0 < h.select(e, "held")) || h.select(e, "rdheld") || (new Boogie.MapSelect(c, e) < 0)
def NonEmptyMask(m: Expr) = ! FunctionApp("EmptyMask", List(m))
def NonPredicateField(f: String) = FunctionApp("NonPredicateField", List(VarExpr(f)))
def PredicateField(f: String) = FunctionApp("PredicateField", List(VarExpr(f)))
def cast(a: Expr, b: Expr) = FunctionApp("cast", List(a, b))
-
+
+ // output a dummy function assumption that serves as trigger for the function
+ // definition axiom.
+ def functionTrigger(receiver: Expr, predicate: Predicate): Stmt = {
+ bassume(FunctionApp("#" + predicate.FullName+"#trigger", receiver :: Nil))
+ }
+
+ def emptyPartialHeap: Expr = Boogie.VarExpr("emptyPartialHeap")
+ def heapFragment(dep: Expr): Expr = Boogie.FunctionApp("heapFragment", List(dep))
+ def combine(l: Expr, r: Expr): Expr = {
+ (l,r) match {
+ case (VarExpr("emptyPartialHeap"), a) => a
+ case (a, VarExpr("emptyPartialHeap")) => a
+ case _ => Boogie.FunctionApp("combine", List(l, r))
+ }
+ }
+ def tpartialheap = NamedType("PartialHeapType");
+
+ def copyState(globals: Globals, et: ExpressionTranslator): List[Stmt] =
+ copyState(globals, et.globals)
+ def copyState(globals: Globals, globalsToCopyFrom: Globals): List[Stmt] = {
+ (for ((a, b) <- globals.list zip globalsToCopyFrom.list) yield (a := b)) :::
+ bassume(wf(globals)) :: Nil
+ }
+ def resetState(et: ExpressionTranslator): List[Stmt] = resetState(et.globals)
+ def resetState(globals: Globals): List[Stmt] = {
+ (globals.mask := ZeroMask) ::
+ (globals.secmask := ZeroMask) ::
+ (globals.credits := ZeroCredits) ::
+ Havoc(globals.heap) ::
+ Nil
+ }
+
// sequences
def createEmptySeq = FunctionApp("Seq#Empty", List())
@@ -2521,38 +2833,48 @@ object TranslationHelper {
true
}
}
-
- def Version(expr: Expression, etran: ExpressionTranslator): Boogie.Expr = {
- val nostate = Boogie.VarExpr("nostate");
- desugar(expr) match {
+
+ /** Generate an expression that represents the state a function can depend on
+ * (as determined by examining the functions preconditions).
+ */
+ def functionDependencies(pre: Expression, etran: ExpressionTranslator): Boogie.Expr = {
+ desugar(pre) match {
case pred@MemberAccess(e, p) if pred.isPredicate =>
- Version(Access(pred, Full), etran)
+ functionDependencies(Access(pred, Full), etran)
case acc@Access(e, _) =>
val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
- new Boogie.MapSelect(etran.Heap, etran.Tr(e.e), memberName)
+ heapFragment(new Boogie.MapSelect(etran.Heap, etran.Tr(e.e), memberName))
case Implies(e0,e1) =>
- Boogie.Ite(etran.Tr(e0), Version(e1, etran), nostate)
+ heapFragment(Boogie.Ite(etran.Tr(e0), functionDependencies(e1, etran), emptyPartialHeap))
case And(e0,e1) =>
- val l = Version(e0, etran);
- val r = Version(e1, etran);
- if (l == nostate) r
- else if (r == nostate) l
- else Boogie.FunctionApp("combine", List(l, r))
+ combine(functionDependencies(e0, etran), functionDependencies(e1, etran))
case IfThenElse(con, then, els) =>
- Boogie.Ite(etran.Tr(con), Version(then, etran), Version(els, etran))
- case _: PermissionExpr => throw new InternalErrorException("unexpected permission expression")
+ heapFragment(Boogie.Ite(etran.Tr(con), functionDependencies(then, etran), functionDependencies(els, etran)))
+ case Unfolding(_, _) =>
+ emptyPartialHeap // the predicate of the unfolding expression needs to have been mentioned already (framing check), so we can safely ignore it now
+ case p: PermissionExpr => println(p); throw new InternalErrorException("unexpected permission expression")
case e =>
- e visit {_ match { case _ : PermissionExpr => throw new InternalErrorException("unexpected permission expression"); case _ =>}}
- nostate
+ e visitOpt {_ match {
+ case Unfolding(_, _) => false
+ case _ : PermissionExpr => throw new InternalErrorException("unexpected permission expression")
+ case _ => true }
+ }
+ emptyPartialHeap
}
}
- // conservative for Implies and IfThenElse
- // returns an expression of Boogie type bool
- def Version(expr: Expression, etran1: ExpressionTranslator, etran2: ExpressionTranslator): Boogie.Expr = {
- desugar(expr) match {
+ /** Generate the boolean condition that needs to be true in order to assume
+ * that a function with precondition pre has the same value in two different
+ * states. Essentially, everything that the function can depend on must be
+ * equal.
+ *
+ * - conservative for Implies and IfThenElse
+ * - returns an expression of Boogie type bool
+ */
+ def functionDependenciesEqual(pre: Expression, etran1: ExpressionTranslator, etran2: ExpressionTranslator): Boogie.Expr = {
+ desugar(pre) match {
case pred@MemberAccess(e, p) if pred.isPredicate =>
- Version(Access(pred, Full), etran1, etran2)
+ functionDependenciesEqual(Access(pred, Full), etran1, etran2)
case Access(e, _) =>
val memberName = if(e.isPredicate) e.predicate.FullName else e.f.FullName;
etran1.Heap.select(etran1.Tr(e.e), memberName) ==@ etran2.Heap.select(etran2.Tr(e.e), memberName)
@@ -2563,14 +2885,20 @@ object TranslationHelper {
((((0 <= i) && (i < SeqLength(etran1.Tr(s)))) ==>
(etran1.Heap.select(SeqIndex(etran1.Tr(s), i), name) ==@ etran2.Heap.select(SeqIndex(etran2.Tr(s), i), name))).forall(iV))
case Implies(e0,e1) =>
- Boogie.Ite(etran1.Tr(e0) || etran2.Tr(e0), Version(e1, etran1, etran2), true)
+ Boogie.Ite(etran1.Tr(e0) || etran2.Tr(e0), functionDependenciesEqual(e1, etran1, etran2), true)
case And(e0,e1) =>
- Version(e0, etran1, etran2) && Version(e1, etran1, etran2)
+ functionDependenciesEqual(e0, etran1, etran2) && functionDependenciesEqual(e1, etran1, etran2)
case IfThenElse(con, then, els) =>
- Version(then, etran1, etran2) && Version(els, etran1, etran2)
+ functionDependenciesEqual(then, etran1, etran2) && functionDependenciesEqual(els, etran1, etran2)
+ case Unfolding(_, _) =>
+ Boogie.BoolLiteral(true) // the predicate of the unfolding expression needs to have been mentioned already (framing check), so we can safely ignore it now
case _: PermissionExpr => throw new InternalErrorException("unexpected permission expression")
case e =>
- e visit {_ match { case _ : PermissionExpr => throw new InternalErrorException("unexpected permission expression"); case _ =>}}
+ e visitOpt {_ match {
+ case Unfolding(_, _) => false
+ case _ : PermissionExpr => throw new InternalErrorException("unexpected permission expression")
+ case _ => true }
+ }
Boogie.BoolLiteral(true)
}
}
@@ -2710,7 +3038,7 @@ object TranslationHelper {
}
def SubstRd(e: Expression): Expression = e match {
- case Access(e, _:Permission) =>
+ case Access(e, p: Permission) if p != Star =>
//val r = Access(e,MonitorEpsilon(None)); r.pos = e.pos; r.typ = BoolClass; r
val r = Access(e,Epsilons(IntLiteral(1))); r.pos = e.pos; r.typ = BoolClass; r
case Implies(e0,e1) =>
@@ -2876,14 +3204,15 @@ object TranslationHelper {
s
}
// Assume the only composite statement in Boogie is If
- def assert2assume(l: List[Stmt]):List[Stmt] =
- if (Chalice.noFreeAssume) l else
+ def assert2assume(l: List[Stmt], b: Boolean):List[Stmt] =
+ if (Chalice.noFreeAssume && b) l else
l flatMap {
case Boogie.If(guard, thn, els) => Boogie.If(guard, assert2assume(thn), assert2assume(els))
case ba @ Boogie.Assert(e) =>
if (ba.tags contains keepTag) ba else Comment(" assert " + ba.pos + ": " + ba.message) :: Boogie.Assume(e)
case s => s
}
+ def assert2assume(l: List[Stmt]):List[Stmt] = assert2assume(l, false)
}
}
diff --git a/Chalice/tests/examples/AssociationList.output.txt b/Chalice/tests/examples/AssociationList.output.txt
index 53d6428f..2955a814 100644
--- a/Chalice/tests/examples/AssociationList.output.txt
+++ b/Chalice/tests/examples/AssociationList.output.txt
@@ -2,9 +2,9 @@ Verification of AssociationList.chalice using parameters=""
28.3: The postcondition at 30.13 might not hold. Insufficient fraction at 30.13 for mu.
73.9: Method execution before loop might lock/unlock more than allowed by lockchange clause of loop.
+ 98.15: Monitor invariant might hot hold. Insufficient fraction at 120.13 for Node.key.
+ 102.15: Monitor invariant might hot hold. Insufficient fraction at 120.13 for Node.key.
+ 73.9: The loop might lock/unlock more than the lockchange clause allows.
+ 107.7: Monitor invariant might hot hold. Insufficient fraction at 120.13 for Node.key.
-The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
- 73.9: The begging of the while-body is unreachable.
- 73.9: The statements after the while-loop are unreachable.
-
-Boogie program verifier finished with 2 errors and 2 smoke test warnings.
+Boogie program verifier finished with 6 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/general-tests/counter.chalice b/Chalice/tests/general-tests/counter.chalice
index 828cf005..c15ed36b 100644
--- a/Chalice/tests/general-tests/counter.chalice
+++ b/Chalice/tests/general-tests/counter.chalice
@@ -53,9 +53,10 @@ class Program {
}
method doRelease(c: Counter, i: int)
- requires c!=null && holds(c) && acc(c.value) && eval(c.acquire, acc(c.value) && i<=c.value);
+ requires c!=null && holds(c) && acc(c.value) && eval(c.acquire, acc(c.value) && c.value <= i);
lockchange c;
{
+ c.value := i+1
release c; // ok, because of atAcquire conjunct in the precondition
}
diff --git a/Chalice/tests/general-tests/counter.output.txt b/Chalice/tests/general-tests/counter.output.txt
index 1d5be0ea..3c7f78b0 100644
--- a/Chalice/tests/general-tests/counter.output.txt
+++ b/Chalice/tests/general-tests/counter.output.txt
@@ -1,17 +1,17 @@
Verification of counter.chalice using parameters=""
- 69.5: Monitor invariant might hot hold. The expression at 4.27 might not evaluate to true.
- 80.5: Assertion might not hold. The expression at 80.12 might not evaluate to true.
- 119.5: The target of the release statement might not be locked by the current thread.
- 128.7: The mu field of the target of the acquire statement might not be above waitlevel.
- 136.7: The mu field of the target of the acquire statement might not be above waitlevel.
- 145.5: The target of the release statement might not be locked by the current thread.
+ 70.5: Monitor invariant might hot hold. The expression at 4.27 might not evaluate to true.
+ 81.5: Assertion might not hold. The expression at 81.12 might not evaluate to true.
+ 120.5: The target of the release statement might not be locked by the current thread.
+ 129.7: The mu field of the target of the acquire statement might not be above waitlevel.
+ 137.7: The mu field of the target of the acquire statement might not be above waitlevel.
+ 146.5: The target of the release statement might not be locked by the current thread.
The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
- 62.3: The end of method main4 is unreachable.
- 116.3: The end of method nestedBad0 is unreachable.
- 128.7: The statements after the acquire statement are unreachable.
- 136.7: The begging of the lock-block is unreachable.
- 141.3: The end of method nestedBad3 is unreachable.
+ 63.3: The end of method main4 is unreachable.
+ 117.3: The end of method nestedBad0 is unreachable.
+ 129.7: The statements after the acquire statement are unreachable.
+ 137.7: The begging of the lock-block is unreachable.
+ 142.3: The end of method nestedBad3 is unreachable.
Boogie program verifier finished with 6 errors and 5 smoke test warnings.
diff --git a/Chalice/tests/general-tests/prog2.chalice b/Chalice/tests/general-tests/prog2.chalice
index 55fe8ff5..3b6f2783 100644
--- a/Chalice/tests/general-tests/prog2.chalice
+++ b/Chalice/tests/general-tests/prog2.chalice
@@ -37,7 +37,6 @@ class C {
{
var prev := F;
call P(2);
- assert false; // succeeds because postcondition of P is not well-defined (i.e. we do not havoc this.F, so the verifier assumes the value is the same in pre and post)
}
method Q(n: int)
diff --git a/Chalice/tests/general-tests/prog2.output.txt b/Chalice/tests/general-tests/prog2.output.txt
index b9d88bbe..68cd4870 100644
--- a/Chalice/tests/general-tests/prog2.output.txt
+++ b/Chalice/tests/general-tests/prog2.output.txt
@@ -2,12 +2,11 @@ Verification of prog2.chalice using parameters=""
24.5: Assertion might not hold. The expression at 24.12 might not evaluate to true.
31.13: Location might not be readable.
- 73.5: Const variable can be assigned to only once.
- 78.5: Assertion might not hold. The expression at 78.12 might not evaluate to true.
+ 72.5: Const variable can be assigned to only once.
+ 77.5: Assertion might not hold. The expression at 77.12 might not evaluate to true.
The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
20.3: The end of method Caller1 is unreachable.
- 39.5: The statements after the method call statement are unreachable.
- 70.3: The end of method M2 is unreachable.
+ 69.3: The end of method M2 is unreachable.
-Boogie program verifier finished with 4 errors and 3 smoke test warnings.
+Boogie program verifier finished with 4 errors and 2 smoke test warnings.
diff --git a/Chalice/tests/predicates/FoldUnfoldExperiments.chalice b/Chalice/tests/predicates/FoldUnfoldExperiments.chalice
new file mode 100644
index 00000000..4bead442
--- /dev/null
+++ b/Chalice/tests/predicates/FoldUnfoldExperiments.chalice
@@ -0,0 +1,32 @@
+class FoldUnfoldExperiments
+{
+ var x:int;
+ var y:int;
+ predicate X { acc(x) }
+ predicate Y { acc(y) }
+
+ function getX():int
+ requires X;
+ { unfolding X in x }
+
+ function getY():int
+ requires Y;
+ { unfolding Y in y }
+
+ method setX(v:int)
+ requires X;
+ ensures X && getX()==v;
+ {
+ unfold X; x:=v; fold X;
+ }
+
+ method check()
+ requires acc(x) && acc(y);
+ ensures acc(y) && y==2 && X && getX()==3;
+ {
+ x:=1; y:=2;
+ fold X; fold Y;
+ call setX(3);
+ unfold Y;
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/FoldUnfoldExperiments.output.txt b/Chalice/tests/predicates/FoldUnfoldExperiments.output.txt
new file mode 100644
index 00000000..7239cf05
--- /dev/null
+++ b/Chalice/tests/predicates/FoldUnfoldExperiments.output.txt
@@ -0,0 +1,4 @@
+Verification of FoldUnfoldExperiments.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/aux-info.chalice b/Chalice/tests/predicates/aux-info.chalice
new file mode 100644
index 00000000..e72e25fa
--- /dev/null
+++ b/Chalice/tests/predicates/aux-info.chalice
@@ -0,0 +1,33 @@
+class Cell {
+ var value: int;
+
+ predicate p { acc(value,1) }
+
+ method test()
+ requires p && acc(value,2)
+ {
+ // previously, the following sequence let to negative secondary permission
+ // to the field value.
+ fold p
+ fold p
+ call void()
+ call void()
+ call void2()
+
+ unfold p
+ var tmp: int := value
+ fold p
+ // make sure that at this point we can retain information about the field value
+ assert tmp == unfolding p in value // ERROR: currently, Chalice cannot prove this, which it should be able to do
+ }
+
+ method void()
+ requires p
+ {}
+
+ method void2()
+ requires p
+ ensures p
+ {}
+
+}
diff --git a/Chalice/tests/predicates/aux-info.output.txt b/Chalice/tests/predicates/aux-info.output.txt
new file mode 100644
index 00000000..97794a51
--- /dev/null
+++ b/Chalice/tests/predicates/aux-info.output.txt
@@ -0,0 +1,5 @@
+Verification of aux-info.chalice using parameters=""
+
+ 21.5: Assertion might not hold. The expression at 21.12 might not evaluate to true.
+
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/generate_reference.bat b/Chalice/tests/predicates/generate_reference.bat
new file mode 100644
index 00000000..6864843c
--- /dev/null
+++ b/Chalice/tests/predicates/generate_reference.bat
@@ -0,0 +1,2 @@
+@echo off
+call "..\test-scripts\%0" %*
diff --git a/Chalice/tests/predicates/generate_reference_all.bat b/Chalice/tests/predicates/generate_reference_all.bat
new file mode 100644
index 00000000..6864843c
--- /dev/null
+++ b/Chalice/tests/predicates/generate_reference_all.bat
@@ -0,0 +1,2 @@
+@echo off
+call "..\test-scripts\%0" %*
diff --git a/Chalice/tests/predicates/mutual-dependence.chalice b/Chalice/tests/predicates/mutual-dependence.chalice
new file mode 100644
index 00000000..a0939607
--- /dev/null
+++ b/Chalice/tests/predicates/mutual-dependence.chalice
@@ -0,0 +1,24 @@
+class Cell {
+ var value: int;
+ var next: Cell;
+
+ predicate p { q }
+ predicate q { acc(value) && acc(next) && (next != null ==> next.p) }
+
+ method test()
+ requires acc(this.*)
+ {
+ value := 1
+ next := null
+ fold q
+ fold p
+ call void()
+ assert unfolding p in unfolding q in value == 1 // ERROR: should not verify
+ }
+
+ method void()
+ requires p
+ ensures p
+ {}
+
+}
diff --git a/Chalice/tests/predicates/mutual-dependence.output.txt b/Chalice/tests/predicates/mutual-dependence.output.txt
new file mode 100644
index 00000000..a35556a9
--- /dev/null
+++ b/Chalice/tests/predicates/mutual-dependence.output.txt
@@ -0,0 +1,5 @@
+Verification of mutual-dependence.chalice using parameters=""
+
+ 16.5: Assertion might not hold. The expression at 16.12 might not evaluate to true.
+
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/reg_test.bat b/Chalice/tests/predicates/reg_test.bat
new file mode 100644
index 00000000..6864843c
--- /dev/null
+++ b/Chalice/tests/predicates/reg_test.bat
@@ -0,0 +1,2 @@
+@echo off
+call "..\test-scripts\%0" %*
diff --git a/Chalice/tests/predicates/reg_test_all.bat b/Chalice/tests/predicates/reg_test_all.bat
new file mode 100644
index 00000000..6864843c
--- /dev/null
+++ b/Chalice/tests/predicates/reg_test_all.bat
@@ -0,0 +1,2 @@
+@echo off
+call "..\test-scripts\%0" %*
diff --git a/Chalice/tests/predicates/test.bat b/Chalice/tests/predicates/test.bat
new file mode 100644
index 00000000..6864843c
--- /dev/null
+++ b/Chalice/tests/predicates/test.bat
@@ -0,0 +1,2 @@
+@echo off
+call "..\test-scripts\%0" %*
diff --git a/Chalice/tests/predicates/test.chalice b/Chalice/tests/predicates/test.chalice
new file mode 100644
index 00000000..6c416671
--- /dev/null
+++ b/Chalice/tests/predicates/test.chalice
@@ -0,0 +1,38 @@
+class List
+{
+ var value:int;
+ var next:List;
+
+ predicate inv { acc(value) && acc(next) && (next!=null ==> next.inv) }
+
+ function len():int
+ requires inv;
+ {
+ unfolding inv in (next==null) ? 1 : (1+next.len())
+ }
+
+ predicate P { acc(value,50) }
+
+ method skip()
+ requires P; ensures P
+ {}
+
+ method goo()
+ requires acc(value);
+ {
+ // mask: value=100, secmask: -
+ fold P;
+ // mask: value=50,p=100, secmask: value=50
+ call skip();
+ // mask: value=50,p=100, secmask: -
+ fold P;
+ // mask: value=0,p=200, secmask: value=50
+ fork t:=skip();
+ // mask: value=0,p=100, secmask: -
+ assert unfolding P in value==old(value);
+ // ERROR: Chalice currently cannot verify this example, as there is neither
+ // primary nor secondary permission available to value directly before the
+ // assertion
+ }
+
+}
diff --git a/Chalice/tests/predicates/test.output.txt b/Chalice/tests/predicates/test.output.txt
new file mode 100644
index 00000000..e05e1b4e
--- /dev/null
+++ b/Chalice/tests/predicates/test.output.txt
@@ -0,0 +1,5 @@
+Verification of test.chalice using parameters=""
+
+ 32.5: Assertion might not hold. The expression at 32.12 might not evaluate to true.
+
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test1.chalice b/Chalice/tests/predicates/test1.chalice
new file mode 100644
index 00000000..7dbde565
--- /dev/null
+++ b/Chalice/tests/predicates/test1.chalice
@@ -0,0 +1,50 @@
+class List
+{
+ var value:int;
+ var next:List;
+
+ predicate inv { acc(value) && acc(next) && (next!=null ==> next.inv) }
+
+ function get():int
+ requires inv;
+ { unfolding inv in value }
+
+ // the purpose of this method is to test whether the methodology can roll back correctly the secondary mask:
+ // s0 unf s1 unf s2 fold, should roll back to state s1 and not s0
+ // note also the unfolding expression in the precondition: the fact that next!=null must be known in the body of the method
+ // this means that the secondary mask must start off containing this.next, according to the proposal
+ method foo()
+ requires inv && unfolding inv in next!=null;
+ ensures inv && unfolding inv in next!=null;
+ {
+ unfold inv;
+ value:=0;
+ unfold next.inv;
+ next.value:=1;
+ fold next.inv;
+ assert next.get()==1;
+ assert value==0;
+ fold inv;
+ assert get()==0;
+ assert unfolding inv in next!=null && next.get()==1;
+ assert unfolding inv in next.get()==1;
+ }
+
+ // this method tests whether the methodology works correctly when (un)folds happen on statically unknown objects
+ method goo(a:List, b:List, c:bool)
+ requires a!=null && b!=null && a.inv && b.inv;
+ {
+ var z:List;
+ unfold a.inv;
+ unfold b.inv;
+ a.value:=0;
+ b.value:=1;
+ if(c) { z:=a } else { z:=b }
+ fold z.inv;
+ assert c ==> a.inv && a.get()==0;
+ assert !c ==> b.inv && b.get()==1;
+ unfold z.inv;
+ assert a.value==0;
+ assert b.value==1;
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test1.output.txt b/Chalice/tests/predicates/test1.output.txt
new file mode 100644
index 00000000..73be63ec
--- /dev/null
+++ b/Chalice/tests/predicates/test1.output.txt
@@ -0,0 +1,4 @@
+Verification of test1.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test10.chalice b/Chalice/tests/predicates/test10.chalice
new file mode 100644
index 00000000..7d45914c
--- /dev/null
+++ b/Chalice/tests/predicates/test10.chalice
@@ -0,0 +1,18 @@
+class List
+{
+ var value:int;
+ var next:List;
+
+ predicate inv { acc(value) && acc(next) && (next!=null ==> next.inv) }
+
+ function get():int
+ requires inv;
+ { unfolding inv in value }
+
+ method foo()
+ requires inv && unfolding inv in next!=null;
+ ensures inv && unfolding inv in next!=null;
+ {
+ assert unfolding inv in unfolding next.inv in true;
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test10.output.txt b/Chalice/tests/predicates/test10.output.txt
new file mode 100644
index 00000000..d38b56a0
--- /dev/null
+++ b/Chalice/tests/predicates/test10.output.txt
@@ -0,0 +1,4 @@
+Verification of test10.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test2.chalice b/Chalice/tests/predicates/test2.chalice
new file mode 100644
index 00000000..f93a1eeb
--- /dev/null
+++ b/Chalice/tests/predicates/test2.chalice
@@ -0,0 +1,55 @@
+class FoldUnfoldExperiments
+{
+ var x:int;
+ var y:int;
+ var z:int;
+ var w:int;
+ predicate X { acc(x) }
+ predicate Y { acc(y) }
+ predicate Z { acc(z) }
+
+ function getX():int
+ requires X;
+ { unfolding X in x }
+
+ function getY():int
+ requires Y;
+ { unfolding Y in y }
+
+ function getZ():int
+ requires Z;
+ { unfolding Z in z }
+
+ method setX(v:int)
+ requires X;
+ ensures X && getX()==v;
+ {
+ unfold X; x:=v; fold X;
+ }
+
+ // this method checks if the methodology frames correctly around a method call: what happens with folded data and unfolded data
+ // also: what happens if we have folded data during the call, that we unfold after the call
+ method check()
+ requires acc(x) && acc(y) && acc(z) && acc(w);
+ ensures acc(y) && y==2 && X && getX()==3 && Z && getZ()==4 && acc(w) && w==10;
+ {
+ x:=1; y:=2; z:=4; w:=10;
+ fold X; fold Y; fold Z;
+ call setX(3);
+ unfold Y;
+ }
+
+ // this method checks that method calls do not interfere with the correct handling of folds and unfolds
+ method check1()
+ requires X && acc(y) && y==1;
+ ensures acc(y) && y==1 && X && getX()==200;
+ {
+ call setX(10);
+ fold Y;
+ call setX(100);
+ unfold Y;
+ fold Y;
+ unfold Y;
+ call setX(200);
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test2.output.txt b/Chalice/tests/predicates/test2.output.txt
new file mode 100644
index 00000000..d0bed944
--- /dev/null
+++ b/Chalice/tests/predicates/test2.output.txt
@@ -0,0 +1,4 @@
+Verification of test2.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test3.chalice b/Chalice/tests/predicates/test3.chalice
new file mode 100644
index 00000000..2a364fee
--- /dev/null
+++ b/Chalice/tests/predicates/test3.chalice
@@ -0,0 +1,29 @@
+class Unsound
+{
+ var value:int;
+
+ predicate inv { acc(value) }
+
+ function get():int
+ requires inv;
+ {
+ unfolding inv in value
+ }
+
+ method set(newval:int)
+ requires inv;
+ ensures inv && get()==newval;
+ {
+ unfold inv;
+ value:=newval;
+ fold inv;
+ }
+
+ method test()
+ requires inv;
+ {
+ call set(3);
+ call set(4);
+ // at this point, Chalice used to be able to prove false
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test3.output.txt b/Chalice/tests/predicates/test3.output.txt
new file mode 100644
index 00000000..7e4e49d6
--- /dev/null
+++ b/Chalice/tests/predicates/test3.output.txt
@@ -0,0 +1,4 @@
+Verification of test3.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test4.chalice b/Chalice/tests/predicates/test4.chalice
new file mode 100644
index 00000000..201b643d
--- /dev/null
+++ b/Chalice/tests/predicates/test4.chalice
@@ -0,0 +1,56 @@
+class Cell
+{
+ var value:int;
+
+ predicate P { acc(value,50) }
+
+ function get():int
+ requires P;
+ {
+ unfolding P in value
+ }
+
+ method boom(x:Cell, y:Cell)
+ requires x!=null && y!=null && x.P && y.P;
+ ensures x.P && y.P && (x==y ==> x.get()==100) && (x!=y ==> x.get()==old(x.get()));
+ {
+ if(x==y)
+ {
+ unfold x.P; unfold x.P;
+ y.value:=100;
+ fold y.P; fold y.P;
+ }
+ }
+
+ method skip()
+ requires P;
+ ensures P;
+ {}
+
+ // is the bookkeeping correct when calculating the secondary mask?
+ // fold happens once on a statically unknown object
+ // intermediate calls to skip happen in all examples to create artificial "changes" to the heap,
+ // thereby testing framing in the bookkeeping of folds/unfolds
+ method foo(z:Cell)
+ requires acc(value,50) && value==2 && z!=null && acc(z.value,50);
+ {
+ fold z.P;
+ call z.skip();
+ fold P;
+ call boom(this, z);
+ assert this!=z ==> unfolding P in value==2;
+ assert this==z ==> unfolding P in value==100;
+ }
+
+ // must fail: give away all permission, even in pieces, and you lose all information about value
+ method hoo()
+ requires acc(value);
+ {
+ fold P;
+ call skip();
+ fold P;
+ fork t:=skip();
+ call skip ();
+ assert unfolding P in value==old(value); // ERROR: should fail
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test4.output.txt b/Chalice/tests/predicates/test4.output.txt
new file mode 100644
index 00000000..5268bec7
--- /dev/null
+++ b/Chalice/tests/predicates/test4.output.txt
@@ -0,0 +1,5 @@
+Verification of test4.chalice using parameters=""
+
+ 54.2: Assertion might not hold. The expression at 54.9 might not evaluate to true.
+
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/test7.chalice b/Chalice/tests/predicates/test7.chalice
new file mode 100644
index 00000000..6ad8e592
--- /dev/null
+++ b/Chalice/tests/predicates/test7.chalice
@@ -0,0 +1,109 @@
+class C
+{
+ var value:int;
+
+ predicate inv { acc(value) }
+
+ function get():int
+ requires inv;
+ {
+ unfolding inv in value
+ }
+
+ method set(newval:int)
+ requires inv;
+ ensures inv && get()==newval;
+ {
+ unfold inv;
+ value:=newval;
+ fold inv;
+ }
+
+ method callmethod0()
+ requires inv;
+ ensures inv && get()==3;
+ {
+ call set(3);
+ }
+
+ method callmethod1()
+ {
+ call set(3); // ERROR: should fail
+ }
+
+ method ifc()
+ requires inv;
+ ensures inv && get()>old(get())
+ {
+ if(get()>0) { call set(get()+get()); }
+ else { call set(2); }
+ }
+
+ method loop0() returns (r:int)
+ requires inv && get()>0;
+ ensures inv && r==get();
+ {
+ r:=0;
+ while (r<unfolding inv in value)
+ invariant inv && r<=get();
+ { r:=r+1; }
+ }
+
+ method loop1() returns (r:int)
+ requires inv && get()>0;
+ ensures inv && r==get();
+ {
+ r:=0;
+ while (r<get())
+ invariant inv && r<=unfolding inv in value;
+ { r:=r+1; }
+ }
+
+ method uf0()
+ requires acc(value);
+ {
+ assert acc(value);
+ fold inv;
+ assert acc(value); // ERROR: should fail
+ }
+
+ method uf1()
+ requires acc(value);
+ {
+ assert acc(value);
+ fold inv;
+ assert acc(inv);
+ }
+
+ method uf2()
+ requires inv;
+ {
+ assert inv;
+ unfold inv;
+ assert acc(value);
+ }
+
+ method uf3()
+ requires inv;
+ {
+ assert inv;
+ unfold inv;
+ assert acc(inv); // ERROR: should fail
+ }
+
+ method badframing0()
+ requires get()==2; // ERROR: should fail
+ {}
+
+ method badframing1()
+ requires value==2; // ERROR: should fail
+ {}
+
+ method badframing2()
+ requires acc(value) && get()==2; // ERROR: should fail
+ {}
+
+ method badframing3()
+ requires inv && value==2; // ERROR: should fail
+ {}
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test7.output.txt b/Chalice/tests/predicates/test7.output.txt
new file mode 100644
index 00000000..46ac796c
--- /dev/null
+++ b/Chalice/tests/predicates/test7.output.txt
@@ -0,0 +1,16 @@
+Verification of test7.chalice using parameters=""
+
+ 31.5: The precondition at 14.14 might not hold. Insufficient fraction at 14.14 for C.inv.
+ 67.5: Assertion might not hold. Insufficient fraction at 67.12 for C.value.
+ 91.5: Assertion might not hold. Insufficient fraction at 91.12 for C.inv.
+ 95.14: Precondition at 8.14 might not hold. Insufficient fraction at 8.14 for C.inv.
+ 99.14: Location might not be readable.
+ 103.28: Precondition at 8.14 might not hold. Insufficient fraction at 8.14 for C.inv.
+ 107.21: Location might not be readable.
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 31.5: The statements after the method call statement are unreachable.
+ 62.3: The end of method uf0 is unreachable.
+ 86.3: The end of method uf3 is unreachable.
+
+Boogie program verifier finished with 7 errors and 3 smoke test warnings.
diff --git a/Chalice/tests/predicates/test8.chalice b/Chalice/tests/predicates/test8.chalice
new file mode 100644
index 00000000..e824f161
--- /dev/null
+++ b/Chalice/tests/predicates/test8.chalice
@@ -0,0 +1,55 @@
+// fold/unfold in various combinations
+class FUFU
+{
+ var value:int;
+ var next:FUFU;
+
+ predicate inv { acc(value) }
+
+ predicate tinv { acc(value) && acc(next) && (next!=null ==> next.tinv) }
+
+ function get():int
+ requires tinv;
+ { unfolding tinv in value }
+
+ method fufu()
+ requires acc(value);
+ {
+ fold inv;
+ unfold inv;
+ fold inv;
+ unfold inv;
+ }
+
+ method fuf()
+ requires acc(value);
+ {
+ fold inv;
+ unfold inv;
+ fold inv;
+ }
+
+ method uf()
+ requires inv;
+ {
+ unfold inv;
+ fold inv;
+ }
+
+ method fu()
+ requires acc(value);
+ {
+ fold inv;
+ unfold inv;
+ }
+
+ method t()
+ requires tinv && unfolding tinv in next!=null;
+ ensures tinv && unfolding tinv in next!=null;
+ {
+ unfold tinv;
+ unfold next.tinv;
+ fold next.tinv;
+ fold tinv;
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/test8.output.txt b/Chalice/tests/predicates/test8.output.txt
new file mode 100644
index 00000000..881b2ef0
--- /dev/null
+++ b/Chalice/tests/predicates/test8.output.txt
@@ -0,0 +1,4 @@
+Verification of test8.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/regressions/internal-bug-1.chalice b/Chalice/tests/regressions/internal-bug-1.chalice
new file mode 100644
index 00000000..10caeebb
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-1.chalice
@@ -0,0 +1,16 @@
+class Test {
+ var next: Test;
+ var elem: int;
+
+ predicate valid {
+ acc(elem) && acc(next) &&
+ (next != null ==> next.valid)
+ }
+
+ function get(index:int):int
+ requires valid
+ // on 2012-02-21, a bug was reported that caused Chalice to crash with an
+ // InternalError for the following precondition.
+ requires unfolding valid in true
+ {0}
+}
diff --git a/Chalice/tests/regressions/internal-bug-1.output.txt b/Chalice/tests/regressions/internal-bug-1.output.txt
new file mode 100644
index 00000000..ea14d3e3
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-1.output.txt
@@ -0,0 +1,4 @@
+Verification of internal-bug-1.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/regressions/workitem-10194.output.txt b/Chalice/tests/regressions/workitem-10194.output.txt
index 3ed31c08..580a8068 100644
--- a/Chalice/tests/regressions/workitem-10194.output.txt
+++ b/Chalice/tests/regressions/workitem-10194.output.txt
@@ -1,5 +1,6 @@
Verification of workitem-10194.chalice using parameters=""
20.35: Location might not be readable.
+ 35.3: Assertion might not hold. The expression at 35.10 might not evaluate to true.
-Boogie program verifier finished with 1 errors and 0 smoke test warnings.
+Boogie program verifier finished with 2 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/runalltests.bat b/Chalice/tests/runalltests.bat
index 54121bbe..ab878804 100644
--- a/Chalice/tests/runalltests.bat
+++ b/Chalice/tests/runalltests.bat
@@ -11,7 +11,7 @@ if "%1"=="-no-summary" (
set t=0
set c=0
-for %%f in (examples permission-model general-tests regressions) do (
+for %%f in (examples permission-model general-tests regressions predicates) do (
echo Running tests in %%f ...
echo ------------------------------------------------------
cd %%f
diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs
index 9a30401d..ed70f14e 100644
--- a/Source/BoogieDriver/BoogieDriver.cs
+++ b/Source/BoogieDriver/BoogieDriver.cs
@@ -429,6 +429,134 @@ namespace Microsoft.Boogie {
}
}
+ static void ProcessOutcome(VC.VCGen.Outcome outcome, List<Counterexample> errors, string timeIndication,
+ ref int errorCount, ref int verified, ref int inconclusives, ref int timeOuts, ref int outOfMemories) {
+ switch (outcome) {
+ default:
+ Contract.Assert(false); // unexpected outcome
+ throw new cce.UnreachableException();
+ case VCGen.Outcome.ReachedBound:
+ Inform(String.Format("{0}verified", timeIndication));
+ Console.WriteLine(string.Format("Stratified Inlining: Reached recursion bound of {0}", CommandLineOptions.Clo.RecursionBound));
+ verified++;
+ break;
+ case VCGen.Outcome.Correct:
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
+ Inform(String.Format("{0}credible", timeIndication));
+ verified++;
+ }
+ else {
+ Inform(String.Format("{0}verified", timeIndication));
+ verified++;
+ }
+ break;
+ case VCGen.Outcome.TimedOut:
+ timeOuts++;
+ Inform(String.Format("{0}timed out", timeIndication));
+ break;
+ case VCGen.Outcome.OutOfMemory:
+ outOfMemories++;
+ Inform(String.Format("{0}out of memory", timeIndication));
+ break;
+ case VCGen.Outcome.Inconclusive:
+ inconclusives++;
+ Inform(String.Format("{0}inconclusive", timeIndication));
+ break;
+ case VCGen.Outcome.Errors:
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
+ Inform(String.Format("{0}doomed", timeIndication));
+ errorCount++;
+ } //else {
+ Contract.Assert(errors != null); // guaranteed by postcondition of VerifyImplementation
+
+ {
+ // BP1xxx: Parsing errors
+ // BP2xxx: Name resolution errors
+ // BP3xxx: Typechecking errors
+ // BP4xxx: Abstract interpretation errors (Is there such a thing?)
+ // BP5xxx: Verification errors
+
+ errors.Sort(new CounterexampleComparer());
+ foreach (Counterexample error in errors) {
+ if (error is CallCounterexample) {
+ CallCounterexample err = (CallCounterexample)error;
+ if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingRequires.ErrorMessage != null) {
+ ReportBplError(err.FailingRequires, err.FailingRequires.ErrorMessage, true, false);
+ }
+ else {
+ ReportBplError(err.FailingCall, "Error BP5002: A precondition for this call might not hold.", true, true);
+ ReportBplError(err.FailingRequires, "Related location: This is the precondition that might not hold.", false, true);
+ }
+ if (CommandLineOptions.Clo.XmlSink != null) {
+ CommandLineOptions.Clo.XmlSink.WriteError("precondition violation", err.FailingCall.tok, err.FailingRequires.tok, error.Trace);
+ }
+ }
+ else if (error is ReturnCounterexample) {
+ ReturnCounterexample err = (ReturnCounterexample)error;
+ if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingEnsures.ErrorMessage != null) {
+ ReportBplError(err.FailingEnsures, err.FailingEnsures.ErrorMessage, true, false);
+ }
+ else {
+ ReportBplError(err.FailingReturn, "Error BP5003: A postcondition might not hold on this return path.", true, true);
+ ReportBplError(err.FailingEnsures, "Related location: This is the postcondition that might not hold.", false, true);
+ }
+ if (CommandLineOptions.Clo.XmlSink != null) {
+ CommandLineOptions.Clo.XmlSink.WriteError("postcondition violation", err.FailingReturn.tok, err.FailingEnsures.tok, error.Trace);
+ }
+ }
+ else // error is AssertCounterexample
+ {
+ AssertCounterexample err = (AssertCounterexample)error;
+ if (err.FailingAssert is LoopInitAssertCmd) {
+ ReportBplError(err.FailingAssert, "Error BP5004: This loop invariant might not hold on entry.", true, true);
+ if (CommandLineOptions.Clo.XmlSink != null) {
+ CommandLineOptions.Clo.XmlSink.WriteError("loop invariant entry violation", err.FailingAssert.tok, null, error.Trace);
+ }
+ }
+ else if (err.FailingAssert is LoopInvMaintainedAssertCmd) {
+ // this assertion is a loop invariant which is not maintained
+ ReportBplError(err.FailingAssert, "Error BP5005: This loop invariant might not be maintained by the loop.", true, true);
+ if (CommandLineOptions.Clo.XmlSink != null) {
+ CommandLineOptions.Clo.XmlSink.WriteError("loop invariant maintenance violation", err.FailingAssert.tok, null, error.Trace);
+ }
+ }
+ else {
+ if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingAssert.ErrorMessage != null) {
+ ReportBplError(err.FailingAssert, err.FailingAssert.ErrorMessage, true, false);
+ }
+ else if (err.FailingAssert.ErrorData is string) {
+ ReportBplError(err.FailingAssert, (string)err.FailingAssert.ErrorData, true, true);
+ }
+ else {
+ ReportBplError(err.FailingAssert, "Error BP5001: This assertion might not hold.", true, true);
+ }
+ if (CommandLineOptions.Clo.XmlSink != null) {
+ CommandLineOptions.Clo.XmlSink.WriteError("assertion violation", err.FailingAssert.tok, null, error.Trace);
+ }
+ }
+ }
+ if (CommandLineOptions.Clo.EnhancedErrorMessages == 1) {
+ foreach (string info in error.relatedInformation) {
+ Contract.Assert(info != null);
+ Console.WriteLine(" " + info);
+ }
+ }
+ if (CommandLineOptions.Clo.ErrorTrace > 0) {
+ Console.WriteLine("Execution trace:");
+ error.Print(4);
+ }
+ if (CommandLineOptions.Clo.ModelViewFile != null) {
+ error.PrintModel();
+ }
+ errorCount++;
+ }
+ //}
+ Inform(String.Format("{0}error{1}", timeIndication, errors.Count == 1 ? "" : "s"));
+ }
+ break;
+ }
+ }
+
/// <summary>
/// Given a resolved and type checked Boogie program, infers invariants for the program
/// and then attempts to verify it. Returns:
@@ -453,30 +581,6 @@ namespace Microsoft.Boogie {
Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program);
}
- if (CommandLineOptions.Clo.ContractInfer) {
- Houdini.Houdini houdini = new Houdini.Houdini(program, true);
- Houdini.HoudiniOutcome outcome = houdini.PerformHoudiniInference();
- int numTrueAssigns = 0;
- Console.WriteLine("Assignment computed by Houdini:");
- foreach (var x in outcome.assignment) {
- Console.WriteLine(x.Key + " = " + x.Value);
- if (x.Value)
- numTrueAssigns++;
- }
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Number of true assignments = " + numTrueAssigns);
- Console.WriteLine("Number of false assignments = " + (outcome.assignment.Count - numTrueAssigns));
- Console.WriteLine("Prover time = " + Houdini.HoudiniSession.proverTime);
- Console.WriteLine("Number of prover queries = " + Houdini.HoudiniSession.numProverQueries);
- }
- errorCount = outcome.ErrorCount;
- verified = outcome.Verified;
- inconclusives = outcome.Inconclusives;
- timeOuts = outcome.TimeOuts;
- outOfMemories = 0;
- return PipelineOutcome.Done;
- }
-
if (CommandLineOptions.Clo.LoopUnrollCount != -1) {
program.UnrollLoops(CommandLineOptions.Clo.LoopUnrollCount);
}
@@ -502,6 +606,40 @@ namespace Microsoft.Boogie {
return PipelineOutcome.Done;
}
+ #region Run Houdini and verify
+ if (CommandLineOptions.Clo.ContractInfer) {
+ Houdini.Houdini houdini = new Houdini.Houdini(program);
+ Houdini.HoudiniOutcome outcome = houdini.PerformHoudiniInference();
+ if (CommandLineOptions.Clo.PrintAssignment) {
+ Console.WriteLine("Assignment computed by Houdini:");
+ foreach (var x in outcome.assignment) {
+ Console.WriteLine(x.Key + " = " + x.Value);
+ }
+ }
+ if (CommandLineOptions.Clo.Trace) {
+ int numTrueAssigns = 0;
+ foreach (var x in outcome.assignment) {
+ if (x.Value)
+ numTrueAssigns++;
+ }
+ Console.WriteLine("Number of true assignments = " + numTrueAssigns);
+ Console.WriteLine("Number of false assignments = " + (outcome.assignment.Count - numTrueAssigns));
+ Console.WriteLine("Prover time = " + Houdini.HoudiniSession.proverTime);
+ Console.WriteLine("Number of prover queries = " + Houdini.HoudiniSession.numProverQueries);
+ }
+
+ foreach (Houdini.VCGenOutcome x in outcome.implementationOutcomes.Values) {
+ ProcessOutcome(x.outcome, x.errors, "", ref errorCount, ref verified, ref inconclusives, ref timeOuts, ref outOfMemories);
+ }
+ //errorCount = outcome.ErrorCount;
+ //verified = outcome.Verified;
+ //inconclusives = outcome.Inconclusives;
+ //timeOuts = outcome.TimeOuts;
+ //outOfMemories = 0;
+ return PipelineOutcome.Done;
+ }
+ #endregion
+
#region Verify each implementation
ConditionGeneration vcgen = null;
@@ -541,42 +679,44 @@ namespace Microsoft.Boogie {
VCGen.Outcome outcome;
try {
- if (CommandLineOptions.Clo.inferLeastForUnsat != null)
- {
- var svcgen = vcgen as VC.StratifiedVCGen;
- Contract.Assert(svcgen != null);
- var ss = new HashSet<string>();
- foreach (var tdecl in program.TopLevelDeclarations)
- {
- var c = tdecl as Constant;
- if (c == null || !c.Name.StartsWith(CommandLineOptions.Clo.inferLeastForUnsat)) continue;
- ss.Add(c.Name);
- }
- outcome = svcgen.FindLeastToVerify(impl, program, ref ss);
- errors = new List<Counterexample>();
- Console.Write("Result: ");
- foreach (var s in ss)
- {
- Console.Write("{0} ", s);
- }
- Console.WriteLine();
+ if (CommandLineOptions.Clo.inferLeastForUnsat != null) {
+ var svcgen = vcgen as VC.StratifiedVCGen;
+ Contract.Assert(svcgen != null);
+ var ss = new HashSet<string>();
+ foreach (var tdecl in program.TopLevelDeclarations) {
+ var c = tdecl as Constant;
+ if (c == null || !c.Name.StartsWith(CommandLineOptions.Clo.inferLeastForUnsat)) continue;
+ ss.Add(c.Name);
}
- else
- {
- outcome = vcgen.VerifyImplementation(impl, program, out errors);
+ outcome = svcgen.FindLeastToVerify(impl, program, ref ss);
+ errors = new List<Counterexample>();
+ Console.Write("Result: ");
+ foreach (var s in ss) {
+ Console.Write("{0} ", s);
}
- } catch (VCGenException e) {
+ Console.WriteLine();
+ }
+ else {
+ outcome = vcgen.VerifyImplementation(impl, program, out errors);
+ if (CommandLineOptions.Clo.ExtractLoops && vcgen is VCGen && errors != null) {
+ for (int i = 0; i < errors.Count; i++) {
+ errors[i] = (vcgen as VCGen).extractLoopTrace(errors[i], impl.Name, program, extractLoopMappingInfo);
+ }
+ }
+ }
+ }
+ catch (VCGenException e) {
ReportBplError(impl, String.Format("Error BP5010: {0} Encountered in implementation {1}.", e.Message, impl.Name), true, true);
errors = null;
outcome = VCGen.Outcome.Inconclusive;
- } catch (UnexpectedProverOutputException upo) {
+ }
+ catch (UnexpectedProverOutputException upo) {
AdvisoryWriteLine("Advisory: {0} SKIPPED because of internal error: unexpected prover output: {1}", impl.Name, upo.Message);
errors = null;
outcome = VCGen.Outcome.Inconclusive;
}
string timeIndication = "";
-
DateTime end = DateTime.UtcNow;
TimeSpan elapsed = end - start;
if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null) {
@@ -586,130 +726,8 @@ namespace Microsoft.Boogie {
}
}
+ ProcessOutcome(outcome, errors, timeIndication, ref errorCount, ref verified, ref inconclusives, ref timeOuts, ref outOfMemories);
- switch (outcome) {
- default:
- Contract.Assert(false); // unexpected outcome
- throw new cce.UnreachableException();
- case VCGen.Outcome.ReachedBound:
- Inform(String.Format("{0}verified", timeIndication));
- Console.WriteLine(string.Format("Stratified Inlining: Reached recursion bound of {0}", CommandLineOptions.Clo.RecursionBound));
- verified++;
- break;
- case VCGen.Outcome.Correct:
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
- Inform(String.Format("{0}credible", timeIndication));
- verified++;
- } else {
- Inform(String.Format("{0}verified", timeIndication));
- verified++;
- }
- break;
- case VCGen.Outcome.TimedOut:
- timeOuts++;
- Inform(String.Format("{0}timed out", timeIndication));
- break;
- case VCGen.Outcome.OutOfMemory:
- outOfMemories++;
- Inform(String.Format("{0}out of memory", timeIndication));
- break;
- case VCGen.Outcome.Inconclusive:
- inconclusives++;
- Inform(String.Format("{0}inconclusive", timeIndication));
- break;
- case VCGen.Outcome.Errors:
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
- Inform(String.Format("{0}doomed", timeIndication));
- errorCount++;
- } //else {
- Contract.Assert(errors != null); // guaranteed by postcondition of VerifyImplementation
-
- {
- // BP1xxx: Parsing errors
- // BP2xxx: Name resolution errors
- // BP3xxx: Typechecking errors
- // BP4xxx: Abstract interpretation errors (Is there such a thing?)
- // BP5xxx: Verification errors
-
- if (CommandLineOptions.Clo.ExtractLoops && (vcgen is VCGen))
- {
- for (int i = 0; i < errors.Count; i++)
- {
- errors[i] = (vcgen as VCGen).extractLoopTrace(errors[i], impl.Name, program, extractLoopMappingInfo);
- }
- }
-
- errors.Sort(new CounterexampleComparer());
- foreach (Counterexample error in errors) {
- if (error is CallCounterexample) {
- CallCounterexample err = (CallCounterexample)error;
- if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingRequires.ErrorMessage != null) {
- ReportBplError(err.FailingRequires, err.FailingRequires.ErrorMessage, true, false);
- } else {
- ReportBplError(err.FailingCall, "Error BP5002: A precondition for this call might not hold.", true, true);
- ReportBplError(err.FailingRequires, "Related location: This is the precondition that might not hold.", false, true);
- }
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteError("precondition violation", err.FailingCall.tok, err.FailingRequires.tok, error.Trace);
- }
- } else if (error is ReturnCounterexample) {
- ReturnCounterexample err = (ReturnCounterexample)error;
- if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingEnsures.ErrorMessage != null) {
- ReportBplError(err.FailingEnsures, err.FailingEnsures.ErrorMessage, true, false);
- } else {
- ReportBplError(err.FailingReturn, "Error BP5003: A postcondition might not hold on this return path.", true, true);
- ReportBplError(err.FailingEnsures, "Related location: This is the postcondition that might not hold.", false, true);
- }
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteError("postcondition violation", err.FailingReturn.tok, err.FailingEnsures.tok, error.Trace);
- }
- } else // error is AssertCounterexample
- {
- AssertCounterexample err = (AssertCounterexample)error;
- if (err.FailingAssert is LoopInitAssertCmd) {
- ReportBplError(err.FailingAssert, "Error BP5004: This loop invariant might not hold on entry.", true, true);
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteError("loop invariant entry violation", err.FailingAssert.tok, null, error.Trace);
- }
- } else if (err.FailingAssert is LoopInvMaintainedAssertCmd) {
- // this assertion is a loop invariant which is not maintained
- ReportBplError(err.FailingAssert, "Error BP5005: This loop invariant might not be maintained by the loop.", true, true);
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteError("loop invariant maintenance violation", err.FailingAssert.tok, null, error.Trace);
- }
- } else {
- if (!CommandLineOptions.Clo.ForceBplErrors && err.FailingAssert.ErrorMessage != null) {
- ReportBplError(err.FailingAssert, err.FailingAssert.ErrorMessage, true, false);
- } else if (err.FailingAssert.ErrorData is string) {
- ReportBplError(err.FailingAssert, (string)err.FailingAssert.ErrorData, true, true);
- } else {
- ReportBplError(err.FailingAssert, "Error BP5001: This assertion might not hold.", true, true);
- }
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteError("assertion violation", err.FailingAssert.tok, null, error.Trace);
- }
- }
- }
- if (CommandLineOptions.Clo.EnhancedErrorMessages == 1) {
- foreach (string info in error.relatedInformation) {
- Contract.Assert(info != null);
- Console.WriteLine(" " + info);
- }
- }
- if (CommandLineOptions.Clo.ErrorTrace > 0) {
- Console.WriteLine("Execution trace:");
- error.Print(4);
- }
- if (CommandLineOptions.Clo.ModelViewFile != null) {
- error.PrintModel();
- }
- errorCount++;
- }
- //}
- Inform(String.Format("{0}error{1}", timeIndication, errors.Count == 1 ? "" : "s"));
- }
- break;
- }
if (CommandLineOptions.Clo.XmlSink != null) {
CommandLineOptions.Clo.XmlSink.WriteEndMethod(outcome.ToString().ToLowerInvariant(), end, elapsed);
}
@@ -718,6 +736,7 @@ namespace Microsoft.Boogie {
}
}
}
+
vcgen.Close();
cce.NonNull(CommandLineOptions.Clo.TheProverFactory).Close();
@@ -726,6 +745,5 @@ namespace Microsoft.Boogie {
return PipelineOutcome.VerificationCompleted;
}
-
}
}
diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg
index 33172e7f..c7465d81 100644
--- a/Source/Core/BoogiePL.atg
+++ b/Source/Core/BoogiePL.atg
@@ -35,26 +35,30 @@ static StructuredCmd/*!*/ dummyStructuredCmd = new BreakCmd(Token.NoToken, null)
///the parsed program.
///</summary>
public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> defines, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
-Contract.Requires(filename != null);
-Contract.Requires(cce.NonNullElements(defines,true));
+ Contract.Requires(filename != null);
+ Contract.Requires(cce.NonNullElements(defines,true));
+ if (defines == null) {
+ defines = new List<string/*!*/>();
+ }
- FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
- var ret = Parse(stream, filename, defines, out program);
- stream.Close();
- return ret;
+ if (filename == "stdin.bpl") {
+ var s = ParserHelper.Fill(Console.In, defines);
+ return Parse(s, filename, out program);
+ } else {
+ FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
+ var s = ParserHelper.Fill(stream, defines);
+ var ret = Parse(s, filename, out program);
+ stream.Close();
+ return ret;
+ }
}
-public static int Parse (Stream stream, string/*!*/ filename, /*maybe null*/ List<string/*!*/> defines, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
-Contract.Requires(stream != null);
-Contract.Requires(filename != null);
-Contract.Requires(cce.NonNullElements(defines,true));
+public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
+ Contract.Requires(s != null);
+ Contract.Requires(filename != null);
- if (defines == null) {
- defines = new List<string/*!*/>();
- }
- string s = ParserHelper.Fill(stream, defines);
byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
Errors errors = new Errors();
diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs
index e75fe867..1a2d7fda 100644
--- a/Source/Core/CommandLineOptions.cs
+++ b/Source/Core/CommandLineOptions.cs
@@ -389,6 +389,7 @@ namespace Microsoft.Boogie {
public int /*(0:3)*/ ErrorTrace = 1;
public bool IntraproceduralInfer = true;
public bool ContractInfer = false;
+ public bool PrintAssignment = false;
public int InlineDepth = -1;
public bool UseUncheckedContracts = false;
public bool SimplifyLogFileAppend = false;
@@ -830,10 +831,6 @@ namespace Microsoft.Boogie {
ps.GetNumericArgument(ref EnhancedErrorMessages, 2);
return true;
- case "contractInfer":
- ContractInfer = true;
- return true;
-
case "inlineDepth":
ps.GetNumericArgument(ref InlineDepth);
return true;
@@ -1007,7 +1004,11 @@ namespace Microsoft.Boogie {
}
}
return true;
-
+ case "siVerbose":
+ if (ps.ConfirmArgumentCount(1)) {
+ StratifiedInliningVerbose = Int32.Parse(cce.NonNull(args[ps.i]));
+ }
+ return true;
case "recursionBound":
if (ps.ConfirmArgumentCount(1)) {
RecursionBound = Int32.Parse(cce.NonNull(args[ps.i]));
@@ -1225,7 +1226,9 @@ namespace Microsoft.Boogie {
ps.CheckBooleanFlag("monomorphize", ref Monomorphize) ||
ps.CheckBooleanFlag("useArrayTheory", ref UseArrayTheory) ||
ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) ||
- ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false)
+ ps.CheckBooleanFlag("doNotUseLabels", ref UseLabels, false) ||
+ ps.CheckBooleanFlag("contractInfer", ref ContractInfer) ||
+ ps.CheckBooleanFlag("printAssignment", ref PrintAssignment)
) {
// one of the boolean flags matched
return true;
diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs
index fe77bcc1..331a7cb9 100644
--- a/Source/Core/Parser.cs
+++ b/Source/Core/Parser.cs
@@ -54,26 +54,30 @@ static StructuredCmd/*!*/ dummyStructuredCmd = new BreakCmd(Token.NoToken, null)
///the parsed program.
///</summary>
public static int Parse (string/*!*/ filename, /*maybe null*/ List<string/*!*/> defines, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
-Contract.Requires(filename != null);
-Contract.Requires(cce.NonNullElements(defines,true));
+ Contract.Requires(filename != null);
+ Contract.Requires(cce.NonNullElements(defines,true));
+ if (defines == null) {
+ defines = new List<string/*!*/>();
+ }
- FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
- var ret = Parse(stream, filename, defines, out program);
- stream.Close();
- return ret;
+ if (filename == "stdin.bpl") {
+ var s = ParserHelper.Fill(Console.In, defines);
+ return Parse(s, filename, out program);
+ } else {
+ FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
+ var s = ParserHelper.Fill(stream, defines);
+ var ret = Parse(s, filename, out program);
+ stream.Close();
+ return ret;
+ }
}
-public static int Parse (Stream stream, string/*!*/ filename, /*maybe null*/ List<string/*!*/> defines, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
-Contract.Requires(stream != null);
-Contract.Requires(filename != null);
-Contract.Requires(cce.NonNullElements(defines,true));
+public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program) /* throws System.IO.IOException */ {
+ Contract.Requires(s != null);
+ Contract.Requires(filename != null);
- if (defines == null) {
- defines = new List<string/*!*/>();
- }
- string s = ParserHelper.Fill(stream, defines);
byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
Errors errors = new Errors();
@@ -85,7 +89,6 @@ Contract.Requires(cce.NonNullElements(defines,true));
if (parser.errors.count == 0)
{
program = Pgm;
- program.ProcessDatatypeConstructors();
return 0;
}
else
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index a1f9e4fc..d5b15300 100644
--- a/Source/Dafny/Compiler.cs
+++ b/Source/Dafny/Compiler.cs
@@ -67,6 +67,10 @@ namespace Microsoft.Dafny {
CompileBuiltIns(program.BuiltIns);
foreach (ModuleDecl m in program.Modules) {
+ if (m.IsGhost) {
+ // the purpose of a ghost module is to skip compilation
+ continue;
+ }
int indent = 0;
if (!m.IsDefaultModule) {
wr.WriteLine("namespace @{0} {{", m.Name);
@@ -599,7 +603,7 @@ namespace Microsoft.Dafny {
return name + "]";
} else if (type is UserDefinedType) {
UserDefinedType udt = (UserDefinedType)type;
- string s = "@" + udt.Name;
+ string s = "@" + udt.FullName;
if (udt.TypeArgs.Count != 0) {
if (Contract.Exists(udt.TypeArgs, argType =>argType is ObjectType)) {
Error("compilation does not support type 'object' as a type parameter; consider introducing a ghost");
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index 3aa7f2d3..740926e5 100644
--- a/Source/Dafny/Dafny.atg
+++ b/Source/Dafny/Dafny.atg
@@ -148,27 +148,35 @@ Dafny
defaultModule = new DefaultModuleDecl();
}
IToken idRefined;
+ bool isGhost;
.)
- { "module" (. attrs = null; idRefined = null; theImports = new List<string/*!*/>();
- namedModuleDefaultClassMembers = new List<MemberDecl>();
- .)
- { Attribute<ref attrs> }
- Ident<out id> (. defaultModule.ImportNames.Add(id.val); .)
- [ "refines" Ident<out idRefined> ]
- [ "imports" Idents<theImports> ] (. module = new ModuleDecl(id, id.val, idRefined == null ? null : idRefined.val, theImports, attrs); .)
- "{" (. module.BodyStartTok = t; .)
- { ClassDecl<module, out c> (. module.TopLevelDecls.Add(c); .)
- | DatatypeDecl<module, out dt> (. module.TopLevelDecls.Add(dt); .)
- | ArbitraryTypeDecl<module, out at>(. module.TopLevelDecls.Add(at); .)
- | ClassMemberDecl<namedModuleDefaultClassMembers, false>
- }
- "}" (. module.BodyEndTok = t;
- module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
- theModules.Add(module); .)
- | ClassDecl<defaultModule, out c> (. defaultModule.TopLevelDecls.Add(c); .)
- | DatatypeDecl<defaultModule, out dt> (. defaultModule.TopLevelDecls.Add(dt); .)
- | ArbitraryTypeDecl<defaultModule, out at> (. defaultModule.TopLevelDecls.Add(at); .)
- | ClassMemberDecl<membersDefaultClass, false>
+ { (. isGhost = false; .)
+ [ "ghost" (. isGhost = true; .) ]
+
+ ( "module" (. attrs = null; idRefined = null; theImports = new List<string/*!*/>();
+ namedModuleDefaultClassMembers = new List<MemberDecl>();
+ .)
+ { Attribute<ref attrs> }
+ Ident<out id> (. defaultModule.ImportNames.Add(id.val); .)
+ [ "refines" Ident<out idRefined> ]
+ [ "imports" Idents<theImports> ] (. module = new ModuleDecl(id, id.val, isGhost, idRefined == null ? null : idRefined.val, theImports, attrs); .)
+ "{" (. module.BodyStartTok = t; .)
+ { ClassDecl<module, out c> (. module.TopLevelDecls.Add(c); .)
+ | DatatypeDecl<module, out dt> (. module.TopLevelDecls.Add(dt); .)
+ | ArbitraryTypeDecl<module, out at>(. module.TopLevelDecls.Add(at); .)
+ | ClassMemberDecl<namedModuleDefaultClassMembers, false, false>
+ }
+ "}" (. module.BodyEndTok = t;
+ module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
+ theModules.Add(module); .)
+ | (. if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); } .)
+ ClassDecl<defaultModule, out c> (. defaultModule.TopLevelDecls.Add(c); .)
+ | (. if (isGhost) { SemErr(t, "a datatype is not allowed to be declared as 'ghost'"); } .)
+ DatatypeDecl<defaultModule, out dt> (. defaultModule.TopLevelDecls.Add(dt); .)
+ | (. if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); } .)
+ ArbitraryTypeDecl<defaultModule, out at> (. defaultModule.TopLevelDecls.Add(at); .)
+ | ClassMemberDecl<membersDefaultClass, isGhost, false>
+ )
}
(. if (defaultModuleCreatedHere) {
defaultModule.TopLevelDecls.Add(new DefaultClassDecl(defaultModule, membersDefaultClass));
@@ -201,7 +209,7 @@ ClassDecl<ModuleDecl/*!*/ module, out ClassDecl/*!*/ c>
Ident<out id>
[ GenericParameters<typeArgs> ]
"{" (. bodyStart = t; .)
- { ClassMemberDecl<members, true>
+ { ClassMemberDecl<members, false, true>
}
"}"
(. c = new ClassDecl(id, id.val, module, typeArgs, members, attrs);
@@ -209,11 +217,12 @@ ClassDecl<ModuleDecl/*!*/ module, out ClassDecl/*!*/ c>
c.BodyEndTok = t;
.)
.
-ClassMemberDecl<.List<MemberDecl/*!*/>/*!*/ mm, bool allowConstructors.>
+ClassMemberDecl<.List<MemberDecl/*!*/>/*!*/ mm, bool isAlreadyGhost, bool allowConstructors.>
= (. Contract.Requires(cce.NonNullElements(mm));
Method/*!*/ m;
Function/*!*/ f;
MemberModifiers mmod = new MemberModifiers();
+ mmod.IsGhost = isAlreadyGhost;
.)
{ "ghost" (. mmod.IsGhost = true; .)
| "static" (. mmod.IsStatic = true; .)
@@ -365,7 +374,7 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
List<Expression/*!*/> dec = new List<Expression/*!*/>();
Attributes decAttrs = null;
Attributes modAttrs = null;
- Statement/*!*/ bb; BlockStmt body = null;
+ BlockStmt body = null;
bool isConstructor = false;
bool signatureOmitted = false;
IToken bodyStart = Token.NoToken;
@@ -401,7 +410,7 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
| "..." (. signatureOmitted = true; openParen = Token.NoToken; .)
)
{ MethodSpec<req, mod, ens, dec, ref decAttrs, ref modAttrs> }
- [ BlockStmt<out bb, out bodyStart, out bodyEnd> (. body = (BlockStmt)bb; .)
+ [ BlockStmt<out body, out bodyStart, out bodyEnd>
]
(. if (isConstructor) {
m = new Constructor(id, id.val, typeArgs, ins,
@@ -526,7 +535,7 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
List<Expression/*!*/> ens = new List<Expression/*!*/>();
List<FrameExpression/*!*/> reads = new List<FrameExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
- Expression/*!*/ bb; Expression body = null;
+ Expression body = null;
bool isPredicate = false;
bool isFunctionMethod = false;
IToken openParen = null;
@@ -571,7 +580,7 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
)
{ FunctionSpec<reqs, reads, ens, decreases> }
- [ FunctionBody<out bb, out bodyStart, out bodyEnd> (. body = bb; .)
+ [ FunctionBody<out body, out bodyStart, out bodyEnd>
]
(. if (isPredicate) {
f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals,
@@ -634,7 +643,7 @@ FunctionBody<out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd>
"}" (. bodyEnd = t; .)
.
/*------------------------------------------------------------------------*/
-BlockStmt<out Statement/*!*/ block, out IToken bodyStart, out IToken bodyEnd>
+BlockStmt<out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd>
= (. Contract.Ensures(Contract.ValueAtReturn(out block) != null);
List<Statement/*!*/> body = new List<Statement/*!*/>();
.)
@@ -652,11 +661,12 @@ Stmt<.List<Statement/*!*/>/*!*/ ss.>
OneStmt<out Statement/*!*/ s>
= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; IToken/*!*/ id; string label = null;
s = dummyStmt; /* to please the compiler */
+ BlockStmt bs;
IToken bodyStart, bodyEnd;
int breakCount;
.)
SYNC
- ( BlockStmt<out s, out bodyStart, out bodyEnd>
+ ( BlockStmt<out bs, out bodyStart, out bodyEnd> (. s = bs; .)
| AssertStmt<out s>
| AssumeStmt<out s>
| PrintStmt<out s>
@@ -793,7 +803,8 @@ VarDeclStatement<.out Statement/*!*/ s.>
IfStmt<out Statement/*!*/ ifStmt>
= (. Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;
Expression guard = null; bool guardOmitted = false;
- Statement/*!*/ thn;
+ BlockStmt/*!*/ thn;
+ BlockStmt/*!*/ bs;
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
@@ -808,7 +819,7 @@ IfStmt<out Statement/*!*/ ifStmt>
BlockStmt<out thn, out bodyStart, out bodyEnd>
[ "else"
( IfStmt<out s> (. els = s; .)
- | BlockStmt<out s, out bodyStart, out bodyEnd> (. els = s; .)
+ | BlockStmt<out bs, out bodyStart, out bodyEnd> (. els = bs; .)
)
]
(. if (guardOmitted) {
@@ -846,7 +857,7 @@ WhileStmt<out Statement/*!*/ stmt>
Attributes decAttrs = null;
Attributes modAttrs = null;
List<FrameExpression/*!*/> mod = null;
- Statement/*!*/ body = null; bool bodyOmitted = false;
+ BlockStmt/*!*/ body = null; bool bodyOmitted = false;
IToken bodyStart = null, bodyEnd = null;
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
@@ -869,7 +880,7 @@ WhileStmt<out Statement/*!*/ stmt>
SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
}
if (body == null) {
- body = new AssertStmt(x, new LiteralExpr(x, true), null);
+ body = new BlockStmt(x, new List<Statement>());
}
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(null, null), new Specification<FrameExpression>(null, null), body);
stmt = new SkeletonStatement(stmt, guardOmitted, bodyOmitted);
@@ -1007,7 +1018,7 @@ ParallelStmt<out Statement/*!*/ s>
var ens = new List<MaybeFreeExpression/*!*/>();
bool isFree;
Expression/*!*/ e;
- Statement/*!*/ block;
+ BlockStmt/*!*/ block;
IToken bodyStart, bodyEnd;
.)
"parallel" (. x = t; .)
diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs
index c9c0ec08..407966bb 100644
--- a/Source/Dafny/DafnyAst.cs
+++ b/Source/Dafny/DafnyAst.cs
@@ -32,7 +32,7 @@ namespace Microsoft.Dafny {
public class BuiltIns
{
- public readonly ModuleDecl SystemModule = new ModuleDecl(Token.NoToken, "_System", null, new List<string>(), null);
+ public readonly ModuleDecl SystemModule = new ModuleDecl(Token.NoToken, "_System", false, null, new List<string>(), null);
Dictionary<int, ClassDecl/*!*/> arrayTypeDecls = new Dictionary<int, ClassDecl>();
public BuiltIns() {
@@ -111,6 +111,28 @@ namespace Microsoft.Dafny {
return false;
}
+ /// <summary>
+ /// Returns true if "nm" is a specified attribute. If it is, then:
+ /// - if the attribute is {:nm true}, then value==true
+ /// - if the attribute is {:nm false}, then value==false
+ /// - if the attribute is anything else, then value returns as whatever it was passed in as.
+ /// </summary>
+ public static bool ContainsBool(Attributes attrs, string nm, ref bool value) {
+ Contract.Requires(nm != null);
+ for (; attrs != null; attrs = attrs.Prev) {
+ if (attrs.Name == nm) {
+ if (attrs.Args.Count == 1) {
+ var arg = attrs.Args[0].E as LiteralExpr;
+ if (arg != null && arg.Value is bool) {
+ value = (bool)arg.Value;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
public class Argument
{
public readonly IToken Tok;
@@ -325,6 +347,16 @@ namespace Microsoft.Dafny {
[Rep]
public readonly List<Type/*!*/>/*!*/ TypeArgs;
+ public string FullName {
+ get {
+ if (ResolvedClass != null && !ResolvedClass.Module.IsDefaultModule) {
+ return ResolvedClass.Module.Name + "." + Name;
+ } else {
+ return Name;
+ }
+ }
+ }
+
public TopLevelDecl ResolvedClass; // filled in by resolution, if Name denotes a class/datatype and TypeArgs match the type parameters of that class/datatype
public TypeParameter ResolvedParam; // filled in by resolution, if Name denotes an enclosing type parameter and TypeArgs is the empty list
@@ -621,6 +653,7 @@ namespace Microsoft.Dafny {
public readonly List<TopLevelDecl/*!*/> TopLevelDecls = new List<TopLevelDecl/*!*/>(); // filled in by the parser; readonly after that
public readonly Graph<MemberDecl/*!*/> CallGraph = new Graph<MemberDecl/*!*/>(); // filled in during resolution
public int Height; // height in the topological sorting of modules; filled in during resolution
+ public readonly bool IsGhost;
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -629,7 +662,7 @@ namespace Microsoft.Dafny {
Contract.Invariant(CallGraph != null);
}
- public ModuleDecl(IToken tok, string name, string refinementBase, [Captured] List<string/*!*/>/*!*/ imports, Attributes attributes)
+ public ModuleDecl(IToken tok, string name, bool isGhost, string refinementBase, [Captured] List<string/*!*/>/*!*/ imports, Attributes attributes)
: base(tok, name, attributes) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
@@ -642,6 +675,7 @@ namespace Microsoft.Dafny {
ImportNames.Add(nm);
}
}
+ IsGhost = isGhost;
}
public virtual bool IsDefaultModule {
get {
@@ -651,7 +685,7 @@ namespace Microsoft.Dafny {
}
public class DefaultModuleDecl : ModuleDecl {
- public DefaultModuleDecl() : base(Token.NoToken, "_default", null, new List<string/*!*/>(), null) {
+ public DefaultModuleDecl() : base(Token.NoToken, "_default", false, null, new List<string/*!*/>(), null) {
}
public override bool IsDefaultModule {
get {
@@ -1066,7 +1100,7 @@ namespace Microsoft.Dafny {
public readonly List<FrameExpression/*!*/>/*!*/ Reads;
public readonly List<Expression/*!*/>/*!*/ Ens;
public readonly Specification<Expression>/*!*/ Decreases;
- public readonly Expression Body; // an extended expression
+ public Expression Body; // an extended expression; Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution
public readonly bool SignatureIsOmitted; // is "false" for all Function objects that survive into resolution
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -1133,7 +1167,7 @@ namespace Microsoft.Dafny {
public readonly Specification<FrameExpression>/*!*/ Mod;
public readonly List<MaybeFreeExpression/*!*/>/*!*/ Ens;
public readonly Specification<Expression>/*!*/ Decreases;
- public readonly BlockStmt Body;
+ public BlockStmt Body; // Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -1238,6 +1272,13 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
this.Tok = tok;
}
+
+ /// <summary>
+ /// Returns the non-null substatements of the Statements.
+ /// </summary>
+ public virtual IEnumerable<Statement> SubStatements {
+ get { yield break; }
+ }
}
public class LabelNode
@@ -1512,6 +1553,10 @@ namespace Microsoft.Dafny {
public ConcreteSyntaxStatement(IToken tok)
: base(tok) {
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get { return ResolvedStatements; }
+ }
}
public class VarDeclStmt : ConcreteSyntaxStatement
@@ -1584,6 +1629,15 @@ namespace Microsoft.Dafny {
this.Lhs = lhs;
this.Rhs = rhs;
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ var trhs = Rhs as TypeRhs;
+ if (trhs != null && trhs.InitCall != null) {
+ yield return trhs.InitCall;
+ }
+ }
+ }
}
public class VarDecl : Statement, IVariable {
@@ -1684,20 +1738,23 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(body));
this.Body = body;
+ }
+ public override IEnumerable<Statement> SubStatements {
+ get { return Body; }
}
}
public class IfStmt : Statement {
public readonly Expression Guard;
- public readonly Statement Thn;
+ public readonly BlockStmt Thn;
public readonly Statement Els;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Thn != null);
Contract.Invariant(Els == null || Els is BlockStmt || Els is IfStmt);
}
- public IfStmt(IToken tok, Expression guard, Statement thn, Statement els)
+ public IfStmt(IToken tok, Expression guard, BlockStmt thn, Statement els)
: base(tok) {
Contract.Requires(tok != null);
Contract.Requires(thn != null);
@@ -1706,6 +1763,14 @@ namespace Microsoft.Dafny {
this.Thn = thn;
this.Els = els;
}
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ yield return Thn;
+ if (Els != null) {
+ yield return Els;
+ }
+ }
+ }
}
public class GuardedAlternative
@@ -1743,6 +1808,15 @@ namespace Microsoft.Dafny {
Contract.Requires(alternatives != null);
this.Alternatives = alternatives;
}
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ foreach (var alt in Alternatives) {
+ foreach (var s in alt.Body) {
+ yield return s;
+ }
+ }
+ }
+ }
}
public abstract class LoopStmt : Statement
@@ -1773,7 +1847,7 @@ namespace Microsoft.Dafny {
public class WhileStmt : LoopStmt
{
public readonly Expression Guard;
- public readonly Statement/*!*/ Body;
+ public readonly BlockStmt/*!*/ Body;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Body != null);
@@ -1781,13 +1855,19 @@ namespace Microsoft.Dafny {
public WhileStmt(IToken tok, Expression guard,
List<MaybeFreeExpression/*!*/>/*!*/ invariants, Specification<Expression>/*!*/ decreases, Specification<FrameExpression>/*!*/ mod,
- Statement/*!*/ body)
+ BlockStmt/*!*/ body)
: base(tok, invariants, decreases, mod) {
Contract.Requires(tok != null);
Contract.Requires(body != null);
this.Guard = guard;
this.Body = body;
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ yield return Body;
+ }
+ }
}
public class AlternativeLoopStmt : LoopStmt
@@ -1805,6 +1885,15 @@ namespace Microsoft.Dafny {
Contract.Requires(alternatives != null);
this.Alternatives = alternatives;
}
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ foreach (var alt in Alternatives) {
+ foreach (var s in alt.Body) {
+ yield return s;
+ }
+ }
+ }
+ }
}
public class ParallelStmt : Statement
@@ -1880,6 +1969,12 @@ namespace Microsoft.Dafny {
}
}
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ yield return Body;
+ }
+ }
}
public class MatchStmt : Statement
@@ -1902,7 +1997,16 @@ namespace Microsoft.Dafny {
Contract.Requires(cce.NonNullElements(cases));
this.Source = source;
this.Cases = cases;
+ }
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ foreach (var kase in Cases) {
+ foreach (var s in kase.Body) {
+ yield return s;
+ }
+ }
+ }
}
}
@@ -1958,6 +2062,19 @@ namespace Microsoft.Dafny {
ConditionOmitted = conditionOmitted;
BodyOmitted = bodyOmitted;
}
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ // The SkeletonStatement is really a modification of its inner statement S. Therefore,
+ // we don't consider S to be a substatement. Instead, the substatements of S are the
+ // substatements of the SkeletonStatement. In the case the SkeletonStatement modifies
+ // S by omitting its body (which is true only for loops), there are no substatements.
+ if (!BodyOmitted) {
+ foreach (var s in S.SubStatements) {
+ yield return s;
+ }
+ }
+ }
+ }
}
// ------------------------------------------------------------------------------------------------------
@@ -2600,6 +2717,88 @@ namespace Microsoft.Dafny {
}
public ResolvedOpcode ResolvedOp; // filled in by resolution
+ public static Opcode ResolvedOp2SyntacticOp(ResolvedOpcode rop) {
+ switch (rop) {
+ case ResolvedOpcode.Iff: return Opcode.Iff;
+ case ResolvedOpcode.Imp: return Opcode.Imp;
+ case ResolvedOpcode.And: return Opcode.And;
+ case ResolvedOpcode.Or: return Opcode.Or;
+
+ case ResolvedOpcode.EqCommon:
+ case ResolvedOpcode.SetEq:
+ case ResolvedOpcode.MultiSetEq:
+ case ResolvedOpcode.SeqEq:
+ return Opcode.Eq;
+
+ case ResolvedOpcode.NeqCommon:
+ case ResolvedOpcode.SetNeq:
+ case ResolvedOpcode.MultiSetNeq:
+ case ResolvedOpcode.SeqNeq:
+ return Opcode.Neq;
+
+ case ResolvedOpcode.Lt:
+ case ResolvedOpcode.ProperSubset:
+ case ResolvedOpcode.ProperMultiSuperset:
+ case ResolvedOpcode.ProperPrefix:
+ case ResolvedOpcode.RankLt:
+ return Opcode.Lt;
+
+ case ResolvedOpcode.Le:
+ case ResolvedOpcode.Subset:
+ case ResolvedOpcode.MultiSubset:
+ case ResolvedOpcode.Prefix:
+ return Opcode.Le;
+
+ case ResolvedOpcode.Ge:
+ case ResolvedOpcode.Superset:
+ case ResolvedOpcode.MultiSuperset:
+ return Opcode.Ge;
+
+ case ResolvedOpcode.Gt:
+ case ResolvedOpcode.ProperSuperset:
+ case ResolvedOpcode.ProperMultiSubset:
+ case ResolvedOpcode.RankGt:
+ return Opcode.Gt;
+
+ case ResolvedOpcode.Add:
+ case ResolvedOpcode.Union:
+ case ResolvedOpcode.MultiSetUnion:
+ case ResolvedOpcode.Concat:
+ return Opcode.Add;
+
+ case ResolvedOpcode.Sub:
+ case ResolvedOpcode.SetDifference:
+ case ResolvedOpcode.MultiSetDifference:
+ return Opcode.Sub;
+
+ case ResolvedOpcode.Mul:
+ case ResolvedOpcode.Intersection:
+ case ResolvedOpcode.MultiSetIntersection:
+ return Opcode.Mul;
+
+ case ResolvedOpcode.Div: return Opcode.Div;
+ case ResolvedOpcode.Mod: return Opcode.Mod;
+
+ case ResolvedOpcode.Disjoint:
+ case ResolvedOpcode.MultiSetDisjoint:
+ return Opcode.Disjoint;
+
+ case ResolvedOpcode.InSet:
+ case ResolvedOpcode.InMultiSet:
+ case ResolvedOpcode.InSeq:
+ return Opcode.In;
+
+ case ResolvedOpcode.NotInSet:
+ case ResolvedOpcode.NotInMultiSet:
+ case ResolvedOpcode.NotInSeq:
+ return Opcode.NotIn;
+
+ default:
+ Contract.Assert(false); // unexpected ResolvedOpcode
+ return Opcode.Add; // please compiler
+ }
+ }
+
public static string OpcodeString(Opcode op) {
Contract.Ensures(Contract.Result<string>() != null);
diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj
index 7264389b..cf2b51eb 100644
--- a/Source/Dafny/DafnyPipeline.csproj
+++ b/Source/Dafny/DafnyPipeline.csproj
@@ -158,6 +158,7 @@
<Compile Include="Printer.cs" />
<Compile Include="RefinementTransformer.cs" />
<Compile Include="Resolver.cs" />
+ <Compile Include="Rewriter.cs" />
<Compile Include="SccGraph.cs" />
<Compile Include="Translator.cs" />
<Compile Include="..\version.cs" />
diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs
index 7de10ac7..bf7d1fe1 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -198,10 +198,16 @@ bool IsAttribute() {
defaultModule = new DefaultModuleDecl();
}
IToken idRefined;
+ bool isGhost;
while (StartOf(1)) {
+ isGhost = false;
if (la.kind == 8) {
Get();
+ isGhost = true;
+ }
+ if (la.kind == 9) {
+ Get();
attrs = null; idRefined = null; theImports = new List<string/*!*/>();
namedModuleDefaultClassMembers = new List<MemberDecl>();
@@ -210,19 +216,19 @@ bool IsAttribute() {
}
Ident(out id);
defaultModule.ImportNames.Add(id.val);
- if (la.kind == 9) {
+ if (la.kind == 10) {
Get();
Ident(out idRefined);
}
- if (la.kind == 10) {
+ if (la.kind == 11) {
Get();
Idents(theImports);
}
- module = new ModuleDecl(id, id.val, idRefined == null ? null : idRefined.val, theImports, attrs);
+ module = new ModuleDecl(id, id.val, isGhost, idRefined == null ? null : idRefined.val, theImports, attrs);
Expect(6);
module.BodyStartTok = t;
while (StartOf(2)) {
- if (la.kind == 11) {
+ if (la.kind == 12) {
ClassDecl(module, out c);
module.TopLevelDecls.Add(c);
} else if (la.kind == 15) {
@@ -232,25 +238,28 @@ bool IsAttribute() {
ArbitraryTypeDecl(module, out at);
module.TopLevelDecls.Add(at);
} else {
- ClassMemberDecl(namedModuleDefaultClassMembers, false);
+ ClassMemberDecl(namedModuleDefaultClassMembers, false, false);
}
}
Expect(7);
module.BodyEndTok = t;
module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
theModules.Add(module);
- } else if (la.kind == 11) {
+ } else if (la.kind == 12) {
+ if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); }
ClassDecl(defaultModule, out c);
defaultModule.TopLevelDecls.Add(c);
} else if (la.kind == 15) {
+ if (isGhost) { SemErr(t, "a datatype is not allowed to be declared as 'ghost'"); }
DatatypeDecl(defaultModule, out dt);
defaultModule.TopLevelDecls.Add(dt);
} else if (la.kind == 21) {
+ if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); }
ArbitraryTypeDecl(defaultModule, out at);
defaultModule.TopLevelDecls.Add(at);
- } else {
- ClassMemberDecl(membersDefaultClass, false);
- }
+ } else if (StartOf(3)) {
+ ClassMemberDecl(membersDefaultClass, isGhost, false);
+ } else SynErr(106);
}
if (defaultModuleCreatedHere) {
defaultModule.TopLevelDecls.Add(new DefaultClassDecl(defaultModule, membersDefaultClass));
@@ -301,8 +310,8 @@ bool IsAttribute() {
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
- while (!(la.kind == 0 || la.kind == 11)) {SynErr(106); Get();}
- Expect(11);
+ while (!(la.kind == 0 || la.kind == 12)) {SynErr(107); Get();}
+ Expect(12);
while (la.kind == 6) {
Attribute(ref attrs);
}
@@ -313,7 +322,7 @@ bool IsAttribute() {
Expect(6);
bodyStart = t;
while (StartOf(3)) {
- ClassMemberDecl(members, true);
+ ClassMemberDecl(members, false, true);
}
Expect(7);
c = new ClassDecl(id, id.val, module, typeArgs, members, attrs);
@@ -331,7 +340,7 @@ bool IsAttribute() {
List<DatatypeCtor/*!*/> ctors = new List<DatatypeCtor/*!*/>();
IToken bodyStart = Token.NoToken; // dummy assignment
- while (!(la.kind == 0 || la.kind == 15)) {SynErr(107); Get();}
+ while (!(la.kind == 0 || la.kind == 15)) {SynErr(108); Get();}
Expect(15);
while (la.kind == 6) {
Attribute(ref attrs);
@@ -347,7 +356,7 @@ bool IsAttribute() {
Get();
DatatypeMemberDecl(ctors);
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(108); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(109); Get();}
Expect(18);
dt = new DatatypeDecl(id, id.val, module, typeArgs, ctors, attrs);
dt.BodyStartTok = bodyStart;
@@ -365,18 +374,19 @@ bool IsAttribute() {
}
Ident(out id);
at = new ArbitraryTypeDecl(id, id.val, module, attrs);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(109); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(110); Get();}
Expect(18);
}
- void ClassMemberDecl(List<MemberDecl/*!*/>/*!*/ mm, bool allowConstructors) {
+ void ClassMemberDecl(List<MemberDecl/*!*/>/*!*/ mm, bool isAlreadyGhost, bool allowConstructors) {
Contract.Requires(cce.NonNullElements(mm));
Method/*!*/ m;
Function/*!*/ f;
MemberModifiers mmod = new MemberModifiers();
+ mmod.IsGhost = isAlreadyGhost;
- while (la.kind == 12 || la.kind == 13 || la.kind == 14) {
- if (la.kind == 12) {
+ while (la.kind == 8 || la.kind == 13 || la.kind == 14) {
+ if (la.kind == 8) {
Get();
mmod.IsGhost = true;
} else if (la.kind == 13) {
@@ -395,7 +405,7 @@ bool IsAttribute() {
} else if (la.kind == 24 || la.kind == 25) {
MethodDecl(mmod, allowConstructors, out m);
mm.Add(m);
- } else SynErr(110);
+ } else SynErr(111);
}
void GenericParameters(List<TypeParameter/*!*/>/*!*/ typeArgs) {
@@ -417,7 +427,7 @@ bool IsAttribute() {
Attributes attrs = null;
IToken/*!*/ id; Type/*!*/ ty;
- while (!(la.kind == 0 || la.kind == 19)) {SynErr(111); Get();}
+ while (!(la.kind == 0 || la.kind == 19)) {SynErr(112); Get();}
Expect(19);
if (mmod.IsUnlimited) { SemErr(t, "fields cannot be declared 'unlimited'"); }
if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); }
@@ -432,7 +442,7 @@ bool IsAttribute() {
IdentType(out id, out ty);
mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs));
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(112); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(113); Get();}
Expect(18);
}
@@ -447,7 +457,7 @@ bool IsAttribute() {
List<Expression/*!*/> ens = new List<Expression/*!*/>();
List<FrameExpression/*!*/> reads = new List<FrameExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
- Expression/*!*/ bb; Expression body = null;
+ Expression body = null;
bool isPredicate = false;
bool isFunctionMethod = false;
IToken openParen = null;
@@ -478,7 +488,7 @@ bool IsAttribute() {
Get();
signatureOmitted = true;
openParen = Token.NoToken;
- } else SynErr(113);
+ } else SynErr(114);
} else if (la.kind == 43) {
Get();
isPredicate = true;
@@ -507,14 +517,13 @@ bool IsAttribute() {
Get();
signatureOmitted = true;
openParen = Token.NoToken;
- } else SynErr(114);
- } else SynErr(115);
+ } else SynErr(115);
+ } else SynErr(116);
while (StartOf(5)) {
FunctionSpec(reqs, reads, ens, decreases);
}
if (la.kind == 6) {
- FunctionBody(out bb, out bodyStart, out bodyEnd);
- body = bb;
+ FunctionBody(out body, out bodyStart, out bodyEnd);
}
if (isPredicate) {
f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals,
@@ -542,13 +551,13 @@ bool IsAttribute() {
List<Expression/*!*/> dec = new List<Expression/*!*/>();
Attributes decAttrs = null;
Attributes modAttrs = null;
- Statement/*!*/ bb; BlockStmt body = null;
+ BlockStmt body = null;
bool isConstructor = false;
bool signatureOmitted = false;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
- while (!(la.kind == 0 || la.kind == 24 || la.kind == 25)) {SynErr(116); Get();}
+ while (!(la.kind == 0 || la.kind == 24 || la.kind == 25)) {SynErr(117); Get();}
if (la.kind == 24) {
Get();
} else if (la.kind == 25) {
@@ -559,7 +568,7 @@ bool IsAttribute() {
SemErr(t, "constructors are only allowed in classes");
}
- } else SynErr(117);
+ } else SynErr(118);
if (mmod.IsUnlimited) { SemErr(t, "methods cannot be declared 'unlimited'"); }
if (isConstructor) {
if (mmod.IsGhost) {
@@ -587,13 +596,12 @@ bool IsAttribute() {
} else if (la.kind == 27) {
Get();
signatureOmitted = true; openParen = Token.NoToken;
- } else SynErr(118);
+ } else SynErr(119);
while (StartOf(6)) {
MethodSpec(req, mod, ens, dec, ref decAttrs, ref modAttrs);
}
if (la.kind == 6) {
- BlockStmt(out bb, out bodyStart, out bodyEnd);
- body = (BlockStmt)bb;
+ BlockStmt(out body, out bodyStart, out bodyEnd);
}
if (isConstructor) {
m = new Constructor(id, id.val, typeArgs, ins,
@@ -649,7 +657,7 @@ bool IsAttribute() {
Contract.Ensures(Contract.ValueAtReturn(out id)!=null);
Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);
isGhost = false;
- if (la.kind == 12) {
+ if (la.kind == 8) {
Get();
if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); }
}
@@ -690,7 +698,7 @@ bool IsAttribute() {
Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);
Contract.Ensures(Contract.ValueAtReturn(out identName)!=null);
string name = null; isGhost = false;
- if (la.kind == 12) {
+ if (la.kind == 8) {
Get();
isGhost = true;
}
@@ -771,7 +779,7 @@ bool IsAttribute() {
ReferenceType(out tok, out ty);
break;
}
- default: SynErr(119); break;
+ default: SynErr(120); break;
}
}
@@ -779,7 +787,7 @@ bool IsAttribute() {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; bool isGhost;
Expect(33);
openParen = t;
- if (la.kind == 1 || la.kind == 12) {
+ if (la.kind == 1 || la.kind == 8) {
GIdentType(allowGhostKeyword, out id, out ty, out isGhost);
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
while (la.kind == 20) {
@@ -796,7 +804,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Requires(cce.NonNullElements(req)); Contract.Requires(cce.NonNullElements(mod)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; Attributes ensAttrs = null;
- while (!(StartOf(8))) {SynErr(120); Get();}
+ while (!(StartOf(8))) {SynErr(121); Get();}
if (la.kind == 28) {
Get();
while (IsAttribute()) {
@@ -811,7 +819,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(121); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(122); Get();}
Expect(18);
} else if (la.kind == 29 || la.kind == 30 || la.kind == 31) {
if (la.kind == 29) {
@@ -821,7 +829,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 30) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(122); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(123); Get();}
Expect(18);
req.Add(new MaybeFreeExpression(e, isFree));
} else if (la.kind == 31) {
@@ -830,22 +838,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Attribute(ref ensAttrs);
}
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(123); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(124); Get();}
Expect(18);
ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));
- } else SynErr(124);
+ } else SynErr(125);
} else if (la.kind == 32) {
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(125); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(126); Get();}
Expect(18);
- } else SynErr(126);
+ } else SynErr(127);
}
- void BlockStmt(out Statement/*!*/ block, out IToken bodyStart, out IToken bodyEnd) {
+ void BlockStmt(out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd) {
Contract.Ensures(Contract.ValueAtReturn(out block) != null);
List<Statement/*!*/> body = new List<Statement/*!*/>();
@@ -936,17 +944,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
GenericInstantiation(gt);
}
ty = new UserDefinedType(tok, tok.val, gt);
- } else SynErr(127);
+ } else SynErr(128);
}
void FunctionSpec(List<Expression/*!*/>/*!*/ reqs, List<FrameExpression/*!*/>/*!*/ reads, List<Expression/*!*/>/*!*/ ens, List<Expression/*!*/>/*!*/ decreases) {
Contract.Requires(cce.NonNullElements(reqs)); Contract.Requires(cce.NonNullElements(reads)); Contract.Requires(cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe;
if (la.kind == 30) {
- while (!(la.kind == 0 || la.kind == 30)) {SynErr(128); Get();}
+ while (!(la.kind == 0 || la.kind == 30)) {SynErr(129); Get();}
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(129); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(130); Get();}
Expect(18);
reqs.Add(e);
} else if (la.kind == 44) {
@@ -960,20 +968,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
reads.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(130); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(131); Get();}
Expect(18);
} else if (la.kind == 31) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(131); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(132); Get();}
Expect(18);
ens.Add(e);
} else if (la.kind == 32) {
Get();
DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(132); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(133); Get();}
Expect(18);
- } else SynErr(133);
+ } else SynErr(134);
}
void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) {
@@ -992,7 +1000,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
fe = new FrameExpression(new WildcardExpr(t), null);
} else if (StartOf(9)) {
FrameExpression(out fe);
- } else SynErr(134);
+ } else SynErr(135);
}
void PossiblyWildExpression(out Expression/*!*/ e) {
@@ -1003,7 +1011,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new WildcardExpr(t);
} else if (StartOf(9)) {
Expression(out e);
- } else SynErr(135);
+ } else SynErr(136);
}
void Stmt(List<Statement/*!*/>/*!*/ ss) {
@@ -1016,13 +1024,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void OneStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; IToken/*!*/ id; string label = null;
s = dummyStmt; /* to please the compiler */
+ BlockStmt bs;
IToken bodyStart, bodyEnd;
int breakCount;
- while (!(StartOf(12))) {SynErr(136); Get();}
+ while (!(StartOf(12))) {SynErr(137); Get();}
switch (la.kind) {
case 6: {
- BlockStmt(out s, out bodyStart, out bodyEnd);
+ BlockStmt(out bs, out bodyStart, out bodyEnd);
+ s = bs;
break;
}
case 63: {
@@ -1041,7 +1051,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
UpdateStmt(out s);
break;
}
- case 12: case 19: {
+ case 8: case 19: {
VarDeclStatement(out s);
break;
}
@@ -1081,8 +1091,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
breakCount++;
}
- } else SynErr(137);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(138); Get();}
+ } else SynErr(138);
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(139); Get();}
Expect(18);
s = label != null ? new BreakStmt(x, label) : new BreakStmt(x, breakCount);
break;
@@ -1097,7 +1107,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(18);
break;
}
- default: SynErr(139); break;
+ default: SynErr(140); break;
}
}
@@ -1114,7 +1124,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression(out e);
} else if (la.kind == 27) {
Get();
- } else SynErr(140);
+ } else SynErr(141);
Expect(18);
if (e == null) {
s = new SkeletonStatement(new AssertStmt(x, new LiteralExpr(x, true), attrs), true, false);
@@ -1186,7 +1196,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 5) {
Get();
SemErr(t, "invalid statement (did you forget the 'label' keyword?)");
- } else SynErr(141);
+ } else SynErr(142);
s = new UpdateStmt(x, lhss, rhss);
}
@@ -1197,7 +1207,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<VarDecl> lhss = new List<VarDecl>();
List<AssignmentRhs> rhss = new List<AssignmentRhs>();
- if (la.kind == 12) {
+ if (la.kind == 8) {
Get();
isGhost = true; x = t;
}
@@ -1242,7 +1252,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void IfStmt(out Statement/*!*/ ifStmt) {
Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;
Expression guard = null; bool guardOmitted = false;
- Statement/*!*/ thn;
+ BlockStmt/*!*/ thn;
+ BlockStmt/*!*/ bs;
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
@@ -1265,9 +1276,9 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IfStmt(out s);
els = s;
} else if (la.kind == 6) {
- BlockStmt(out s, out bodyStart, out bodyEnd);
- els = s;
- } else SynErr(142);
+ BlockStmt(out bs, out bodyStart, out bodyEnd);
+ els = bs;
+ } else SynErr(143);
}
if (guardOmitted) {
ifStmt = new SkeletonStatement(new IfStmt(x, guard, thn, els), true, false);
@@ -1278,7 +1289,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 6) {
AlternativeBlock(out alternatives);
ifStmt = new AlternativeStmt(x, alternatives);
- } else SynErr(143);
+ } else SynErr(144);
}
void WhileStmt(out Statement/*!*/ stmt) {
@@ -1289,7 +1300,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Attributes decAttrs = null;
Attributes modAttrs = null;
List<FrameExpression/*!*/> mod = null;
- Statement/*!*/ body = null; bool bodyOmitted = false;
+ BlockStmt/*!*/ body = null; bool bodyOmitted = false;
IToken bodyStart = null, bodyEnd = null;
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
@@ -1310,7 +1321,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 27) {
Get();
bodyOmitted = true;
- } else SynErr(144);
+ } else SynErr(145);
if (guardOmitted || bodyOmitted) {
if (decreases.Count != 0) {
SemErr(decreases[0].tok, "'decreases' clauses are not allowed on refining loops");
@@ -1319,7 +1330,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
}
if (body == null) {
- body = new AssertStmt(x, new LiteralExpr(x, true), null);
+ body = new BlockStmt(x, new List<Statement>());
}
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(null, null), new Specification<FrameExpression>(null, null), body);
stmt = new SkeletonStatement(stmt, guardOmitted, bodyOmitted);
@@ -1331,7 +1342,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
LoopSpec(out invariants, out decreases, out mod, ref decAttrs, ref modAttrs);
AlternativeBlock(out alternatives);
stmt = new AlternativeLoopStmt(x, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), alternatives);
- } else SynErr(145);
+ } else SynErr(146);
}
void MatchStmt(out Statement/*!*/ s) {
@@ -1359,7 +1370,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
var ens = new List<MaybeFreeExpression/*!*/>();
bool isFree;
Expression/*!*/ e;
- Statement/*!*/ block;
+ BlockStmt/*!*/ block;
IToken bodyStart, bodyEnd;
Expect(66);
@@ -1461,7 +1472,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (StartOf(9)) {
Expression(out e);
r = new ExprRhs(e);
- } else SynErr(146);
+ } else SynErr(147);
while (la.kind == 6) {
Attribute(ref attrs);
}
@@ -1482,7 +1493,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
while (la.kind == 52 || la.kind == 54) {
Suffix(ref e);
}
- } else SynErr(147);
+ } else SynErr(148);
}
void Expressions(List<Expression/*!*/>/*!*/ args) {
@@ -1505,7 +1516,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (StartOf(9)) {
Expression(out ee);
e = ee;
- } else SynErr(148);
+ } else SynErr(149);
Expect(34);
}
@@ -1540,20 +1551,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
while (StartOf(16)) {
if (la.kind == 29 || la.kind == 61) {
Invariant(out invariant);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(149); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(150); Get();}
Expect(18);
invariants.Add(invariant);
} else if (la.kind == 32) {
- while (!(la.kind == 0 || la.kind == 32)) {SynErr(150); Get();}
+ while (!(la.kind == 0 || la.kind == 32)) {SynErr(151); Get();}
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, true);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(151); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(152); Get();}
Expect(18);
} else {
- while (!(la.kind == 0 || la.kind == 28)) {SynErr(152); Get();}
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(153); Get();}
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
@@ -1568,7 +1579,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(153); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(154); Get();}
Expect(18);
}
}
@@ -1576,7 +1587,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void Invariant(out MaybeFreeExpression/*!*/ invariant) {
bool isFree = false; Expression/*!*/ e; List<string> ids = new List<string>(); invariant = null; Attributes attrs = null;
- while (!(la.kind == 0 || la.kind == 29 || la.kind == 61)) {SynErr(154); Get();}
+ while (!(la.kind == 0 || la.kind == 29 || la.kind == 61)) {SynErr(155); Get();}
if (la.kind == 29) {
Get();
isFree = true;
@@ -1625,7 +1636,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (StartOf(9)) {
Expression(out e);
arg = new Attributes.Argument(t, e);
- } else SynErr(155);
+ } else SynErr(156);
}
void QuantifierDomain(out List<BoundVar/*!*/> bvars, out Attributes attrs, out Expression range) {
@@ -1677,7 +1688,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 68) {
Get();
- } else SynErr(156);
+ } else SynErr(157);
}
void LogicalExpression(out Expression/*!*/ e0) {
@@ -1715,7 +1726,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 70) {
Get();
- } else SynErr(157);
+ } else SynErr(158);
}
void RelationalExpression(out Expression/*!*/ e) {
@@ -1813,7 +1824,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 72) {
Get();
- } else SynErr(158);
+ } else SynErr(159);
}
void OrOp() {
@@ -1821,7 +1832,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 74) {
Get();
- } else SynErr(159);
+ } else SynErr(160);
}
void Term(out Expression/*!*/ e0) {
@@ -1913,7 +1924,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- default: SynErr(160); break;
+ default: SynErr(161); break;
}
}
@@ -1935,7 +1946,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 86) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(161);
+ } else SynErr(162);
}
void UnaryExpression(out Expression/*!*/ e) {
@@ -1981,7 +1992,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
break;
}
- default: SynErr(162); break;
+ default: SynErr(163); break;
}
}
@@ -1996,7 +2007,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 88) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(163);
+ } else SynErr(164);
}
void NegOp() {
@@ -2004,7 +2015,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 89) {
Get();
- } else SynErr(164);
+ } else SynErr(165);
}
void EndlessExpression(out Expression e) {
@@ -2081,7 +2092,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new LetExpr(x, letVars, letRHSs, e);
break;
}
- default: SynErr(165); break;
+ default: SynErr(166); break;
}
}
@@ -2155,7 +2166,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
multipleIndices.Add(ee);
}
- } else SynErr(166);
+ } else SynErr(167);
} else if (la.kind == 98) {
Get();
anyDots = true;
@@ -2163,7 +2174,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression(out ee);
e1 = ee;
}
- } else SynErr(167);
+ } else SynErr(168);
if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
// make sure an array class with this dimensionality exists
@@ -2187,7 +2198,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
Expect(53);
- } else SynErr(168);
+ } else SynErr(169);
}
void DisplayExpr(out Expression e) {
@@ -2211,7 +2222,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
e = new SeqDisplayExpr(x, elements);
Expect(53);
- } else SynErr(169);
+ } else SynErr(170);
}
void MultiSetExpr(out Expression e) {
@@ -2237,7 +2248,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(34);
} else if (StartOf(19)) {
SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses.");
- } else SynErr(170);
+ } else SynErr(171);
}
void ConstAtomExpression(out Expression/*!*/ e) {
@@ -2314,7 +2325,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(34);
break;
}
- default: SynErr(171); break;
+ default: SynErr(172); break;
}
}
@@ -2357,7 +2368,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 101 || la.kind == 102) {
Exists();
x = t;
- } else SynErr(172);
+ } else SynErr(173);
QuantifierDomain(out bvars, out attrs, out range);
QSep();
Expression(out body);
@@ -2427,7 +2438,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 100) {
Get();
- } else SynErr(173);
+ } else SynErr(174);
}
void Exists() {
@@ -2435,7 +2446,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 102) {
Get();
- } else SynErr(174);
+ } else SynErr(175);
}
void QSep() {
@@ -2443,7 +2454,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
} else if (la.kind == 104) {
Get();
- } else SynErr(175);
+ } else SynErr(176);
}
void AttributeBody(ref Attributes attrs) {
@@ -2479,19 +2490,19 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
static readonly bool[,]/*!*/ set = {
- {T,T,T,x, x,x,T,x, x,x,x,T, T,x,x,T, x,T,T,T, x,x,x,x, T,T,x,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,T, x,x,x,T, x,T,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, x,x,x,T, x,T,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {T,x,x,x, x,x,T,T, T,x,x,T, T,T,T,T, x,x,x,T, x,T,T,x, T,T,x,x, x,x,T,T, T,T,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {T,T,T,x, x,x,T,x, T,x,x,x, T,x,x,T, x,T,T,T, x,x,x,x, T,T,x,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, T,T,x,x, T,T,T,T, x,x,x,T, x,T,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, T,x,x,x, T,T,T,T, x,x,x,T, x,T,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,x,x,x, x,x,x,x, T,x,x,x, x,T,T,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {T,x,x,x, x,x,T,T, T,T,x,x, T,T,T,T, x,x,x,T, x,T,T,x, T,T,x,x, x,x,T,T, T,T,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,T,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
+ {x,T,x,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, T,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {x,T,T,x, x,x,T,x, x,x,x,x, T,x,x,x, x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
+ {x,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
{x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, x,T,x,x, x,x,x,x, T,x,x,x, T,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {T,T,T,x, x,x,T,x, x,x,x,x, T,x,x,x, x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
+ {T,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, T,x,x,x, T,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
{x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
{x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, x,x,x,x, x,T,x,x, x,x,x,T, T,x,x,T, T,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
{x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
@@ -2532,11 +2543,11 @@ public class Errors {
case 5: s = "colon expected"; break;
case 6: s = "lbrace expected"; break;
case 7: s = "rbrace expected"; break;
- case 8: s = "\"module\" expected"; break;
- case 9: s = "\"refines\" expected"; break;
- case 10: s = "\"imports\" expected"; break;
- case 11: s = "\"class\" expected"; break;
- case 12: s = "\"ghost\" expected"; break;
+ case 8: s = "\"ghost\" expected"; break;
+ case 9: s = "\"module\" expected"; break;
+ case 10: s = "\"refines\" expected"; break;
+ case 11: s = "\"imports\" expected"; break;
+ case 12: s = "\"class\" expected"; break;
case 13: s = "\"static\" expected"; break;
case 14: s = "\"unlimited\" expected"; break;
case 15: s = "\"datatype\" expected"; break;
@@ -2630,76 +2641,77 @@ public class Errors {
case 103: s = "\"::\" expected"; break;
case 104: s = "\"\\u2022\" expected"; break;
case 105: s = "??? expected"; break;
- case 106: s = "this symbol not expected in ClassDecl"; break;
- case 107: s = "this symbol not expected in DatatypeDecl"; break;
+ case 106: s = "invalid Dafny"; break;
+ case 107: s = "this symbol not expected in ClassDecl"; break;
case 108: s = "this symbol not expected in DatatypeDecl"; break;
- case 109: s = "this symbol not expected in ArbitraryTypeDecl"; break;
- case 110: s = "invalid ClassMemberDecl"; break;
- case 111: s = "this symbol not expected in FieldDecl"; break;
+ case 109: s = "this symbol not expected in DatatypeDecl"; break;
+ case 110: s = "this symbol not expected in ArbitraryTypeDecl"; break;
+ case 111: s = "invalid ClassMemberDecl"; break;
case 112: s = "this symbol not expected in FieldDecl"; break;
- case 113: s = "invalid FunctionDecl"; break;
+ case 113: s = "this symbol not expected in FieldDecl"; break;
case 114: s = "invalid FunctionDecl"; break;
case 115: s = "invalid FunctionDecl"; break;
- case 116: s = "this symbol not expected in MethodDecl"; break;
- case 117: s = "invalid MethodDecl"; break;
+ case 116: s = "invalid FunctionDecl"; break;
+ case 117: s = "this symbol not expected in MethodDecl"; break;
case 118: s = "invalid MethodDecl"; break;
- case 119: s = "invalid TypeAndToken"; break;
- case 120: s = "this symbol not expected in MethodSpec"; break;
+ case 119: s = "invalid MethodDecl"; break;
+ case 120: s = "invalid TypeAndToken"; break;
case 121: s = "this symbol not expected in MethodSpec"; break;
case 122: s = "this symbol not expected in MethodSpec"; break;
case 123: s = "this symbol not expected in MethodSpec"; break;
- case 124: s = "invalid MethodSpec"; break;
- case 125: s = "this symbol not expected in MethodSpec"; break;
- case 126: s = "invalid MethodSpec"; break;
- case 127: s = "invalid ReferenceType"; break;
- case 128: s = "this symbol not expected in FunctionSpec"; break;
+ case 124: s = "this symbol not expected in MethodSpec"; break;
+ case 125: s = "invalid MethodSpec"; break;
+ case 126: s = "this symbol not expected in MethodSpec"; break;
+ case 127: s = "invalid MethodSpec"; break;
+ case 128: s = "invalid ReferenceType"; break;
case 129: s = "this symbol not expected in FunctionSpec"; break;
case 130: s = "this symbol not expected in FunctionSpec"; break;
case 131: s = "this symbol not expected in FunctionSpec"; break;
case 132: s = "this symbol not expected in FunctionSpec"; break;
- case 133: s = "invalid FunctionSpec"; break;
- case 134: s = "invalid PossiblyWildFrameExpression"; break;
- case 135: s = "invalid PossiblyWildExpression"; break;
- case 136: s = "this symbol not expected in OneStmt"; break;
- case 137: s = "invalid OneStmt"; break;
- case 138: s = "this symbol not expected in OneStmt"; break;
- case 139: s = "invalid OneStmt"; break;
- case 140: s = "invalid AssertStmt"; break;
- case 141: s = "invalid UpdateStmt"; break;
- case 142: s = "invalid IfStmt"; break;
+ case 133: s = "this symbol not expected in FunctionSpec"; break;
+ case 134: s = "invalid FunctionSpec"; break;
+ case 135: s = "invalid PossiblyWildFrameExpression"; break;
+ case 136: s = "invalid PossiblyWildExpression"; break;
+ case 137: s = "this symbol not expected in OneStmt"; break;
+ case 138: s = "invalid OneStmt"; break;
+ case 139: s = "this symbol not expected in OneStmt"; break;
+ case 140: s = "invalid OneStmt"; break;
+ case 141: s = "invalid AssertStmt"; break;
+ case 142: s = "invalid UpdateStmt"; break;
case 143: s = "invalid IfStmt"; break;
- case 144: s = "invalid WhileStmt"; break;
+ case 144: s = "invalid IfStmt"; break;
case 145: s = "invalid WhileStmt"; break;
- case 146: s = "invalid Rhs"; break;
- case 147: s = "invalid Lhs"; break;
- case 148: s = "invalid Guard"; break;
- case 149: s = "this symbol not expected in LoopSpec"; break;
+ case 146: s = "invalid WhileStmt"; break;
+ case 147: s = "invalid Rhs"; break;
+ case 148: s = "invalid Lhs"; break;
+ case 149: s = "invalid Guard"; break;
case 150: s = "this symbol not expected in LoopSpec"; break;
case 151: s = "this symbol not expected in LoopSpec"; break;
case 152: s = "this symbol not expected in LoopSpec"; break;
case 153: s = "this symbol not expected in LoopSpec"; break;
- case 154: s = "this symbol not expected in Invariant"; break;
- case 155: s = "invalid AttributeArg"; break;
- case 156: s = "invalid EquivOp"; break;
- case 157: s = "invalid ImpliesOp"; break;
- case 158: s = "invalid AndOp"; break;
- case 159: s = "invalid OrOp"; break;
- case 160: s = "invalid RelOp"; break;
- case 161: s = "invalid AddOp"; break;
- case 162: s = "invalid UnaryExpression"; break;
- case 163: s = "invalid MulOp"; break;
- case 164: s = "invalid NegOp"; break;
- case 165: s = "invalid EndlessExpression"; break;
- case 166: s = "invalid Suffix"; break;
+ case 154: s = "this symbol not expected in LoopSpec"; break;
+ case 155: s = "this symbol not expected in Invariant"; break;
+ case 156: s = "invalid AttributeArg"; break;
+ case 157: s = "invalid EquivOp"; break;
+ case 158: s = "invalid ImpliesOp"; break;
+ case 159: s = "invalid AndOp"; break;
+ case 160: s = "invalid OrOp"; break;
+ case 161: s = "invalid RelOp"; break;
+ case 162: s = "invalid AddOp"; break;
+ case 163: s = "invalid UnaryExpression"; break;
+ case 164: s = "invalid MulOp"; break;
+ case 165: s = "invalid NegOp"; break;
+ case 166: s = "invalid EndlessExpression"; break;
case 167: s = "invalid Suffix"; break;
case 168: s = "invalid Suffix"; break;
- case 169: s = "invalid DisplayExpr"; break;
- case 170: s = "invalid MultiSetExpr"; break;
- case 171: s = "invalid ConstAtomExpression"; break;
- case 172: s = "invalid QuantifierGuts"; break;
- case 173: s = "invalid Forall"; break;
- case 174: s = "invalid Exists"; break;
- case 175: s = "invalid QSep"; break;
+ case 169: s = "invalid Suffix"; break;
+ case 170: s = "invalid DisplayExpr"; break;
+ case 171: s = "invalid MultiSetExpr"; break;
+ case 172: s = "invalid ConstAtomExpression"; break;
+ case 173: s = "invalid QuantifierGuts"; break;
+ case 174: s = "invalid Forall"; break;
+ case 175: s = "invalid Exists"; break;
+ case 176: s = "invalid QSep"; break;
default: s = "error " + n; break;
}
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index 351df668..28ce83f4 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -347,7 +347,7 @@ namespace Microsoft.Dafny {
void PrintDecreasesSpec(Specification<Expression> decs, int indent) {
Contract.Requires(decs != null);
- if (decs.Expressions.Count != 0) {
+ if (decs.Expressions != null && decs.Expressions.Count != 0) {
Indent(indent);
wr.Write("decreases");
if (decs.HasAttributes())
@@ -360,14 +360,14 @@ namespace Microsoft.Dafny {
}
}
- void PrintFrameSpecLine(string kind, List<FrameExpression/*!*/>/*!*/ ee, int indent, Attributes attrs) {
+ void PrintFrameSpecLine(string kind, List<FrameExpression/*!*/> ee, int indent, Attributes attrs) {
Contract.Requires(kind != null);
Contract.Requires(cce.NonNullElements(ee));
- if (ee.Count != 0) {
+ if (ee != null && ee.Count != 0) {
Indent(indent);
wr.Write("{0}", kind);
if (attrs != null) {
- PrintAttributes(attrs);
+ PrintAttributes(attrs);
}
wr.Write(" ");
PrintFrameExpressionList(ee);
diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs
index 1626cdb4..36ae8f22 100644
--- a/Source/Dafny/RefinementTransformer.cs
+++ b/Source/Dafny/RefinementTransformer.cs
@@ -450,7 +450,7 @@ namespace Microsoft.Dafny {
} else if (stmt is IfStmt) {
var s = (IfStmt)stmt;
- r = new IfStmt(Tok(s.Tok), CloneExpr(s.Guard), CloneStmt(s.Thn), CloneStmt(s.Els));
+ r = new IfStmt(Tok(s.Tok), CloneExpr(s.Guard), CloneBlockStmt(s.Thn), CloneStmt(s.Els));
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
@@ -458,7 +458,7 @@ namespace Microsoft.Dafny {
} else if (stmt is WhileStmt) {
var s = (WhileStmt)stmt;
- r = new WhileStmt(Tok(s.Tok), CloneExpr(s.Guard), s.Invariants.ConvertAll(CloneMayBeFreeExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), CloneStmt(s.Body));
+ r = new WhileStmt(Tok(s.Tok), CloneExpr(s.Guard), s.Invariants.ConvertAll(CloneMayBeFreeExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), CloneBlockStmt(s.Body));
} else if (stmt is AlternativeLoopStmt) {
var s = (AlternativeLoopStmt)stmt;
@@ -494,7 +494,11 @@ namespace Microsoft.Dafny {
void AddStmtLabels(Statement s, LabelNode node) {
if (node != null) {
AddStmtLabels(s, node.Next);
- s.Labels = new LabelNode(Tok(node.Tok), node.Label, s.Labels);
+ if (node.Label == null) {
+ // this indicates an implicit-target break statement that has been resolved; don't add it
+ } else {
+ s.Labels = new LabelNode(Tok(node.Tok), node.Label, s.Labels);
+ }
}
}
@@ -790,60 +794,258 @@ namespace Microsoft.Dafny {
* TODO: should also handle labels and some form of new "replace" statement
*/
if (cur is SkeletonStatement) {
- var ass = ((SkeletonStatement)cur).S as AssertStmt;
- if (ass != null) {
+ var S = ((SkeletonStatement)cur).S;
+ if (S == null) {
+ if (i + 1 == skeleton.Body.Count) {
+ // this "...;" is the last statement of the skeleton, so treat it like the default case
+ } else {
+ var nxt = skeleton.Body[i+1];
+ if (nxt is SkeletonStatement && ((SkeletonStatement)nxt).S == null) {
+ // "...; ...;" is the same as just "...;", so skip this one
+ } else {
+ // skip up until the next thing that matches "nxt"
+ while (!PotentialMatch(nxt, oldS)) {
+ // loop invariant: oldS == oldStmt.Body[j]
+ body.Add(CloneStmt(oldS));
+ j++;
+ if (j == oldStmt.Body.Count) { break; }
+ oldS = oldStmt.Body[j];
+ }
+ }
+ }
+ i++;
+
+ } else if (S is AssertStmt) {
+ var skel = (AssertStmt)S;
Contract.Assert(((SkeletonStatement)cur).ConditionOmitted);
var oldAssume = oldS as PredicateStmt;
if (oldAssume == null) {
- reporter.Error(cur.Tok, "assert template does not match old statement");
+ reporter.Error(cur.Tok, "assert template does not match inherited statement");
+ i++;
} else {
// Clone the expression, but among the new assert's attributes, indicate
// that this assertion is supposed to be translated into a check. That is,
// it is not allowed to be just assumed in the translation, despite the fact
// that the condition is inherited.
var e = CloneExpr(oldAssume.Expr);
- body.Add(new AssertStmt(ass.Tok, e, new Attributes("prependAssertToken", new List<Attributes.Argument>(), null)));
+ body.Add(new AssertStmt(skel.Tok, e, new Attributes("prependAssertToken", new List<Attributes.Argument>(), null)));
+ i++; j++;
+ }
+
+ } else if (S is IfStmt) {
+ var skel = (IfStmt)S;
+ Contract.Assert(((SkeletonStatement)cur).ConditionOmitted);
+ var oldIf = oldS as IfStmt;
+ if (oldIf == null) {
+ reporter.Error(cur.Tok, "if-statement template does not match inherited statement");
+ i++;
+ } else {
+ var resultingThen = MergeBlockStmt(skel.Thn, oldIf.Thn);
+ var resultingElse = MergeElse(skel.Els, oldIf.Els);
+ var r = new IfStmt(skel.Tok, skel.Guard, resultingThen, resultingElse);
+ body.Add(r);
+ i++; j++;
}
+
+ } else if (S is WhileStmt) {
+ var skel = (WhileStmt)S;
+ var oldWhile = oldS as WhileStmt;
+ if (oldWhile == null) {
+ reporter.Error(cur.Tok, "while-statement template does not match inherited statement");
+ i++;
+ } else {
+ Expression guard;
+ if (((SkeletonStatement)cur).ConditionOmitted) {
+ guard = CloneExpr(oldWhile.Guard);
+ } else {
+ if (oldWhile.Guard != null) {
+ reporter.Error(skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard");
+ }
+ guard = skel.Guard;
+ }
+ // Note, if the loop body is omitted in the skeleton, the parser will have set the loop body to an empty block,
+ // which has the same merging behavior.
+ var r = MergeWhileStmt(skel, oldWhile, guard);
+ body.Add(r);
+ i++; j++;
+ }
+
+ } else {
+ Contract.Assume(false); // unexpected skeleton statement
+ }
+
+ } else if (cur is AssertStmt) {
+ MergeAddStatement(cur, body);
+ i++;
+
+ } else if (cur is VarDeclStmt) {
+ var cNew = (VarDeclStmt)cur;
+ var cOld = oldS as VarDeclStmt;
+ if (cOld != null && cNew.Lhss.Count == 1 && cOld.Lhss.Count == 1 && cNew.Lhss[0].Name == cOld.Lhss[0].Name && cOld.Update == null) {
+ // Note, we allow switching between ghost and non-ghost, since that seems unproblematic.
+ // Go ahead with the merge:
+ body.Add(cNew);
i++; j++;
} else {
- reporter.Error(cur.Tok, "sorry, this skeleton statement is not yet supported");
+ MergeAddStatement(cur, body);
i++;
}
- } else {
- var cNew = cur as VarDeclStmt;
- var cOld = oldS as VarDeclStmt;
- if (cNew != null && cOld != null && cNew.Lhss.Count == 1 && cOld.Lhss.Count == 1 &&
- cNew.Lhss[0].Name == cOld.Lhss[0].Name && cOld.Update == null) {
- body.Add(cNew); // TODO: there should perhaps be some more validity checks here first
+
+ } else if (cur is IfStmt) {
+ var cNew = (IfStmt)cur;
+ var cOld = oldS as IfStmt;
+ if (cOld != null && cOld.Guard == null) {
+ var r = new IfStmt(cNew.Tok, cNew.Guard, MergeBlockStmt(cNew.Thn, cOld.Thn), MergeElse(cNew.Els, cOld.Els));
+ body.Add(r);
i++; j++;
} else {
MergeAddStatement(cur, body);
i++;
}
+
+ } else if (cur is WhileStmt) {
+ var cNew = (WhileStmt)cur;
+ var cOld = oldS as WhileStmt;
+ if (cOld != null && cOld.Guard == null) {
+ var r = MergeWhileStmt(cNew, cOld, cNew.Guard);
+ body.Add(r);
+ i++; j++;
+ } else {
+ MergeAddStatement(cur, body);
+ i++;
+ }
+
+ } else {
+ MergeAddStatement(cur, body);
+ i++;
}
}
}
// implement the implicit "...;" at the end of each block statement skeleton
for (; j < oldStmt.Body.Count; j++) {
- MergeAddStatement(CloneStmt(oldStmt.Body[j]), body);
+ body.Add(CloneStmt(oldStmt.Body[j]));
}
return new BlockStmt(skeleton.Tok, body);
}
+ bool PotentialMatch(Statement nxt, Statement other) {
+ Contract.Requires(!(nxt is SkeletonStatement) || ((SkeletonStatement)nxt).S != null); // nxt is not "...;"
+ Contract.Requires(other != null);
+
+ if (nxt is SkeletonStatement) {
+ var S = ((SkeletonStatement)nxt).S;
+ if (S is AssertStmt) {
+ return other is PredicateStmt;
+ } else if (S is IfStmt) {
+ return other is IfStmt;
+ } else if (S is WhileStmt) {
+ return other is WhileStmt;
+ } else {
+ Contract.Assume(false); // unexpected skeleton
+ }
+
+ } else if (nxt is IfStmt) {
+ var oth = other as IfStmt;
+ return oth != null && oth.Guard == null;
+ } else if (nxt is WhileStmt) {
+ var oth = other as WhileStmt;
+ return oth != null && oth.Guard == null;
+ }
+
+ // not a potential match
+ return false;
+ }
+
+ WhileStmt MergeWhileStmt(WhileStmt cNew, WhileStmt cOld, Expression guard) {
+ Contract.Requires(cNew != null);
+ Contract.Requires(cOld != null);
+
+ // Note, the parser produces errors if there are any decreases or modifies clauses (and it creates
+ // the Specification structures with a null list).
+ Contract.Assume(cNew.Decreases.Expressions == null);
+ Contract.Assume(cNew.Mod.Expressions == null);
+
+ var invs = cOld.Invariants.ConvertAll(CloneMayBeFreeExpr);
+ invs.AddRange(cNew.Invariants);
+ var r = new WhileStmt(cNew.Tok, guard, invs, CloneSpecExpr(cOld.Decreases), CloneSpecFrameExpr(cOld.Mod), MergeBlockStmt(cNew.Body, cOld.Body));
+ return r;
+ }
+
+ Statement MergeElse(Statement skeleton, Statement oldStmt) {
+ Contract.Requires(skeleton == null || skeleton is BlockStmt || skeleton is IfStmt);
+ Contract.Requires(oldStmt == null || oldStmt is BlockStmt || oldStmt is IfStmt);
+
+ if (skeleton == null) {
+ return CloneStmt(oldStmt);
+ } else if (skeleton is IfStmt) {
+ // wrap a block statement around the if statement
+ skeleton = new BlockStmt(skeleton.Tok, new List<Statement>() { skeleton });
+ }
+
+ if (oldStmt == null) {
+ // make it into an empty block statement
+ oldStmt = new BlockStmt(skeleton.Tok, new List<Statement>());
+ } else if (oldStmt is IfStmt) {
+ // wrap a block statement around the if statement
+ oldStmt = new BlockStmt(oldStmt.Tok, new List<Statement>() { oldStmt });
+ }
+
+ Contract.Assert(skeleton is BlockStmt && oldStmt is BlockStmt);
+ return MergeBlockStmt((BlockStmt)skeleton, (BlockStmt)oldStmt);
+ }
+
/// <summary>
- /// Add "s" to "stmtList", but complain if "s" contains further occurrences of "..." or if "s" assigns to a
- /// variable that was not declared in the refining module.
- /// TODO: and what about new control flow?
+ /// Add "s" to "stmtList", but complain if "s" contains further occurrences of "...", if "s" assigns to a
+ /// variable that was not declared in the refining module, or if "s" has some control flow that jumps to a
+ /// place outside "s".
/// </summary>
void MergeAddStatement(Statement s, List<Statement> stmtList) {
Contract.Requires(s != null);
Contract.Requires(stmtList != null);
- if (s is AssertStmt) {
- // this is fine to add
+ var prevErrorCount = reporter.ErrorCount;
+ CheckIsOkayNewStatement(s, new Stack<string>(), 0);
+ if (reporter.ErrorCount == prevErrorCount) {
+ stmtList.Add(s);
+ }
+ }
+
+ /// <summary>
+ /// See comment on MergeAddStatement.
+ /// </summary>
+ void CheckIsOkayNewStatement(Statement s, Stack<string> labels, int loopLevels) {
+ Contract.Requires(s != null);
+ Contract.Requires(labels != null);
+ Contract.Requires(0 <= loopLevels);
+
+ for (LabelNode n = s.Labels; n != null; n = n.Next) {
+ labels.Push(n.Label);
+ }
+
+ if (s is SkeletonStatement) {
+ reporter.Error(s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced");
+ } else if (s is ReturnStmt) {
+ reporter.Error(s, "return statements are not allowed in skeletons");
+ } else if (s is BreakStmt) {
+ var b = (BreakStmt)s;
+ if (b.TargetLabel != null ? !labels.Contains(b.TargetLabel) : loopLevels < b.BreakCount) {
+ reporter.Error(s, "break statement in skeleton is not allowed to break outside the skeleton fragment");
+ }
+ } else if (s is AssignStmt) {
+ // TODO: To be a refinement automatically (that is, without any further verification), only variables and fields defined
+ // in this module are allowed. This needs to be checked. If the LHS refers to an l-value that was not declared within
+ // this module, then either an error should be reported or the Translator needs to know to translate new proof obligations.
} else {
- // TODO: validity checks
+ if (s is WhileStmt || s is AlternativeLoopStmt) {
+ loopLevels++;
+ }
+ foreach (var ss in s.SubStatements) {
+ CheckIsOkayNewStatement(ss, labels, loopLevels);
+ }
+ }
+
+ for (LabelNode n = s.Labels; n != null; n = n.Next) {
+ labels.Pop();
}
- stmtList.Add(s);
}
// ---------------------- additional methods -----------------------------------------------------------------------------
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index f66a2c5c..b259e426 100644
--- a/Source/Dafny/Resolver.cs
+++ b/Source/Dafny/Resolver.cs
@@ -170,19 +170,21 @@ namespace Microsoft.Dafny {
}
// register top-level declarations
+ Rewriter rewriter = new AutoContractsRewriter();
var systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule.TopLevelDecls);
var moduleNameInfo = new ModuleNameInformation[h];
+ var datatypeDependencies = new Graph<DatatypeDecl>();
foreach (var m in mm) {
+ rewriter.PreResolve(m);
if (m.RefinementBase != null) {
var transformer = new RefinementTransformer(this);
transformer.Construct(m);
}
moduleNameInfo[m.Height] = RegisterTopLevelDecls(m.TopLevelDecls);
- }
+// }
// resolve top-level declarations
- Graph<DatatypeDecl> datatypeDependencies = new Graph<DatatypeDecl>();
- foreach (ModuleDecl m in mm) {
+// foreach (ModuleDecl m in mm) {
// set up environment
ModuleNameInformation info = ModuleNameInformation.Merge(m, systemNameInfo, moduleNameInfo);
classes = info.Classes;
@@ -193,6 +195,8 @@ namespace Microsoft.Dafny {
// tear down
classes = null;
allDatatypeCtors = null;
+ // give rewriter a chance to do processing
+ rewriter.PostResolve(m);
}
// compute IsRecursive bit for mutually recursive functions
@@ -1733,8 +1737,7 @@ namespace Microsoft.Dafny {
if (arrayRangeLhs == null && !sse.SelectOne) {
arrayRangeLhs = sse;
}
- }
- else {
+ } else {
ResolveExpression(lhs, true);
}
}
diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs
new file mode 100644
index 00000000..addcce0a
--- /dev/null
+++ b/Source/Dafny/Rewriter.cs
@@ -0,0 +1,321 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Dafny
+{
+ public interface Rewriter
+ {
+ void PreResolve(ModuleDecl m);
+ void PostResolve(ModuleDecl m);
+ }
+
+ /// <summary>
+ /// AutoContracts is an experimental feature that will fill much of the dynamic-frames boilerplate
+ /// into a class. From the user's perspective, what needs to be done is simply:
+ /// - mark the class with {:autocontracts}
+ /// - declare a function (or predicate) called Valid()
+ ///
+ /// AutoContracts will then:
+ ///
+ /// Declare:
+ /// ghost var Repr: set(object);
+ ///
+ /// For function/predicate Valid(), insert:
+ /// reads this, Repr;
+ /// Into body of Valid(), insert (at the beginning of the body):
+ /// this in Repr && null !in Repr
+ /// and also insert, for every array-valued field A declared in the class:
+ /// (A != null ==> A in Repr) &&
+ /// and for every field F of a class type T where T has a field called Repr, also insert:
+ /// (F != null ==> F in Repr && F.Repr SUBSET Repr && this !in Repr)
+ /// Except, if A or F is declared with {:autocontracts false}, then the implication will not
+ /// be added.
+ ///
+ /// For every constructor, add:
+ /// modifies this;
+ /// ensures Valid() && fresh(Repr - {this});
+ /// At the end of the body of the constructor, add:
+ /// Repr := {this};
+ /// if (A != null) { Repr := Repr + {A}; }
+ /// if (F != null) { Repr := Repr + {F} + F.Repr; }
+ ///
+ /// For every method, add:
+ /// requires Valid();
+ /// modifies Repr;
+ /// ensures Valid() && fresh(Repr - old(Repr));
+ /// At the end of the body of the method, add:
+ /// if (A != null) { Repr := Repr + {A}; }
+ /// if (F != null) { Repr := Repr + {F} + F.Repr; }
+ /// </summary>
+ public class AutoContractsRewriter : Rewriter
+ {
+ public void PreResolve(ModuleDecl m) {
+ foreach (var d in m.TopLevelDecls) {
+ bool sayYes = true;
+ if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) {
+ ProcessClassPreResolve((ClassDecl)d);
+ }
+ }
+ }
+
+ void ProcessClassPreResolve(ClassDecl cl) {
+ // Add: ghost var Repr: set<object>;
+ // ...unless a field with that name is already present
+ if (!cl.Members.Exists(member => member is Field && member.Name == "Repr")) {
+ Type ty = new SetType(new ObjectType());
+ cl.Members.Add(new Field(cl.tok, "Repr", true, ty, null));
+ }
+
+ foreach (var member in cl.Members) {
+ bool sayYes = true;
+ if (Attributes.ContainsBool(member.Attributes, "autocontracts", ref sayYes) && !sayYes) {
+ continue;
+ }
+ var tok = member.tok;
+ if (member is Function && member.Name == "Valid" && !member.IsStatic) {
+ var valid = (Function)member;
+ // reads this;
+ valid.Reads.Add(new FrameExpression(new ThisExpr(tok), null));
+ // reads Repr;
+ valid.Reads.Add(new FrameExpression(new FieldSelectExpr(tok, new ImplicitThisExpr(tok), "Repr"), null));
+ } else if (member is Constructor) {
+ var ctor = (Constructor)member;
+ // modifies this;
+ ctor.Mod.Expressions.Add(new FrameExpression(new ImplicitThisExpr(tok), null));
+ // ensures Valid();
+ ctor.Ens.Insert(0, new MaybeFreeExpression(new FunctionCallExpr(tok, "Valid", new ImplicitThisExpr(tok), tok, new List<Expression>())));
+ // ensures fresh(Repr - {this});
+ var freshness = new FreshExpr(tok, new BinaryExpr(tok, BinaryExpr.Opcode.Sub,
+ new FieldSelectExpr(tok, new ImplicitThisExpr(tok), "Repr"),
+ new SetDisplayExpr(tok, new List<Expression>() { new ThisExpr(tok) })));
+ ctor.Ens.Insert(1, new MaybeFreeExpression(freshness));
+ } else if (member is Method && !member.IsStatic) {
+ var m = (Method)member;
+ // requires Valid();
+ m.Req.Insert(0, new MaybeFreeExpression(new FunctionCallExpr(tok, "Valid", new ImplicitThisExpr(tok), tok, new List<Expression>())));
+ // If this is a mutating method, we should also add a modifies clause and a postcondition, but we don't do that if it's
+ // a simple query method. However, we won't know if it's a simple query method until after resolution, so we'll add the
+ // rest of the spec then.
+ }
+ }
+ }
+
+ public void PostResolve(ModuleDecl m) {
+ foreach (var d in m.TopLevelDecls) {
+ bool sayYes = true;
+ if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) {
+ ProcessClassPostResolve((ClassDecl)d);
+ }
+ }
+ }
+
+ void ProcessClassPostResolve(ClassDecl cl) {
+ // Find all fields of a reference type, and make a note of whether or not the reference type has a Repr field.
+ // Also, find the Repr field and the function Valid in class "cl"
+ Field ReprField = null;
+ Function Valid = null;
+ var subobjects = new List<Tuple<Field, Field>>();
+ foreach (var member in cl.Members) {
+ var field = member as Field;
+ if (field != null) {
+ bool sayYes = true;
+ if (field.Name == "Repr") {
+ ReprField = field;
+ } else if (Attributes.ContainsBool(field.Attributes, "autocontracts", ref sayYes) && !sayYes) {
+ // ignore this field
+ } else if (field.Type is ObjectType) {
+ subobjects.Add(new Tuple<Field, Field>(field, null));
+ } else if (field.Type.IsRefType) {
+ var rcl = (ClassDecl)((UserDefinedType)field.Type).ResolvedClass;
+ Field rRepr = null;
+ foreach (var memb in rcl.Members) {
+ var f = memb as Field;
+ if (f != null && f.Name == "Repr") {
+ rRepr = f;
+ break;
+ }
+ }
+ subobjects.Add(new Tuple<Field, Field>(field, rRepr));
+ }
+ } else if (member is Function && member.Name == "Valid" && !member.IsStatic) {
+ var fn = (Function)member;
+ if (fn.Formals.Count == 0 && fn.ResultType is BoolType) {
+ Valid = fn;
+ }
+ }
+ }
+ Contract.Assert(ReprField != null); // we expect there to be a "Repr" field, since we added one in PreResolve
+
+ Type ty = new UserDefinedType(cl.tok, cl.Name, cl, new List<Type>());
+ var self = new ThisExpr(cl.tok);
+ self.Type = ty;
+ var implicitSelf = new ImplicitThisExpr(cl.tok);
+ implicitSelf.Type = ty;
+ var Repr = new FieldSelectExpr(cl.tok, implicitSelf, "Repr");
+ Repr.Field = ReprField;
+ Repr.Type = ReprField.Type;
+ var cNull = new LiteralExpr(cl.tok);
+ cNull.Type = new ObjectType();
+
+ foreach (var member in cl.Members) {
+ bool sayYes = true;
+ if (Attributes.ContainsBool(member.Attributes, "autocontracts", ref sayYes) && !sayYes) {
+ continue;
+ }
+ var tok = member.tok;
+ if (member is Function && member.Name == "Valid" && !member.IsStatic) {
+ var valid = (Function)member;
+ if (valid.IsGhost && valid.ResultType is BoolType) {
+ var c0 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.InSet, self, Repr); // this in Repr
+ var c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NotInSet, cNull, Repr); // null !in Repr
+ var c = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c0, c1);
+
+ foreach (var ff in subobjects) {
+ var F = new FieldSelectExpr(tok, implicitSelf, ff.Item1.Name);
+ F.Field = ff.Item1;
+ F.Type = ff.Item1.Type;
+
+ c0 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NeqCommon, F, cNull);
+ c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.InSet, F, Repr);
+ if (ff.Item2 == null) {
+ // F != null ==> F in Repr (so, nothing else to do)
+ } else {
+ // F != null ==> F in Repr && F.Repr <= Repr && this !in F.Repr
+ var FRepr = new FieldSelectExpr(tok, F, ff.Item2.Name);
+ FRepr.Field = ff.Item2;
+ FRepr.Type = ff.Item2.Type;
+ var c2 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.Subset, FRepr, Repr);
+ var c3 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NotInSet, self, FRepr);
+ c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c1, BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c2, c3));
+ }
+ c = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c, BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.Imp, c0, c1));
+ }
+
+ if (valid.Body == null) {
+ valid.Body = c;
+ } else {
+ valid.Body = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c, valid.Body);
+ }
+ }
+
+ } else if (member is Constructor) {
+ var ctor = (Constructor)member;
+ if (ctor.Body == null) {
+ ctor.Body = new BlockStmt(tok, new List<Statement>());
+ }
+ // TODO: these assignments should be included on every return path
+ var bodyStatements = ((BlockStmt)ctor.Body).Body;
+ // Repr := {this};
+ var e = new SetDisplayExpr(tok, new List<Expression>() { self });
+ e.Type = new SetType(new ObjectType());
+ Statement s = new AssignStmt(tok, Repr, new ExprRhs(e));
+ s.IsGhost = true;
+ bodyStatements.Add(s);
+
+ AddSubobjectReprs(tok, subobjects, bodyStatements, self, implicitSelf, cNull, Repr);
+
+ } else if (member is Method && !member.IsStatic) {
+ var m = (Method)member;
+ if (Valid != null && !IsSimpleQueryMethod(m)) {
+ // modifies Repr;
+ m.Mod.Expressions.Add(new FrameExpression(Repr, null));
+ // ensures Valid();
+ var valid = new FunctionCallExpr(tok, "Valid", implicitSelf, tok, new List<Expression>());
+ valid.Function = Valid;
+ valid.Type = Type.Bool;
+ m.Ens.Insert(0, new MaybeFreeExpression(valid));
+ // ensures fresh(Repr - old(Repr));
+ var e0 = new OldExpr(tok, Repr);
+ e0.Type = Repr.Type;
+ var e1 = new BinaryExpr(tok, BinaryExpr.Opcode.Sub, Repr, e0);
+ e1.ResolvedOp = BinaryExpr.ResolvedOpcode.SetDifference;
+ e1.Type = Repr.Type;
+ var freshness = new FreshExpr(tok, e1);
+ freshness.Type = Type.Bool;
+ m.Ens.Insert(1, new MaybeFreeExpression(freshness));
+
+ if (m.Body == null) {
+ m.Body = new BlockStmt(tok, new List<Statement>());
+ }
+ // TODO: these assignments should be included on every return path
+ var bodyStatements = ((BlockStmt)m.Body).Body;
+ AddSubobjectReprs(tok, subobjects, bodyStatements, self, implicitSelf, cNull, Repr);
+ }
+ }
+ }
+ }
+
+ void AddSubobjectReprs(Boogie.IToken tok, List<Tuple<Field, Field>> subobjects, List<Statement> bodyStatements,
+ Expression self, Expression implicitSelf, Expression cNull, Expression Repr) {
+
+ foreach (var ff in subobjects) {
+ var F = new FieldSelectExpr(tok, implicitSelf, ff.Item1.Name);
+ F.Field = ff.Item1;
+ F.Type = ff.Item1.Type;
+
+ Expression e = new SetDisplayExpr(tok, new List<Expression>() { F });
+ e.Type = new SetType(new ObjectType());
+ var rhs = new BinaryExpr(tok, BinaryExpr.Opcode.Add, Repr, e);
+ rhs.ResolvedOp = BinaryExpr.ResolvedOpcode.Union;
+ rhs.Type = Repr.Type;
+ if (ff.Item2 == null) {
+ // Repr := Repr + {F} (so, nothing else to do)
+ } else {
+ // Repr := Repr + {F} + F.Repr
+ var FRepr = new FieldSelectExpr(tok, F, ff.Item2.Name);
+ FRepr.Field = ff.Item2;
+ FRepr.Type = ff.Item2.Type;
+ rhs = new BinaryExpr(tok, BinaryExpr.Opcode.Add, rhs, FRepr);
+ rhs.ResolvedOp = BinaryExpr.ResolvedOpcode.Union;
+ rhs.Type = Repr.Type;
+ }
+ // Repr := Repr + ...;
+ Statement s = new AssignStmt(tok, Repr, new ExprRhs(rhs));
+ s.IsGhost = true;
+ // wrap if statement around s
+ e = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NeqCommon, F, cNull);
+ var thn = new BlockStmt(tok, new List<Statement>() { s });
+ thn.IsGhost = true;
+ s = new IfStmt(tok, e, thn, null);
+ s.IsGhost = true;
+ // finally, add s to the body
+ bodyStatements.Add(s);
+ }
+ }
+
+ bool IsSimpleQueryMethod(Method m) {
+ // A simple query method has out parameters, its body has no effect other than to assign to them,
+ // and the postcondition does not explicitly mention the pre-state.
+ return m.Outs.Count != 0 && m.Body != null && LocalAssignsOnly(m.Body) &&
+ m.Ens.TrueForAll(mfe => !Translator.MentionsOldState(mfe.E));
+ }
+
+ bool LocalAssignsOnly(Statement s) {
+ Contract.Requires(s != null);
+ if (s is AssignStmt) {
+ var ss = (AssignStmt)s;
+ return ss.Lhs.Resolved is IdentifierExpr;
+ } else if (s is UpdateStmt) {
+ var ss = (UpdateStmt)s;
+ return ss.Lhss.TrueForAll(e => e.Resolved is IdentifierExpr);
+ } else if (s is CallStmt) {
+ return false;
+ } else {
+ foreach (var ss in s.SubStatements) {
+ if (!LocalAssignsOnly(ss)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ BinaryExpr BinBoolExpr(Boogie.IToken tok, BinaryExpr.ResolvedOpcode rop, Expression e0, Expression e1) {
+ var p = new BinaryExpr(tok, BinaryExpr.ResolvedOp2SyntacticOp(rop), e0, e1);
+ p.ResolvedOp = rop;
+ p.Type = Type.Bool;
+ return p;
+ }
+ }
+}
diff --git a/Source/Dafny/Scanner.cs b/Source/Dafny/Scanner.cs
index 56d53e19..3e021fa5 100644
--- a/Source/Dafny/Scanner.cs
+++ b/Source/Dafny/Scanner.cs
@@ -488,11 +488,11 @@ public class Scanner {
void CheckLiteral() {
switch (t.val) {
- case "module": t.kind = 8; break;
- case "refines": t.kind = 9; break;
- case "imports": t.kind = 10; break;
- case "class": t.kind = 11; break;
- case "ghost": t.kind = 12; break;
+ case "ghost": t.kind = 8; break;
+ case "module": t.kind = 9; break;
+ case "refines": t.kind = 10; break;
+ case "imports": t.kind = 11; break;
+ case "class": t.kind = 12; break;
case "static": t.kind = 13; break;
case "unlimited": t.kind = 14; break;
case "datatype": t.kind = 15; break;
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index c0a56d05..a285a577 100644
--- a/Source/Dafny/Translator.cs
+++ b/Source/Dafny/Translator.cs
@@ -269,7 +269,7 @@ namespace Microsoft.Dafny {
}
Bpl.Program prelude;
- int errorCount = Bpl.Parser.Parse(preludePath, null, out prelude);
+ int errorCount = Bpl.Parser.Parse(preludePath, (List<string>)null, out prelude);
if (prelude == null || errorCount > 0) {
return null;
} else {
@@ -2406,10 +2406,21 @@ namespace Microsoft.Dafny {
} else if (expr is LetExpr) {
var e = (LetExpr)expr;
- foreach (var rhs in e.RHSs) {
- CheckWellformed(rhs, options, locals, builder, etran);
+
+ var substMap = new Dictionary<IVariable, Expression>();
+ Contract.Assert(e.Vars.Count == e.RHSs.Count); // checked by resolution
+ for (int i = 0; i < e.Vars.Count; i++) {
+ var vr = e.Vars[i];
+ var tp = TrType(vr.Type);
+ var v = new Bpl.LocalVariable(vr.tok, new Bpl.TypedIdent(vr.tok, vr.UniqueName, tp));
+ locals.Add(v);
+ var lhs = new Bpl.IdentifierExpr(vr.tok, vr.UniqueName, tp);
+
+ CheckWellformedWithResult(e.RHSs[i], options, lhs, vr.Type, locals, builder, etran);
+ substMap.Add(vr, new BoogieWrapper(lhs, vr.Type));
}
- CheckWellformedWithResult(etran.GetSubstitutedBody(e), options, result, resultType, locals, builder, etran);
+ CheckWellformedWithResult(Substitute(e.Body, null, substMap), options, result, resultType, locals, builder, etran);
+ result = null;
} else if (expr is ComprehensionExpr) {
var e = (ComprehensionExpr)expr;
@@ -7061,7 +7072,7 @@ namespace Microsoft.Dafny {
/// <summary>
/// Returns true iff 'expr' is a two-state expression, that is, if it mentions "old(...)" or "fresh(...)".
/// </summary>
- static bool MentionsOldState(Expression expr) {
+ public static bool MentionsOldState(Expression expr) {
Contract.Requires(expr != null);
if (expr is OldExpr || expr is FreshExpr) {
return true;
diff --git a/Source/DafnyDriver/DafnyDriver.cs b/Source/DafnyDriver/DafnyDriver.cs
index 5e227011..04e86519 100644
--- a/Source/DafnyDriver/DafnyDriver.cs
+++ b/Source/DafnyDriver/DafnyDriver.cs
@@ -346,7 +346,7 @@ namespace Microsoft.Dafny
Bpl.Program programSnippet;
int errorCount;
try {
- errorCount = Microsoft.Boogie.Parser.Parse(bplFileName, null, out programSnippet);
+ errorCount = Microsoft.Boogie.Parser.Parse(bplFileName, (List<string>)null, out programSnippet);
if (programSnippet == null || errorCount != 0) {
Console.WriteLine("{0} parse errors detected in {1}", errorCount, bplFileName);
okay = false;
diff --git a/Source/GPUVerify.sln b/Source/GPUVerify.sln
index a78d449e..a31d8600 100644
--- a/Source/GPUVerify.sln
+++ b/Source/GPUVerify.sln
@@ -21,22 +21,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Isabelle", "Provers\Isabelle\Isabelle.csproj", "{435D5BD0-6F62-49F8-BB24-33E2257519AD}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z3", "Provers\Z3\Z3.csproj", "{BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMTLib", "Provers\SMTLib\SMTLib.csproj", "{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TPTP", "Provers\TPTP\TPTP.csproj", "{A598ED5A-93AD-4125-A555-3921A2F936FA}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simplify", "Provers\Simplify\Simplify.csproj", "{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCGeneration", "VCGeneration\VCGeneration.csproj", "{E1F10180-C7B9-4147-B51F-FA1B701966DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Isabelle", "Provers\Isabelle\Isabelle.csproj", "{435D5BD0-6F62-49F8-BB24-33E2257519AD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Checked|Any CPU = Checked|Any CPU
@@ -255,46 +249,6 @@ Global
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.ActiveCfg = Checked|Any CPU
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Checked|Any CPU
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Any CPU.Build.0 = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|x86.ActiveCfg = Checked|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|x86.ActiveCfg = Debug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Any CPU.Build.0 = Release|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|x86.ActiveCfg = Release|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
- {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|Any CPU.Build.0 = Checked|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|x86.ActiveCfg = Checked|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Release|Any CPU.Build.0 = Release|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Release|x86.ActiveCfg = Release|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Any CPU.Build.0 = Checked|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
@@ -315,46 +269,6 @@ Global
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|Any CPU.Build.0 = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|x86.ActiveCfg = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Release|Any CPU.Build.0 = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Release|x86.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Any CPU.ActiveCfg = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Any CPU.Build.0 = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Mixed Platforms.ActiveCfg = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Mixed Platforms.Build.0 = Checked|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|x86.ActiveCfg = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|Any CPU.Build.0 = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|x86.ActiveCfg = Checked|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Release|Any CPU.Build.0 = Release|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Release|x86.ActiveCfg = Release|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
{E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
{E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Any CPU.Build.0 = Checked|Any CPU
{E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
@@ -415,6 +329,26 @@ Global
{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Any CPU.ActiveCfg = Checked|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Any CPU.Build.0 = Checked|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|Mixed Platforms.Build.0 = Checked|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Checked|x86.ActiveCfg = Checked|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.Release|x86.ActiveCfg = Release|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
+ {435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Source/GPUVerify/AccessInvariantProcessor.cs b/Source/GPUVerify/AccessInvariantProcessor.cs
new file mode 100644
index 00000000..4a5c34e8
--- /dev/null
+++ b/Source/GPUVerify/AccessInvariantProcessor.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class AccessInvariantProcessor : StandardVisitor
+ {
+
+ private const string NO_READ = "__no_read_";
+ private const string NO_WRITE = "__no_write_";
+ private const string READ = "__read_";
+ private const string WRITE = "__write_";
+ private const string READ_OFFSET = "__read_offset_";
+ private const string WRITE_OFFSET = "__write_offset_";
+ private const string READ_IMPLIES = "__read_implies_";
+ private const string WRITE_IMPLIES = "__write_implies_";
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+
+ if (node.Fun is FunctionCall)
+ {
+ FunctionCall call = node.Fun as FunctionCall;
+
+ if (MatchesIntrinsic(call.Func, NO_READ))
+ {
+ return Expr.Not(
+ MakeReadHasOccurred(node, call, NO_READ)
+ );
+ }
+
+ if (MatchesIntrinsic(call.Func, NO_WRITE))
+ {
+ return Expr.Not(
+ MakeWriteHasOccurred(node, call, NO_WRITE)
+ );
+ }
+
+ if (MatchesIntrinsic(call.Func, READ_OFFSET))
+ {
+ return new IdentifierExpr(node.tok, new GlobalVariable(
+ node.tok, new TypedIdent(node.tok, "_READ_OFFSET_X_" +
+ call.Func.Name.Substring(READ_OFFSET.Length), Microsoft.Boogie.Type.GetBvType(32)))
+ );
+ }
+
+ if (MatchesIntrinsic(call.Func, WRITE_OFFSET))
+ {
+ return new IdentifierExpr(node.tok, new GlobalVariable(
+ node.tok, new TypedIdent(node.tok, "_WRITE_OFFSET_X_" +
+ call.Func.Name.Substring(WRITE_OFFSET.Length), Microsoft.Boogie.Type.GetBvType(32)))
+ );
+ }
+
+ if (MatchesIntrinsic(call.Func, READ))
+ {
+ return MakeReadHasOccurred(node, call, READ);
+ }
+
+ if (MatchesIntrinsic(call.Func, WRITE))
+ {
+ return MakeWriteHasOccurred(node, call, WRITE);
+ }
+
+ if (MatchesIntrinsic(call.Func, READ_IMPLIES))
+ {
+ return Expr.Imp(MakeReadHasOccurred(node, call, READ_IMPLIES), node.Args[0]);
+ }
+
+ if (MatchesIntrinsic(call.Func, WRITE_IMPLIES))
+ {
+ return Expr.Imp(MakeWriteHasOccurred(node, call, WRITE_IMPLIES), node.Args[0]);
+ }
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+ private static IdentifierExpr MakeReadHasOccurred(NAryExpr node, FunctionCall call, string intrinsicPrefix)
+ {
+ return new IdentifierExpr(node.tok, new GlobalVariable(
+ node.tok, new TypedIdent(node.tok, "_READ_HAS_OCCURRED_" +
+ call.Func.Name.Substring(intrinsicPrefix.Length), Microsoft.Boogie.Type.Bool)));
+ }
+
+ private static IdentifierExpr MakeWriteHasOccurred(NAryExpr node, FunctionCall call, string intrinsicPrefix)
+ {
+ return new IdentifierExpr(node.tok, new GlobalVariable(
+ node.tok, new TypedIdent(node.tok, "_WRITE_HAS_OCCURRED_" +
+ call.Func.Name.Substring(intrinsicPrefix.Length), Microsoft.Boogie.Type.Bool)));
+ }
+
+
+ private bool MatchesIntrinsic(Function function, string intrinsicPrefix)
+ {
+ return function.Name.Length > intrinsicPrefix.Length &&
+ function.Name.Substring(0, intrinsicPrefix.Length).Equals(intrinsicPrefix);
+ }
+
+
+ }
+}
diff --git a/Source/GPUVerify/AsymmetricExpressionFinder.cs b/Source/GPUVerify/AsymmetricExpressionFinder.cs
new file mode 100644
index 00000000..40c7eb32
--- /dev/null
+++ b/Source/GPUVerify/AsymmetricExpressionFinder.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class AsymmetricExpressionFinder : StandardVisitor
+ {
+ private bool found = false;
+
+ internal bool foundAsymmetricExpr()
+ {
+ return found;
+ }
+
+ public override Variable VisitVariable(Variable node)
+ {
+ if (node.TypedIdent.Name.Contains("_READ_HAS_OCCURRED") ||
+ node.TypedIdent.Name.Contains("_READ_OFFSET"))
+ {
+ found = true;
+ }
+ return node;
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/CrossThreadInvariantProcessor.cs b/Source/GPUVerify/CrossThreadInvariantProcessor.cs
new file mode 100644
index 00000000..c9b4c26c
--- /dev/null
+++ b/Source/GPUVerify/CrossThreadInvariantProcessor.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class CrossThreadInvariantProcessor : StandardVisitor
+ {
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+
+ if (node.Fun is FunctionCall)
+ {
+ FunctionCall call = node.Fun as FunctionCall;
+
+ if (call.Func.Name.Equals("__uniform_bv32") || call.Func.Name.Equals("__uniform_bool"))
+ {
+ return Expr.Eq(new VariableDualiser(1).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2).VisitExpr(node.Args[0].Clone() as Expr));
+ }
+
+ if (call.Func.Name.Equals("__distinct_bv32") || call.Func.Name.Equals("__distinct_bool"))
+ {
+ return Expr.Neq(new VariableDualiser(1).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2).VisitExpr(node.Args[0].Clone() as Expr));
+ }
+
+ if (call.Func.Name.Equals("__all"))
+ {
+ return Expr.And(new VariableDualiser(1).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2).VisitExpr(node.Args[0].Clone() as Expr));
+ }
+
+ if (call.Func.Name.Equals("__at_most_one"))
+ {
+ return Expr.Not(Expr.And(new VariableDualiser(1).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2).VisitExpr(node.Args[0].Clone() as Expr)));
+ }
+
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+
+
+ }
+}
diff --git a/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs b/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
index 84624e5d..103974ec 100644
--- a/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
+++ b/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
@@ -191,46 +191,46 @@ namespace GPUVerify
bb.simpleCmds.Add(new AssignCmd(tok, lhss, rhss));
}
- public override void CheckForRaces(IToken tok, BigBlock bb, Variable v, bool ReadWriteOnly)
+ public override void CheckForRaces(BigBlock bb, Variable v, bool ReadWriteOnly)
{
if (!ReadWriteOnly)
{
- bb.simpleCmds.Add(new AssertCmd(tok, Expr.Not(GenerateRaceCondition(tok, v, "WRITE", "WRITE"))));
+ bb.simpleCmds.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "WRITE", "WRITE"))));
}
- bb.simpleCmds.Add(new AssertCmd(tok, Expr.Not(GenerateRaceCondition(tok, v, "READ", "WRITE"))));
+ bb.simpleCmds.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "READ", "WRITE"))));
if (!CommandLineOptions.Symmetry)
{
- bb.simpleCmds.Add(new AssertCmd(tok, Expr.Not(GenerateRaceCondition(tok, v, "WRITE", "READ"))));
+ bb.simpleCmds.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "WRITE", "READ"))));
}
}
- private static Expr GenerateRaceCondition(IToken tok, Variable v, string FirstAccessType, string SecondAccessType)
+ protected override Expr GenerateRaceCondition(Variable v, string FirstAccessType, string SecondAccessType)
{
Expr RaceCondition = Expr.And(
- new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, FirstAccessType))),
- new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, SecondAccessType))));
+ new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, SecondAccessType))));
if (GPUVerifier.HasXDimension(v))
{
RaceCondition = Expr.And(RaceCondition, Expr.Eq(
- new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, FirstAccessType))),
- new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, SecondAccessType)))
+ new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, SecondAccessType)))
));
}
if (GPUVerifier.HasYDimension(v))
{
RaceCondition = Expr.And(RaceCondition, Expr.Eq(
- new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, FirstAccessType))),
- new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, SecondAccessType)))
+ new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, SecondAccessType)))
));
}
if (GPUVerifier.HasZDimension(v))
{
RaceCondition = Expr.And(RaceCondition, Expr.Eq(
- new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, FirstAccessType))),
- new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, SecondAccessType)))
+ new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, SecondAccessType)))
));
}
diff --git a/Source/GPUVerify/EnabledToPredicateVisitor.cs b/Source/GPUVerify/EnabledToPredicateVisitor.cs
new file mode 100644
index 00000000..3cedd075
--- /dev/null
+++ b/Source/GPUVerify/EnabledToPredicateVisitor.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class EnabledToPredicateVisitor : StandardVisitor
+ {
+
+ public EnabledToPredicateVisitor(TypedIdent currentPredicate)
+ {
+ this.currentPredicate = currentPredicate;
+
+ }
+
+ private TypedIdent currentPredicate;
+
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+ if (node.Fun is FunctionCall)
+ {
+ FunctionCall call = node.Fun as FunctionCall;
+
+ if (call.Func.Name.Equals("__enabled"))
+ {
+ return new IdentifierExpr(node.tok, new LocalVariable(node.tok, currentPredicate));
+ }
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs
index 2f9be79b..86938ab2 100644
--- a/Source/GPUVerify/GPUVerifier.cs
+++ b/Source/GPUVerify/GPUVerifier.cs
@@ -310,6 +310,8 @@ namespace GPUVerify
return;
}
+ ProcessAccessInvariants();
+
if (CommandLineOptions.ShowStages)
{
emitProgram(outputFilename + "_instrumented");
@@ -336,6 +338,13 @@ namespace GPUVerify
emitProgram(outputFilename + "_dualised");
}
+ ProcessCrossThreadInvariants();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_cross_thread_invariants");
+ }
+
if (CommandLineOptions.Eager)
{
AddEagerRaceChecking();
@@ -343,7 +352,7 @@ namespace GPUVerify
GenerateBarrierImplementation();
- GenerateKernelPrecondition();
+ GenerateStandardKernelContract();
if (CommandLineOptions.ShowStages)
{
@@ -399,6 +408,186 @@ namespace GPUVerify
}
+ private void ProcessAccessInvariants()
+ {
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Procedure)
+ {
+ Procedure p = d as Procedure;
+ p.Requires = ProcessAccessInvariants(p.Requires);
+ p.Ensures = ProcessAccessInvariants(p.Ensures);
+ }
+
+ if (d is Implementation)
+ {
+ Implementation i = d as Implementation;
+ ProcessAccessInvariants(i.StructuredStmts);
+ }
+ }
+ }
+
+ private void ProcessAccessInvariants(StmtList stmtList)
+ {
+
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ ProcessAccessInvariants(bb);
+ }
+ }
+
+ private void ProcessAccessInvariants(BigBlock bb)
+ {
+ CmdSeq newCommands = new CmdSeq();
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssertCmd)
+ {
+ newCommands.Add(new AssertCmd(c.tok, new AccessInvariantProcessor().VisitExpr((c as AssertCmd).Expr.Clone() as Expr)));
+ }
+ else if (c is AssumeCmd)
+ {
+ newCommands.Add(new AssumeCmd(c.tok, new AccessInvariantProcessor().VisitExpr((c as AssumeCmd).Expr.Clone() as Expr)));
+ }
+ else
+ {
+ newCommands.Add(c);
+ }
+ }
+
+ bb.simpleCmds = newCommands;
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd whileCmd = bb.ec as WhileCmd;
+ whileCmd.Invariants = ProcessAccessInvariants(whileCmd.Invariants);
+ ProcessAccessInvariants(whileCmd.Body);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ ProcessAccessInvariants((bb.ec as IfCmd).thn);
+ if ((bb.ec as IfCmd).elseBlock != null)
+ {
+ ProcessAccessInvariants((bb.ec as IfCmd).elseBlock);
+ }
+ }
+ }
+
+ private List<PredicateCmd> ProcessAccessInvariants(List<PredicateCmd> invariants)
+ {
+ List<PredicateCmd> result = new List<PredicateCmd>();
+
+ foreach (PredicateCmd p in invariants)
+ {
+ result.Add(new AssertCmd(p.tok, new AccessInvariantProcessor().VisitExpr(p.Expr.Clone() as Expr)));
+ }
+
+ return result;
+ }
+
+ private EnsuresSeq ProcessAccessInvariants(EnsuresSeq ensuresSeq)
+ {
+ EnsuresSeq result = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq)
+ {
+ result.Add(new Ensures(e.Free, new AccessInvariantProcessor().VisitExpr(e.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ private RequiresSeq ProcessAccessInvariants(RequiresSeq requiresSeq)
+ {
+ RequiresSeq result = new RequiresSeq();
+ foreach (Requires r in requiresSeq)
+ {
+ result.Add(new Requires(r.Free, new AccessInvariantProcessor().VisitExpr(r.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ private void ProcessCrossThreadInvariants()
+ {
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Procedure)
+ {
+ Procedure p = d as Procedure;
+ p.Requires = ProcessCrossThreadInvariants(p.Requires);
+ p.Ensures = ProcessCrossThreadInvariants(p.Ensures);
+ }
+ if (d is Implementation)
+ {
+ Implementation i = d as Implementation;
+ ProcessCrossThreadInvariants(i.StructuredStmts);
+ }
+
+ }
+ }
+
+ private EnsuresSeq ProcessCrossThreadInvariants(EnsuresSeq ensuresSeq)
+ {
+ EnsuresSeq result = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq)
+ {
+ result.Add(new Ensures(e.Free, new CrossThreadInvariantProcessor().VisitExpr(e.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ private RequiresSeq ProcessCrossThreadInvariants(RequiresSeq requiresSeq)
+ {
+ RequiresSeq result = new RequiresSeq();
+ foreach (Requires r in requiresSeq)
+ {
+ result.Add(new Requires(r.Free, new CrossThreadInvariantProcessor().VisitExpr(r.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ private void ProcessCrossThreadInvariants(StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ ProcessCrossThreadInvariants(bb);
+ }
+ }
+
+ private void ProcessCrossThreadInvariants(BigBlock bb)
+ {
+ CmdSeq newCommands = new CmdSeq();
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssertCmd)
+ {
+ newCommands.Add(new AssertCmd(c.tok, new CrossThreadInvariantProcessor().VisitExpr((c as AssertCmd).Expr.Clone() as Expr)));
+ }
+ else if (c is AssumeCmd)
+ {
+ newCommands.Add(new AssumeCmd(c.tok, new CrossThreadInvariantProcessor().VisitExpr((c as AssumeCmd).Expr.Clone() as Expr)));
+ }
+ else
+ {
+ newCommands.Add(c);
+ }
+ }
+
+ bb.simpleCmds = newCommands;
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd whileCmd = bb.ec as WhileCmd;
+ List<PredicateCmd> newInvariants = new List<PredicateCmd>();
+ foreach(PredicateCmd p in whileCmd.Invariants)
+ {
+ newInvariants.Add(new AssertCmd(p.tok, new CrossThreadInvariantProcessor().VisitExpr(p.Expr)));
+ }
+ whileCmd.Invariants = newInvariants;
+ ProcessCrossThreadInvariants(whileCmd.Body);
+ }
+ }
+
private void emitProgram(string filename)
{
using (TokenTextWriter writer = new TokenTextWriter(filename + ".bpl"))
@@ -423,7 +612,7 @@ namespace GPUVerify
if (impl.Name.Equals("_LOG_READ_" + v.Name) || impl.Name.Equals("_LOG_WRITE_" + v.Name))
{
BigBlock bb = new BigBlock(v.tok, "__CheckForRaces", new CmdSeq(), null, null);
- RaceInstrumenter.CheckForRaces(v.tok, bb, v, impl.Name.Equals("_LOG_READ_" + v.Name));
+ RaceInstrumenter.CheckForRaces(bb, v, impl.Name.Equals("_LOG_READ_" + v.Name));
StmtList newStatements = new StmtList(new List<BigBlock>(), v.tok);
foreach(BigBlock bb2 in impl.StructuredStmts.BigBlocks)
@@ -936,18 +1125,6 @@ namespace GPUVerify
return _GROUP_SIZE_Z != null;
}
- public bool KernelHasId(string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- if (dimension.Equals("X")) return KernelHasIdX();
- if (dimension.Equals("Y")) return KernelHasIdY();
- if (dimension.Equals("Z")) return KernelHasIdZ();
- Debug.Assert(false);
- return false;
- }
-
-
-
public void AddCandidateInvariant(WhileCmd wc, Expr e)
{
Constant ExistentialBooleanConstant = MakeExistentialBoolean(wc.tok);
@@ -989,7 +1166,7 @@ namespace GPUVerify
KernelImplementation.StructuredStmts.BigBlocks.Add(bb);
}
- private void GenerateKernelPrecondition()
+ private void GenerateStandardKernelContract()
{
RaceInstrumenter.AddKernelPrecondition();
@@ -1019,6 +1196,12 @@ namespace GPUVerify
Proc.Requires.Add(new Requires(false, AssumeDistinctThreads));
Proc.Requires.Add(new Requires(false, AssumeThreadIdsInRange));
+
+ if (Proc != KernelProcedure)
+ {
+ RaceInstrumenter.AddNoRaceContract(Proc);
+ }
+
}
}
else
@@ -1033,6 +1216,9 @@ namespace GPUVerify
continue;
}
Implementation Impl = D as Implementation;
+
+ RaceInstrumenter.AddNoRaceInvariants(Impl);
+
if (QKeyValue.FindIntAttribute(Impl.Proc.Attributes, "inline", -1) == 1)
{
continue;
@@ -1138,68 +1324,65 @@ namespace GPUVerify
private void GeneratePreconditionsForDimension(ref Expr AssumeDistinctThreads, ref Expr AssumeThreadIdsInRange, IToken tok, String dimension)
{
- if (KernelHasId(dimension))
+ foreach (Declaration D in Program.TopLevelDeclarations)
{
- foreach (Declaration D in Program.TopLevelDeclarations)
+ if (!(D is Procedure))
{
- if (!(D is Procedure))
- {
- continue;
- }
- Procedure Proc = D as Procedure;
- if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
- {
- continue;
- }
+ continue;
+ }
+ Procedure Proc = D as Procedure;
+ if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
+ {
+ continue;
+ }
- if (GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)))
- {
- Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GT", new IdentifierExpr(tok, GetGroupSize(dimension)), ZeroBV(tok))));
- Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GT", new IdentifierExpr(tok, GetNumGroups(dimension)), ZeroBV(tok))));
- Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, GetGroupId(dimension)), ZeroBV(tok))));
- Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)))));
- }
- else
- {
- Proc.Requires.Add(new Requires(false, Expr.Gt(new IdentifierExpr(tok, GetGroupSize(dimension)), Zero(tok))));
- Proc.Requires.Add(new Requires(false, Expr.Gt(new IdentifierExpr(tok, GetNumGroups(dimension)), Zero(tok))));
- Proc.Requires.Add(new Requires(false, Expr.Ge(new IdentifierExpr(tok, GetGroupId(dimension)), Zero(tok))));
- Proc.Requires.Add(new Requires(false, Expr.Lt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)))));
- }
+ if (GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)))
+ {
+ Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GT", new IdentifierExpr(tok, GetGroupSize(dimension)), ZeroBV(tok))));
+ Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GT", new IdentifierExpr(tok, GetNumGroups(dimension)), ZeroBV(tok))));
+ Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, GetGroupId(dimension)), ZeroBV(tok))));
+ Proc.Requires.Add(new Requires(false, MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)))));
}
+ else
+ {
+ Proc.Requires.Add(new Requires(false, Expr.Gt(new IdentifierExpr(tok, GetGroupSize(dimension)), Zero(tok))));
+ Proc.Requires.Add(new Requires(false, Expr.Gt(new IdentifierExpr(tok, GetNumGroups(dimension)), Zero(tok))));
+ Proc.Requires.Add(new Requires(false, Expr.Ge(new IdentifierExpr(tok, GetGroupId(dimension)), Zero(tok))));
+ Proc.Requires.Add(new Requires(false, Expr.Lt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)))));
+ }
+ }
- Expr AssumeThreadsDistinctInDimension =
- Expr.Neq(
- new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)),
- new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2))
- );
+ Expr AssumeThreadsDistinctInDimension =
+ Expr.Neq(
+ new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)),
+ new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2))
+ );
- AssumeDistinctThreads = (null == AssumeDistinctThreads) ? AssumeThreadsDistinctInDimension : Expr.Or(AssumeDistinctThreads, AssumeThreadsDistinctInDimension);
+ AssumeDistinctThreads = (null == AssumeDistinctThreads) ? AssumeThreadsDistinctInDimension : Expr.Or(AssumeDistinctThreads, AssumeThreadsDistinctInDimension);
- Expr AssumeThreadIdsInRangeInDimension =
- GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
+ Expr AssumeThreadIdsInRangeInDimension =
+ GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
+ Expr.And(
Expr.And(
- Expr.And(
- MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), ZeroBV(tok)),
- MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), ZeroBV(tok))
- ),
- Expr.And(
- MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), new IdentifierExpr(tok, GetGroupSize(dimension))),
- MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), new IdentifierExpr(tok, GetGroupSize(dimension)))
- ))
- :
+ MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), ZeroBV(tok)),
+ MakeBitVectorBinaryBoolean("BV32_GEQ", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), ZeroBV(tok))
+ ),
Expr.And(
- Expr.And(
- Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), Zero(tok)),
- Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), Zero(tok))
- ),
- Expr.And(
- Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), new IdentifierExpr(tok, GetGroupSize(dimension))),
- Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), new IdentifierExpr(tok, GetGroupSize(dimension)))
- ));
+ MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), new IdentifierExpr(tok, GetGroupSize(dimension))),
+ MakeBitVectorBinaryBoolean("BV32_LT", new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), new IdentifierExpr(tok, GetGroupSize(dimension)))
+ ))
+ :
+ Expr.And(
+ Expr.And(
+ Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), Zero(tok)),
+ Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), Zero(tok))
+ ),
+ Expr.And(
+ Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 1)), new IdentifierExpr(tok, GetGroupSize(dimension))),
+ Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension, 2)), new IdentifierExpr(tok, GetGroupSize(dimension)))
+ ));
- AssumeThreadIdsInRange = (null == AssumeThreadIdsInRange) ? AssumeThreadIdsInRangeInDimension : Expr.And(AssumeThreadIdsInRange, AssumeThreadIdsInRangeInDimension);
- }
+ AssumeThreadIdsInRange = (null == AssumeThreadIdsInRange) ? AssumeThreadIdsInRangeInDimension : Expr.And(AssumeThreadIdsInRange, AssumeThreadIdsInRangeInDimension);
}
private Expr MakeBitVectorBinaryBoolean(string functionName, Expr lhs, Expr rhs)
@@ -1888,6 +2071,9 @@ namespace GPUVerify
bool HalfDualise = HalfDualisedProcedureNames.Contains(proc.Name);
+ proc.Requires = DualiseRequires(proc.Requires);
+ proc.Ensures = DualiseEnsures(proc.Ensures);
+
proc.InParams = DualiseVariableSequence(proc.InParams, HalfDualise);
proc.OutParams = DualiseVariableSequence(proc.OutParams, HalfDualise);
IdentifierExprSeq NewModifies = new IdentifierExprSeq();
@@ -1952,6 +2138,42 @@ namespace GPUVerify
}
+ private EnsuresSeq DualiseEnsures(EnsuresSeq ensuresSeq)
+ {
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq)
+ {
+ newEnsures.Add(new Ensures(e.Free, new VariableDualiser(1).VisitExpr(e.Condition.Clone() as Expr)));
+ if (!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(e.Condition))
+ {
+ newEnsures.Add(new Ensures(e.Free, new VariableDualiser(2).VisitExpr(e.Condition.Clone() as Expr)));
+ }
+ }
+ return newEnsures;
+ }
+
+ private RequiresSeq DualiseRequires(RequiresSeq requiresSeq)
+ {
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in requiresSeq)
+ {
+ newRequires.Add(new Requires(r.Free, new VariableDualiser(1).VisitExpr(r.Condition.Clone() as Expr)));
+
+ if (!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(r.Condition))
+ {
+ newRequires.Add(new Requires(r.Free, new VariableDualiser(2).VisitExpr(r.Condition.Clone() as Expr)));
+ }
+ }
+ return newRequires;
+ }
+
+ private bool ContainsAsymmetricExpression(Expr expr)
+ {
+ AsymmetricExpressionFinder finder = new AsymmetricExpressionFinder();
+ finder.VisitExpr(expr);
+ return finder.foundAsymmetricExpr();
+ }
+
private static VariableSeq DualiseVariableSequence(VariableSeq seq, bool HalfDualise)
{
VariableSeq result = new VariableSeq();
@@ -1981,12 +2203,29 @@ namespace GPUVerify
// Add predicate to start of parameter list
Procedure proc = d as Procedure;
VariableSeq NewIns = new VariableSeq();
- NewIns.Add(new LocalVariable(proc.tok, new TypedIdent(proc.tok, "_P", Microsoft.Boogie.Type.Bool)));
+ TypedIdent enabled = new TypedIdent(proc.tok, "_P", Microsoft.Boogie.Type.Bool);
+ NewIns.Add(new LocalVariable(proc.tok, enabled));
foreach (Variable v in proc.InParams)
{
NewIns.Add(v);
}
proc.InParams = NewIns;
+
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in proc.Requires)
+ {
+ newRequires.Add(new Requires(r.Free, Predicator.ProcessEnabledIntrinsics(r.Condition, enabled)));
+ }
+ proc.Requires = newRequires;
+
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in proc.Ensures)
+ {
+ newEnsures.Add(new Ensures(e.Free, Predicator.ProcessEnabledIntrinsics(e.Condition, enabled)));
+ }
+ proc.Ensures = newEnsures;
+
+
}
}
@@ -2109,7 +2348,7 @@ namespace GPUVerify
else if (c is AssertCmd)
{
AssertCmd ass = c as AssertCmd;
- if (HalfDualise)
+ if (HalfDualise || ContainsAsymmetricExpression(ass.Expr))
{
result.simpleCmds.Add(new AssertCmd(c.tok, new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr)));
}
@@ -2121,7 +2360,7 @@ namespace GPUVerify
else if (c is AssumeCmd)
{
AssumeCmd ass = c as AssumeCmd;
- if (HalfDualise)
+ if (HalfDualise || ContainsAsymmetricExpression(ass.Expr))
{
result.simpleCmds.Add(new AssumeCmd(c.tok, new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr)));
}
@@ -2138,7 +2377,11 @@ namespace GPUVerify
if (bb.ec is WhileCmd)
{
- result.ec = new WhileCmd(bb.ec.tok, Expr.Or(new VariableDualiser(1).VisitExpr((bb.ec as WhileCmd).Guard), new VariableDualiser(2).VisitExpr((bb.ec as WhileCmd).Guard)), (bb.ec as WhileCmd).Invariants, MakeDual((bb.ec as WhileCmd).Body, HalfDualise));
+ result.ec = new WhileCmd(bb.ec.tok,
+ Expr.Or(new VariableDualiser(1).VisitExpr((bb.ec as WhileCmd).Guard),
+ new VariableDualiser(2).VisitExpr((bb.ec as WhileCmd).Guard)
+ ),
+ MakeDualInvariants((bb.ec as WhileCmd).Invariants), MakeDual((bb.ec as WhileCmd).Body, HalfDualise));
}
else
{
@@ -2149,6 +2392,21 @@ namespace GPUVerify
}
+ private List<PredicateCmd> MakeDualInvariants(List<PredicateCmd> originalInvariants)
+ {
+ List<PredicateCmd> result = new List<PredicateCmd>();
+ foreach(PredicateCmd p in originalInvariants)
+ {
+ result.Add(new AssertCmd(p.tok, new VariableDualiser(1).VisitExpr(p.Expr.Clone() as Expr)));
+ if (!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(p.Expr))
+ {
+ result.Add(new AssertCmd(p.tok, new VariableDualiser(2).VisitExpr(p.Expr.Clone() as Expr)));
+ }
+ }
+
+ return result;
+ }
+
private void MakeDualLocalVariables(Implementation impl, bool HalfDualise)
{
VariableSeq NewLocalVars = new VariableSeq();
@@ -2204,101 +2462,90 @@ namespace GPUVerify
if (!KernelHasIdX())
{
- MissingKernelAttributeError("Kernel", LOCAL_ID_X_STRING);
+ MissingKernelAttributeError(LOCAL_ID_X_STRING);
}
if (!KernelHasGroupSizeX())
{
- MissingKernelAttributeError("Kernel", GROUP_SIZE_X_STRING);
+ MissingKernelAttributeError(GROUP_SIZE_X_STRING);
}
if (!KernelHasNumGroupsX())
{
- MissingKernelAttributeError("Kernel", NUM_GROUPS_X_STRING);
+ MissingKernelAttributeError(NUM_GROUPS_X_STRING);
}
if (!KernelHasGroupIdX())
{
- MissingKernelAttributeError("Kernel", GROUP_ID_X_STRING);
+ MissingKernelAttributeError(GROUP_ID_X_STRING);
}
- if (KernelHasIdY() || KernelHasGroupSizeY() || KernelHasNumGroupsY() || KernelHasGroupIdY())
+ if (!KernelHasIdY())
{
-
- if (!KernelHasIdY())
- {
- MissingKernelAttributeError("2D kernel", LOCAL_ID_Y_STRING);
- }
-
- if (!KernelHasGroupSizeY())
- {
- MissingKernelAttributeError("2D kernel", GROUP_SIZE_Y_STRING);
- }
-
- if (!KernelHasNumGroupsY())
- {
- MissingKernelAttributeError("2D kernel", NUM_GROUPS_Y_STRING);
- }
-
- if (!KernelHasGroupIdY())
- {
- MissingKernelAttributeError("2D kernel", GROUP_ID_Y_STRING);
- }
-
+ MissingKernelAttributeError(LOCAL_ID_Y_STRING);
}
- if (KernelHasIdZ() || KernelHasGroupSizeZ() || KernelHasNumGroupsZ() || KernelHasGroupIdZ())
+ if (!KernelHasGroupSizeY())
{
+ MissingKernelAttributeError(GROUP_SIZE_Y_STRING);
+ }
- if (!KernelHasIdY())
- {
- MissingKernelAttributeError("3D kernel", LOCAL_ID_Y_STRING);
- }
+ if (!KernelHasNumGroupsY())
+ {
+ MissingKernelAttributeError(NUM_GROUPS_Y_STRING);
+ }
- if (!KernelHasGroupSizeY())
- {
- MissingKernelAttributeError("3D kernel", GROUP_SIZE_Y_STRING);
- }
+ if (!KernelHasGroupIdY())
+ {
+ MissingKernelAttributeError(GROUP_ID_Y_STRING);
+ }
- if (!KernelHasNumGroupsY())
- {
- MissingKernelAttributeError("3D kernel", NUM_GROUPS_Y_STRING);
- }
+ if (!KernelHasIdY())
+ {
+ MissingKernelAttributeError(LOCAL_ID_Y_STRING);
+ }
- if (!KernelHasGroupIdY())
- {
- MissingKernelAttributeError("3D kernel", GROUP_ID_Y_STRING);
- }
+ if (!KernelHasGroupSizeY())
+ {
+ MissingKernelAttributeError(GROUP_SIZE_Y_STRING);
+ }
- if (!KernelHasIdZ())
- {
- MissingKernelAttributeError("3D kernel", LOCAL_ID_Z_STRING);
- }
+ if (!KernelHasNumGroupsY())
+ {
+ MissingKernelAttributeError(NUM_GROUPS_Y_STRING);
+ }
- if (!KernelHasGroupSizeZ())
- {
- MissingKernelAttributeError("3D kernel", GROUP_SIZE_Z_STRING);
- }
+ if (!KernelHasGroupIdY())
+ {
+ MissingKernelAttributeError(GROUP_ID_Y_STRING);
+ }
- if (!KernelHasNumGroupsZ())
- {
- MissingKernelAttributeError("3D kernel", NUM_GROUPS_Z_STRING);
- }
+ if (!KernelHasIdZ())
+ {
+ MissingKernelAttributeError(LOCAL_ID_Z_STRING);
+ }
- if (!KernelHasGroupIdZ())
- {
- MissingKernelAttributeError("3D kernel", GROUP_ID_Z_STRING);
- }
+ if (!KernelHasGroupSizeZ())
+ {
+ MissingKernelAttributeError(GROUP_SIZE_Z_STRING);
+ }
+ if (!KernelHasNumGroupsZ())
+ {
+ MissingKernelAttributeError(NUM_GROUPS_Z_STRING);
+ }
+ if (!KernelHasGroupIdZ())
+ {
+ MissingKernelAttributeError(GROUP_ID_Z_STRING);
}
return ErrorCount;
}
- private void MissingKernelAttributeError(string kindOfKernel, string attribute)
+ private void MissingKernelAttributeError(string attribute)
{
- Error(KernelProcedure.tok, kindOfKernel + " must declare global constant marked with attribute ':" + attribute + "'");
+ Error(KernelProcedure.tok, "Kernel must declare global constant marked with attribute ':" + attribute + "'");
}
public static bool IsThreadLocalIdConstant(Variable variable)
diff --git a/Source/GPUVerify/GPUVerify.csproj b/Source/GPUVerify/GPUVerify.csproj
index 6956b973..66be025a 100644
--- a/Source/GPUVerify/GPUVerify.csproj
+++ b/Source/GPUVerify/GPUVerify.csproj
@@ -104,7 +104,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AccessCollector.cs" />
+ <Compile Include="AccessInvariantProcessor.cs" />
<Compile Include="AccessRecord.cs" />
+ <Compile Include="AsymmetricExpressionFinder.cs" />
+ <Compile Include="StructuredProgramVisitor.cs" />
+ <Compile Include="CrossThreadInvariantProcessor.cs" />
+ <Compile Include="EnabledToPredicateVisitor.cs" />
<Compile Include="CommandLineOptions.cs" />
<Compile Include="ElementEncodingraceInstrumenter.cs" />
<Compile Include="GPUVerifier.cs" />
diff --git a/Source/GPUVerify/IRaceInstrumenter.cs b/Source/GPUVerify/IRaceInstrumenter.cs
index 9a1c0d8c..2c9d2410 100644
--- a/Source/GPUVerify/IRaceInstrumenter.cs
+++ b/Source/GPUVerify/IRaceInstrumenter.cs
@@ -20,10 +20,14 @@ namespace GPUVerify
BigBlock MakeRaceCheckingStatements(IToken tok);
- void CheckForRaces(IToken tok, BigBlock bb, Variable v, bool ReadWriteOnly);
+ void CheckForRaces(BigBlock bb, Variable v, bool ReadWriteOnly);
void AddRaceCheckingCandidateRequires(Procedure Proc);
void AddRaceCheckingCandidateEnsures(Procedure Proc);
+
+ void AddNoRaceContract(Procedure Proc);
+
+ void AddNoRaceInvariants(Implementation Impl);
}
}
diff --git a/Source/GPUVerify/NullRaceInstrumenter.cs b/Source/GPUVerify/NullRaceInstrumenter.cs
index a825a2eb..3a8f8356 100644
--- a/Source/GPUVerify/NullRaceInstrumenter.cs
+++ b/Source/GPUVerify/NullRaceInstrumenter.cs
@@ -19,7 +19,7 @@ namespace GPUVerify
}
- public void CheckForRaces(IToken tok, BigBlock bb, Variable v, bool ReadWriteOnly)
+ public void CheckForRaces(BigBlock bb, Variable v, bool ReadWriteOnly)
{
}
@@ -42,6 +42,17 @@ namespace GPUVerify
{
}
-
+
+
+ public void AddNoRaceContract(Procedure proc)
+ {
+
+ }
+
+ public void AddNoRaceInvariants(Implementation impl)
+ {
+
+ }
+
}
}
diff --git a/Source/GPUVerify/Predicator.cs b/Source/GPUVerify/Predicator.cs
index e2af8185..a2059b56 100644
--- a/Source/GPUVerify/Predicator.cs
+++ b/Source/GPUVerify/Predicator.cs
@@ -7,19 +7,24 @@ using Microsoft.Boogie;
namespace GPUVerify
{
- class Predicator
+ class Predicator : StructuredProgramVisitor
{
private bool AddPredicateParameter;
private int WhileLoopCounter;
private int IfCounter;
private static HashSet<Microsoft.Boogie.Type> RequiredHavocVariables;
+ private Stack<Expr> predicate;
+ private Stack<IdentifierExpr> enclosingLoopPredicate;
+
internal Predicator(bool AddPredicateParameter)
{
this.AddPredicateParameter = AddPredicateParameter;
WhileLoopCounter = 0;
IfCounter = 0;
RequiredHavocVariables = new HashSet<Microsoft.Boogie.Type>();
+ predicate = new Stack<Expr>();
+ enclosingLoopPredicate = new Stack<IdentifierExpr>();
}
internal void transform(Implementation impl)
@@ -43,205 +48,238 @@ namespace GPUVerify
Predicate = Expr.True;
}
- impl.StructuredStmts = MakePredicated(impl.StructuredStmts, Predicate, null);
+ predicate.Push(Predicate);
+ enclosingLoopPredicate.Push(null);
+
+ impl.StructuredStmts = VisitStmtList(impl.StructuredStmts);
+
AddPredicateLocalVariables(impl);
}
+ public override CmdSeq VisitCmd(Cmd c)
+ {
+ if (c is CallCmd || !predicate.Peek().Equals(Expr.True))
+ {
+ return base.VisitCmd(c);
+ }
+
+ return new CmdSeq(new Cmd[] { c });
- private StmtList MakePredicated(StmtList sl, Expr predicate, IdentifierExpr EnclosingLoopPredicate)
+ }
+
+ public override CmdSeq VisitCallCmd(CallCmd Call)
{
- StmtList result = new StmtList(new List<BigBlock>(), sl.EndCurly);
+ List<Expr> NewIns = new List<Expr>();
+ NewIns.Add(predicate.Peek());
- foreach (BigBlock bodyBlock in sl.BigBlocks)
+ foreach (Expr e in Call.Ins)
{
- List<BigBlock> newBigBlocks = MakePredicated(bodyBlock, predicate, EnclosingLoopPredicate);
- foreach (BigBlock newBigBlock in newBigBlocks)
- {
- result.BigBlocks.Add(newBigBlock);
- }
+ NewIns.Add(e);
}
- return result;
+ return new CmdSeq(
+ new Cmd[] { new CallCmd(Call.tok, Call.callee, NewIns, Call.Outs) });
}
- private List<BigBlock> MakePredicated(BigBlock b, Expr IncomingPredicate, IdentifierExpr EnclosingLoopPredicate)
+ public override CmdSeq VisitAssignCmd(AssignCmd assign)
{
- // Not sure what to do about the transfer command
+ Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
- List<BigBlock> result = new List<BigBlock>();
+ ExprSeq iteArgs = new ExprSeq();
+ iteArgs.Add(predicate.Peek());
+ iteArgs.Add(assign.Rhss.ElementAt(0));
+ iteArgs.Add(assign.Lhss.ElementAt(0).AsExpr);
+ NAryExpr ite = new NAryExpr(assign.tok, new IfThenElse(assign.tok), iteArgs);
- BigBlock firstBigBlock = new BigBlock(b.tok, b.LabelName, new CmdSeq(), null, b.tc);
- result.Add(firstBigBlock);
+ List<Expr> newRhs = new List<Expr>();
+ newRhs.Add(ite);
- foreach (Cmd c in b.simpleCmds)
- {
- if (c is CallCmd)
- {
+ return new CmdSeq(new Cmd[] { new AssignCmd(assign.tok, assign.Lhss, newRhs) });
- CallCmd Call = c as CallCmd;
+ }
- List<Expr> NewIns = new List<Expr>();
- NewIns.Add(IncomingPredicate);
+ public override CmdSeq VisitHavocCmd(HavocCmd havoc)
+ {
+ CmdSeq result = new CmdSeq();
- foreach (Expr e in Call.Ins)
- {
- NewIns.Add(e);
- }
+ Debug.Assert(havoc.Vars.Length == 1);
- CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, NewIns, Call.Outs);
+ Microsoft.Boogie.Type type = havoc.Vars[0].Decl.TypedIdent.Type;
+ Debug.Assert(type != null);
- firstBigBlock.simpleCmds.Add(NewCallCmd);
- }
- else if (IncomingPredicate.Equals(Expr.True))
- {
- firstBigBlock.simpleCmds.Add(c);
- }
- else if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
- Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
+ RequiredHavocVariables.Add(type);
- ExprSeq iteArgs = new ExprSeq();
- iteArgs.Add(IncomingPredicate);
- iteArgs.Add(assign.Rhss.ElementAt(0));
- iteArgs.Add(assign.Lhss.ElementAt(0).AsExpr);
- NAryExpr ite = new NAryExpr(assign.tok, new IfThenElse(assign.tok), iteArgs);
+ IdentifierExpr HavocTempExpr = new IdentifierExpr(havoc.tok, new LocalVariable(havoc.tok, new TypedIdent(havoc.tok, "_HAVOC_" + type.ToString(), type)));
+ result.Add(new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
+ HavocTempExpr
+ })));
- List<Expr> newRhs = new List<Expr>();
- newRhs.Add(ite);
+ List<AssignLhs> lhss = new List<AssignLhs>();
+ lhss.Add(new SimpleAssignLhs(havoc.tok, havoc.Vars[0]));
- AssignCmd newAssign = new AssignCmd(assign.tok, assign.Lhss, newRhs);
+ List<Expr> rhss = new List<Expr>();
+ rhss.Add(new NAryExpr(havoc.tok, new IfThenElse(havoc.tok), new ExprSeq(
+ new Expr[] { predicate.Peek(), HavocTempExpr, havoc.Vars[0] })));
- firstBigBlock.simpleCmds.Add(newAssign);
- }
- else if (c is HavocCmd)
- {
- HavocCmd havoc = c as HavocCmd;
- Debug.Assert(havoc.Vars.Length == 1);
+ result.Add(new AssignCmd(havoc.tok, lhss, rhss));
- Microsoft.Boogie.Type type = havoc.Vars[0].Decl.TypedIdent.Type;
- Debug.Assert(type != null);
+ return result;
- RequiredHavocVariables.Add(type);
+ }
- IdentifierExpr HavocTempExpr = new IdentifierExpr(havoc.tok, new LocalVariable(havoc.tok, new TypedIdent(havoc.tok, "_HAVOC_" + type.ToString(), type)));
- firstBigBlock.simpleCmds.Add(new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
- HavocTempExpr
- })));
+ public override CmdSeq VisitAssertCmd(AssertCmd assert)
+ {
+ return new CmdSeq(new Cmd[] {
+ new AssertCmd(assert.tok, Expr.Imp(predicate.Peek(), assert.Expr))
+ });
+ }
- List<AssignLhs> lhss = new List<AssignLhs>();
- lhss.Add(new SimpleAssignLhs(havoc.tok, havoc.Vars[0]));
+ public override CmdSeq VisitAssumeCmd(AssumeCmd assume)
+ {
+ return new CmdSeq(new Cmd[] {
+ new AssumeCmd(assume.tok, Expr.Imp(predicate.Peek(), assume.Expr))
+ });
+ }
- List<Expr> rhss = new List<Expr>();
- rhss.Add(new NAryExpr(havoc.tok, new IfThenElse(havoc.tok), new ExprSeq(new Expr[] { IncomingPredicate, HavocTempExpr, havoc.Vars[0] })));
+ public override List<BigBlock> VisitBigBlock(BigBlock bb)
+ {
+ BigBlock firstBigBlock = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
- firstBigBlock.simpleCmds.Add(new AssignCmd(havoc.tok, lhss, rhss));
+ List<BigBlock> result = new List<BigBlock>();
+ result.Add(firstBigBlock);
- }
- else if (c is AssertCmd)
- {
- firstBigBlock.simpleCmds.Add(new AssertCmd(c.tok, Expr.Imp(IncomingPredicate, (c as AssertCmd).Expr)));
- }
- else if (c is AssumeCmd)
- {
- firstBigBlock.simpleCmds.Add(new AssumeCmd(c.tok, Expr.Imp(IncomingPredicate, (c as AssumeCmd).Expr)));
- }
- else
- {
- Debug.Assert(false);
- }
- }
+ firstBigBlock.simpleCmds = VisitCmdSeq(bb.simpleCmds);
- if (b.ec is WhileCmd)
+ if (bb.ec is WhileCmd)
{
+ WhileCmd whileCmd = bb.ec as WhileCmd;
+
string LoopPredicate = "_LC" + WhileLoopCounter;
WhileLoopCounter++;
- IdentifierExpr PredicateExpr = new IdentifierExpr(b.ec.tok, new LocalVariable(b.ec.tok, new TypedIdent(b.ec.tok, LoopPredicate, Microsoft.Boogie.Type.Bool)));
- Expr GuardExpr = (b.ec as WhileCmd).Guard;
+ TypedIdent LoopPredicateTypedIdent = new TypedIdent(whileCmd.tok, LoopPredicate, Microsoft.Boogie.Type.Bool);
+
+ IdentifierExpr PredicateExpr = new IdentifierExpr(whileCmd.tok, new LocalVariable(whileCmd.tok, LoopPredicateTypedIdent));
+ Expr GuardExpr = whileCmd.Guard;
List<AssignLhs> WhilePredicateLhss = new List<AssignLhs>();
- WhilePredicateLhss.Add(new SimpleAssignLhs(b.ec.tok, PredicateExpr));
+ WhilePredicateLhss.Add(new SimpleAssignLhs(whileCmd.tok, PredicateExpr));
List<Expr> WhilePredicateRhss = new List<Expr>();
- WhilePredicateRhss.Add(IncomingPredicate.Equals(Expr.True) ? GuardExpr : Expr.And(IncomingPredicate, GuardExpr));
+ WhilePredicateRhss.Add(predicate.Peek().Equals(Expr.True) ? GuardExpr : Expr.And(predicate.Peek(), GuardExpr));
- firstBigBlock.simpleCmds.Add(new AssignCmd(b.ec.tok, WhilePredicateLhss, WhilePredicateRhss));
+ firstBigBlock.simpleCmds.Add(new AssignCmd(whileCmd.tok, WhilePredicateLhss, WhilePredicateRhss));
- WhileCmd NewWhile = new WhileCmd(b.ec.tok, PredicateExpr, (b.ec as WhileCmd).Invariants, MakePredicated((b.ec as WhileCmd).Body, PredicateExpr, PredicateExpr));
+ predicate.Push(PredicateExpr);
+ enclosingLoopPredicate.Push(PredicateExpr);
+ WhileCmd NewWhile = new WhileCmd(whileCmd.tok, PredicateExpr,
+ VisitWhileInvariants(whileCmd.Invariants),
+ VisitStmtList(whileCmd.Body));
+ enclosingLoopPredicate.Pop();
+ predicate.Pop();
List<Expr> UpdatePredicateRhss = new List<Expr>();
UpdatePredicateRhss.Add(Expr.And(PredicateExpr, GuardExpr));
CmdSeq updateCmd = new CmdSeq();
- updateCmd.Add(new AssignCmd(b.ec.tok, WhilePredicateLhss, UpdatePredicateRhss));
+ updateCmd.Add(new AssignCmd(whileCmd.tok, WhilePredicateLhss, UpdatePredicateRhss));
- NewWhile.Body.BigBlocks.Add(new BigBlock(b.ec.tok, "update_" + LoopPredicate, updateCmd, null, null));
+ NewWhile.Body.BigBlocks.Add(new BigBlock(whileCmd.tok, "update_" + LoopPredicate, updateCmd, null, null));
firstBigBlock.ec = NewWhile;
}
- else if (b.ec is IfCmd)
+ else if (bb.ec is IfCmd)
{
- IfCmd IfCommand = b.ec as IfCmd;
+ IfCmd IfCommand = bb.ec as IfCmd;
string IfPredicate = "_P" + IfCounter;
IfCounter++;
- IdentifierExpr PredicateExpr = new IdentifierExpr(b.ec.tok, new LocalVariable(b.ec.tok, new TypedIdent(b.ec.tok, IfPredicate, Microsoft.Boogie.Type.Bool)));
+ IdentifierExpr PredicateExpr = new IdentifierExpr(IfCommand.tok,
+ new LocalVariable(IfCommand.tok, new TypedIdent(IfCommand.tok, IfPredicate, Microsoft.Boogie.Type.Bool)));
Expr GuardExpr = IfCommand.Guard;
List<AssignLhs> IfPredicateLhss = new List<AssignLhs>();
- IfPredicateLhss.Add(new SimpleAssignLhs(b.ec.tok, PredicateExpr));
+ IfPredicateLhss.Add(new SimpleAssignLhs(IfCommand.tok, PredicateExpr));
List<Expr> IfPredicateRhss = new List<Expr>();
IfPredicateRhss.Add(GuardExpr);
- firstBigBlock.simpleCmds.Add(new AssignCmd(b.ec.tok, IfPredicateLhss, IfPredicateRhss));
+ firstBigBlock.simpleCmds.Add(new AssignCmd(IfCommand.tok, IfPredicateLhss, IfPredicateRhss));
Debug.Assert(IfCommand.elseIf == null); // We need to preprocess these away
- StmtList PredicatedThen = MakePredicated(IfCommand.thn, Expr.And(IncomingPredicate, PredicateExpr), EnclosingLoopPredicate);
+ predicate.Push(Expr.And(predicate.Peek(), PredicateExpr));
+ StmtList PredicatedThen = VisitStmtList(IfCommand.thn);
+ predicate.Pop();
+ result.AddRange(PredicatedThen.BigBlocks);
- foreach (BigBlock bb in PredicatedThen.BigBlocks)
+ if(IfCommand.elseIf != null)
{
- result.Add(bb);
+ throw new InvalidOperationException();
}
if (IfCommand.elseBlock != null)
{
- StmtList PredicatedElse = MakePredicated(IfCommand.elseBlock, Expr.And(IncomingPredicate, Expr.Not(PredicateExpr)), EnclosingLoopPredicate);
-
- foreach (BigBlock bb in PredicatedElse.BigBlocks)
- {
- result.Add(bb);
- }
+ predicate.Push(Expr.And(predicate.Peek(), Expr.Not(PredicateExpr)));
+ StmtList PredicatedElse = VisitStmtList(IfCommand.elseBlock);
+ predicate.Pop();
+ result.AddRange(PredicatedElse.BigBlocks);
}
+ }
+ else if (bb.ec is BreakCmd)
+ {
+ firstBigBlock.simpleCmds.Add(new AssignCmd(bb.tok,
+ new List<AssignLhs>(new AssignLhs[] { new SimpleAssignLhs(bb.tok, enclosingLoopPredicate.Peek()) }),
+ new List<Expr>(new Expr[] { new NAryExpr(bb.tok, new IfThenElse(bb.tok), new ExprSeq(
+ new Expr[] { predicate.Peek(), Expr.False, enclosingLoopPredicate.Peek() })) })
+ ));
+ firstBigBlock.ec = null;
+ }
+ else if (bb.ec != null)
+ {
+ throw new InvalidOperationException();
+ }
+ return result;
+ }
- }
- else if (b.ec is BreakCmd)
- {
+ public override IfCmd VisitIfCmd(IfCmd ifCmd)
+ {
+ throw new InvalidOperationException();
+ }
+ public override WhileCmd VisitWhileCmd(WhileCmd whileCmd)
+ {
+ throw new InvalidOperationException();
+ }
- firstBigBlock.simpleCmds.Add(new AssignCmd(b.tok,
- new List<AssignLhs>(new AssignLhs[] { new SimpleAssignLhs(b.tok, EnclosingLoopPredicate) }),
- new List<Expr>(new Expr[] { new NAryExpr(b.tok, new IfThenElse(b.tok), new ExprSeq(new Expr[] { IncomingPredicate, Expr.False, EnclosingLoopPredicate })) })
- ));
- firstBigBlock.ec = null;
+ public override BreakCmd VisitBreakCmd(BreakCmd breakCmd)
+ {
+ throw new InvalidOperationException();
+ }
- }
- else
+ public override List<PredicateCmd> VisitWhileInvariants(List<PredicateCmd> invariants)
+ {
+ List<PredicateCmd> result = new List<PredicateCmd>();
+
+ foreach (PredicateCmd cmd in invariants)
{
- Debug.Assert(b.ec == null);
+ result.Add(new AssertCmd(cmd.tok, ProcessEnabledIntrinsics(cmd.Expr, enclosingLoopPredicate.Peek().Decl.TypedIdent)));
}
return result;
}
+ internal static Expr ProcessEnabledIntrinsics(Expr expr, TypedIdent currentPredicate)
+ {
+ return new EnabledToPredicateVisitor(currentPredicate).VisitExpr(expr);
+ }
+
private void AddPredicateLocalVariables(Implementation impl)
{
diff --git a/Source/GPUVerify/RaceInstrumenterBase.cs b/Source/GPUVerify/RaceInstrumenterBase.cs
index 692f1288..5909ec07 100644
--- a/Source/GPUVerify/RaceInstrumenterBase.cs
+++ b/Source/GPUVerify/RaceInstrumenterBase.cs
@@ -353,7 +353,7 @@ namespace GPUVerify
{
foreach (Variable v in NonLocalStateToCheck.getAllNonLocalVariables())
{
- CheckForRaces(tok, checkForRaces, v, false);
+ CheckForRaces(checkForRaces, v, false);
}
}
@@ -372,7 +372,7 @@ namespace GPUVerify
protected abstract void SetNoAccessOccurred(IToken tok, BigBlock bb, Variable v, string AccessType);
- public abstract void CheckForRaces(IToken tok, BigBlock bb, Variable v, bool ReadWriteOnly);
+ public abstract void CheckForRaces(BigBlock bb, Variable v, bool ReadWriteOnly);
protected void MakeLogAccessProcedureHeader(Variable v, string ReadOrWrite, out Variable XParameterVariable, out Variable YParameterVariable, out Variable ZParameterVariable, out Procedure LogReadOrWriteProcedure)
{
@@ -462,6 +462,74 @@ namespace GPUVerify
protected abstract Expr NoReadOrWriteExpr(Variable v, string ReadOrWrite, string OneOrTwo);
+ public void AddNoRaceContract(Procedure proc)
+ {
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalVariables())
+ {
+ proc.Requires.Add(new Requires(false, Expr.Not(GenerateRaceCondition(v, "WRITE", "WRITE"))));
+ proc.Requires.Add(new Requires(false, Expr.Not(GenerateRaceCondition(v, "READ", "WRITE"))));
+ if (!CommandLineOptions.Symmetry)
+ {
+ proc.Requires.Add(new Requires(false, Expr.Not(GenerateRaceCondition(v, "WRITE", "READ"))));
+ }
+
+ proc.Ensures.Add(new Ensures(false, Expr.Not(GenerateRaceCondition(v, "WRITE", "WRITE"))));
+ proc.Ensures.Add(new Ensures(false, Expr.Not(GenerateRaceCondition(v, "READ", "WRITE"))));
+ if (!CommandLineOptions.Symmetry)
+ {
+ proc.Ensures.Add(new Ensures(false, Expr.Not(GenerateRaceCondition(v, "WRITE", "READ"))));
+ }
+
+ }
+ }
+
+ public void AddNoRaceInvariants(Implementation impl)
+ {
+ AddNoRaceInvariants(impl.StructuredStmts);
+ }
+
+ private void AddNoRaceInvariants(StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ AddNoRaceInvariants(bb);
+ }
+ }
+
+ private void AddNoRaceInvariants(BigBlock bb)
+ {
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalVariables())
+ {
+ wc.Invariants.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "WRITE", "WRITE"))));
+ wc.Invariants.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "READ", "WRITE"))));
+ if (!CommandLineOptions.Symmetry)
+ {
+ wc.Invariants.Add(new AssertCmd(v.tok, Expr.Not(GenerateRaceCondition(v, "WRITE", "READ"))));
+ }
+ }
+
+ AddNoRaceInvariants(wc.Body);
+
+ }
+ else if (bb.ec is IfCmd)
+ {
+ AddNoRaceInvariants((bb.ec as IfCmd).thn);
+ if ((bb.ec as IfCmd).elseBlock != null)
+ {
+ AddNoRaceInvariants((bb.ec as IfCmd).elseBlock);
+ }
+ }
+ else
+ {
+ Debug.Assert(bb.ec == null);
+ }
+ }
+
+
+ protected abstract Expr GenerateRaceCondition(Variable v, string FirstAccessType, string SecondAccessType);
}
}
diff --git a/Source/GPUVerify/SetEncodingRaceInstrumenter.cs b/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
index e7e5854e..d9f674da 100644
--- a/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
+++ b/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
@@ -206,7 +206,7 @@ namespace GPUVerify
}
- public override void CheckForRaces(IToken tok, BigBlock bb, Variable v, bool ReadWriteOnly)
+ public override void CheckForRaces(BigBlock bb, Variable v, bool ReadWriteOnly)
{
if (!ReadWriteOnly)
{
@@ -257,14 +257,21 @@ namespace GPUVerify
return mt3.Arguments[0];
}
- private static void AddRaceCheck(BigBlock bb, Variable v, String Access1, String Access2)
+ private void AddRaceCheck(BigBlock bb, Variable v, String Access1, String Access2)
+ {
+ Expr AssertExpr = GenerateRaceCondition(v, Access1, Access2);
+
+ bb.simpleCmds.Add(new AssertCmd(v.tok, AssertExpr));
+ }
+
+ protected override Expr GenerateRaceCondition(Variable v, String Access1, String Access2)
{
VariableSeq DummyVars1;
Expr SetExpr1 = AccessExpr(v, Access1, 1, out DummyVars1);
VariableSeq DummyVars2;
Expr SetExpr2 = AccessExpr(v, Access2, 2, out DummyVars2);
-
+
Debug.Assert(DummyVars1.Length == DummyVars2.Length);
for (int i = 0; i < DummyVars1.Length; i++)
{
@@ -294,8 +301,7 @@ namespace GPUVerify
{
AssertExpr = new ForallExpr(v.tok, DummyVars1, AssertExpr);
}
-
- bb.simpleCmds.Add(new AssertCmd(v.tok, AssertExpr));
+ return AssertExpr;
}
private static void SetNameDeep(IdentifierExpr e, string name)
diff --git a/Source/GPUVerify/StructuredProgramVisitor.cs b/Source/GPUVerify/StructuredProgramVisitor.cs
new file mode 100644
index 00000000..4b2d1c47
--- /dev/null
+++ b/Source/GPUVerify/StructuredProgramVisitor.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class StructuredProgramVisitor
+ {
+
+ public virtual StmtList VisitStmtList(StmtList stmtList)
+ {
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ result.BigBlocks.AddRange(VisitBigBlock(bb));
+ }
+
+ return result;
+
+ }
+
+ public virtual List<BigBlock> VisitBigBlock(BigBlock bb)
+ {
+ BigBlock firstBigBlock = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
+
+ firstBigBlock.simpleCmds = VisitCmdSeq(bb.simpleCmds);
+
+ if (bb.ec is WhileCmd)
+ {
+ firstBigBlock.ec = VisitWhileCmd(bb.ec as WhileCmd);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ firstBigBlock.ec = VisitIfCmd(bb.ec as IfCmd);
+ }
+ else if (bb.ec is BreakCmd)
+ {
+ firstBigBlock.ec = VisitBreakCmd(bb.ec as BreakCmd);
+ }
+ else if (bb.ec != null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return new List<BigBlock>(new BigBlock[] { firstBigBlock });
+
+ }
+
+ public virtual IfCmd VisitIfCmd(IfCmd ifCmd)
+ {
+ if(ifCmd.elseIf != null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return new IfCmd(ifCmd.tok, VisitIfGuard(ifCmd.Guard), VisitStmtList(ifCmd.thn), ifCmd.elseIf,
+ (ifCmd.elseBlock == null ? ifCmd.elseBlock : VisitStmtList(ifCmd.elseBlock)));
+
+ throw new NotImplementedException();
+ }
+
+ public virtual Expr VisitIfGuard(Expr expr)
+ {
+ return expr;
+ }
+
+ public virtual WhileCmd VisitWhileCmd(WhileCmd whileCmd)
+ {
+ return new WhileCmd(whileCmd.tok, VisitWhileGuard(whileCmd.Guard), VisitWhileInvariants(whileCmd.Invariants), VisitStmtList(whileCmd.Body));
+ }
+
+ public virtual BreakCmd VisitBreakCmd(BreakCmd breakCmd)
+ {
+ return breakCmd;
+ }
+
+
+ public virtual List<PredicateCmd> VisitWhileInvariants(List<PredicateCmd> invariants)
+ {
+ return invariants;
+ }
+
+ public virtual Expr VisitWhileGuard(Expr expr)
+ {
+ return expr;
+ }
+
+ public virtual CmdSeq VisitCmdSeq(CmdSeq cmdSeq)
+ {
+ CmdSeq result = new CmdSeq();
+ foreach (Cmd c in cmdSeq)
+ {
+ result.AddRange(VisitCmd(c));
+ }
+ return result;
+ }
+
+ public virtual CmdSeq VisitCmd(Cmd c)
+ {
+ if (c is CallCmd)
+ {
+ return VisitCallCmd(c as CallCmd);
+ }
+ if (c is AssignCmd)
+ {
+ return VisitAssignCmd(c as AssignCmd);
+ }
+ if (c is HavocCmd)
+ {
+ return VisitHavocCmd(c as HavocCmd);
+ }
+ if (c is AssertCmd)
+ {
+ return VisitAssertCmd(c as AssertCmd);
+ }
+ if (c is AssumeCmd)
+ {
+ return VisitAssumeCmd(c as AssumeCmd);
+ }
+ throw new InvalidOperationException();
+ }
+
+ public virtual CmdSeq VisitAssumeCmd(AssumeCmd assumeCmd)
+ {
+ return new CmdSeq(new Cmd[] { assumeCmd });
+ }
+
+ public virtual CmdSeq VisitAssertCmd(AssertCmd assertCmd)
+ {
+ return new CmdSeq(new Cmd[] { assertCmd });
+ }
+
+ public virtual CmdSeq VisitHavocCmd(HavocCmd havocCmd)
+ {
+ return new CmdSeq(new Cmd[] { havocCmd });
+ }
+
+ public virtual CmdSeq VisitAssignCmd(AssignCmd assignCmd)
+ {
+ return new CmdSeq(new Cmd[] { assignCmd });
+ }
+
+ public virtual CmdSeq VisitCallCmd(CallCmd callCmd)
+ {
+ return new CmdSeq(new Cmd[] { callCmd });
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/VariableDualiser.cs b/Source/GPUVerify/VariableDualiser.cs
index 5cbfed99..add50f08 100644
--- a/Source/GPUVerify/VariableDualiser.cs
+++ b/Source/GPUVerify/VariableDualiser.cs
@@ -49,6 +49,29 @@ namespace GPUVerify
return base.VisitVariable(node);
}
+
+ public override Expr VisitNAryExpr(NAryExpr node)
+ {
+ // The point of this override is to avoid dualisation of certain special
+ // intrinsics that are cross-thread
+
+ if (node.Fun is FunctionCall)
+ {
+ FunctionCall call = node.Fun as FunctionCall;
+
+ if (call.Func.Name.Equals("__uniform_bv32") || call.Func.Name.Equals("__uniform_bool") ||
+ call.Func.Name.Equals("__distinct_bv32") || call.Func.Name.Equals("__distinct_bool") ||
+ call.Func.Name.Equals("__all") || call.Func.Name.Equals("__at_most_one"))
+ {
+ return node;
+ }
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+
}
}
diff --git a/Source/Houdini/Checker.cs b/Source/Houdini/Checker.cs
index c12c6d8b..f99c4651 100644
--- a/Source/Houdini/Checker.cs
+++ b/Source/Houdini/Checker.cs
@@ -22,8 +22,6 @@ namespace Microsoft.Boogie.Houdini {
private VCExpr conjecture;
private ProverInterface.ErrorHandler handler;
ConditionGeneration.CounterexampleCollector collector;
- LocalVariable controlFlowVariable;
- int entryBlockId;
public HoudiniSession(VCGen vcgen, Checker checker, Program program, Implementation impl) {
descriptiveName = impl.Name;
@@ -35,13 +33,16 @@ namespace Microsoft.Boogie.Houdini {
Hashtable/*TransferCmd->ReturnCmd*/ gotoCmdOrigins = vcgen.PassifyImpl(impl, program, out mvInfo);
Hashtable/*<int, Absy!>*/ label2absy;
+ var exprGen = checker.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ conjecture = vcgen.GenerateVC(impl, controlFlowVariableExpr, out label2absy, checker);
+
if (!CommandLineOptions.Clo.UseLabels) {
- controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
- impl.LocVars.Add(controlFlowVariable);
- entryBlockId = impl.Blocks[0].UniqueId;
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ conjecture = exprGen.Implies(eqExpr, conjecture);
}
-
- conjecture = vcgen.GenerateVC(impl, controlFlowVariable, out label2absy, checker);
if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local) {
handler = new VCGen.ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, vcgen.incarnationOriginMap, collector, mvInfo, vcgen.implName2LazyInliningInfo, checker.TheoremProver.Context, program);
@@ -55,36 +56,21 @@ namespace Microsoft.Boogie.Houdini {
collector.examples.Clear();
VCExpr vc = checker.VCExprGen.Implies(axiom, conjecture);
- if (!CommandLineOptions.Clo.UseLabels) {
- var ctx = checker.TheoremProver.Context;
- var bet = ctx.BoogieExprTranslator;
- VCExpr controlFlowVariableExpr = bet.LookupVariable(controlFlowVariable);
- VCExpr eqExpr1 = ctx.ExprGen.Eq(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr controlFlowFunctionAppl = ctx.ExprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr2 = ctx.ExprGen.Eq(controlFlowFunctionAppl, ctx.ExprGen.Integer(BigNum.FromInt(entryBlockId)));
- vc = ctx.ExprGen.Implies(eqExpr1, ctx.ExprGen.Implies(eqExpr2, vc));
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Verifying " + descriptiveName);
}
-
DateTime now = DateTime.UtcNow;
checker.BeginCheck(descriptiveName, vc, handler);
WaitHandle.WaitAny(new WaitHandle[] { checker.ProverDone });
ProverInterface.Outcome proverOutcome = checker.ReadOutcome();
- proverTime += (DateTime.UtcNow - now).TotalSeconds;
+ double queryTime = (DateTime.UtcNow - now).TotalSeconds;
+ proverTime += queryTime;
numProverQueries++;
-
- if (proverOutcome == ProverInterface.Outcome.Invalid) {
- Contract.Assume(collector.examples != null);
- if (collector.examples.Count == 0) {
- string memStr = System.Convert.ToString(System.GC.GetTotalMemory(false));
- if (memStr != null)
- memStr = "?";
- throw new UnexpectedProverOutputException("Outcome.Errors w/ 0 counter examples. " + memStr + " memory used");
- }
- errors = collector.examples;
- }
- else {
- errors = null;
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Time taken = " + queryTime);
}
+
+ errors = collector.examples;
return proverOutcome;
}
diff --git a/Source/Houdini/Houdini.cs b/Source/Houdini/Houdini.cs
index 68a8efb6..f6c334e7 100644
--- a/Source/Houdini/Houdini.cs
+++ b/Source/Houdini/Houdini.cs
@@ -303,12 +303,10 @@ namespace Microsoft.Boogie.Houdini {
private VCGen vcgen;
private Checker checker;
private Graph<Implementation> callGraph;
- private bool continueAtError;
private HashSet<Implementation> vcgenFailures;
- public Houdini(Program program, bool continueAtError) {
+ public Houdini(Program program) {
this.program = program;
- this.continueAtError = continueAtError;
if (CommandLineOptions.Clo.Trace)
Console.WriteLine("Collecting existential constants...");
@@ -511,51 +509,6 @@ namespace Microsoft.Boogie.Houdini {
return initial;
}
- private ProverInterface.Outcome VerifyUsingAxiom(HoudiniSession session, Implementation implementation, VCExpr axiom, out List<Counterexample> errors) {
- if (vcgen == null)
- throw new Exception("HdnVCGen not found for implementation: " + implementation.Name);
- ProverInterface.Outcome outcome = TryCatchVerify(session, axiom, out errors);
- return outcome;
- }
-
- // the main procedure that checks a procedure and updates the
- // assignment and the worklist
- private ProverInterface.Outcome HoudiniVerifyCurrent(
- HoudiniSession session,
- HoudiniState current,
- Program program,
- out List<Counterexample> errors,
- out bool exc) {
- if (current.Implementation == null)
- throw new Exception("HoudiniVerifyCurrent has null implementation");
-
- Implementation implementation = current.Implementation;
- if (vcgen == null)
- throw new Exception("HdnVCGen not found for implementation: " + implementation.Name);
-
- ProverInterface.Outcome outcome = HoudiniVerifyCurrentAux(session, current, program, out errors, out exc);
- return outcome;
- }
-
- private ProverInterface.Outcome VerifyCurrent(
- HoudiniSession session,
- HoudiniState current,
- Program program,
- out List<Counterexample> errors,
- out bool exc) {
- if (current.Implementation != null) {
- Implementation implementation = current.Implementation;
- if (vcgen == null)
- throw new Exception("HdnVCGen not found for implementation: " + implementation.Name);
-
- ProverInterface.Outcome outcome = TrySpinSameFunc(session, current, program, out errors, out exc);
- return outcome;
- }
- else {
- throw new Exception("VerifyCurrent has null implementation");
- }
- }
-
private bool IsOutcomeNotHoudini(ProverInterface.Outcome outcome, List<Counterexample> errors) {
switch (outcome) {
case ProverInterface.Outcome.Valid:
@@ -572,44 +525,24 @@ namespace Microsoft.Boogie.Houdini {
}
}
- // returns true if at least one of the violations is non-candidate
- private bool AnyNonCandidateViolation(ProverInterface.Outcome outcome, List<Counterexample> errors) {
- switch (outcome) {
- case ProverInterface.Outcome.Invalid:
- Contract.Assert(errors != null);
- foreach (Counterexample error in errors) {
- if (ExtractRefutedAnnotation(error) == null)
- return true;
- }
- return false;
- default:
- return false;
- }
- }
-
- private List<Counterexample> emptyList = new List<Counterexample>();
-
- // Record most current Non-Candidate errors found by Boogie, etc.
- private void UpdateHoudiniOutcome(HoudiniOutcome houdiniOutcome,
+ // Record most current non-candidate errors found
+ // Return true if there was at least one non-candidate error
+ private bool UpdateHoudiniOutcome(HoudiniOutcome houdiniOutcome,
Implementation implementation,
- ProverInterface.Outcome verificationOutcome,
+ ProverInterface.Outcome outcome,
List<Counterexample> errors) {
- string implName = implementation.ToString();
+ string implName = implementation.Name;
houdiniOutcome.implementationOutcomes.Remove(implName);
List<Counterexample> nonCandidateErrors = new List<Counterexample>();
- switch (verificationOutcome) {
- case ProverInterface.Outcome.Invalid:
- Contract.Assume(errors != null);
+ if (outcome == ProverInterface.Outcome.Invalid) {
foreach (Counterexample error in errors) {
if (ExtractRefutedAnnotation(error) == null)
nonCandidateErrors.Add(error);
}
- break;
- default:
- break;
}
- houdiniOutcome.implementationOutcomes.Add(implName, new VCGenOutcome(verificationOutcome, nonCandidateErrors));
+ houdiniOutcome.implementationOutcomes.Add(implName, new VCGenOutcome(outcome, nonCandidateErrors));
+ return nonCandidateErrors.Count > 0;
}
private void FlushWorkList(HoudiniState current) {
@@ -624,13 +557,12 @@ namespace Microsoft.Boogie.Houdini {
HoudiniSession session;
houdiniSessions.TryGetValue(current.Implementation, out session);
List<Counterexample> errors;
- ProverInterface.Outcome outcome = VerifyUsingAxiom(session, current.Implementation, axiom, out errors);
+ ProverInterface.Outcome outcome = TryCatchVerify(session, axiom, out errors);
UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
this.NotifyOutcome(outcome);
current.WorkQueue.Dequeue();
this.NotifyDequeue();
-
}
this.NotifyFlushFinish();
}
@@ -651,51 +583,6 @@ namespace Microsoft.Boogie.Houdini {
}
}
- private void UpdateWorkList(HoudiniState current,
- ProverInterface.Outcome outcome,
- List<Counterexample> errors) {
- Contract.Assume(current.Implementation != null);
-
- switch (outcome) {
- case ProverInterface.Outcome.Valid:
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- break;
- case ProverInterface.Outcome.Invalid:
- Contract.Assume(errors != null);
- bool dequeue = false;
- foreach (Counterexample error in errors) {
- RefutedAnnotation refutedAnnotation = ExtractRefutedAnnotation(error);
- if (refutedAnnotation != null) {
- foreach (Implementation implementation in FindImplementationsToEnqueue(refutedAnnotation, current.Implementation)) { AddToWorkList(current, implementation); }
- UpdateAssignment(current, refutedAnnotation);
- }
- else {
- dequeue = true; //once one non-houdini error is hit dequeue?!
- }
- }
- if (dequeue) {
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- }
- break;
- case ProverInterface.Outcome.TimeOut:
- // TODO: reset session instead of blocking timed out funcs?
- current.addToBlackList(current.Implementation.Name);
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- break;
- case ProverInterface.Outcome.OutOfMemory:
- case ProverInterface.Outcome.Undetermined:
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- break;
- default:
- throw new Exception("Unknown vcgen outcome");
- }
- }
-
-
private void AddRelatedToWorkList(HoudiniState current, RefutedAnnotation refutedAnnotation) {
Contract.Assume(current.Implementation != null);
foreach (Implementation implementation in FindImplementationsToEnqueue(refutedAnnotation, current.Implementation)) {
@@ -705,7 +592,7 @@ namespace Microsoft.Boogie.Houdini {
// Updates the worklist and current assignment
- // @return true if the current function is kept on the queue
+ // @return true if the current function is dequeued
private bool UpdateAssignmentWorkList(HoudiniState current,
ProverInterface.Outcome outcome,
List<Counterexample> errors) {
@@ -727,22 +614,12 @@ namespace Microsoft.Boogie.Houdini {
}
}
break;
-
- case ProverInterface.Outcome.TimeOut:
- // TODO: reset session instead of blocking timed out funcs?
+ default:
current.addToBlackList(current.Implementation.Name);
break;
- case ProverInterface.Outcome.Undetermined:
- case ProverInterface.Outcome.OutOfMemory:
- break;
- default:
- throw new Exception("Unknown vcgen outcome");
- }
- if (dequeue) {
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
}
- return !dequeue;
+
+ return dequeue;
}
private class WorkQueue {
@@ -810,106 +687,6 @@ namespace Microsoft.Boogie.Houdini {
}
}
- private void PrintBadList(string kind, List<string> list) {
- if (list.Count != 0) {
- Console.WriteLine("----------------------------------------");
- Console.WriteLine("Functions: {0}", kind);
- foreach (string fname in list) {
- Console.WriteLine("\t{0}", fname);
- }
- Console.WriteLine("----------------------------------------");
- }
- }
-
- private void PrintBadOutcomes(List<string> timeouts, List<string> inconc, List<string> errors) {
- PrintBadList("TimedOut", timeouts);
- PrintBadList("Inconclusive", inconc);
- PrintBadList("Errors", errors);
- }
-
- public HoudiniOutcome VerifyProgram() {
- HoudiniOutcome outcome = VerifyProgramSameFuncFirst();
- PrintBadOutcomes(outcome.ListOfTimeouts, outcome.ListOfInconclusives, outcome.ListOfErrors);
- return outcome;
- }
-
- // Old main loop
- public HoudiniOutcome VerifyProgramUnorderedWork() {
- HoudiniState current = new HoudiniState(BuildWorkList(program), BuildAssignment(houdiniConstants.Keys));
- this.NotifyStart(program, houdiniConstants.Keys.Count);
-
- while (current.WorkQueue.Count > 0) {
- //System.GC.Collect();
- this.NotifyIteration();
-
- VCExpr axiom = BuildAxiom(current.Assignment);
- this.NotifyAssignment(current.Assignment);
-
- current.Implementation = current.WorkQueue.Peek();
- this.NotifyImplementation(current.Implementation);
-
- List<Counterexample> errors;
- HoudiniSession session;
- houdiniSessions.TryGetValue(current.Implementation, out session);
- ProverInterface.Outcome outcome = VerifyUsingAxiom(session, current.Implementation, axiom, out errors);
- this.NotifyOutcome(outcome);
-
- UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
- if (IsOutcomeNotHoudini(outcome, errors) && !continueAtError) {
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- FlushWorkList(current);
- }
- else
- UpdateWorkList(current, outcome, errors);
- }
- this.NotifyEnd(true);
- current.Outcome.assignment = current.Assignment;
- return current.Outcome;
- }
-
- // New main loop
- public HoudiniOutcome VerifyProgramSameFuncFirst() {
- HoudiniState current = new HoudiniState(BuildWorkList(program), BuildAssignment(houdiniConstants.Keys));
- this.NotifyStart(program, houdiniConstants.Keys.Count);
-
- while (current.WorkQueue.Count > 0) {
- bool exceptional = false;
- //System.GC.Collect();
- this.NotifyIteration();
-
- current.Implementation = current.WorkQueue.Peek();
- this.NotifyImplementation(current.Implementation);
-
- HoudiniSession session;
- houdiniSessions.TryGetValue(current.Implementation, out session);
- List<Counterexample> errors;
- ProverInterface.Outcome outcome = VerifyCurrent(session, current, program, out errors, out exceptional);
-
- // updates to worklist already done in VerifyCurrent, unless there was an exception
- if (exceptional) {
- this.NotifyOutcome(outcome);
- UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
- if (IsOutcomeNotHoudini(outcome, errors) && !continueAtError) {
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- FlushWorkList(current);
- }
- else {
- UpdateAssignmentWorkList(current, outcome, errors);
- }
- exceptional = false;
- }
- }
- this.NotifyEnd(true);
- current.Outcome.assignment = current.Assignment;
- return current.Outcome;
- }
-
- //Clean houdini (Based on "Houdini Spec in Boogie" email 10/22/08
- //Aborts when there is a violation of non-candidate assertion
- //This can be used in eager mode (continueAfterError) by simply making
- //all non-candidate annotations as unchecked (free requires/ensures, assumes)
public HoudiniOutcome PerformHoudiniInference() {
HoudiniState current = new HoudiniState(BuildWorkList(program), BuildAssignment(houdiniConstants.Keys));
this.NotifyStart(program, houdiniConstants.Keys.Count);
@@ -918,31 +695,14 @@ namespace Microsoft.Boogie.Houdini {
}
while (current.WorkQueue.Count > 0) {
- bool exceptional = false;
- //System.GC.Collect();
this.NotifyIteration();
current.Implementation = current.WorkQueue.Peek();
this.NotifyImplementation(current.Implementation);
- List<Counterexample> errors;
HoudiniSession session;
this.houdiniSessions.TryGetValue(current.Implementation, out session);
- ProverInterface.Outcome outcome = HoudiniVerifyCurrent(session, current, program, out errors, out exceptional);
-
- // updates to worklist already done in VerifyCurrent, unless there was an exception
- if (exceptional) {
- this.NotifyOutcome(outcome);
- UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
- if (AnyNonCandidateViolation(outcome, errors)) { //abort
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- FlushWorkList(current);
- }
- else { //continue
- UpdateAssignmentWorkList(current, outcome, errors);
- }
- }
+ HoudiniVerifyCurrent(session, current);
}
this.NotifyEnd(true);
current.Outcome.assignment = current.Assignment;
@@ -1028,7 +788,6 @@ namespace Microsoft.Boogie.Houdini {
}
}
-
private void DebugRefutedCandidates(Implementation curFunc, List<Counterexample> errors) {
XmlSink xmlRefuted = CommandLineOptions.Clo.XmlRefuted;
if (xmlRefuted != null && errors != null) {
@@ -1085,11 +844,6 @@ namespace Microsoft.Boogie.Houdini {
try {
outcome = session.Verify(checker, axiom, out errors);
}
- catch (VCGenException e) {
- Contract.Assume(e != null);
- errors = null;
- outcome = ProverInterface.Outcome.Undetermined;
- }
catch (UnexpectedProverOutputException upo) {
Contract.Assume(upo != null);
errors = null;
@@ -1098,144 +852,54 @@ namespace Microsoft.Boogie.Houdini {
return outcome;
}
- //version of TryCatchVerify that spins on the same function
- //as long as the current assignment is changing
- private ProverInterface.Outcome TrySpinSameFunc(
- HoudiniSession session,
- HoudiniState current,
- Program program,
- out List<Counterexample> errors,
- out bool exceptional) {
- Contract.Assert(current.Implementation != null);
- ProverInterface.Outcome outcome;
- errors = null;
- outcome = ProverInterface.Outcome.Undetermined;
- try {
- bool trySameFunc = true;
- bool pastFirstIter = false; //see if this new loop is even helping
-
- do {
- if (pastFirstIter) {
- //System.GC.Collect();
- this.NotifyIteration();
- }
-
- VCExpr currentAx = BuildAxiom(current.Assignment);
- this.NotifyAssignment(current.Assignment);
-
- outcome = session.Verify(checker, currentAx, out errors);
- this.NotifyOutcome(outcome);
-
- DebugRefutedCandidates(current.Implementation, errors);
- UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
- if (!continueAtError && IsOutcomeNotHoudini(outcome, errors)) {
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- trySameFunc = false;
- FlushWorkList(current);
- }
- else {
- trySameFunc = UpdateAssignmentWorkList(current, outcome, errors);
- //reset for the next round
- errors = null;
- outcome = ProverInterface.Outcome.Undetermined;
- }
- pastFirstIter = true;
- } while (trySameFunc && current.WorkQueue.Count > 0);
-
- }
- catch (VCGenException e) {
- Contract.Assume(e != null);
- NotifyException("VCGen");
- exceptional = true;
- return outcome;
- }
- catch (UnexpectedProverOutputException upo) {
- Contract.Assume(upo != null);
- NotifyException("UnexpectedProverOutput");
- exceptional = true;
- return outcome;
- }
- exceptional = false;
- return outcome;
- }
-
- //Similar to TrySpinSameFunc except no Candidate logic
- private ProverInterface.Outcome HoudiniVerifyCurrentAux(
- HoudiniSession session,
- HoudiniState current,
- Program program,
- out List<Counterexample> errors,
- out bool exceptional) {
- Contract.Assert(current.Implementation != null);
- ProverInterface.Outcome outcome;
- // the following initialization is there just to satisfy the compiler
- // which apparently does not understand the semantics of do-while statements
- errors = null;
- outcome = ProverInterface.Outcome.Undetermined;
-
- try {
- bool trySameFunc = true;
- bool pastFirstIter = false; //see if this new loop is even helping
-
- do {
- errors = null;
- outcome = ProverInterface.Outcome.Undetermined;
-
- if (pastFirstIter) {
- //System.GC.Collect();
- this.NotifyIteration();
- }
-
- VCExpr currentAx = BuildAxiom(current.Assignment);
- this.NotifyAssignment(current.Assignment);
+ private void HoudiniVerifyCurrent(HoudiniSession session, HoudiniState current) {
+ while (true) {
+ VCExpr currentAx = BuildAxiom(current.Assignment);
+ this.NotifyAssignment(current.Assignment);
- //check the VC with the current assignment
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine("Verifying " + session.descriptiveName);
- }
- outcome = session.Verify(checker, currentAx, out errors);
- this.NotifyOutcome(outcome);
+ //check the VC with the current assignment
+ List<Counterexample> errors;
+ ProverInterface.Outcome outcome = TryCatchVerify(session, currentAx, out errors);
+ this.NotifyOutcome(outcome);
- DebugRefutedCandidates(current.Implementation, errors);
- UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors);
+ DebugRefutedCandidates(current.Implementation, errors);
- if (AnyNonCandidateViolation(outcome, errors)) { //abort
- current.WorkQueue.Dequeue();
- this.NotifyDequeue();
- trySameFunc = false;
- FlushWorkList(current);
- }
- else { //continue
- trySameFunc = UpdateAssignmentWorkList(current, outcome, errors);
- }
- pastFirstIter = true;
- } while (trySameFunc && current.WorkQueue.Count > 0);
- }
- catch (VCGenException e) {
- Contract.Assume(e != null);
- NotifyException("VCGen");
- exceptional = true;
- return outcome;
- }
- catch (UnexpectedProverOutputException upo) {
- Contract.Assume(upo != null);
- NotifyException("UnexpectedProverOutput");
- exceptional = true;
- return outcome;
- }
- exceptional = false;
- return outcome;
+ if (UpdateHoudiniOutcome(current.Outcome, current.Implementation, outcome, errors)) { // abort
+ current.WorkQueue.Dequeue();
+ this.NotifyDequeue();
+ FlushWorkList(current);
+ return;
+ }
+ else if (UpdateAssignmentWorkList(current, outcome, errors)) {
+ current.WorkQueue.Dequeue();
+ this.NotifyDequeue();
+ return;
+ }
+ }
}
}
- public enum HoudiniOutcomeKind { Done, FatalError, VerificationCompleted }
-
public class VCGenOutcome {
- public ProverInterface.Outcome outcome;
+ public VCGen.Outcome outcome;
public List<Counterexample> errors;
public VCGenOutcome(ProverInterface.Outcome outcome, List<Counterexample> errors) {
- this.outcome = outcome;
+ switch (outcome) {
+ case ProverInterface.Outcome.Invalid:
+ this.outcome = ConditionGeneration.Outcome.Errors;
+ break;
+ case ProverInterface.Outcome.OutOfMemory:
+ this.outcome = ConditionGeneration.Outcome.OutOfMemory;
+ break;
+ case ProverInterface.Outcome.TimeOut:
+ this.outcome = ConditionGeneration.Outcome.TimedOut;
+ break;
+ case ProverInterface.Outcome.Undetermined:
+ this.outcome = ConditionGeneration.Outcome.Inconclusive;
+ break;
+ case ProverInterface.Outcome.Valid:
+ this.outcome = ConditionGeneration.Outcome.Correct;
+ break;
+ }
this.errors = errors;
}
}
@@ -1245,12 +909,10 @@ namespace Microsoft.Boogie.Houdini {
public Dictionary<string, bool> assignment = new Dictionary<string, bool>();
// boogie errors
public Dictionary<string, VCGenOutcome> implementationOutcomes = new Dictionary<string, VCGenOutcome>();
- // outcome kind
- public HoudiniOutcomeKind kind;
// statistics
- private int CountResults(ProverInterface.Outcome outcome) {
+ private int CountResults(VCGen.Outcome outcome) {
int outcomeCount = 0;
foreach (VCGenOutcome verifyOutcome in implementationOutcomes.Values) {
if (verifyOutcome.outcome == outcome)
@@ -1259,7 +921,7 @@ namespace Microsoft.Boogie.Houdini {
return outcomeCount;
}
- private List<string> ListOutcomeMatches(ProverInterface.Outcome outcome) {
+ private List<string> ListOutcomeMatches(VCGen.Outcome outcome) {
List<string> result = new List<string>();
foreach (KeyValuePair<string, VCGenOutcome> kvpair in implementationOutcomes) {
if (kvpair.Value.outcome == outcome)
@@ -1270,37 +932,37 @@ namespace Microsoft.Boogie.Houdini {
public int ErrorCount {
get {
- return CountResults(ProverInterface.Outcome.Invalid);
+ return CountResults(VCGen.Outcome.Errors);
}
}
public int Verified {
get {
- return CountResults(ProverInterface.Outcome.Valid);
+ return CountResults(VCGen.Outcome.Correct);
}
}
public int Inconclusives {
get {
- return CountResults(ProverInterface.Outcome.Undetermined);
+ return CountResults(VCGen.Outcome.Inconclusive);
}
}
public int TimeOuts {
get {
- return CountResults(ProverInterface.Outcome.TimeOut);
+ return CountResults(VCGen.Outcome.TimedOut);
}
}
public List<string> ListOfTimeouts {
get {
- return ListOutcomeMatches(ProverInterface.Outcome.TimeOut);
+ return ListOutcomeMatches(VCGen.Outcome.TimedOut);
}
}
public List<string> ListOfInconclusives {
get {
- return ListOutcomeMatches(ProverInterface.Outcome.Undetermined);
+ return ListOutcomeMatches(VCGen.Outcome.Inconclusive);
}
}
public List<string> ListOfErrors {
get {
- return ListOutcomeMatches(ProverInterface.Outcome.Invalid);
+ return ListOutcomeMatches(VCGen.Outcome.Errors);
}
}
}
diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs
index 4c0597f9..6ef3778d 100644
--- a/Source/Provers/SMTLib/ProverInterface.cs
+++ b/Source/Provers/SMTLib/ProverInterface.cs
@@ -21,7 +21,7 @@ using System.Text;
namespace Microsoft.Boogie.SMTLib
{
- public class SMTLibProcessTheoremProver : ApiProverInterface
+ public class SMTLibProcessTheoremProver : ProverInterface
{
private readonly SMTLibProverContext ctx;
private readonly VCExpressionGenerator gen;
@@ -93,7 +93,6 @@ namespace Microsoft.Boogie.SMTLib
PrepareCommon();
}
prevOutcomeAvailable = false;
- pendingPop = false;
}
void SetupProcess()
@@ -382,7 +381,19 @@ namespace Microsoft.Boogie.SMTLib
[NoDefaultContract]
public override Outcome CheckOutcome(ErrorHandler handler)
- { //Contract.Requires(handler != null);
+ {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ var result = CheckOutcomeCore(handler);
+ SendThisVC("(pop 1)");
+ FlushLogFile();
+
+ return result;
+ }
+
+ [NoDefaultContract]
+ public override Outcome CheckOutcomeCore(ErrorHandler handler)
+ {
Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
var result = Outcome.Undetermined;
@@ -400,40 +411,47 @@ namespace Microsoft.Boogie.SMTLib
var globalResult = Outcome.Undetermined;
- while (errorsLeft-- > 0) {
+ while (true) {
+ errorsLeft--;
string[] labels = null;
result = GetResponse();
if (globalResult == Outcome.Undetermined)
globalResult = result;
- if (result == Outcome.Invalid && options.UseZ3) {
- labels = GetLabelsInfo(handler);
+ if (result == Outcome.Invalid) {
+ IList<string> xlabels;
+ if (CommandLineOptions.Clo.UseLabels) {
+ labels = GetLabelsInfo();
+ xlabels = labels.Select(a => a.Replace("@", "").Replace("+", "")).ToList();
+ }
+ else {
+ labels = CalculatePath(0);
+ xlabels = labels;
+ }
+ ErrorModel errorModel = GetErrorModel();
+ handler.OnModel(xlabels, errorModel);
}
- if (labels == null) break;
+ if (labels == null || errorsLeft == 0) break;
- var negLabels = labels.Where(l => l.StartsWith("@")).ToArray();
- var posLabels = labels.Where(l => !l.StartsWith("@"));
- Func<string, string> lbl = (s) => SMTLibNamer.QuoteId(SMTLibNamer.LabelVar(s));
- if (!options.MultiTraces)
- posLabels = Enumerable.Empty<string>();
- var conjuncts = posLabels.Select(s => "(not " + lbl(s) + ")").Concat(negLabels.Select(lbl)).ToArray();
- var expr = conjuncts.Length == 1 ? conjuncts[0] : ("(or " + conjuncts.Concat(" ") + ")");
- if (errorsLeft > 0) {
+ if (CommandLineOptions.Clo.UseLabels) {
+ var negLabels = labels.Where(l => l.StartsWith("@")).ToArray();
+ var posLabels = labels.Where(l => !l.StartsWith("@"));
+ Func<string, string> lbl = (s) => SMTLibNamer.QuoteId(SMTLibNamer.LabelVar(s));
+ if (!options.MultiTraces)
+ posLabels = Enumerable.Empty<string>();
+ var conjuncts = posLabels.Select(s => "(not " + lbl(s) + ")").Concat(negLabels.Select(lbl)).ToArray();
+ var expr = conjuncts.Length == 1 ? conjuncts[0] : ("(or " + conjuncts.Concat(" ") + ")");
SendThisVC("(assert " + expr + ")");
SendThisVC("(check-sat)");
}
- }
-
- if (CommandLineOptions.Clo.StratifiedInlining == 0)
- {
- SendThisVC("(pop 1)");
- }
- else if (CommandLineOptions.Clo.StratifiedInlining > 0 && pendingPop)
- {
- pendingPop = false;
- SendThisVC("(pop 1)");
+ else {
+ string source = labels[labels.Length - 2];
+ string target = labels[labels.Length - 1];
+ SendThisVC("(assert (not (= (ControlFlow 0 " + source + ") (- " + target + "))))");
+ SendThisVC("(check-sat)");
+ }
}
FlushLogFile();
@@ -448,100 +466,91 @@ namespace Microsoft.Boogie.SMTLib
}
}
- private string[] CalculatePath() {
- SendThisVC("(get-value ((ControlFlow 0 0)))");
+ public override string[] CalculatePath(int controlFlowConstant) {
+ SendThisVC("(get-value ((ControlFlow " + controlFlowConstant + " 0)))");
var path = new List<string>();
while (true) {
var resp = Process.GetProverResponse();
- if (resp == null)
- break;
+ if (resp == null) break;
if (!(resp.Name == "" && resp.ArgCount == 1)) break;
resp = resp.Arguments[0];
if (!(resp.Name == "" && resp.ArgCount == 2)) break;
resp = resp.Arguments[1];
var v = resp.Name;
- if (v == "-" && resp.ArgCount == 1)
- v += resp.Arguments[0].Name;
- else if (resp.ArgCount != 0)
+ if (v == "-" && resp.ArgCount == 1) {
+ v = resp.Arguments[0].Name;
+ path.Add(v);
+ break;
+ }
+ else if (resp.ArgCount != 0)
break;
- if (v.StartsWith("-")) {
- path.Add("@" + v.Substring(1));
+ path.Add(v);
+ SendThisVC("(get-value ((ControlFlow " + controlFlowConstant + " " + v + ")))");
+ }
+ return path.ToArray();
+ }
+
+ private ErrorModel GetErrorModel() {
+ if (!options.ExpectingModel())
+ return null;
+ SendThisVC("(get-model)");
+ Process.Ping();
+ Model theModel = null;
+ while (true) {
+ var resp = Process.GetProverResponse();
+ if (resp == null || Process.IsPong(resp))
break;
+ if (theModel != null)
+ HandleProverError("Expecting only one model but got many");
+
+ string modelStr = null;
+ if (resp.Name == "model" && resp.ArgCount >= 1) {
+ modelStr = resp[0].Name;
+ }
+ else if (resp.ArgCount == 0 && resp.Name.Contains("->")) {
+ modelStr = resp.Name;
}
else {
- path.Add("+" + v);
+ HandleProverError("Unexpected prover response getting model: " + resp.ToString());
+ }
+ List<Model> models = null;
+ try {
+ models = Model.ParseModels(new StringReader("Z3 error model: \n" + modelStr));
}
- SendThisVC("(get-value ((ControlFlow 0 " + v + ")))");
+ catch (ArgumentException exn) {
+ HandleProverError("Model parsing error: " + exn.Message);
+ }
+ if (models == null)
+ HandleProverError("Could not parse any models");
+ else if (models.Count == 0)
+ HandleProverError("Could not parse any models");
+ else if (models.Count > 1)
+ HandleProverError("Expecting only one model but got many");
+ else
+ theModel = models[0];
}
- return path.ToArray();
+ return new ErrorModel(theModel);
}
- private string[] GetLabelsInfo(ErrorHandler handler)
+ private string[] GetLabelsInfo()
{
- if (CommandLineOptions.Clo.UseLabels)
- SendThisVC("(labels)");
- if (options.ExpectingModel())
- SendThisVC("(get-model)");
+ SendThisVC("(labels)");
Process.Ping();
- List<string> labelNums = null;
- Model theModel = null;
string[] res = null;
-
while (true) {
var resp = Process.GetProverResponse();
if (resp == null || Process.IsPong(resp))
break;
+ if (res != null)
+ HandleProverError("Expecting only one sequence of labels but got many");
if (resp.Name == "labels" && resp.ArgCount >= 1) {
- var labels = resp.Arguments.Select(a => a.Name.Replace("|", "")).ToArray();
- res = labels;
- if (labelNums != null) HandleProverError("Got multiple :labels responses");
- labelNums = labels.Select(a => a.Replace("@", "").Replace("+", "")).ToList();
- } else {
- string modelStr = null;
- if (resp.Name == "model" && resp.ArgCount >= 1) {
- modelStr = resp[0].Name;
- } else if (resp.ArgCount == 0 && resp.Name.Contains("->")) {
- modelStr = resp.Name;
- }
-
- if (modelStr != null) {
- List<Model> models = null;
- try {
- models = Model.ParseModels(new StringReader("Z3 error model: \n" + modelStr));
- } catch (ArgumentException exn) {
- HandleProverError("Model parsing error: " + exn.Message);
- }
-
- if (models != null) {
- if (models.Count == 0) HandleProverError("Could not parse any models");
- else {
- if (models.Count > 1) HandleProverError("Expecting only one model, got multiple");
- if (theModel != null) HandleProverError("Got multiple :model responses");
- theModel = models[0];
- }
- }
- } else {
- HandleProverError("Unexpected prover response (getting labels/model): " + resp.ToString());
- }
+ res = resp.Arguments.Select(a => a.Name.Replace("|", "")).ToArray();
+ }
+ else {
+ HandleProverError("Unexpected prover response getting labels: " + resp.ToString());
}
}
-
- if (!CommandLineOptions.Clo.UseLabels) {
- res = CalculatePath();
- if (res.Length == 0)
- res = null;
- else
- labelNums = res.Select(a => a.Replace("@", "").Replace("+", "")).ToList();
- }
-
- if (labelNums != null) {
- ErrorModel m = null;
- if (theModel != null)
- m = new ErrorModel(theModel);
- handler.OnModel(labelNums, m);
- }
-
return res;
}
@@ -754,7 +763,6 @@ namespace Microsoft.Boogie.SMTLib
throw new NotImplementedException();
}
- // For implementing ApiProverInterface
public override void Assert(VCExpr vc, bool polarity)
{
string a = "";
@@ -777,7 +785,7 @@ namespace Microsoft.Boogie.SMTLib
public override void Check()
{
- Contract.Assert(pendingPop == false && prevOutcomeAvailable == false);
+ Contract.Assert(prevOutcomeAvailable == false);
PrepareCommon();
SendThisVC("(check-sat)");
@@ -793,15 +801,13 @@ namespace Microsoft.Boogie.SMTLib
/// Extra state for ApiChecker (used by stratifiedInlining)
/// </summary>
bool prevOutcomeAvailable;
- bool pendingPop;
Outcome prevOutcome;
static int nameCounter = 0;
public override void CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore)
{
- Contract.Assert(pendingPop == false && prevOutcomeAvailable == false);
+ Contract.Assert(prevOutcomeAvailable == false);
- Push();
unsatCore = new List<int>();
// Name the assumptions
@@ -822,7 +828,6 @@ namespace Microsoft.Boogie.SMTLib
prevOutcomeAvailable = true;
if (prevOutcome != Outcome.Valid)
{
- pendingPop = true;
return;
}
Contract.Assert(usingUnsatCore, "SMTLib prover not setup for computing unsat cores");
@@ -832,8 +837,6 @@ namespace Microsoft.Boogie.SMTLib
if(resp.Name != "") unsatCore.Add(nameToAssumption[resp.Name]);
foreach (var s in resp.Arguments) unsatCore.Add(nameToAssumption[s.Name]);
- Pop();
-
FlushLogFile();
}
diff --git a/Source/Provers/Z3api/ProverLayer.cs b/Source/Provers/Z3api/ProverLayer.cs
index 947d4eae..3b7b8f43 100644
--- a/Source/Provers/Z3api/ProverLayer.cs
+++ b/Source/Provers/Z3api/ProverLayer.cs
@@ -8,7 +8,7 @@ using Microsoft.Boogie.AbstractInterpretation;
using Microsoft.Boogie;
using Microsoft.Boogie.Z3;
using Microsoft.Boogie.VCExprAST;
-using Microsoft.Boogie.Simplify;
+using System.Diagnostics.Contracts;
using TypeAst = System.IntPtr;
using TermAst = System.IntPtr;
@@ -19,7 +19,146 @@ using PatternAst = System.IntPtr;
namespace Microsoft.Boogie.Z3
{
- public class Z3apiProcessTheoremProver : ApiProverInterface
+ public class Z3InstanceOptions : ProverOptions {
+ public int Timeout { get { return TimeLimit / 1000; } }
+ public int Lets {
+ get {
+ Contract.Ensures(0 <= Contract.Result<int>() && Contract.Result<int>() < 4);
+ return CommandLineOptions.Clo.Z3lets;
+ }
+ }
+ public bool DistZ3 = false;
+ public string ExeName = "z3.exe";
+ public bool InverseImplies = false;
+ public string Inspector = null;
+ public bool OptimizeForBv = false;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(ExeName != null);
+ }
+
+ protected override bool Parse(string opt) {
+ //Contract.Requires(opt!=null);
+ return ParseBool(opt, "REVERSE_IMPLIES", ref InverseImplies) ||
+ ParseString(opt, "INSPECTOR", ref Inspector) ||
+ ParseBool(opt, "DIST", ref DistZ3) ||
+ ParseBool(opt, "OPTIMIZE_FOR_BV", ref OptimizeForBv) ||
+ base.Parse(opt);
+ }
+
+ public override void PostParse() {
+ base.PostParse();
+
+ if (DistZ3) {
+ ExeName = "z3-dist.exe";
+ CommandLineOptions.Clo.RestartProverPerVC = true;
+ }
+ }
+
+ public override string Help {
+ get {
+ return
+@"
+Z3-specific options:
+~~~~~~~~~~~~~~~~~~~~
+INSPECTOR=<string> Use the specified Z3Inspector binary.
+OPTIMIZE_FOR_BV=<bool> Optimize Z3 options for bitvector reasoning, and not quantifier instantiation. Defaults to false.
+
+Obscure options:
+~~~~~~~~~~~~~~~~
+DIST=<bool> Use z3-dist.exe binary.
+REVERSE_IMPLIES=<bool> Encode P==>Q as Q||!P.
+
+" + base.Help;
+ // DIST requires non-public binaries
+ }
+ }
+ }
+
+ public class Z3LineariserOptions : LineariserOptions {
+ private readonly Z3InstanceOptions opts;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(opts != null);
+ }
+
+
+ public Z3LineariserOptions(bool asTerm, Z3InstanceOptions opts, List<VCExprVar/*!>!*/> letVariables)
+ : base(asTerm) {
+ Contract.Requires(opts != null);
+ Contract.Requires(cce.NonNullElements(letVariables));
+
+ this.opts = opts;
+ this.LetVariablesAttr = letVariables;
+ }
+
+ public override bool UseWeights {
+ get {
+ return true;
+ }
+ }
+
+ public override bool UseTypes {
+ get {
+ return true;
+ }
+ }
+
+ public override bool QuantifierIds {
+ get {
+ return true;
+ }
+ }
+
+ public override bool InverseImplies {
+ get {
+ return opts.InverseImplies;
+ }
+ }
+
+ public override LineariserOptions SetAsTerm(bool newVal) {
+ Contract.Ensures(Contract.Result<LineariserOptions>() != null);
+
+ if (newVal == AsTerm)
+ return this;
+ return new Z3LineariserOptions(newVal, opts, LetVariables);
+ }
+
+ // variables representing formulas in let-bindings have to be
+ // printed in a different way than other variables
+ private readonly List<VCExprVar/*!>!*/> LetVariablesAttr;
+ public override List<VCExprVar/*!>!*/> LetVariables {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<VCExprVar>>()));
+
+ return LetVariablesAttr;
+ }
+ }
+
+ public override LineariserOptions AddLetVariable(VCExprVar furtherVar) {
+ //Contract.Requires(furtherVar != null);
+ Contract.Ensures(Contract.Result<LineariserOptions>() != null);
+
+ List<VCExprVar/*!>!*/> allVars = new List<VCExprVar/*!*/>();
+ allVars.AddRange(LetVariables);
+ allVars.Add(furtherVar);
+ return new Z3LineariserOptions(AsTerm, opts, allVars);
+ }
+
+ public override LineariserOptions AddLetVariables(List<VCExprVar/*!>!*/> furtherVars) {
+ //Contract.Requires(furtherVars != null);
+ Contract.Ensures(Contract.Result<LineariserOptions>() != null);
+
+ List<VCExprVar/*!>!*/> allVars = new List<VCExprVar/*!*/>();
+ allVars.AddRange(LetVariables);
+ allVars.AddRange(furtherVars);
+ return new Z3LineariserOptions(AsTerm, opts, allVars);
+ }
+ }
+
+ public class Z3apiProcessTheoremProver : ProverInterface
{
public Z3apiProcessTheoremProver(Z3InstanceOptions opts, DeclFreeProverContext ctxt)
{
@@ -152,6 +291,16 @@ namespace Microsoft.Boogie.Z3
return outcome;
}
+ public override Outcome CheckOutcomeCore(ErrorHandler handler) {
+ if (outcome == Outcome.Invalid) {
+ foreach (Z3ErrorModelAndLabels z3LabelModel in z3LabelModels) {
+ List<string> unprefixedLabels = RemovePrefixes(z3LabelModel.RelevantLabels);
+ handler.OnModel(unprefixedLabels, z3LabelModel.ErrorModel);
+ }
+ }
+ return outcome;
+ }
+
private List<string> RemovePrefixes(List<string> labels)
{
List<string> result = new List<string>();
diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs
index 9b7b6e36..d74497c0 100644
--- a/Source/VCGeneration/Check.cs
+++ b/Source/VCGeneration/Check.cs
@@ -734,7 +734,7 @@ namespace Microsoft.Boogie {
Undetermined
}
public class ErrorHandler {
- public virtual void OnModel(IList<string>/*!>!*/ labels, ErrorModel errModel) {
+ public virtual void OnModel(IList<string> labels, ErrorModel errModel) {
Contract.Requires(cce.NonNullElements(labels));
}
@@ -743,7 +743,6 @@ namespace Microsoft.Boogie {
}
public virtual void OnProverWarning(string message)
- //modifies Console.Out.*, Console.Error.*;
{
Contract.Requires(message != null);
switch (CommandLineOptions.Clo.PrintProverWarnings) {
@@ -761,7 +760,6 @@ namespace Microsoft.Boogie {
}
}
-
public virtual Absy Label2Absy(string label) {
Contract.Requires(label != null);
Contract.Ensures(Contract.Result<Absy>() != null);
@@ -772,6 +770,9 @@ namespace Microsoft.Boogie {
public abstract void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler);
[NoDefaultContract]
public abstract Outcome CheckOutcome(ErrorHandler handler);
+ public virtual string[] CalculatePath(int controlFlowConstant) {
+ throw new System.NotImplementedException();
+ }
public virtual void LogComment(string comment) {
Contract.Requires(comment != null);
}
@@ -804,6 +805,44 @@ namespace Microsoft.Boogie {
throw new NotImplementedException();
}
+ // (assert vc)
+ public virtual void Assert(VCExpr vc, bool polarity)
+ {
+ throw new NotImplementedException();
+ }
+
+ // (assert implicit-axioms)
+ public virtual void AssertAxioms()
+ {
+ throw new NotImplementedException();
+ }
+
+ // (check-sat)
+ public virtual void Check()
+ {
+ throw new NotImplementedException();
+ }
+
+ // (check-sat + get-unsat-core)
+ public virtual void CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual Outcome CheckOutcomeCore(ErrorHandler handler)
+ {
+ throw new NotImplementedException();
+ }
+
+ // (push 1)
+ public virtual void Push()
+ {
+ throw new NotImplementedException();
+ }
+
+ // Set theorem prover timeout for the next "check-sat"
+ public virtual void SetTimeOut(int ms)
+ { }
public abstract ProverContext Context {
get;
@@ -812,6 +851,7 @@ namespace Microsoft.Boogie {
get;
}
}
+
public class ProverInterfaceContracts : ProverInterface {
public override ProverContext Context {
get {
@@ -840,17 +880,6 @@ namespace Microsoft.Boogie {
}
}
- // Exposes an api in line with z3's api
- public abstract class ApiProverInterface : ProverInterface
- {
- public abstract void Assert(VCExpr vc, bool polarity);
- public abstract void AssertAxioms();
- public abstract void Check();
- public abstract void CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore);
- public abstract void Push();
- public virtual void SetTimeOut(int ms) { }
- }
-
public class ProverException : Exception {
public ProverException(string s)
: base(s) {
diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs
index e0d7b4a7..b9b0928c 100644
--- a/Source/VCGeneration/StratifiedVC.cs
+++ b/Source/VCGeneration/StratifiedVC.cs
@@ -87,7 +87,6 @@ namespace VC
{
Contract.Invariant(cce.NonNullElements(privateVars));
Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
}
public bool initialized;
@@ -127,9 +126,6 @@ namespace VC
{
StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, checker.TheoremProver.Context, QuantifierExpr.GetNextSkolemId());
implName2StratifiedInliningInfo[impl.Name] = info;
- // We don't need controlFlowVariable for stratified Inlining
- //impl.LocVars.Add(info.controlFlowVariable);
-
ExprSeq exprs = new ExprSeq();
foreach (Variable v in program.GlobalVariables())
@@ -209,10 +205,18 @@ namespace VC
VCExpressionGenerator gen = checker.VCExprGen;
Contract.Assert(gen != null);
+ var ctx = checker.TheoremProver.Context;
+ var exprGen = ctx.ExprGen;
+ var bet = ctx.BoogieExprTranslator;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : bet.LookupVariable(info.controlFlowVariable);
- VCExpr vcexpr = gen.Not(GenerateVC(impl, null, out label2absy, checker));
+ VCExpr vcexpr = gen.Not(GenerateVC(impl, controlFlowVariableExpr, out label2absy, checker));
Contract.Assert(vcexpr != null);
-
+ if (!CommandLineOptions.Clo.UseLabels) {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vcexpr = exprGen.And(eqExpr, vcexpr);
+ }
info.label2absy = label2absy;
info.mvInfo = mvInfo;
@@ -272,7 +276,7 @@ namespace VC
Dictionary<string, List<CallSite>> calleeToCallSites;
Dictionary<string, List<CallSite>> callerToCallSites;
- private void CreateProcedureCopies(Implementation impl, Program program, StratifiedCheckerInterface checker, VCExpr vcMain) {
+ private void CreateProcedureCopies(Implementation impl, Program program, ApiChecker checker, VCExpr vcMain) {
interfaceVarCopies = new Dictionary<string, List<VCExprVar>>();
privateVarCopies = new Dictionary<string, List<VCExprVar>>();
procVcCopies = new Dictionary<string, VCExpr>();
@@ -556,14 +560,14 @@ namespace VC
}
public class BoundingVCMutator : MutatingVCExprVisitor<bool> {
- StratifiedCheckerInterface checker;
+ ApiChecker checker;
string implName;
Dictionary<string, List<VCExprVar>> interfaceVarCopies;
Dictionary<string, List<CallSite>> calleeToCallSites;
Dictionary<string, List<CallSite>> callerToCallSites;
public BoundingVCMutator(
- StratifiedCheckerInterface checker,
+ ApiChecker checker,
string implName,
Dictionary<string, List<VCExprVar>> interfaceVarCopies,
Dictionary<string, List<CallSite>> calleeToCallSites,
@@ -626,7 +630,8 @@ namespace VC
} // end BoundingVCMutator
- private void CreateProcedureCopy(StratifiedInliningInfo info, StratifiedCheckerInterface checker) {
+ private void CreateProcedureCopy(StratifiedInliningInfo info, ApiChecker checker)
+ {
var translator = checker.underlyingChecker.TheoremProver.Context.BoogieExprTranslator;
var Gen = checker.underlyingChecker.VCExprGen;
var expr = info.vcexpr;
@@ -1023,148 +1028,7 @@ namespace VC
}
- // Unifies the interface between standard checker and z3api-based checker
- abstract public class StratifiedCheckerInterface
- {
- // Underlying checker
- public Checker underlyingChecker;
- // Statistics
- public int numQueries;
-
- abstract public Outcome CheckVC();
- abstract public void Push();
- abstract public void Pop();
- abstract public void AddAxiom(VCExpr vc);
- abstract public void LogComment(string str);
- abstract public void updateMainVC(VCExpr vcMain);
- virtual public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore)
- {
- Outcome ret;
-
- unsatCore = new List<int>();
- for (int i = 0; i < assumptions.Count; i++)
- unsatCore.Add(i);
-
- if (assumptions.Count == 0)
- {
- return CheckVC();
- }
-
- Push();
-
- foreach (var a in assumptions)
- {
- AddAxiom(a);
- }
- ret = CheckVC();
-
- Pop();
-
- return ret;
- }
- virtual public void SetTimeOut(int msec)
- {
- // default behavior is to ignore this timeout
- }
- }
-
- public class NormalChecker : StratifiedCheckerInterface
- {
- // The VC of main
- public VCExpr vcMain;
- // Error reporter (stores models)
- public ProverInterface.ErrorHandler reporter;
- // The theorem prover interface
- public Checker checker;
- // stores the number of axioms pushed since pervious backtracking point
- private List<int> numAxiomsPushed;
-
- public NormalChecker(VCExpr vcMain, ProverInterface.ErrorHandler reporter, Checker checker)
- {
- this.vcMain = vcMain;
- this.reporter = reporter;
- this.checker = checker;
- this.underlyingChecker = checker;
- numAxiomsPushed = new List<int>();
- numQueries = 0;
- }
-
- public override void updateMainVC(VCExpr vcMain)
- {
- this.vcMain = vcMain;
- }
-
- public override Outcome CheckVC()
- {
- Contract.Requires(vcMain != null);
- Contract.Requires(reporter != null);
- Contract.Requires(checker != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- checker.TheoremProver.FlushAxiomsToTheoremProver();
- checker.BeginCheck("the_main", vcMain, reporter);
- checker.ProverDone.WaitOne();
-
- ProverInterface.Outcome outcome = (checker).ReadOutcome();
- numQueries++;
-
- switch (outcome)
- {
- case ProverInterface.Outcome.Valid:
- return Outcome.Correct;
- case ProverInterface.Outcome.Invalid:
- return Outcome.Errors;
- case ProverInterface.Outcome.OutOfMemory:
- return Outcome.OutOfMemory;
- case ProverInterface.Outcome.TimeOut:
- return Outcome.TimedOut;
- case ProverInterface.Outcome.Undetermined:
- return Outcome.Inconclusive;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
-
- }
-
- public override void Push()
- {
- numAxiomsPushed.Add(0);
- }
-
- public override void Pop()
- {
- Debug.Assert(numAxiomsPushed.Count > 0);
- checker.TheoremProver.FlushAxiomsToTheoremProver();
- var n = numAxiomsPushed.Last();
- numAxiomsPushed.RemoveAt(numAxiomsPushed.Count - 1);
-
- for (int i = 0; i < n; i++)
- {
- checker.TheoremProver.Pop();
- }
- }
-
- public override void AddAxiom(VCExpr vc)
- {
- Debug.Assert(numAxiomsPushed.Count > 0);
- int oldnum = checker.TheoremProver.NumAxiomsPushed();
-
- checker.TheoremProver.PushVCExpression(vc);
-
- int newnum = checker.TheoremProver.NumAxiomsPushed();
- numAxiomsPushed[numAxiomsPushed.Count - 1] += (newnum - oldnum);
- }
-
- public override void LogComment(string str)
- {
- checker.TheoremProver.LogComment(str);
- }
-
- }
-
-
- public class ApiChecker : StratifiedCheckerInterface {
+ public class ApiChecker {
// The VC of main
private VCExpr vcMain;
// Error reporter (stores models)
@@ -1174,34 +1038,40 @@ namespace VC
// stores the number of axioms pushed since pervious backtracking point
private List<int> numAxiomsPushed;
// Api-based theorem prover
- private ApiProverInterface TheoremProver;
+ private ProverInterface TheoremProver;
// Use checkAssumptions?
public static bool UseCheckAssumptions = true;
+ private FCallHandler calls;
+ // Underlying checker
+ public Checker underlyingChecker;
+ // Statistics
+ public int numQueries;
- public ApiChecker(VCExpr vcMain, ProverInterface.ErrorHandler reporter, Checker checker) {
+ public ApiChecker(VCExpr vcMain, ProverInterface.ErrorHandler reporter, Checker checker, FCallHandler calls) {
this.vcMain = vcMain;
this.reporter = reporter;
this.checker = checker;
this.underlyingChecker = checker;
+ this.calls = calls;
numAxiomsPushed = new List<int>();
numQueries = 0;
- TheoremProver = checker.TheoremProver as ApiProverInterface;
+ TheoremProver = checker.TheoremProver;
Debug.Assert(TheoremProver != null);
// Add main to the TP stack
TheoremProver.Assert(vcMain, false);
}
- public override void updateMainVC(VCExpr vcMain) {
+ public void updateMainVC(VCExpr vcMain) {
throw new NotImplementedException("Stratified non-incremental search is not yet supported with z3api");
}
- public override Outcome CheckVC() {
+ public Outcome CheckVC() {
Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
TheoremProver.AssertAxioms();
TheoremProver.Check();
- ProverInterface.Outcome outcome = TheoremProver.CheckOutcome(reporter);
+ ProverInterface.Outcome outcome = TheoremProver.CheckOutcomeCore(reporter);
numQueries++;
switch (outcome) {
@@ -1221,26 +1091,48 @@ namespace VC
}
}
- public override void Push() {
+ public void Push() {
TheoremProver.Push();
}
- public override void Pop() {
+ public void Pop() {
TheoremProver.AssertAxioms();
TheoremProver.Pop();
}
- public override void AddAxiom(VCExpr vc) {
+ public void AddAxiom(VCExpr vc) {
TheoremProver.Assert(vc, true);
}
- public override void LogComment(string str) {
+ public void LogComment(string str) {
checker.TheoremProver.LogComment(str);
}
- public override Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) {
+ public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) {
if (!UseCheckAssumptions) {
- return base.CheckAssumptions(assumptions, out unsatCore);
+ Outcome ret;
+
+ unsatCore = new List<int>();
+ for (int i = 0; i < assumptions.Count; i++)
+ unsatCore.Add(i);
+
+ if (assumptions.Count == 0)
+ {
+ return CheckVC();
+ }
+
+ Push();
+
+ foreach (var a in assumptions)
+ {
+ AddAxiom(a);
+ }
+ ret = CheckVC();
+
+ Pop();
+
+ return ret;
+
}
if (assumptions.Count == 0) {
@@ -1248,11 +1140,11 @@ namespace VC
return CheckVC();
}
- //TheoremProver.Push();
+ TheoremProver.Push();
TheoremProver.AssertAxioms();
TheoremProver.CheckAssumptions(assumptions, out unsatCore);
- ProverInterface.Outcome outcome = TheoremProver.CheckOutcome(reporter);
- //TheoremProver.Pop();
+ ProverInterface.Outcome outcome = TheoremProver.CheckOutcomeCore(reporter);
+ TheoremProver.Pop();
numQueries++;
switch (outcome) {
@@ -1272,7 +1164,7 @@ namespace VC
}
}
- public override void SetTimeOut(int msec)
+ public void SetTimeOut(int msec)
{
TheoremProver.SetTimeOut(msec);
}
@@ -1289,7 +1181,7 @@ namespace VC
public ProverInterface.ErrorHandler reporter;
// The theorem prover interface
//public Checker checker;
- public StratifiedCheckerInterface checker;
+ public ApiChecker checker;
// The coverage graph reporter
public CoverageGraphManager coverageManager;
// For statistics
@@ -1303,7 +1195,7 @@ namespace VC
}
}
// For making summary queries on the side
- public StratifiedCheckerInterface checker2;
+ public ApiChecker checker2;
public VerificationState(VCExpr vcMain, FCallHandler calls,
ProverInterface.ErrorHandler reporter, Checker checker, Checker checker2)
@@ -1311,18 +1203,10 @@ namespace VC
this.vcMain = vcMain;
this.calls = calls;
this.reporter = reporter;
- if (checker.TheoremProver is ApiProverInterface)
- {
- this.checker = new ApiChecker(vcMain, reporter , checker);
- if(checker2 != null)
- this.checker2 = new ApiChecker(VCExpressionGenerator.False, new EmptyErrorHandler(), checker2);
- }
- else
- {
- this.checker = new NormalChecker(vcMain, reporter, checker);
+
+ this.checker = new ApiChecker(vcMain, reporter, checker, calls);
if(checker2 != null)
- this.checker2 = new NormalChecker(VCExpressionGenerator.False, new EmptyErrorHandler(), checker2);
- }
+ this.checker2 = new ApiChecker(VCExpressionGenerator.False, new EmptyErrorHandler(), checker2, calls);
vcSize = 0;
expansionCount = 0;
@@ -1369,7 +1253,14 @@ namespace VC
ConvertCFG2DAG(impl, program);
Hashtable/*TransferCmd->ReturnCmd*/ gotoCmdOrigins = PassifyImpl(impl, program, out mvInfo);
- vcMain = GenerateVC(impl, null, out mainLabel2absy, checker);
+ var exprGen = checker.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+ vcMain = GenerateVC(impl, controlFlowVariableExpr, out mainLabel2absy, checker);
+ if (!CommandLineOptions.Clo.UseLabels) {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vcMain = exprGen.Implies(eqExpr, vcMain);
+ }
// Find all procedure calls in vc and put labels on them
FCallHandler calls = new FCallHandler(checker.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
@@ -1424,7 +1315,7 @@ namespace VC
return Outcome.Correct;
}
- private HashSet<VCExprVar> refinementLoop(StratifiedCheckerInterface apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars)
+ private HashSet<VCExprVar> refinementLoop(ApiChecker apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars)
{
Debug.Assert(trackedVars.IsSubsetOf(trackedVarsUpperBound));
@@ -1466,7 +1357,7 @@ namespace VC
Dictionary<int, List<HashSet<string>>> satQueryCache;
Dictionary<int, List<HashSet<string>>> unsatQueryCache;
- private bool refinementLoopCheckPath(StratifiedCheckerInterface apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars)
+ private bool refinementLoopCheckPath(ApiChecker apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars)
{
var assumptions = new List<VCExpr>();
List<int> temp = null;
@@ -1635,9 +1526,6 @@ namespace VC
Hashtable/*<int, Absy!>*/ mainLabel2absy;
GetVC(impl, program, callback, out vc, out mainLabel2absy, out reporter);
- if (CommandLineOptions.Clo.ProcedureCopyBound > 0) {
- return SuperAwesomeMethod(checker, impl, vc);
- }
// Find all procedure calls in vc and put labels on them
FCallHandler calls = new FCallHandler(checker.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
@@ -1706,9 +1594,9 @@ namespace VC
#endregion
#region Coverage reporter
- if (CommandLineOptions.Clo.CoverageReporterPath == "Console")
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
{
- Console.WriteLine("Stratified Inlining: Size of VC after eager inlining: {0}", vState.vcSize);
+ Console.WriteLine(">> SI: Size of VC after eager inlining: {0}", vState.vcSize);
}
#endregion
@@ -1896,13 +1784,13 @@ namespace VC
vState.checker.Pop();
#region Coverage reporter
- if (CommandLineOptions.Clo.CoverageReporterPath == "Console")
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
{
- Console.WriteLine("Stratified Inlining: Calls to Z3: {0}", vState.numQueries);
- Console.WriteLine("Stratified Inlining: Expansions performed: {0}", vState.expansionCount);
- Console.WriteLine("Stratified Inlining: Candidates left: {0}", calls.currCandidates.Count);
- Console.WriteLine("Stratified Inlining: Nontrivial Candidates left: {0}", calls.numNonTrivialCandidates());
- Console.WriteLine("Stratified Inlining: VC Size: {0}", vState.vcSize);
+ Console.WriteLine(">> SI: Calls to Z3: {0}", vState.numQueries);
+ Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount);
+ Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count);
+ Console.WriteLine(">> SI: Nontrivial Candidates left: {0}", calls.numNonTrivialCandidates());
+ Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize);
}
#endregion
coverageManager.stop();
@@ -1963,7 +1851,8 @@ namespace VC
} // end PCBInliner
- private void InlineCallSite(CallSite cs, StratifiedCheckerInterface checker) {
+ private void InlineCallSite(CallSite cs, ApiChecker checker)
+ {
var Gen = checker.underlyingChecker.VCExprGen;
var callee = cs.calleeName;
var caller = cs.callerName;
@@ -2023,7 +1912,8 @@ namespace VC
calleeToCallSites[callee].Remove(cs);
}
- private Outcome FindUnsatCoreInMainCallees(Implementation impl, StratifiedCheckerInterface checker, VCExpressionGenerator Gen, PCBErrorReporter reporter, List<VCExpr> assumptions, out HashSet<VCExprVar> unsatCore) {
+ private Outcome FindUnsatCoreInMainCallees(Implementation impl, ApiChecker checker, VCExpressionGenerator Gen, PCBErrorReporter reporter, List<VCExpr> assumptions, out HashSet<VCExprVar> unsatCore)
+ {
Debug.Assert(checker is ApiChecker);
unsatCore = null;
List<int> unsatCoreIndices;
@@ -2044,7 +1934,8 @@ namespace VC
return Outcome.Correct;
}
- private Outcome FindUnsatCore(Implementation impl, StratifiedCheckerInterface checker, VCExpressionGenerator Gen, PCBErrorReporter reporter, List<VCExpr> assumptions, out HashSet<VCExprVar> unsatCore) {
+ private Outcome FindUnsatCore(Implementation impl, ApiChecker checker, VCExpressionGenerator Gen, PCBErrorReporter reporter, List<VCExpr> assumptions, out HashSet<VCExprVar> unsatCore)
+ {
Helpers.ExtraTraceInformation("Number of assumptions = " + assumptions.Count);
unsatCore = null;
List<int> unsatCoreIndices;
@@ -2175,7 +2066,8 @@ namespace VC
return verified;
}
- private void InlineBottomUp(StratifiedCheckerInterface checker, HashSet<VCExprVar> unsatCore) {
+ private void InlineBottomUp(ApiChecker checker, HashSet<VCExprVar> unsatCore)
+ {
Graph<string> callGraph = new Graph<string>();
foreach (string name in calleeToCallSites.Keys) {
callGraph.AddSource(name);
@@ -2197,7 +2089,8 @@ namespace VC
}
}
- private void InlineIntoMain(StratifiedCheckerInterface checker, Implementation impl, HashSet<VCExprVar> unsatCore) {
+ private void InlineIntoMain(ApiChecker checker, Implementation impl, HashSet<VCExprVar> unsatCore)
+ {
HashSet<CallSite> toBeInlined = new HashSet<CallSite>();
foreach (CallSite cs in callerToCallSites[impl.Name]) {
if (unsatCore.Contains(cs.callSiteConstant)) {
@@ -2220,8 +2113,8 @@ namespace VC
var Gen = underlyingChecker.VCExprGen;
PCBErrorReporter reporter = new PCBErrorReporter(impl);
- StratifiedCheckerInterface checker;
- checker = new ApiChecker(VCExpressionGenerator.False, reporter, underlyingChecker);
+ ApiChecker checker;
+ checker = new ApiChecker(VCExpressionGenerator.False, reporter, underlyingChecker, null);
CreateProcedureCopies(impl, program, checker, vcMain);
int iter = 0;
@@ -2460,6 +2353,14 @@ namespace VC
}
//Console.WriteLine("Inlining {0}", procName);
VCExpr expansion = cce.NonNull(info.vcexpr);
+
+ if (!CommandLineOptions.Clo.UseLabels) {
+ var ctx = checker.TheoremProver.Context;
+ var bet = ctx.BoogieExprTranslator;
+ VCExpr controlFlowVariableExpr = bet.LookupVariable(info.controlFlowVariable);
+ VCExpr eqExpr = ctx.ExprGen.Eq(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.FromInt(id)));
+ expansion = ctx.ExprGen.And(eqExpr, expansion);
+ }
// Instantiate the "forall" variables
Dictionary<VCExprVar, VCExpr> substForallDict = new Dictionary<VCExprVar, VCExpr>();
@@ -2629,8 +2530,17 @@ namespace VC
Hashtable/*TransferCmd->ReturnCmd*/ gotoCmdOrigins = PassifyImpl(impl, program, out mvInfo);
Checker checker = FindCheckerFor(impl, CommandLineOptions.Clo.ProverKillTime);
Contract.Assert(checker != null);
-
- vc = GenerateVC(impl, null, out label2absy, checker);
+
+ var exprGen = checker.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ vc = GenerateVC(impl, controlFlowVariableExpr, out label2absy, checker);
+
+ if (!CommandLineOptions.Clo.UseLabels) {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vc = exprGen.Implies(eqExpr, vc);
+ }
reporter = new StratifiedInliningErrorReporter(
cce.NonNull(implName2StratifiedInliningInfo), checker.TheoremProver, callback, mvInfo,
@@ -3159,6 +3069,10 @@ namespace VC
summaryTemp.Clear();
}
+ public IEnumerable<int> getInlinedCandidates() {
+ return candidateParent.Keys.Except(currCandidates).Union(new int[] { 0 });
+ }
+
} // end FCallHandler
// Collects the set of all VCExprVar in a given VCExpr
@@ -3435,9 +3349,131 @@ namespace VC
return;
}
- public override void OnModel(IList<string/*!*/>/*!*/ labels, ErrorModel errModel)
+ public override void OnModel(IList<string> labels, ErrorModel errModel) {
+ if (CommandLineOptions.Clo.UseLabels)
+ OnModelOld(labels, errModel);
+ else
+ OnModelNew(labels, errModel);
+ }
+
+ private void OnModelNew(IList<string> labels, ErrorModel errModel) {
+ List<Absy> absyList = new List<Absy>();
+ foreach (var label in labels) {
+ absyList.Add(Label2Absy(label));
+ }
+
+ orderedStateIds = new List<Tuple<int, int>>();
+ candidatesToExpand = new List<int>();
+
+ Model model = null;
+ if (errModel != null) model = errModel.ToModel();
+
+ if (underapproximationMode) {
+ var cex = NewTrace(0, absyList, model);
+ Debug.Assert(candidatesToExpand.Count == 0);
+ if (cex != null) {
+ GetModelWithStates(model);
+ callback.OnCounterexample(cex, null);
+ this.PrintModel(model);
+ }
+ return;
+ }
+
+ NewTrace(0, absyList, model);
+ }
+
+ private Counterexample NewTrace(int candidateId, List<Absy> absyList, Model model) {
+ AssertCmd assertCmd = (AssertCmd)absyList[absyList.Count - 1];
+ BlockSeq trace = new BlockSeq();
+ var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+ for (int j = 0; j < absyList.Count - 1; j++) {
+ Block b = (Block)absyList[j];
+ trace.Add(b);
+ CmdSeq cmdSeq = b.Cmds;
+ for (int i = 0; i < cmdSeq.Length; i++) {
+ Cmd cmd = cmdSeq[i];
+ if (cmd == assertCmd) break;
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ if (assumeCmd == null) continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null)
+ continue;
+ string calleeName = naryExpr.Fun.FunctionName;
+ Contract.Assert(calleeName != null);
+
+ BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
+ if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) {
+ Expr expr = naryExpr.Args[0];
+ NAryExpr mvStateExpr = expr as NAryExpr;
+ if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) {
+ LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
+ orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt));
+ }
+ }
+
+ if (calleeName.StartsWith(recordProcName) && model != null) {
+ var expr = calls.recordExpr2Var[new BoogieCallExpr(naryExpr, candidateId)];
+
+ // Record concrete value of the argument to this procedure
+ var args = new List<Model.Element>();
+ if (expr is VCExprIntLit) {
+ args.Add(model.MkElement((expr as VCExprIntLit).Val.ToString()));
+ }
+ else if (expr == VCExpressionGenerator.True) {
+ args.Add(model.MkElement("true"));
+ }
+ else if (expr == VCExpressionGenerator.False) {
+ args.Add(model.MkElement("false"));
+ }
+ else if (expr is VCExprVar) {
+ var idExpr = expr as VCExprVar;
+ string name = context.Lookup(idExpr);
+ Contract.Assert(name != null);
+ Model.Func f = model.TryGetFunc(name);
+ if (f != null) {
+ args.Add(f.GetConstant());
+ }
+ }
+ else {
+ Contract.Assert(false);
+ }
+ calleeCounterexamples[new TraceLocation(trace.Length - 1, i)] =
+ new CalleeCounterexampleInfo(null, args);
+ continue;
+ }
+
+ if (!implName2StratifiedInliningInfo.ContainsKey(calleeName))
+ continue;
+
+ int calleeId = calls.boogieExpr2Id[new BoogieCallExpr(naryExpr, candidateId)];
+
+ if (calls.currCandidates.Contains(calleeId)) {
+ candidatesToExpand.Add(calleeId);
+ }
+ else {
+ orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL));
+ string[] labels = theoremProver.CalculatePath(calleeId);
+ List<Absy> calleeAbsyList = new List<Absy>();
+ foreach (string label in labels) {
+ VCExprNAry expr = calls.id2Candidate[calleeId];
+ string procName = (cce.NonNull(expr.Op as VCExprBoogieFunctionOp)).Func.Name;
+ calleeAbsyList.Add(Label2Absy(procName, label));
+ }
+ calleeCounterexamples[new TraceLocation(trace.Length - 1, i)] =
+ new CalleeCounterexampleInfo(NewTrace(calleeId, calleeAbsyList, model), new List<Model.Element>());
+ orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
+ }
+ }
+ }
+
+ Block lastBlock = (Block)absyList[absyList.Count - 2];
+ Counterexample newCounterexample = AssertCmdToCounterexample(assertCmd, lastBlock.TransferCmd, trace, model, mvInfo, context);
+ newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
+ return newCounterexample;
+ }
+
+ public void OnModelOld(IList<string/*!*/>/*!*/ labels, ErrorModel errModel)
{
- //if (procBoundingMode) return; // shaz hack
Contract.Assert(CommandLineOptions.Clo.StratifiedInliningWithoutModels || errModel != null);
candidatesToExpand = new List<int>();
@@ -3445,7 +3481,6 @@ namespace VC
Model model = null;
if (errModel != null) model = errModel.ToModel();
- //Contract.Requires(cce.NonNullElements(labels));
if (underapproximationMode)
{
var cex = GenerateTraceMain(labels, model, mvInfo);
@@ -3475,7 +3510,7 @@ namespace VC
orderedStateIds = new List<Tuple<int,int>>();
Counterexample newCounterexample =
- GenerateTrace(labels, errModel, mvInfo, 0, orderedStateIds, mainImpl);
+ GenerateTrace(labels, errModel, 0, mainImpl);
if (newCounterexample == null)
return null;
@@ -3501,8 +3536,8 @@ namespace VC
return newCounterexample;
}
- private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo,
- int candidateId, List<Tuple<int,int>> orderedStateIds, Implementation procImpl)
+ private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel,
+ int candidateId, Implementation procImpl)
{
Contract.Requires(cce.NonNullElements(labels));
Contract.Requires(procImpl != null);
@@ -3542,14 +3577,14 @@ namespace VC
trace.Add(entryBlock);
var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
- Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, orderedStateIds, entryBlock, traceNodes, trace, calleeCounterexamples);
+ Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, entryBlock, traceNodes, trace, calleeCounterexamples);
return newCounterexample;
}
private Counterexample GenerateTraceRec(
IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo,
- int candidateId, List<Tuple<int,int>> orderedStateIds,
+ int candidateId,
Block/*!*/ b, Hashtable/*!*/ traceNodes, BlockSeq/*!*/ trace,
Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples)
{
@@ -3570,7 +3605,7 @@ namespace VC
// Skip if 'cmd' not contained in the trace or not an assert
if (cmd is AssertCmd && traceNodes.Contains(cmd))
{
- Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context, new Dictionary<Incarnation, Absy/*!*/>());
+ Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context);
newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
return newCounterexample;
}
@@ -3591,9 +3626,7 @@ namespace VC
NAryExpr mvStateExpr = expr as NAryExpr;
if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) {
LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
- Debug.Assert(x != null);
- int foo = x.asBigNum.ToInt;
- orderedStateIds.Add(new Tuple<int, int>(candidateId, foo));
+ orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt));
}
}
@@ -3652,7 +3685,7 @@ namespace VC
orderedStateIds.Add(new Tuple<int, int>(actualId, StratifiedInliningErrorReporter.CALL));
calleeCounterexamples[new TraceLocation(trace.Length - 1, i)] =
new CalleeCounterexampleInfo(
- cce.NonNull(GenerateTrace(labels, errModel, mvInfo, actualId, orderedStateIds, implName2StratifiedInliningInfo[calleeName].impl)),
+ cce.NonNull(GenerateTrace(labels, errModel, actualId, implName2StratifiedInliningInfo[calleeName].impl)),
new List<Model.Element>());
orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
}
@@ -3670,7 +3703,7 @@ namespace VC
orderedStateIds.Add(new Tuple<int, int>(actualId, StratifiedInliningErrorReporter.CALL));
calleeCounterexamples[new TraceLocation(trace.Length - 1, i)] =
new CalleeCounterexampleInfo(
- cce.NonNull(GenerateTrace(labels, errModel, mvInfo, actualId, orderedStateIds, implName2StratifiedInliningInfo[calleeName].impl)),
+ cce.NonNull(GenerateTrace(labels, errModel, actualId, implName2StratifiedInliningInfo[calleeName].impl)),
new List<Model.Element>());
orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
}
@@ -3682,7 +3715,7 @@ namespace VC
orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL));
calleeCounterexamples[new TraceLocation(trace.Length - 1, i)] =
new CalleeCounterexampleInfo(
- cce.NonNull(GenerateTrace(labels, errModel, mvInfo, calleeId, orderedStateIds, implName2StratifiedInliningInfo[calleeName].impl)),
+ cce.NonNull(GenerateTrace(labels, errModel, calleeId, implName2StratifiedInliningInfo[calleeName].impl)),
new List<Model.Element>());
orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
}
diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs
index 1c0aeee8..008810cb 100644
--- a/Source/VCGeneration/VC.cs
+++ b/Source/VCGeneration/VC.cs
@@ -102,7 +102,7 @@ namespace VC {
this.impl = impl;
this.uniqueId = uniqueId;
- this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "cfc", Microsoft.Boogie.Type.Int));
+ this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
impl.LocVars.Add(controlFlowVariable);
List<Variable> interfaceVars = new List<Variable>();
@@ -272,7 +272,7 @@ namespace VC {
TypecheckingContext tc = new TypecheckingContext(null);
impl.Typecheck(tc);
int assertionCount;
- VCExpr vcexpr = gen.Not(LetVC(impl.Blocks[0], info.controlFlowVariable, null, checker.TheoremProver.Context, out assertionCount));
+ VCExpr vcexpr = gen.Not(LetVC(impl.Blocks[0], translator.LookupVariable(info.controlFlowVariable), null, checker.TheoremProver.Context, out assertionCount));
CumulativeAssertionCount += assertionCount;
Contract.Assert(vcexpr != null);
ResetPredecessors(impl.Blocks);
@@ -608,27 +608,16 @@ namespace VC {
Checker ch = parent.FindCheckerFor(impl, CommandLineOptions.Clo.SmokeTimeout);
Contract.Assert(ch != null);
- Variable controlFlowVariable = null;
- if (!CommandLineOptions.Clo.UseLabels) {
- foreach (Variable v in impl.LocVars) {
- if (v.Name == "@cfc") {
- controlFlowVariable = v;
- break;
- }
- }
- }
+ var exprGen = ch.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
- VCExpr vc = parent.GenerateVC(impl, controlFlowVariable, out label2Absy, ch);
+ VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch);
Contract.Assert(vc != null);
-
+
if (!CommandLineOptions.Clo.UseLabels) {
- var ctx = ch.TheoremProver.Context;
- var bet = ctx.BoogieExprTranslator;
- VCExpr controlFlowVariableExpr = bet.LookupVariable(controlFlowVariable);
- VCExpr eqExpr1 = ctx.ExprGen.Eq(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr controlFlowFunctionAppl = ctx.ExprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr2 = ctx.ExprGen.Eq(controlFlowFunctionAppl, ctx.ExprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = ctx.ExprGen.Implies(eqExpr1, ctx.ExprGen.Implies(eqExpr2, vc));
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vc = exprGen.Implies(eqExpr, vc);
}
impl.Blocks = backup;
@@ -1351,7 +1340,7 @@ namespace VC {
foreach (Cmd c in b.Cmds) {
Contract.Assert(c != null);
if (c is AssertCmd) {
- return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context, new Dictionary<Incarnation, Absy>());
+ return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context);
}
}
}
@@ -1558,21 +1547,16 @@ namespace VC {
}
));
- LocalVariable controlFlowVariable = null;
- if (!CommandLineOptions.Clo.UseLabels) {
- controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
- impl.LocVars.Add(controlFlowVariable);
- }
+ var exprGen = ctx.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
- VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariable, label2absy, checker);
+ VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker);
Contract.Assert(vc != null);
if (!CommandLineOptions.Clo.UseLabels) {
- VCExpr controlFlowVariableExpr = bet.LookupVariable(controlFlowVariable);
- VCExpr eqExpr1 = ctx.ExprGen.Eq(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr controlFlowFunctionAppl = ctx.ExprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, ctx.ExprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr2 = ctx.ExprGen.Eq(controlFlowFunctionAppl, ctx.ExprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = ctx.ExprGen.Implies(eqExpr1, ctx.ExprGen.Implies(eqExpr2, vc));
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vc = exprGen.Implies(eqExpr, vc);
}
if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local) {
@@ -1646,7 +1630,7 @@ namespace VC {
}
#endregion
- public VCExpr GenerateVC(Implementation/*!*/ impl, Variable controlFlowVariable, out Hashtable/*<int, Absy!>*//*!*/ label2absy, Checker/*!*/ ch)
+ public VCExpr GenerateVC(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, out Hashtable/*<int, Absy!>*//*!*/ label2absy, Checker/*!*/ ch)
{
Contract.Requires(impl != null);
Contract.Requires(ch != null);
@@ -1654,10 +1638,10 @@ namespace VC {
Contract.Ensures(Contract.Result<VCExpr>() != null);
label2absy = new Hashtable/*<int, Absy!>*/();
- return GenerateVCAux(impl, controlFlowVariable, label2absy, ch);
+ return GenerateVCAux(impl, controlFlowVariableExpr, label2absy, ch);
}
- protected VCExpr GenerateVCAux(Implementation/*!*/ impl, Variable controlFlowVariable, Hashtable/*<int, Absy!>*//*!*/ label2absy, Checker/*!*/ ch) {
+ protected VCExpr GenerateVCAux(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, Hashtable/*<int, Absy!>*//*!*/ label2absy, Checker/*!*/ ch) {
Contract.Requires(impl != null);
Contract.Requires(ch != null);
Contract.Ensures(Contract.Result<VCExpr>() != null);
@@ -1688,13 +1672,13 @@ namespace VC {
break;
case CommandLineOptions.VCVariety.Dag:
if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags) {
- vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariable, label2absy, new Hashtable/*<Block, VCExpr!>*/(), ch.TheoremProver.Context, out assertionCount);
+ vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, new Hashtable/*<Block, VCExpr!>*/(), ch.TheoremProver.Context, out assertionCount);
} else {
- vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariable, label2absy, ch.TheoremProver.Context, out assertionCount);
+ vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, ch.TheoremProver.Context, out assertionCount);
}
break;
case CommandLineOptions.VCVariety.DagIterative:
- vc = LetVCIterative(impl.Blocks, controlFlowVariable, label2absy, ch.TheoremProver.Context, out assertionCount);
+ vc = LetVCIterative(impl.Blocks, controlFlowVariableExpr, label2absy, ch.TheoremProver.Context, out assertionCount);
break;
case CommandLineOptions.VCVariety.Doomed:
vc = FlatBlockVC(impl, label2absy, false, false, true, ch.TheoremProver.Context, out assertionCount);
@@ -2086,7 +2070,7 @@ namespace VC {
if (b.Cmds.Has(a)) {
BlockSeq trace = new BlockSeq();
trace.Add(b);
- Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, errModel == null ? null : errModel.ToModel(), MvInfo, context, incarnationOriginMap);
+ Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, errModel == null ? null : errModel.ToModel(), MvInfo, context);
callback.OnCounterexample(newCounterexample, null);
goto NEXT_ASSERT;
}
@@ -2737,7 +2721,7 @@ namespace VC {
if (assertCmd != null && controlFlowFunction.TryEval(cfcValue, errModel.MkIntElement(b.UniqueId)).AsInt() == assertCmd.UniqueId)
{
Counterexample newCounterexample;
- newCounterexample = AssertCmdToCounterexample(assertCmd, transferCmd, trace, errModel, mvInfo, context, cce.NonNull(info.incarnationOriginMap));
+ newCounterexample = AssertCmdToCounterexample(assertCmd, transferCmd, trace, errModel, mvInfo, context);
newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
return newCounterexample;
}
@@ -2875,7 +2859,7 @@ namespace VC {
// Skip if 'cmd' not contained in the trace or not an assert
if (cmd is AssertCmd && traceNodes.Contains(cmd))
{
- Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context, incarnationOriginMap);
+ Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context);
Contract.Assert(newCounterexample != null);
newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
return newCounterexample;
@@ -3420,14 +3404,12 @@ namespace VC {
}
}
- protected static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, BlockSeq trace, Model errModel, ModelViewInfo mvInfo, ProverContext context,
- Dictionary<Incarnation, Absy> incarnationOriginMap)
+ protected static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, BlockSeq trace, Model errModel, ModelViewInfo mvInfo, ProverContext context)
{
Contract.Requires(cmd != null);
Contract.Requires(transferCmd != null);
Contract.Requires(trace != null);
Contract.Requires(context != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
Contract.Ensures(Contract.Result<Counterexample>() != null);
List<string> relatedInformation = new List<string>();
@@ -3459,7 +3441,7 @@ namespace VC {
}
static VCExpr LetVC(Block startBlock,
- Variable controlFlowVariable,
+ VCExpr controlFlowVariableExpr,
Hashtable/*<int, Absy!>*/ label2absy,
ProverContext proverCtxt,
out int assertionCount) {
@@ -3470,12 +3452,12 @@ namespace VC {
Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- VCExpr startCorrect = LetVC(startBlock, controlFlowVariable, label2absy, blockVariables, bindings, proverCtxt, out assertionCount);
+ VCExpr startCorrect = LetVC(startBlock, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out assertionCount);
return proverCtxt.ExprGen.Let(bindings, startCorrect);
}
static VCExpr LetVCIterative(List<Block> blocks,
- Variable controlFlowVariable,
+ VCExpr controlFlowVariableExpr,
Hashtable label2absy,
ProverContext proverCtxt,
out int assertionCount) {
@@ -3522,8 +3504,7 @@ namespace VC {
foreach (Block successor in gotocmd.labelTargets) {
Contract.Assert(successor != null);
VCExpr s = blockVariables[successor];
- if (controlFlowVariable != null) {
- VCExprVar controlFlowVariableExpr = proverCtxt.BoogieExprTranslator.LookupVariable(controlFlowVariable);
+ if (controlFlowVariableExpr != null) {
VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
s = gen.Implies(controlTransferExpr, s);
@@ -3533,7 +3514,7 @@ namespace VC {
SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
}
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariable);
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
VCExpr vc = Wlp.Block(block, SuccCorrect, context);
assertionCount += context.AssertionCount;
@@ -3546,7 +3527,7 @@ namespace VC {
}
static VCExpr LetVC(Block block,
- Variable controlFlowVariable,
+ VCExpr controlFlowVariableExpr,
Hashtable/*<int, Absy!>*/ label2absy,
Hashtable/*<Block, VCExprVar!>*/ blockVariables,
List<VCExprLetBinding/*!*/>/*!*/ bindings,
@@ -3587,11 +3568,10 @@ namespace VC {
foreach (Block successor in gotocmd.labelTargets) {
Contract.Assert(successor != null);
int ac;
- VCExpr s = LetVC(successor, controlFlowVariable, label2absy, blockVariables, bindings, proverCtxt, out ac);
+ VCExpr s = LetVC(successor, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out ac);
assertionCount += ac;
- if (controlFlowVariable != null)
+ if (controlFlowVariableExpr != null)
{
- VCExprVar controlFlowVariableExpr = proverCtxt.BoogieExprTranslator.LookupVariable(controlFlowVariable);
VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
s = gen.Implies(controlTransferExpr, s);
@@ -3602,7 +3582,7 @@ namespace VC {
}
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariable);
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
VCExpr vc = Wlp.Block(block, SuccCorrect, context);
assertionCount += context.AssertionCount;
@@ -3614,7 +3594,7 @@ namespace VC {
}
static VCExpr DagVC(Block block,
- Variable controlFlowVariable,
+ VCExpr controlFlowVariableExpr,
Hashtable/*<int, Absy!>*/ label2absy,
Hashtable/*<Block, VCExpr!>*/ blockEquations,
ProverContext proverCtxt,
@@ -3645,10 +3625,9 @@ namespace VC {
foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
Contract.Assert(successor != null);
int ac;
- VCExpr c = DagVC(successor, controlFlowVariable, label2absy, blockEquations, proverCtxt, out ac);
+ VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac);
assertionCount += ac;
- if (controlFlowVariable != null) {
- VCExprVar controlFlowVariableExpr = proverCtxt.BoogieExprTranslator.LookupVariable(controlFlowVariable);
+ if (controlFlowVariableExpr != null) {
VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
c = gen.Implies(controlTransferExpr, c);
@@ -3660,7 +3639,7 @@ namespace VC {
SuccCorrect = VCExpressionGenerator.True;
}
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariable);
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
vc = Wlp.Block(block, SuccCorrect, context);
assertionCount += context.AssertionCount;
diff --git a/Source/VCGeneration/Wlp.cs b/Source/VCGeneration/Wlp.cs
index 94892c29..eb1ce4e1 100644
--- a/Source/VCGeneration/Wlp.cs
+++ b/Source/VCGeneration/Wlp.cs
@@ -22,7 +22,7 @@ namespace VC {
[Rep] public readonly Hashtable/*<int, Absy!>*/ Label2absy;
[Rep] public readonly ProverContext Ctxt;
- public readonly Variable ControlFlowVariable;
+ public readonly VCExpr ControlFlowVariableExpr;
public int AssertionCount; // counts the number of assertions for which Wlp has been computed
public VCContext(Hashtable/*<int, Absy!>*/ label2absy, ProverContext ctxt)
@@ -33,12 +33,12 @@ namespace VC {
// base();
}
- public VCContext(Hashtable/*<int, Absy!>*/ label2absy, ProverContext ctxt, Variable controlFlowVariable)
+ public VCContext(Hashtable/*<int, Absy!>*/ label2absy, ProverContext ctxt, VCExpr controlFlowVariableExpr)
{
Contract.Requires(ctxt != null);
this.Label2absy = label2absy;
this.Ctxt = ctxt;
- this.ControlFlowVariable = controlFlowVariable;
+ this.ControlFlowVariableExpr = controlFlowVariableExpr;
}
}
@@ -126,13 +126,11 @@ namespace VC {
return gen.Implies(C, N);
ctxt.AssertionCount++;
- if (ctxt.ControlFlowVariable == null) {
+ if (ctxt.ControlFlowVariableExpr == null) {
Contract.Assert(ctxt.Label2absy != null);
return gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), C), N);
} else {
- VCExpr controlFlowVariableExpr = ctxt.Ctxt.BoogieExprTranslator.LookupVariable(ctxt.ControlFlowVariable);
- Contract.Assert(controlFlowVariableExpr != null);
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId)));
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(ctxt.ControlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId)));
Contract.Assert(controlFlowFunctionAppl != null);
VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId)));
if (ctxt.Label2absy == null) {
diff --git a/Test/dafny0/Answer b/Test/dafny0/Answer
index d0dfc9be..9995c817 100644
--- a/Test/dafny0/Answer
+++ b/Test/dafny0/Answer
@@ -1445,7 +1445,7 @@ Execution trace:
(0,0): anon0
(0,0): anon11_Then
-Dafny program verifier finished with 13 verified, 2 errors
+Dafny program verifier finished with 19 verified, 2 errors
-------------------- Predicates.dfy --------------------
Predicates.dfy[B](18,5): Error BP5003: A postcondition might not hold on this return path.
@@ -1476,6 +1476,20 @@ Execution trace:
Dafny program verifier finished with 52 verified, 6 errors
+-------------------- Skeletons.dfy --------------------
+Skeletons.dfy(42,3): Error BP5003: A postcondition might not hold on this return path.
+Skeletons.dfy(41,15): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon0
+ Skeletons.dfy[C0](29,5): anon12_LoopHead
+ (0,0): anon12_LoopBody
+ Skeletons.dfy[C0](29,5): anon13_Else
+ (0,0): anon9
+ Skeletons.dfy[C0](34,19): anon16_Else
+ (0,0): anon11
+
+Dafny program verifier finished with 9 verified, 1 error
+
-------------------- SmallTests.dfy --------------------
SmallTests.dfy(30,11): Error: index out of range
Execution trace:
@@ -1705,7 +1719,7 @@ Execution trace:
(0,0): anon0
(0,0): anon11_Then
-Dafny program verifier finished with 13 verified, 2 errors
+Dafny program verifier finished with 19 verified, 2 errors
out.tmp.dfy(10,12): Error: assertion violation
Execution trace:
(0,0): anon0
@@ -1714,4 +1728,4 @@ Execution trace:
(0,0): anon0
(0,0): anon11_Then
-Dafny program verifier finished with 13 verified, 2 errors
+Dafny program verifier finished with 19 verified, 2 errors
diff --git a/Test/dafny0/LetExpr.dfy b/Test/dafny0/LetExpr.dfy
index 48e4810b..11bf4fbe 100644
--- a/Test/dafny0/LetExpr.dfy
+++ b/Test/dafny0/LetExpr.dfy
@@ -107,3 +107,43 @@ method PMain(a: array<int>)
assert index == old(index) ==> a[index] == 21 && old(a[index]) == 19;
}
}
+
+// ---------- lemmas ----------
+
+method Theorem0(n: int)
+ requires 1 <= n;
+ ensures 1 <= Fib(n);
+{
+ if (n < 3) {
+ } else {
+ Theorem0(n-2);
+ Theorem0(n-1);
+ }
+}
+
+ghost method Theorem1(n: int)
+ requires 1 <= n;
+ ensures 1 <= Fib(n);
+{
+ // in a ghost method, the induction tactic takes care of it
+}
+
+function Theorem2(n: int): int
+ requires 1 <= n;
+ ensures 1 <= Fib(n);
+{
+ if n < 3 then 5 else
+ var x := Theorem2(n-2);
+ var y := Theorem2(n-1);
+ x + y
+}
+
+function Theorem3(n: int): int
+ requires 1 <= n;
+ ensures 1 <= Fib(n);
+{
+ if n < 3 then 5 else
+ var x := Theorem3(n-2);
+ var y := Theorem3(n-1);
+ 5
+}
diff --git a/Test/dafny0/Skeletons.dfy b/Test/dafny0/Skeletons.dfy
new file mode 100644
index 00000000..e9fef946
--- /dev/null
+++ b/Test/dafny0/Skeletons.dfy
@@ -0,0 +1,63 @@
+module A {
+ method M(p: int) returns (y: int)
+ requires p <= 30;
+ {
+ assume p < 100;
+ var x;
+ assume x == p + 20;
+ x := x + 1;
+ while (*)
+ invariant x <= 120;
+ decreases 120 - x;
+ {
+ if (x == 120) { break; }
+ x := x + 1;
+ }
+ y := x;
+ }
+}
+
+module B refines A {
+ method M ...
+ {
+ assert p < 50;
+ assert ...;
+ var x := p + 20;
+ assert ...;
+ var k := x + 1;
+ ...;
+ while ...
+ invariant k == x;
+ {
+ k := k + 1;
+ }
+ assert k == x || k == x + 1; // there are two exits from the loop
+ }
+}
+
+
+module C0 refines B {
+ method M ...
+ ensures y == 120; // error: this holds only if the loop does not end early
+ {
+ }
+}
+
+module C1 refines B {
+ method M ...
+ ensures y <= 120;
+ {
+ }
+}
+
+module C2 refines B {
+ method M ...
+ ensures y == 120;
+ {
+ ...;
+ while (true)
+ ...
+ assert k == x + 1; // only one loop exit remains
+ ...;
+ }
+}
diff --git a/Test/dafny0/runtest.bat b/Test/dafny0/runtest.bat
index b1402e83..608b7358 100644
--- a/Test/dafny0/runtest.bat
+++ b/Test/dafny0/runtest.bat
@@ -22,7 +22,7 @@ for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
LoopModifies.dfy Refinement.dfy RefinementErrors.dfy
ReturnErrors.dfy ReturnTests.dfy ChainingDisjointTests.dfy
CallStmtTests.dfy MultiSets.dfy PredExpr.dfy LetExpr.dfy
- Predicates.dfy) do (
+ Predicates.dfy Skeletons.dfy) do (
echo.
echo -------------------- %%f --------------------
%DAFNY_EXE% /compile:0 /print:out.bpl.tmp /dprint:out.dfy.tmp %* %%f
diff --git a/Test/dafny1/Answer b/Test/dafny1/Answer
index ab10d944..023d80df 100644
--- a/Test/dafny1/Answer
+++ b/Test/dafny1/Answer
@@ -15,6 +15,10 @@ Dafny program verifier finished with 24 verified, 0 errors
Dafny program verifier finished with 11 verified, 0 errors
+-------------------- ExtensibleArrayAuto.dfy --------------------
+
+Dafny program verifier finished with 11 verified, 0 errors
+
-------------------- BinaryTree.dfy --------------------
Dafny program verifier finished with 24 verified, 0 errors
diff --git a/Test/dafny1/ExtensibleArrayAuto.dfy b/Test/dafny1/ExtensibleArrayAuto.dfy
new file mode 100644
index 00000000..f7f97deb
--- /dev/null
+++ b/Test/dafny1/ExtensibleArrayAuto.dfy
@@ -0,0 +1,113 @@
+class {:autocontracts} ExtensibleArray<T> {
+ ghost var Contents: seq<T>;
+
+ var elements: array<T>;
+ var more: ExtensibleArray<array<T>>;
+ var length: int;
+ var M: int; // shorthand for: if more == null then 0 else 256 * |more.Contents|
+
+ function Valid(): bool
+ {
+ // shape of data structure
+ elements != null && elements.Length == 256 &&
+ (more != null ==>
+ elements !in more.Repr &&
+ more.Valid() &&
+ |more.Contents| != 0 &&
+ forall j :: 0 <= j && j < |more.Contents| ==>
+ more.Contents[j] != null && more.Contents[j].Length == 256 &&
+ more.Contents[j] in Repr && more.Contents[j] !in more.Repr &&
+ more.Contents[j] != elements &&
+ forall k :: 0 <= k && k < |more.Contents| && k != j ==> more.Contents[j] != more.Contents[k]) &&
+
+ // length
+ M == (if more == null then 0 else 256 * |more.Contents|) &&
+ 0 <= length && length <= M + 256 &&
+ (more != null ==> M < length) &&
+
+ // Contents
+ length == |Contents| &&
+ (forall i :: 0 <= i && i < M ==> Contents[i] == more.Contents[i / 256][i % 256]) &&
+ (forall i :: M <= i && i < length ==> Contents[i] == elements[i - M])
+ }
+
+ constructor Init()
+ ensures Contents == [];
+ {
+ elements := new T[256];
+ more := null;
+ length := 0;
+ M := 0;
+
+ Contents := [];
+ }
+
+ method Get(i: int) returns (t: T)
+ requires 0 <= i && i < |Contents|;
+ ensures t == Contents[i];
+ decreases Repr;
+ {
+ if (M <= i) {
+ t := elements[i - M];
+ } else {
+ var arr := more.Get(i / 256);
+ t := arr[i % 256];
+ }
+ }
+
+ method Set(i: int, t: T)
+ requires 0 <= i && i < |Contents|;
+ ensures Contents == old(Contents)[i := t];
+ {
+ if (M <= i) {
+ elements[i - M] := t;
+ } else {
+ var arr := more.Get(i / 256);
+ arr[i % 256] := t;
+ }
+ Contents := Contents[i := t];
+ }
+
+ method Append(t: T)
+ ensures Contents == old(Contents) + [t];
+ decreases Repr;
+ {
+ if (length == 0 || length % 256 != 0) {
+ // there is room in "elements"
+ elements[length - M] := t;
+ } else {
+ if (more == null) {
+ more := new ExtensibleArray<array<T>>.Init();
+ Repr := Repr + {more} + more.Repr;
+ }
+ // "elements" is full, so move it into "more" and allocate a new array
+ more.Append(elements);
+ Repr := Repr + more.Repr;
+ M := M + 256;
+ elements := new T[256];
+ Repr := Repr + {elements};
+ elements[0] := t;
+ }
+ length := length + 1;
+ Contents := Contents + [t];
+ }
+}
+
+method Main() {
+ var a := new ExtensibleArray<int>.Init();
+ var n := 0;
+ while (n < 256*256+600)
+ invariant a.Valid() && fresh(a.Repr);
+ invariant |a.Contents| == n;
+ {
+ a.Append(n);
+ n := n + 1;
+ }
+ var k := a.Get(570); print k, "\n";
+ k := a.Get(0); print k, "\n";
+ k := a.Get(1000); print k, "\n";
+ a.Set(1000, 23);
+ k := a.Get(0); print k, "\n";
+ k := a.Get(1000); print k, "\n";
+ k := a.Get(66000); print k, "\n";
+}
diff --git a/Test/dafny1/runtest.bat b/Test/dafny1/runtest.bat
index 524765cf..0ad75ffa 100644
--- a/Test/dafny1/runtest.bat
+++ b/Test/dafny1/runtest.bat
@@ -12,7 +12,8 @@ for %%f in (BQueue.bpl) do (
%BPLEXE% %* %%f
)
-for %%f in (Queue.dfy PriorityQueue.dfy ExtensibleArray.dfy
+for %%f in (Queue.dfy PriorityQueue.dfy
+ ExtensibleArray.dfy ExtensibleArrayAuto.dfy
BinaryTree.dfy
UnboundedStack.dfy
SeparationLogicList.dfy
diff --git a/Test/houdini/Answer b/Test/houdini/Answer
index 6053b442..d7edbce6 100644
--- a/Test/houdini/Answer
+++ b/Test/houdini/Answer
@@ -9,6 +9,10 @@ Boogie program verifier finished with 1 verified, 0 errors
Assignment computed by Houdini:
b1 = False
b2 = True
+houd2.bpl(12,1): Error BP5003: A postcondition might not hold on this return path.
+houd2.bpl(9,1): Related location: This is the postcondition that might not hold.
+Execution trace:
+ houd2.bpl(11,3): anon0
Boogie program verifier finished with 1 verified, 1 error
@@ -72,6 +76,9 @@ Assignment computed by Houdini:
b1 = True
b2 = True
b3 = True
+houd9.bpl(19,3): Error BP5001: This assertion might not hold.
+Execution trace:
+ houd9.bpl(18,9): anon0
Boogie program verifier finished with 0 verified, 1 error
@@ -80,11 +87,18 @@ Assignment computed by Houdini:
b1 = True
b2 = True
b3 = True
+houd10.bpl(15,3): Error BP5002: A precondition for this call might not hold.
+houd10.bpl(20,1): Related location: This is the precondition that might not hold.
+Execution trace:
+ houd10.bpl(14,9): anon0
Boogie program verifier finished with 0 verified, 1 error
-------------------- houd11.bpl --------------------
Assignment computed by Houdini:
+houd11.bpl(8,3): Error BP5001: This assertion might not hold.
+Execution trace:
+ houd11.bpl(7,9): anon0
Boogie program verifier finished with 0 verified, 1 error
diff --git a/Test/houdini/runtest.bat b/Test/houdini/runtest.bat
index f0065b0d..b9816bb9 100644
--- a/Test/houdini/runtest.bat
+++ b/Test/houdini/runtest.bat
@@ -6,11 +6,11 @@ set BGEXE=..\..\Binaries\Boogie.exe
for %%f in (houd1.bpl houd2.bpl houd3.bpl houd4.bpl houd5.bpl houd6.bpl houd7.bpl houd8.bpl houd9.bpl houd10.bpl houd11.bpl houd12.bpl) do (
echo.
echo -------------------- %%f --------------------
- %BGEXE% %* /nologo /noinfer /contractInfer %%f
+ %BGEXE% %* /nologo /noinfer /contractInfer /printAssignment %%f
)
for %%f in (test1.bpl test2.bpl test7.bpl test8.bpl test9.bpl test10.bpl) do (
echo .
echo -------------------- %%f --------------------
- %BGEXE% %* /nologo /noinfer /contractInfer /inlineDepth:1 %%f
+ %BGEXE% %* /nologo /noinfer /contractInfer /printAssignment /inlineDepth:1 %%f
)
diff --git a/Test/vstte2012/Answer b/Test/vstte2012/Answer
index 15a95de1..bca270c3 100644
--- a/Test/vstte2012/Answer
+++ b/Test/vstte2012/Answer
@@ -11,6 +11,10 @@ Dafny program verifier finished with 25 verified, 0 errors
Dafny program verifier finished with 13 verified, 0 errors
+-------------------- RingBufferAuto.dfy --------------------
+
+Dafny program verifier finished with 13 verified, 0 errors
+
-------------------- Tree.dfy --------------------
Dafny program verifier finished with 15 verified, 0 errors
diff --git a/Test/vstte2012/RingBufferAuto.dfy b/Test/vstte2012/RingBufferAuto.dfy
new file mode 100644
index 00000000..712236a8
--- /dev/null
+++ b/Test/vstte2012/RingBufferAuto.dfy
@@ -0,0 +1,75 @@
+class {:autocontracts} RingBuffer<T>
+{
+ // public view of the class:
+ ghost var Contents: seq<T>; // the contents of the ring buffer
+ ghost var N: nat; // the capacity of the ring buffer
+
+ // private implementation:
+ var data: array<T>;
+ var first: nat;
+ var len: nat;
+
+ // Valid encodes the consistency of RingBuffer objects (think, invariant)
+ predicate Valid
+ {
+ data != null &&
+ data.Length == N &&
+ (N == 0 ==> len == first == 0 && Contents == []) &&
+ (N != 0 ==> len <= N && first < N) &&
+ Contents == if first + len <= N then data[first..first+len]
+ else data[first..] + data[..first+len-N]
+ }
+
+ constructor Create(n: nat)
+ ensures Contents == [] && N == n;
+ {
+ data := new T[n];
+ first, len := 0, 0;
+ Contents, N := [], n;
+ }
+
+ method Clear()
+ ensures Contents == [] && N == old(N);
+ {
+ len := 0;
+ Contents := [];
+ }
+
+ method Head() returns (x: T)
+ requires Contents != [];
+ ensures x == Contents[0];
+ {
+ x := data[first];
+ }
+
+ method Enqueue(x: T)
+ requires |Contents| != N;
+ ensures Contents == old(Contents) + [x] && N == old(N);
+ {
+ var nextEmpty := if first + len < data.Length
+ then first + len else first + len - data.Length;
+ data[nextEmpty] := x;
+ len := len + 1;
+ Contents := Contents + [x];
+ }
+
+ method Dequeue() returns (x: T)
+ requires Contents != [];
+ ensures x == old(Contents)[0] && Contents == old(Contents)[1..] && N == old(N);
+ {
+ x := data[first];
+ first, len := if first + 1 == data.Length then 0 else first + 1, len - 1;
+ Contents := Contents[1..];
+ }
+}
+
+method TestHarness(x: int, y: int, z: int)
+{
+ var b := new RingBuffer.Create(2);
+ b.Enqueue(x);
+ b.Enqueue(y);
+ var h := b.Dequeue(); assert h == x;
+ b.Enqueue(z);
+ h := b.Dequeue(); assert h == y;
+ h := b.Dequeue(); assert h == z;
+}
diff --git a/Test/vstte2012/runtest.bat b/Test/vstte2012/runtest.bat
index 5145cb56..770f41dc 100644
--- a/Test/vstte2012/runtest.bat
+++ b/Test/vstte2012/runtest.bat
@@ -8,7 +8,7 @@ set CSC=c:/Windows/Microsoft.NET/Framework/v4.0.30319/csc.exe
for %%f in (
Two-Way-Sort.dfy
Combinators.dfy
- RingBuffer.dfy
+ RingBuffer.dfy RingBufferAuto.dfy
Tree.dfy
BreadthFirstSearch.dfy
) do (
diff --git a/_admin/Boogie/aste/summary.log b/_admin/Boogie/aste/summary.log
index 312f9ab6..f4940f9e 100644
--- a/_admin/Boogie/aste/summary.log
+++ b/_admin/Boogie/aste/summary.log
@@ -1,30 +1,29 @@
-# Aste started: 2012-02-26 07:00:08
+# Aste started: 2012-03-11 07:00:07
# Host id: Boogiebox
# Configuration: boogie.cfg
# Task: aste.tasks.boogie.FullBuild
-# [2012-02-26 07:03:15] SpecSharp revision: d97f82db382a
-# [2012-02-26 07:03:15] SscBoogie revision: d97f82db382a
-# [2012-02-26 07:05:14] Boogie revision: 7b344fd70ce1
-[2012-02-26 07:06:58] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com SpecSharp.sln /Project "Checkin Tests" /Build
+# [2012-03-11 07:03:34] SpecSharp revision: 25f96c711498
+# [2012-03-11 07:03:34] SscBoogie revision: 25f96c711498
+# [2012-03-11 07:05:51] Boogie revision: 8e5f22ac87cf
+[2012-03-11 07:07:31] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com SpecSharp.sln /Project "Checkin Tests" /Build
1>corflags : warning CF011: The specified file is strong name signed. Using /Force will invalidate the signature of this image and will require the assembly to be resigned.
warning CF011: The specified file is strong name signed. Using /Force will invalidate the signature of this image and will require the assembly to be resigned.
-[2012-02-26 07:08:17] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
+[2012-03-11 07:09:01] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
D:\Temp\aste\Boogie\Source\Core\AbsyType.cs(823,16): warning CS0659: 'Microsoft.Boogie.BasicType' overrides Object.Equals(object o) but does not override Object.GetHashCode()
D:\Temp\aste\Boogie\Source\Core\AbsyType.cs(2802,16): warning CS0659: 'Microsoft.Boogie.CtorType' overrides Object.Equals(object o) but does not override Object.GetHashCode()
D:\Temp\aste\Boogie\Source\Core\OOLongUtil.cs(109,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\Core\Absy.cs(708,7): warning CC1036: Detected call to method 'Graphing.Graph`1<Microsoft.Boogie.Block>.TopologicalSort' without [Pure] in contracts of method 'Microsoft.Boogie.Program.GraphFromImpl(Microsoft.Boogie.Implementation)'.
EXEC : warning CC1079: Type Microsoft.Boogie.Variable implements Microsoft.AbstractInterpretationFramework.IVariable.get_Name by inheriting Microsoft.Boogie.NamedDeclaration.get_Name causing the interface contract to not be checked at runtime. Consider adding a wrapper method.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(112,3): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Resolve(Microsoft.Boogie.ResolutionContext)' overrides 'Microsoft.Boogie.Absy.Resolve(Microsoft.Boogie.ResolutionContext)', thus cannot add Requires.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(117,5): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)' overrides 'Microsoft.Boogie.Expr.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)', thus cannot add Requires.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(120,74): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(115,3): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Resolve(Microsoft.Boogie.ResolutionContext)' overrides 'Microsoft.Boogie.Absy.Resolve(Microsoft.Boogie.ResolutionContext)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(120,5): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)' overrides 'Microsoft.Boogie.Expr.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(123,74): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)', thus cannot add Requires.
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(247,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(266,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\IntervalDomain.cs(49,9): warning CC1036: Detected call to method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.StrictlyBefore(Microsoft.Boogie.Variable,Microsoft.Boogie.Variable)' without [Pure] in contracts of method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.#ctor(Microsoft.Boogie.Variable,System.Nullable`1<System.Numerics.BigInteger>,System.Nullable`1<System.Numerics.BigInteger>,Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node)'.
- D:\Temp\aste\Boogie\Source\VCGeneration\VC.cs(1733,11): warning CS0162: Unreachable code detected
- D:\Temp\aste\Boogie\Source\VCGeneration\VC.cs(1894,11): warning CS0162: Unreachable code detected
- D:\Temp\aste\Boogie\Source\VCGeneration\StratifiedVC.cs(1099,17): warning CC1032: Method 'VC.StratifiedVCGen+NormalChecker.CheckVC' overrides 'VC.StratifiedVCGen+StratifiedCheckerInterface.CheckVC', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\VCGeneration\VC.cs(1717,11): warning CS0162: Unreachable code detected
+ D:\Temp\aste\Boogie\Source\VCGeneration\VC.cs(1878,11): warning CS0162: Unreachable code detected
EXEC : warning CC1032: Method 'Microsoft.Boogie.Houdini.InlineRequiresVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)' overrides 'Microsoft.Boogie.StandardVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)', thus cannot add Requires.
EXEC : warning CC1032: Method 'Microsoft.Boogie.Houdini.FreeRequiresVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)' overrides 'Microsoft.Boogie.StandardVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)', thus cannot add Requires.
warning CS0659: 'Microsoft.Boogie.BasicType' overrides Object.Equals(object o) but does not override Object.GetHashCode()
@@ -40,8 +39,7 @@
warning CC1036: Detected call to method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.StrictlyBefore(Microsoft.Boogie.Variable,Microsoft.Boogie.Variable)' without [Pure] in contracts of method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.#ctor(Microsoft.Boogie.Variable,System.Nullable`1<System.Numerics.BigInteger>,System.Nullable`1<System.Numerics.BigInteger>,Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node)'.
warning CS0162: Unreachable code detected
warning CS0162: Unreachable code detected
- warning CC1032: Method 'VC.StratifiedVCGen+NormalChecker.CheckVC' overrides 'VC.StratifiedVCGen+StratifiedCheckerInterface.CheckVC', thus cannot add Requires.
warning CC1032: Method 'Microsoft.Boogie.Houdini.InlineRequiresVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)' overrides 'Microsoft.Boogie.StandardVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)', thus cannot add Requires.
warning CC1032: Method 'Microsoft.Boogie.Houdini.FreeRequiresVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)' overrides 'Microsoft.Boogie.StandardVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)', thus cannot add Requires.
-[2012-02-26 08:06:27] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
-# [2012-02-26 08:07:08] Released nightly of Boogie
+[2012-03-11 08:06:42] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
+# [2012-03-11 08:07:25] Released nightly of Boogie