summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore3
-rw-r--r--.hgtags1
-rw-r--r--BCT/BCT.sln71
-rw-r--r--BCT/BytecodeTranslator/ExpressionTraverser.cs208
-rw-r--r--BCT/BytecodeTranslator/Heap.cs49
-rw-r--r--BCT/BytecodeTranslator/HeapFactory.cs207
-rw-r--r--BCT/BytecodeTranslator/Program.cs115
-rw-r--r--BCT/BytecodeTranslator/Sink.cs13
-rw-r--r--BCT/BytecodeTranslator/StatementTraverser.cs26
-rw-r--r--BCT/BytecodeTranslator/WholeProgram.cs2
-rw-r--r--Chalice/build.sbt2
-rw-r--r--Chalice/chalice.bat9
-rw-r--r--Chalice/src/main/scala/Ast.scala163
-rw-r--r--Chalice/src/main/scala/Boogie.scala10
-rw-r--r--Chalice/src/main/scala/Chalice.scala184
-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.scala15
-rw-r--r--Chalice/src/main/scala/Translator.scala1107
-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.txt4
-rw-r--r--Chalice/tests/predicates/framing-fields.chalice24
-rw-r--r--Chalice/tests/predicates/framing-fields.output.txt5
-rw-r--r--Chalice/tests/predicates/framing-functions.chalice25
-rw-r--r--Chalice/tests/predicates/framing-functions.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/setset.chalice57
-rw-r--r--Chalice/tests/predicates/setset.output.txt8
-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/predicates/unfolding.chalice31
-rw-r--r--Chalice/tests/predicates/unfolding.output.txt5
-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/internal-bug-2.chalice13
-rw-r--r--Chalice/tests/regressions/internal-bug-2.output.txt8
-rw-r--r--Chalice/tests/regressions/internal-bug-3.chalice8
-rw-r--r--Chalice/tests/regressions/internal-bug-3.output.txt4
-rw-r--r--Chalice/tests/regressions/workitem-10194.output.txt3
-rw-r--r--Chalice/tests/runalltests.bat4
-rw-r--r--Jennisys/Jennisys.sln3
-rw-r--r--Jennisys/Jennisys/Analyzer.fs110
-rw-r--r--Jennisys/Jennisys/AstUtils.fs16
-rw-r--r--Jennisys/Jennisys/CodeGen.fs72
-rw-r--r--Jennisys/Jennisys/DafnyModelUtils.fs24
-rw-r--r--Jennisys/Jennisys/FixpointSolver.fs4
-rw-r--r--Jennisys/Jennisys/Jennisys.fsproj5
-rw-r--r--Jennisys/Jennisys/Options.fs1
-rw-r--r--Jennisys/Jennisys/Utils.fs8
-rw-r--r--Jennisys/Jennisys/examples/DList.jen63
-rw-r--r--Jennisys/Jennisys/examples/mod2/jennisys-synth_DList.dfy255
-rw-r--r--Source/Boogie.sln83
-rw-r--r--Source/BoogieDriver/BoogieDriver.cs371
-rw-r--r--Source/BoogieDriver/BoogieDriver.csproj12
-rw-r--r--Source/Core/Absy.cs31
-rw-r--r--Source/Core/AbsyCmd.cs1
-rw-r--r--Source/Core/AbsyType.cs4
-rw-r--r--Source/Core/BoogiePL.atg48
-rw-r--r--Source/Core/CommandLineOptions.cs18
-rw-r--r--Source/Core/Parser.cs40
-rw-r--r--Source/Core/Scanner.cs204
-rw-r--r--Source/Dafny/Compiler.cs53
-rw-r--r--Source/Dafny/Dafny.atg243
-rw-r--r--Source/Dafny/DafnyAst.cs318
-rw-r--r--Source/Dafny/DafnyPipeline.csproj1
-rw-r--r--Source/Dafny/Parser.cs1377
-rw-r--r--Source/Dafny/Printer.cs189
-rw-r--r--Source/Dafny/RefinementTransformer.cs402
-rw-r--r--Source/Dafny/Resolver.cs311
-rw-r--r--Source/Dafny/Rewriter.cs321
-rw-r--r--Source/Dafny/Scanner.cs370
-rw-r--r--Source/Dafny/Translator.cs50
-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/CommandLineOptions.cs50
-rw-r--r--Source/GPUVerify/CrossThreadInvariantProcessor.cs124
-rw-r--r--Source/GPUVerify/ElementEncodingRaceInstrumenter.cs62
-rw-r--r--Source/GPUVerify/EnabledToPredicateVisitor.cs39
-rw-r--r--Source/GPUVerify/EnsureDisabledThreadHasNoEffectInstrumenter.cs94
-rw-r--r--Source/GPUVerify/GPUVerifier.cs1178
-rw-r--r--Source/GPUVerify/GPUVerify.csproj15
-rw-r--r--Source/GPUVerify/IRaceInstrumenter.cs8
-rw-r--r--Source/GPUVerify/KernelDualiser.cs403
-rw-r--r--Source/GPUVerify/LiveVariableAnalyser.cs124
-rw-r--r--Source/GPUVerify/LoopInvariantGenerator.cs323
-rw-r--r--Source/GPUVerify/Main.cs6
-rw-r--r--Source/GPUVerify/MayBePowerOfTwoAnalyser.cs241
-rw-r--r--Source/GPUVerify/MayBeTidAnalyser.cs220
-rw-r--r--Source/GPUVerify/MayBeTidPlusConstantAnalyser.cs258
-rw-r--r--Source/GPUVerify/NullRaceInstrumenter.cs17
-rw-r--r--Source/GPUVerify/Predicator.cs354
-rw-r--r--Source/GPUVerify/RaceInstrumenterBase.cs276
-rw-r--r--Source/GPUVerify/SetEncodingRaceInstrumenter.cs28
-rw-r--r--Source/GPUVerify/StructuredProgramVisitor.cs160
-rw-r--r--Source/GPUVerify/UniformExpressionAnalysisVisitor.cs39
-rw-r--r--Source/GPUVerify/UniformityAnalyser.cs332
-rw-r--r--Source/GPUVerify/VariableDualiser.cs40
-rw-r--r--Source/GPUVerify/VariablesOccurringInExpressionVisitor.cs26
-rw-r--r--Source/Houdini/Checker.cs43
-rw-r--r--Source/Houdini/Houdini.cs466
-rw-r--r--Source/Houdini/Houdini.csproj8
-rw-r--r--Source/Model/Model.cs6
-rw-r--r--Source/ModelViewer/ModelViewer.csproj8
-rw-r--r--Source/ModelViewer/VccProvider.cs46
-rw-r--r--Source/Provers/SMTLib/Inspector.cs1
-rw-r--r--Source/Provers/SMTLib/ProverInterface.cs199
-rw-r--r--Source/Provers/SMTLib/SMTLib.csproj4
-rw-r--r--Source/Provers/SMTLib/SMTLibNamer.cs6
-rw-r--r--Source/Provers/SMTLib/SMTLibProverOptions.cs6
-rw-r--r--Source/Provers/SMTLib/TypeDeclCollector.cs27
-rw-r--r--Source/Provers/SMTLib/Z3.cs6
-rw-r--r--Source/Provers/TPTP/TPTP.csproj4
-rw-r--r--Source/Provers/Z3api/ProverLayer.cs153
-rw-r--r--Source/Provers/Z3api/Z3api.csproj8
-rw-r--r--Source/VCGeneration/Check.cs57
-rw-r--r--Source/VCGeneration/StratifiedVC.cs491
-rw-r--r--Source/VCGeneration/VC.cs82
-rw-r--r--Source/VCGeneration/Wlp.cs18
-rw-r--r--Test/alltests.txt12
-rw-r--r--Test/dafny0/Answer176
-rw-r--r--Test/dafny0/LetExpr.dfy40
-rw-r--r--Test/dafny0/NoTypeArgs.dfy82
-rw-r--r--Test/dafny0/ParallelResolveErrors.dfy7
-rw-r--r--Test/dafny0/Refinement.dfy39
-rw-r--r--Test/dafny0/RefinementErrors.dfy2
-rw-r--r--Test/dafny0/ResolutionErrors.dfy37
-rw-r--r--Test/dafny0/Skeletons.dfy63
-rw-r--r--Test/dafny0/SmallTests.dfy68
-rw-r--r--Test/dafny0/runtest.bat5
-rw-r--r--Test/dafny1/Answer4
-rw-r--r--Test/dafny1/ExtensibleArrayAuto.dfy113
-rw-r--r--Test/dafny1/runtest.bat3
-rw-r--r--Test/dafny2/Answer4
-rw-r--r--Test/dafny2/StoreAndRetrieve.dfy72
-rw-r--r--Test/dafny2/runtest.bat1
-rw-r--r--Test/houdini/Answer14
-rw-r--r--Test/houdini/runtest.bat4
-rw-r--r--Test/test0/Answer6
-rw-r--r--Test/test0/AttributeParsing.bpl13
-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
-rw-r--r--_admin/Chalice/aste/summary.log12
173 files changed, 10844 insertions, 4416 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/.hgtags b/.hgtags
index de9a92e1..50119793 100644
--- a/.hgtags
+++ b/.hgtags
@@ -12,3 +12,4 @@ f5c14add09d2f57402c94574eeef490d900d58e8 emicvccbld_build_2.1.31109.0
a25a1feb48848a6cac9ab0fd6480871ad5e9a881 emicvccbld_build_2.1.31116.0
e2af2d88d523eebe5e183839ed9d32c9d5ace55a emicvccbld_build_2.1.31203.0
019becd8203f71f3f28368f87e14421cba209b3b emicvccbld_build_2.1.31207.0
+4afa7ea66506aed88223d4236cb3d7cff870abf8 emicvccbld_build_2.1.40227.0
diff --git a/BCT/BCT.sln b/BCT/BCT.sln
index c8c132bb..27b91c01 100644
--- a/BCT/BCT.sln
+++ b/BCT/BCT.sln
@@ -18,8 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TranslationPlugins", "TranslationPlugins\TranslationPlugins.csproj", "{8C242D42-9714-440F-884D-F64F09E78C7B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssertionInjector", "GetMeHere\AssertionInjector\AssertionInjector.csproj", "{F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeModel", "..\..\CCICodeBox\CoreObjectModel\CodeModel\CodeModel.csproj", "{035FEA7F-0D36-4AE4-B694-EC45191B9AF2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContractExtractor", "..\..\CCICodeBox\Converters\ContractExtractor\ContractExtractor.csproj", "{0703D916-A881-45E6-A5CD-6BC50E2E30E2}"
@@ -54,9 +52,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILGarbageCollect", "..\..\C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlAndDataFlowGraph", "..\..\ccicodebox\CodeGenerators\ControlAndDataFlowGraph\ControlAndDataFlowGraph.csproj", "{2596EFB0-87AE-42CE-89EB-84F35D6350D2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewILToCodeModel", "..\..\CCICodeBox\Converters\NewILToCodeModel\NewILToCodeModel.csproj", "{A555D4CB-F16F-4049-A8CF-180B8A05C755}"
+EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
- SccNumberOfProjects = 17
+ SccNumberOfProjects = 18
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http://vstfcodebox:8080/tfs/psi
SccProjectUniqueName0 = ..\\..\\CCICodeBox\\CoreObjectModel\\CodeModel\\CodeModel.csproj
@@ -144,6 +144,11 @@ Global
SccAuxPath16 = http://vstfcodebox:8080/tfs/psi
SccLocalPath16 = ..\\..\\ccicodebox\\CodeGenerators\\ControlAndDataFlowGraph
SccProvider16 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
+ SccProjectUniqueName17 = ..\\..\\ccicodebox\\Converters\\NewILToCodeModel\\NewILToCodeModel.csproj
+ SccProjectName17 = $/cci/Converters/NewILToCodeModel
+ SccAuxPath17 = http://vstfcodebox:8080/tfs/psi
+ SccLocalPath17 = ..\\..\\ccicodebox\\Converters\\NewILToCodeModel
+ SccProvider17 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = BCT.vsmdi
@@ -289,36 +294,6 @@ Global
{8C242D42-9714-440F-884D-F64F09E78C7B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8C242D42-9714-440F-884D-F64F09E78C7B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8C242D42-9714-440F-884D-F64F09E78C7B}.Release|x86.ActiveCfg = Release|Any CPU
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.CompilerOnly|Any CPU.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.CompilerOnly|Mixed Platforms.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.CompilerOnly|Mixed Platforms.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.CompilerOnly|x86.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.CompilerOnly|x86.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Debug|Any CPU.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Debug|Mixed Platforms.Build.0 = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Debug|x86.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Debug|x86.Build.0 = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.FastpathSim|Any CPU.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.FastpathSim|Mixed Platforms.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.FastpathSim|Mixed Platforms.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.FastpathSim|x86.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.FastpathSim|x86.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyDebug|Any CPU.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyDebug|Mixed Platforms.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyDebug|Mixed Platforms.Build.0 = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyDebug|x86.ActiveCfg = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyDebug|x86.Build.0 = Debug|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyRelease|Any CPU.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyRelease|Mixed Platforms.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyRelease|Mixed Platforms.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyRelease|x86.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.NightlyRelease|x86.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Release|Any CPU.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Release|Mixed Platforms.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Release|Mixed Platforms.Build.0 = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Release|x86.ActiveCfg = Release|x86
- {F55B9215-F618-4DCD-AD4C-2DB72CAE5A99}.Release|x86.Build.0 = Release|x86
{035FEA7F-0D36-4AE4-B694-EC45191B9AF2}.CompilerOnly|Any CPU.ActiveCfg = Release|Any CPU
{035FEA7F-0D36-4AE4-B694-EC45191B9AF2}.CompilerOnly|Any CPU.Build.0 = Release|Any CPU
{035FEA7F-0D36-4AE4-B694-EC45191B9AF2}.CompilerOnly|Mixed Platforms.ActiveCfg = Release|Any CPU
@@ -829,6 +804,36 @@ Global
{2596EFB0-87AE-42CE-89EB-84F35D6350D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2596EFB0-87AE-42CE-89EB-84F35D6350D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2596EFB0-87AE-42CE-89EB-84F35D6350D2}.Release|x86.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.CompilerOnly|Any CPU.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.CompilerOnly|Any CPU.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.CompilerOnly|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.CompilerOnly|Mixed Platforms.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.CompilerOnly|x86.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.FastpathSim|Any CPU.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.FastpathSim|Any CPU.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.FastpathSim|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.FastpathSim|Mixed Platforms.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.FastpathSim|x86.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyDebug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyDebug|Any CPU.Build.0 = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyDebug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyDebug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyDebug|x86.ActiveCfg = Debug|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyRelease|Any CPU.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyRelease|Any CPU.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyRelease|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyRelease|Mixed Platforms.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.NightlyRelease|x86.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {A555D4CB-F16F-4049-A8CF-180B8A05C755}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/BCT/BytecodeTranslator/ExpressionTraverser.cs b/BCT/BytecodeTranslator/ExpressionTraverser.cs
index aa4141e2..a9e1f9b0 100644
--- a/BCT/BytecodeTranslator/ExpressionTraverser.cs
+++ b/BCT/BytecodeTranslator/ExpressionTraverser.cs
@@ -326,27 +326,18 @@ namespace BytecodeTranslator
var boogieT = this.sink.CciTypeToBoogie(t);
if (t is IGenericParameterReference) {
- if (boogieT == this.sink.Heap.BoxType) {
+ if (boogieT == this.sink.Heap.UnionType) {
// then the expression will be represented by something of type Box
// but the address of it must be a ref, so do the conversion
this.Traverse(addressOf.Expression);
var e = this.TranslatedExpressions.Pop();
- this.TranslatedExpressions.Push(this.sink.Heap.Unbox(addressOf.Token(), this.sink.Heap.RefType, e));
+ this.TranslatedExpressions.Push(this.sink.Heap.FromUnion(addressOf.Token(), this.sink.Heap.RefType, e));
} else {
this.Traverse(addressOf.Expression);
}
} else {
this.Traverse(addressOf.Expression);
return;
- // TODO: Sometimes the value must still be boxed: for anythign that is not going to be represented as a Ref in Boogie!
- //this.Traverse(addressOf.Expression);
- //var e = this.TranslatedExpressions.Pop();
-
- //Bpl.Variable a = this.sink.CreateFreshLocal(addressOf.Type);
- //this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(Bpl.Token.NoToken, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
- //this.StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(Bpl.Token.NoToken, Bpl.Expr.Ident(a), Bpl.Expr.Ident(this.sink.Heap.BoxField), e, AccessType.Heap, boogieT));
- //this.TranslatedExpressions.Push(Bpl.Expr.Ident(a));
-
}
}
#endregion
@@ -481,8 +472,8 @@ namespace BytecodeTranslator
e = lit;
} else if (bplType == this.sink.Heap.RefType) {
e = Bpl.Expr.Ident(this.sink.Heap.NullRef);
- } else if (bplType == this.sink.Heap.BoxType) {
- e = Bpl.Expr.Ident(this.sink.Heap.DefaultBox);
+ } else if (bplType == this.sink.Heap.UnionType) {
+ e = Bpl.Expr.Ident(this.sink.Heap.DefaultHeapValue);
} else if (bplType == this.sink.Heap.RealType) {
e = Bpl.Expr.Ident(this.sink.Heap.DefaultReal);
} else {
@@ -554,7 +545,7 @@ namespace BytecodeTranslator
List<Bpl.Expr> inexpr;
List<Bpl.IdentifierExpr> outvars;
Bpl.IdentifierExpr thisExpr;
- Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toBoxed;
var proc = TranslateArgumentsAndReturnProcedure(methodCallToken, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
string methodname = proc.Name;
var translateAsFunctionCall = proc is Bpl.Function;
@@ -596,6 +587,7 @@ namespace BytecodeTranslator
this.TranslatedExpressions.Push(callFunction);
return;
} else {
+ EmitLineDirective(methodCallToken);
if (attrib != null)
call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars, attrib);
else
@@ -604,8 +596,20 @@ namespace BytecodeTranslator
}
}
- foreach (KeyValuePair<Bpl.IdentifierExpr, Bpl.IdentifierExpr> kv in toBoxed) {
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(kv.Key, this.sink.Heap.Unbox(Bpl.Token.NoToken, kv.Key.Type, kv.Value)));
+ foreach (KeyValuePair<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> kv in toBoxed) {
+ var lhs = kv.Key;
+ var tuple = kv.Value;
+ var rhs = tuple.Item1;
+ Bpl.Expr fromUnion;
+ if (tuple.Item2) {
+ // Since both structs and objects are represented by "Ref", need to make a distinction here.
+ // Review: Introduce an explicit type "Struct"?
+ fromUnion = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Union2Struct), new Bpl.ExprSeq(rhs));
+ } else {
+ fromUnion = this.sink.Heap.FromUnion(Bpl.Token.NoToken, lhs.Type, rhs);
+ //this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(lhs, this.sink.Heap.FromUnion(Bpl.Token.NoToken, lhs.Type, rhs)));
+ }
+ this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(lhs, fromUnion));
}
Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef));
@@ -630,6 +634,17 @@ namespace BytecodeTranslator
}
}
+ private void EmitLineDirective(Bpl.IToken methodCallToken) {
+ var sloc = this.StmtTraverser.lastSourceLocation;
+ if (sloc != null) {
+ var fileName = sloc.Document.Location;
+ var lineNumber = sloc.StartLine;
+ var attrib = new Bpl.QKeyValue(methodCallToken, "sourceLine", new List<object> { Bpl.Expr.Literal((int)lineNumber) }, null);
+ attrib = new Bpl.QKeyValue(methodCallToken, "sourceFile", new List<object> { fileName }, attrib);
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.AssertCmd(methodCallToken, Bpl.Expr.True, attrib));
+ }
+ }
+
private Bpl.CallCmd translateAddRemoveCall(IMethodCall methodCall, IMethodDefinition resolvedMethod, Bpl.IToken methodCallToken, List<Bpl.Expr> inexpr, List<Bpl.IdentifierExpr> outvars, Bpl.IdentifierExpr thisExpr, bool isEventAdd) {
Bpl.CallCmd call;
var mName = resolvedMethod.Name.Value;
@@ -670,6 +685,7 @@ namespace BytecodeTranslator
this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(thisExpr)));
// Second, generate the call to the appropriate ctor
+ EmitLineDirective(methodCallToken);
this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(methodCallToken, proc.Name, inexpr, outvars));
// Generate an assumption about the dynamic type of the just allocated object
@@ -684,7 +700,7 @@ namespace BytecodeTranslator
}
// REVIEW: Does "thisExpr" really need to come back as an identifier? Can't it be a general expression?
- protected Bpl.DeclWithFormals TranslateArgumentsAndReturnProcedure(Bpl.IToken token, IMethodReference methodToCall, IMethodDefinition resolvedMethod, IExpression/*?*/ thisArg, IEnumerable<IExpression> arguments, out List<Bpl.Expr> inexpr, out List<Bpl.IdentifierExpr> outvars, out Bpl.IdentifierExpr thisExpr, out Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed) {
+ protected Bpl.DeclWithFormals TranslateArgumentsAndReturnProcedure(Bpl.IToken token, IMethodReference methodToCall, IMethodDefinition resolvedMethod, IExpression/*?*/ thisArg, IEnumerable<IExpression> arguments, out List<Bpl.Expr> inexpr, out List<Bpl.IdentifierExpr> outvars, out Bpl.IdentifierExpr thisExpr, out Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toUnioned) {
inexpr = new List<Bpl.Expr>();
outvars = new List<Bpl.IdentifierExpr>();
@@ -718,7 +734,7 @@ namespace BytecodeTranslator
}
#endregion
- toBoxed = new Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr>();
+ toUnioned = new Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>>();
IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator();
penum.MoveNext();
foreach (IExpression exp in arguments) {
@@ -755,9 +771,16 @@ namespace BytecodeTranslator
e = bplLocal;
}
- if (currentType is IGenericParameterReference && this.sink.CciTypeToBoogie(currentType) == this.sink.Heap.BoxType)
- inexpr.Add(sink.Heap.Box(token, this.sink.CciTypeToBoogie(expressionToTraverse.Type), e));
- else {
+ if (currentType is IGenericParameterReference && this.sink.CciTypeToBoogie(currentType) == this.sink.Heap.UnionType) {
+ if (TranslationHelper.IsStruct(expressionToTraverse.Type)) {
+ // Since both structs and objects are represented by "Ref", need to make a distinction here.
+ // Review: Introduce an explicit type "Struct"?
+ var toUnion = new Bpl.NAryExpr(token, new Bpl.FunctionCall(this.sink.Heap.Struct2Union), new Bpl.ExprSeq(e));
+ inexpr.Add(toUnion);
+ } else {
+ inexpr.Add(sink.Heap.ToUnion(token, this.sink.CciTypeToBoogie(expressionToTraverse.Type), e));
+ }
+ } else {
inexpr.Add(e);
}
if (penum.Current.IsByReference) {
@@ -767,9 +790,9 @@ namespace BytecodeTranslator
}
if (penum.Current.Type is IGenericParameterReference) {
var boogieType = this.sink.CciTypeToBoogie(penum.Current.Type);
- if (boogieType == this.sink.Heap.BoxType) {
- Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(sink.CreateFreshLocal(this.sink.Heap.BoxType));
- toBoxed[unboxed] = boxed;
+ if (boogieType == this.sink.Heap.UnionType) {
+ Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(sink.CreateFreshLocal(this.sink.Heap.UnionType));
+ toUnioned[unboxed] = Tuple.Create(boxed,false);
outvars.Add(boxed);
} else {
outvars.Add(unboxed);
@@ -800,20 +823,20 @@ namespace BytecodeTranslator
if (!translateAsFunctionCall) {
if (resolvedMethod.Type.ResolvedType.TypeCode != PrimitiveTypeCode.Void) {
Bpl.Variable v = this.sink.CreateFreshLocal(methodToCall.ResolvedMethod.Type.ResolvedType);
- Bpl.IdentifierExpr unboxed = new Bpl.IdentifierExpr(token, v);
+ Bpl.IdentifierExpr unUnioned = new Bpl.IdentifierExpr(token, v);
if (resolvedMethod.Type is IGenericParameterReference) {
var boogieType = this.sink.CciTypeToBoogie(resolvedMethod.Type);
- if (boogieType == this.sink.Heap.BoxType) {
- Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(this.sink.CreateFreshLocal(this.sink.Heap.BoxType));
- toBoxed[unboxed] = boxed;
- outvars.Add(boxed);
+ if (boogieType == this.sink.Heap.UnionType) {
+ Bpl.IdentifierExpr unioned = Bpl.Expr.Ident(this.sink.CreateFreshLocal(this.sink.Heap.UnionType));
+ toUnioned[unUnioned] = Tuple.Create(unioned, TranslationHelper.IsStruct(methodToCall.ResolvedMethod.Type.ResolvedType));
+ outvars.Add(unioned);
} else {
- outvars.Add(unboxed);
+ outvars.Add(unUnioned);
}
} else {
- outvars.Add(unboxed);
+ outvars.Add(unUnioned);
}
- TranslatedExpressions.Push(unboxed);
+ TranslatedExpressions.Push(unUnioned);
}
}
@@ -882,6 +905,8 @@ namespace BytecodeTranslator
}
Bpl.Cmd cmd;
+ EmitLineDirective(tok);
+
var/*?*/ local = container as ILocalDefinition;
if (local != null) {
Contract.Assume(instance == null);
@@ -1025,9 +1050,12 @@ namespace BytecodeTranslator
List<Bpl.Expr> inexpr;
List<Bpl.IdentifierExpr> outvars;
Bpl.IdentifierExpr thisExpr;
- Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toBoxed;
var proc = TranslateArgumentsAndReturnProcedure(token, ctor, resolvedMethod, null, createObjectInstance.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
inexpr.Insert(0, Bpl.Expr.Ident(a));
+
+ EmitLineDirective(token);
+
this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(token, proc.Name, inexpr, outvars));
// Generate an assumption about the dynamic type of the just allocated object
@@ -1574,7 +1602,8 @@ namespace BytecodeTranslator
this.Traverse(conversion.ValueToConvert);
var boogieTypeOfValue = this.sink.CciTypeToBoogie(conversion.ValueToConvert.Type);
var boogieTypeToBeConvertedTo = this.sink.CciTypeToBoogie(conversion.TypeAfterConversion);
- if (boogieTypeOfValue == boogieTypeToBeConvertedTo) {
+ if (boogieTypeOfValue == boogieTypeToBeConvertedTo && !TranslationHelper.IsStruct(conversion.ValueToConvert.Type)
+ && !TranslationHelper.IsStruct(conversion.TypeAfterConversion)) {
// then this conversion is a nop, just ignore it
return;
}
@@ -1584,20 +1613,44 @@ namespace BytecodeTranslator
var exp = TranslatedExpressions.Pop();
+ if (boogieTypeOfValue == this.sink.Heap.UnionType && boogieTypeToBeConvertedTo != this.sink.Heap.RefType) {
+ var e = this.sink.Heap.FromUnion(tok, boogieTypeToBeConvertedTo, exp);
+ TranslatedExpressions.Push(e);
+ return;
+ }
+ if (boogieTypeToBeConvertedTo == this.sink.Heap.UnionType) {
+ Bpl.Expr e;
+ if (boogieTypeOfValue == this.sink.Heap.RefType)
+ e = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Union), new Bpl.ExprSeq(exp));
+ else
+ e = this.sink.Heap.ToUnion(tok, boogieTypeOfValue, exp);
+ TranslatedExpressions.Push(e);
+ return;
+ }
+
+ if (boogieTypeToBeConvertedTo == this.sink.Heap.RefType &&
+ TranslationHelper.IsStruct(conversion.TypeAfterConversion) &&
+ boogieTypeOfValue == this.sink.Heap.RefType) {
+ // REVIEW: This also applies to conversions from one struct type to another!
+ var e = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Struct), new Bpl.ExprSeq(exp));
+ TranslatedExpressions.Push(e);
+ return;
+ }
+
if (boogieTypeToBeConvertedTo == Bpl.Type.Bool) {
Bpl.Expr expr;
if (boogieTypeOfValue == Bpl.Type.Int) {
expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, exp, Bpl.Expr.Literal(0));
}
else if (boogieTypeOfValue == this.sink.Heap.RefType) {
- expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, exp, Bpl.Expr.Ident(this.sink.Heap.NullRef));
+ expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Bool), new Bpl.ExprSeq(exp));
}
else if (boogieTypeOfValue == this.sink.Heap.RealType) {
expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Real2Int), new Bpl.ExprSeq(exp));
expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, expr, Bpl.Expr.Literal(0));
}
- else if (boogieTypeOfValue == this.sink.Heap.BoxType) {
- expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Box2Bool), new Bpl.ExprSeq(exp));
+ else if (boogieTypeOfValue == this.sink.Heap.UnionType) {
+ expr = this.sink.Heap.FromUnion(tok, Bpl.Type.Bool, exp);
}
else {
throw new NotImplementedException(msg);
@@ -1612,13 +1665,13 @@ namespace BytecodeTranslator
expr = new Bpl.NAryExpr(tok, new Bpl.IfThenElse(tok), new Bpl.ExprSeq(exp, Bpl.Expr.Literal(1), Bpl.Expr.Literal(0)));
}
else if (boogieTypeOfValue == this.sink.Heap.RefType) {
- expr = this.sink.Heap.ReadHeap(exp, Bpl.Expr.Ident(this.sink.Heap.BoxField), AccessType.Heap, Bpl.Type.Int);
+ expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Int), new Bpl.ExprSeq(exp));
}
else if (boogieTypeOfValue == this.sink.Heap.RealType) {
expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Real2Int), new Bpl.ExprSeq(exp));
}
- else if (boogieTypeOfValue == this.sink.Heap.BoxType) {
- expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Box2Int), new Bpl.ExprSeq(exp));
+ else if (boogieTypeOfValue == this.sink.Heap.UnionType) {
+ expr = this.sink.Heap.FromUnion(Bpl.Token.NoToken, Bpl.Type.Int, exp);
}
else {
throw new NotImplementedException(msg);
@@ -1628,9 +1681,32 @@ namespace BytecodeTranslator
}
if (boogieTypeToBeConvertedTo == this.sink.Heap.RefType) {
+ // var a = BoxFromXXX(exp);
Bpl.Variable a = this.sink.CreateFreshLocal(conversion.TypeAfterConversion);
- this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(Bpl.Token.NoToken, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
- this.StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(Bpl.Token.NoToken, Bpl.Expr.Ident(a), Bpl.Expr.Ident(this.sink.Heap.BoxField), exp, AccessType.Heap, boogieTypeOfValue));
+ Bpl.Procedure boxOperator;
+ if (boogieTypeOfValue == Bpl.Type.Bool)
+ boxOperator = this.sink.Heap.BoxFromBool;
+ else if (boogieTypeOfValue == Bpl.Type.Int)
+ boxOperator = this.sink.Heap.BoxFromInt;
+ else if (boogieTypeOfValue == this.sink.Heap.RealType)
+ boxOperator = this.sink.Heap.BoxFromReal;
+ else if (TranslationHelper.IsStruct(conversion.ValueToConvert.Type)) {
+ // Boxing a struct implicitly makes a copy of the struct
+ var typeOfValue = conversion.ValueToConvert.Type;
+ var proc = this.sink.FindOrCreateProcedureForStructCopy(typeOfValue);
+ var bplLocal = Bpl.Expr.Ident(this.sink.CreateFreshLocal(typeOfValue));
+ var cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { exp, }, new List<Bpl.IdentifierExpr> { bplLocal, });
+ this.StmtTraverser.StmtBuilder.Add(cmd);
+ exp = bplLocal;
+ boxOperator = this.sink.Heap.BoxFromStruct;
+ } else {
+ if (boogieTypeOfValue != this.sink.Heap.UnionType)
+ throw new NotImplementedException(msg);
+ boxOperator = this.sink.Heap.BoxFromUnion;
+ }
+ var name = boxOperator.Name;
+
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(Bpl.Token.NoToken, name, new Bpl.ExprSeq(exp), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
TranslatedExpressions.Push(Bpl.Expr.Ident(a));
return;
}
@@ -1645,10 +1721,10 @@ namespace BytecodeTranslator
expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Int2Real), new Bpl.ExprSeq(exp));
}
else if (boogieTypeOfValue == this.sink.Heap.RefType) {
- expr = this.sink.Heap.ReadHeap(exp, Bpl.Expr.Ident(this.sink.Heap.BoxField), AccessType.Heap, this.sink.Heap.RealType);
+ expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Real), new Bpl.ExprSeq(exp));
}
- else if (boogieTypeOfValue == this.sink.Heap.BoxType) {
- expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Box2Real), new Bpl.ExprSeq(exp));
+ else if (boogieTypeOfValue == this.sink.Heap.UnionType) {
+ expr = this.sink.Heap.FromUnion(tok, this.sink.Heap.RealType, exp);
}
else {
throw new NotImplementedException(msg);
@@ -1657,27 +1733,27 @@ namespace BytecodeTranslator
return;
}
- if (boogieTypeToBeConvertedTo == this.sink.Heap.BoxType) {
- Bpl.Function func;
- if (boogieTypeOfValue == Bpl.Type.Bool) {
- func = this.sink.Heap.Bool2Box;
- }
- else if (boogieTypeOfValue == Bpl.Type.Int) {
- func = this.sink.Heap.Int2Box;
- }
- else if (boogieTypeOfValue == this.sink.Heap.RefType) {
- func = this.sink.Heap.Ref2Box;
- }
- else if (boogieTypeOfValue == this.sink.Heap.RealType) {
- func = this.sink.Heap.Real2Box;
- }
- else {
- throw new NotImplementedException(msg);
- }
- var boxExpr = new Bpl.NAryExpr(conversion.Token(), new Bpl.FunctionCall(func), new Bpl.ExprSeq(exp));
- TranslatedExpressions.Push(boxExpr);
- return;
- }
+ //if (boogieTypeToBeConvertedTo == this.sink.Heap.UnionType) {
+ // Bpl.Function func;
+ // if (boogieTypeOfValue == Bpl.Type.Bool) {
+ // func = this.sink.Heap.Bool2Union;
+ // }
+ // else if (boogieTypeOfValue == Bpl.Type.Int) {
+ // func = this.sink.Heap.Int2Union;
+ // }
+ // else if (boogieTypeOfValue == this.sink.Heap.RefType) {
+ // func = this.sink.Heap.Ref2Union;
+ // }
+ // else if (boogieTypeOfValue == this.sink.Heap.RealType) {
+ // func = this.sink.Heap.Real2Union;
+ // }
+ // else {
+ // throw new NotImplementedException(msg);
+ // }
+ // var boxExpr = new Bpl.NAryExpr(conversion.Token(), new Bpl.FunctionCall(func), new Bpl.ExprSeq(exp));
+ // TranslatedExpressions.Push(boxExpr);
+ // return;
+ //}
}
public override void TraverseChildren(IOnesComplement onesComplement) {
diff --git a/BCT/BytecodeTranslator/Heap.cs b/BCT/BytecodeTranslator/Heap.cs
index abc3068d..731d5e66 100644
--- a/BCT/BytecodeTranslator/Heap.cs
+++ b/BCT/BytecodeTranslator/Heap.cs
@@ -29,15 +29,6 @@ namespace BytecodeTranslator {
/// </summary>
public class SplitFieldsHeap : Heap {
- #region "Boxing" as done in the CLR
- /// <summary>
- /// Used to represent "boxing" as it is done in the CLR.
- /// </summary>
- [RepresentationFor("$BoxField", "var $BoxField: [Ref]Box;")]
- private Bpl.GlobalVariable boxField = null;
- public override Bpl.Variable BoxField { get { return boxField; } }
- #endregion
-
/// <summary>
/// Prelude text for which access to the ASTs is not needed
/// </summary>
@@ -52,7 +43,7 @@ namespace BytecodeTranslator {
string prelude = this.InitialPreludeText + this.CommonText;
var b = RepresentationFor.ParsePrelude(prelude, this, out program);
if (b) {
- this.BoxType = new Bpl.CtorType(this.BoxTypeDecl.tok, this.BoxTypeDecl, new Bpl.TypeSeq());
+ this.UnionType = new Bpl.CtorType(this.UnionTypeDecl.tok, this.UnionTypeDecl, new Bpl.TypeSeq());
this.DelegateType = new Bpl.CtorType(this.DelegateTypeDecl.tok, this.DelegateTypeDecl, new Bpl.TypeSeq());
this.DelegateMultisetType = new Bpl.TypeSynonymAnnotation(this.DelegateMultisetTypeDecl.tok, this.DelegateMultisetTypeDecl, new Bpl.TypeSeq());
this.FieldType = new Bpl.CtorType(this.FieldTypeDecl.tok, this.FieldTypeDecl, new Bpl.TypeSeq());
@@ -122,13 +113,10 @@ namespace BytecodeTranslator {
if (accessType == AccessType.Struct || accessType == AccessType.Heap) {
Bpl.IdentifierExpr field = f as Bpl.IdentifierExpr;
Debug.Assert(field != null);
- if (field.Decl == this.BoxField)
- return Unbox(f.tok, unboxType, Bpl.Expr.Select(field, o));
- else
- return Bpl.Expr.Select(field, o);
+ return Bpl.Expr.Select(field, o);
}
else
- return Unbox(f.tok, unboxType, Bpl.Expr.Select(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f));
+ return FromUnion(f.tok, unboxType, Bpl.Expr.Select(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f));
}
/// <summary>
@@ -140,13 +128,10 @@ namespace BytecodeTranslator {
if (accessType == AccessType.Struct || accessType == AccessType.Heap) {
Bpl.IdentifierExpr field = f as Bpl.IdentifierExpr;
Debug.Assert(field != null);
- if (field.Decl == this.BoxField)
- return Bpl.Cmd.MapAssign(tok, field, o, Box(tok, boxType, value));
- else
- return Bpl.Cmd.MapAssign(tok, field, o, value);
+ return Bpl.Cmd.MapAssign(tok, field, o, value);
}
else {
- return TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(ArrayContentsVariable), Bpl.Expr.Store(Bpl.Expr.Ident(ArrayContentsVariable), o, Bpl.Expr.Store(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f, Box(f.tok, boxType, value))));
+ return TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(ArrayContentsVariable), Bpl.Expr.Store(Bpl.Expr.Ident(ArrayContentsVariable), o, Bpl.Expr.Store(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f, ToUnion(f.tok, boxType, value))));
}
}
@@ -159,31 +144,22 @@ namespace BytecodeTranslator {
/// </summary>
public class GeneralHeap : Heap {
- #region "Boxing" as done in the CLR
- /// <summary>
- /// Used to represent "boxing" as it is done in the CLR.
- /// </summary>
- [RepresentationFor("$BoxField", "const unique $BoxField: Field;")]
- private Bpl.Constant boxField = null;
- public override Bpl.Variable BoxField { get { return boxField; } }
- #endregion
-
#region Fields
[RepresentationFor("$Heap", "var $Heap: HeapType;", true)]
private Bpl.Variable HeapVariable = null;
- [RepresentationFor("Read", "function {:inline true} Read(H:HeapType, o:Ref, f:Field): Box { H[o][f] }")]
+ [RepresentationFor("Read", "function {:inline true} Read(H:HeapType, o:Ref, f:Field): Union { H[o][f] }")]
private Bpl.Function Read = null;
- [RepresentationFor("Write", "function {:inline true} Write(H:HeapType, o:Ref, f:Field, v:Box): HeapType { H[o := H[o][f := v]] }")]
+ [RepresentationFor("Write", "function {:inline true} Write(H:HeapType, o:Ref, f:Field, v:Union): HeapType { H[o := H[o][f := v]] }")]
private Bpl.Function Write = null;
/// <summary>
/// Prelude text for which access to the ASTs is not needed
/// </summary>
private readonly string InitialPreludeText =
- @"type HeapType = [Ref][Field]Box;
+ @"type HeapType = [Ref][Field]Union;
";
private Sink sink;
@@ -197,7 +173,7 @@ namespace BytecodeTranslator {
string prelude = this.InitialPreludeText + this.CommonText;
var b = RepresentationFor.ParsePrelude(prelude, this, out program);
if (b) {
- this.BoxType = new Bpl.CtorType(this.BoxTypeDecl.tok, this.BoxTypeDecl, new Bpl.TypeSeq());
+ this.UnionType = new Bpl.CtorType(this.UnionTypeDecl.tok, this.UnionTypeDecl, new Bpl.TypeSeq());
this.DelegateType = new Bpl.CtorType(this.DelegateTypeDecl.tok, this.DelegateTypeDecl, new Bpl.TypeSeq());
this.DelegateMultisetType = new Bpl.TypeSynonymAnnotation(this.DelegateMultisetTypeDecl.tok, this.DelegateMultisetTypeDecl, new Bpl.TypeSeq());
this.FieldType = new Bpl.CtorType(this.FieldTypeDecl.tok, this.FieldTypeDecl, new Bpl.TypeSeq());
@@ -268,7 +244,7 @@ namespace BytecodeTranslator {
callRead = Bpl.Expr.Select(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f);
// wrap it in the right conversion function
- var callExpr = Unbox(f.tok, unboxType, callRead);
+ var callExpr = FromUnion(f.tok, unboxType, callRead);
return callExpr;
}
@@ -281,7 +257,7 @@ namespace BytecodeTranslator {
Bpl.IdentifierExpr h;
Bpl.NAryExpr callWrite;
- var callConversion = Box(f.tok, boxType, value);
+ var callConversion = ToUnion(f.tok, boxType, value);
if (accessType == AccessType.Struct || accessType == AccessType.Heap) {
h = Bpl.Expr.Ident(HeapVariable);
@@ -338,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/HeapFactory.cs b/BCT/BytecodeTranslator/HeapFactory.cs
index 6553efba..d637586d 100644
--- a/BCT/BytecodeTranslator/HeapFactory.cs
+++ b/BCT/BytecodeTranslator/HeapFactory.cs
@@ -66,15 +66,13 @@ namespace BytecodeTranslator {
public abstract class Heap : HeapFactory, IHeap
{
- [RepresentationFor("$ArrayContents", "var $ArrayContents: [Ref][int]Box;")]
+ [RepresentationFor("$ArrayContents", "var $ArrayContents: [Ref][int]Union;")]
public Bpl.Variable ArrayContentsVariable = null;
[RepresentationFor("$ArrayLength", "function $ArrayLength(Ref): int;")]
public Bpl.Function ArrayLengthFunction = null;
public abstract Bpl.Variable CreateFieldVariable(IFieldReference field);
- public abstract Bpl.Variable BoxField { get; }
-
#region Boogie Types
[RepresentationFor("Delegate", "type {:datatype} Delegate;")]
@@ -88,25 +86,25 @@ namespace BytecodeTranslator {
[RepresentationFor("MultisetEmpty", "const unique MultisetEmpty: DelegateMultiset;")]
public Bpl.Constant MultisetEmpty = null;
- [RepresentationFor("MultisetSingleton", "function {:inline} MultisetSingleton(x: Delegate): DelegateMultiset { MultisetEmpty[x := 1] }")]
+ [RepresentationFor("MultisetSingleton", "function {:inline true} MultisetSingleton(x: Delegate): DelegateMultiset { MultisetEmpty[x := 1] }")]
public Bpl.Function MultisetSingleton = null;
- [RepresentationFor("MultisetPlus", "function {:inline} MultisetPlus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapadd(x, y) }")]
+ [RepresentationFor("MultisetPlus", "function {:inline true} MultisetPlus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapadd(x, y) }")]
public Bpl.Function MultisetPlus = null;
- [RepresentationFor("MultisetMinus", "function {:inline} MultisetMinus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapiteint(mapgt(x, y), mapsub(x, y), mapconstint(0)) }")]
+ [RepresentationFor("MultisetMinus", "function {:inline true} MultisetMinus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapiteint(mapgt(x, y), mapsub(x, y), mapconstint(0)) }")]
public Bpl.Function MultisetMinus = null;
[RepresentationFor("Field", "type Field;")]
public Bpl.TypeCtorDecl FieldTypeDecl = null;
public Bpl.CtorType FieldType;
- [RepresentationFor("Box", "type Box;")]
- public Bpl.TypeCtorDecl BoxTypeDecl = null;
- public Bpl.CtorType BoxType;
+ [RepresentationFor("Union", "type Union;")]
+ public Bpl.TypeCtorDecl UnionTypeDecl = null;
+ public Bpl.CtorType UnionType;
- [RepresentationFor("$DefaultBox", "const unique $DefaultBox : Box;")]
- public Bpl.Constant DefaultBox;
+ [RepresentationFor("$DefaultHeapValue", "const unique $DefaultHeapValue : Union;")]
+ public Bpl.Constant DefaultHeapValue;
[RepresentationFor("Ref", "type Ref;")]
public Bpl.TypeCtorDecl RefTypeDecl = null;
@@ -126,49 +124,92 @@ namespace BytecodeTranslator {
#endregion
+ #region CLR Boxing
+
+ [RepresentationFor("$BoxFromBool", "procedure {:inline 1} $BoxFromBool(b: bool) returns (r: Ref) { call r := Alloc(); assume $BoxedValue(r) == Bool2Union(b); }")]
+ public Bpl.Procedure BoxFromBool = null;
+
+ [RepresentationFor("$BoxFromInt", "procedure {:inline 1} $BoxFromInt(i: int) returns (r: Ref) { call r := Alloc(); assume $BoxedValue(r) == Int2Union(i); }")]
+ public Bpl.Procedure BoxFromInt = null;
+
+ [RepresentationFor("$BoxFromReal", "procedure {:inline 1} $BoxFromReal(r: Real) returns (rf: Ref) { call rf := Alloc(); assume $BoxedValue(rf) == Real2Union(r); }")]
+ public Bpl.Procedure BoxFromReal = null;
+
+ [RepresentationFor("$BoxFromStruct", "procedure {:inline 1} $BoxFromStruct(s: Ref) returns (r: Ref) { call r := Alloc(); assume $BoxedValue(r) == Struct2Union(s); }")]
+ public Bpl.Procedure BoxFromStruct = null;
+
+ [RepresentationFor("$BoxFromUnion", "procedure {:inline 1} $BoxFromUnion(u: Union) returns (r: Ref) { if (IsRef(u)) { r := Union2Ref(u); } else { call r := Alloc(); assume $BoxedValue(r) == u; } }")]
+ public Bpl.Procedure BoxFromUnion = null;
+
+ [RepresentationFor("$BoxedValue", "function $BoxedValue(r: Ref): Union;")]
+ public Bpl.Function BoxedValue = null;
+
+ [RepresentationFor("$Unbox2Bool", "function {:inline true} $Unbox2Bool(r: Ref): (bool) { Union2Bool($BoxedValue(r)) }")]
+ public Bpl.Function Unbox2Bool = null;
+
+ [RepresentationFor("$Unbox2Int", "function {:inline true} $Unbox2Int(r: Ref): (int) { Union2Int($BoxedValue(r)) }")]
+ public Bpl.Function Unbox2Int = null;
+
+ [RepresentationFor("$Unbox2Real", "function {:inline true} $Unbox2Real(r: Ref): (Real) { Union2Real($BoxedValue(r)) }")]
+ public Bpl.Function Unbox2Real = null;
+
+ [RepresentationFor("$Unbox2Struct", "function {:inline true} $Unbox2Struct(r: Ref): (Ref) { Union2Struct($BoxedValue(r)) }")]
+ public Bpl.Function Unbox2Struct = null;
+
+ [RepresentationFor("$Unbox2Union", "function {:inline true} $Unbox2Union(r: Ref): (Union) { $BoxedValue(r) }")]
+ public Bpl.Function Unbox2Union = null;
+
+ #endregion
+
#region Conversions
#region Heap values
- [RepresentationFor("Box2Bool", "function Box2Bool(Box): bool;")]
- public Bpl.Function Box2Bool = null;
-
- [RepresentationFor("Box2Int", "function Box2Int(Box): int;")]
- public Bpl.Function Box2Int = null;
-
- [RepresentationFor("Box2Ref", "function Box2Ref(Box): Ref;")]
- public Bpl.Function Box2Ref = null;
+ [RepresentationFor("Union2Bool", "function Union2Bool(u: Union): (bool);")]
+ public Bpl.Function Union2Bool = null;
- [RepresentationFor("Box2Real", "function Box2Real(Box): Real;")]
- public Bpl.Function Box2Real = null;
+ [RepresentationFor("Union2Int", "function Union2Int(u: Union): (int);")]
+ public Bpl.Function Union2Int = null;
- [RepresentationFor("Bool2Box", "function Bool2Box(bool): Box;")]
- public Bpl.Function Bool2Box = null;
+ [RepresentationFor("Union2Ref", "function Union2Ref(u: Union): (Ref);")]
+ public Bpl.Function Union2Ref = null;
- [RepresentationFor("Int2Box", "function Int2Box(int): Box;")]
- public Bpl.Function Int2Box = null;
+ [RepresentationFor("Union2Real", "function Union2Real(u: Union): (Real);")]
+ public Bpl.Function Union2Real = null;
- [RepresentationFor("Ref2Box", "function Ref2Box(Ref): Box;")]
- public Bpl.Function Ref2Box = null;
+ [RepresentationFor("Union2Struct", "function Union2Struct(u: Union): (Ref);")]
+ public Bpl.Function Union2Struct = null;
- [RepresentationFor("Real2Box", "function Real2Box(Real): Box;")]
- public Bpl.Function Real2Box = null;
+ [RepresentationFor("Bool2Union", "function Bool2Union(boolValue: bool): Union;")]
+ public Bpl.Function Bool2Union = null;
- [RepresentationFor("Box2Box", "function {:inline true} Box2Box(b: Box): Box { b }")]
- public Bpl.Function Box2Box = null;
+ [RepresentationFor("Int2Union", "function Int2Union(intValue: int): Union;")]
+ public Bpl.Function Int2Union = null;
- public Bpl.Expr Box(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
+ [RepresentationFor("Ref2Union", "function Ref2Union(refValue: Ref): Union;")]
+ public Bpl.Function Ref2Union = null;
+
+ [RepresentationFor("Real2Union", "function Real2Union(realValue: Real): Union;")]
+ public Bpl.Function Real2Union = null;
+
+ [RepresentationFor("Struct2Union", "function Struct2Union(structValue: Ref): Union;")]
+ public Bpl.Function Struct2Union = null;
+
+ [RepresentationFor("Union2Union", "function {:inline true} Union2Union(u: Union): Union { u }")]
+ public Bpl.Function Union2Union = null;
+
+ public Bpl.Expr ToUnion(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion;
if (boogieType == Bpl.Type.Bool)
- conversion = this.Bool2Box;
+ conversion = this.Bool2Union;
else if (boogieType == Bpl.Type.Int)
- conversion = this.Int2Box;
+ conversion = this.Int2Union;
else if (boogieType == RefType)
- conversion = this.Ref2Box;
+ conversion = this.Ref2Union;
else if (boogieType == RealType)
- conversion = this.Real2Box;
- else if (boogieType == BoxType)
- conversion = this.Box2Box;
+ conversion = this.Real2Union;
+ else if (boogieType == UnionType)
+ conversion = this.Union2Union;
else
throw new InvalidOperationException(String.Format("Unknown Boogie type: '{0}'", boogieType.ToString()));
@@ -180,18 +221,18 @@ namespace BytecodeTranslator {
return callConversion;
}
- public Bpl.Expr Unbox(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
+ public Bpl.Expr FromUnion(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion = null;
if (boogieType == Bpl.Type.Bool)
- conversion = this.Box2Bool;
+ conversion = this.Union2Bool;
else if (boogieType == Bpl.Type.Int)
- conversion = this.Box2Int;
+ conversion = this.Union2Int;
else if (boogieType == RefType)
- conversion = this.Box2Ref;
+ conversion = this.Union2Ref;
else if (boogieType == RealType)
- conversion = this.Box2Real;
- else if (boogieType == BoxType)
- conversion = this.Box2Box;
+ conversion = this.Union2Real;
+ else if (boogieType == UnionType)
+ conversion = this.Union2Union;
else
throw new InvalidOperationException(String.Format("Unknown Boogie type: '{0}'", boogieType.ToString()));
@@ -354,6 +395,14 @@ function {:builtin ""MapIff""} mapiff([Delegate]bool, [Delegate]bool) : [Delegat
function {:builtin ""MapImp""} mapimp([Delegate]bool, [Delegate]bool) : [Delegate]bool;
axiom MultisetEmpty == mapconstint(0);
+function IsRef(u: Union) : (bool);
+axiom (forall x: bool :: {Bool2Union(x)} Union2Bool(Bool2Union(x)) == x && !IsRef(Bool2Union(x)));
+axiom (forall x: int :: {Int2Union(x)} Union2Int(Int2Union(x)) == x && !IsRef(Int2Union(x)));
+axiom (forall x: Real :: {Real2Union(x)} Union2Real(Real2Union(x)) == x && !IsRef(Real2Union(x)));
+axiom (forall x: Ref :: {Ref2Union(x)} Union2Ref(Ref2Union(x)) == x && IsRef(Ref2Union(x)));
+axiom (forall x: Ref :: {Struct2Union(x)} Union2Struct(Struct2Union(x)) == x && !IsRef(Struct2Union(x)));
+
+
/*
// Subtype is reflexive
axiom (forall t: Type :: $Subtype(t, t) );
@@ -380,13 +429,9 @@ procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref)
$result := $TypeOf($DynamicType(this));
}
-axiom Box2Int($DefaultBox) == 0;
-axiom Box2Bool($DefaultBox) == false;
-axiom Box2Ref($DefaultBox) == null;
-
-axiom (forall x: int :: { Int2Box(x) } Box2Int(Int2Box(x)) == x );
-axiom (forall x: bool :: { Bool2Box(x) } Box2Bool(Bool2Box(x)) == x );
-axiom (forall x: Ref :: { Ref2Box(x) } Box2Ref(Ref2Box(x)) == x );
+axiom Union2Int($DefaultHeapValue) == 0;
+axiom Union2Bool($DefaultHeapValue) == false;
+axiom Union2Ref($DefaultHeapValue) == null;
function $ThreadDelegate(Ref) : Ref;
@@ -398,7 +443,7 @@ procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, par
{
call {:async} Wrapper_System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
}
-procedure {:inline 1} Wrapper_System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref) {
+procedure Wrapper_System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref) {
$Exception := null;
call System.Threading.ParameterizedThreadStart.Invoke$System.Object(this, obj$in);
}
@@ -412,7 +457,7 @@ procedure {:inline 1} System.Threading.Thread.Start(this: Ref)
{
call {:async} Wrapper_System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
}
-procedure {:inline 1} Wrapper_System.Threading.ThreadStart.Invoke(this: Ref) {
+procedure Wrapper_System.Threading.ThreadStart.Invoke(this: Ref) {
$Exception := null;
call System.Threading.ThreadStart.Invoke(this);
}
@@ -433,7 +478,8 @@ procedure {:inline 1} DelegateAdd(a: Ref, b: Ref) returns (c: Ref)
else
{
call c := Alloc();
- assume $Delegate(c) == MultisetPlus($Delegate(a), $Delegate(b));
+ assume $RefToDelegate(c) == $RefToDelegate(a) || $RefToDelegate(c) == $RefToDelegate(b);
+ assume $RefToDelegateMultiset(c) == MultisetPlus($RefToDelegateMultiset(a), $RefToDelegateMultiset(b));
}
}
@@ -449,21 +495,23 @@ procedure {:inline 1} DelegateRemove(a: Ref, b: Ref) returns (c: Ref)
{
c := a;
}
- else if (MultisetMinus($Delegate(a), $Delegate(b)) == MultisetEmpty)
+ else if (MultisetMinus($RefToDelegateMultiset(a), $RefToDelegateMultiset(b)) == MultisetEmpty)
{
c := null;
}
else
{
call c := Alloc();
- assume $Delegate(c) == MultisetMinus($Delegate(a), $Delegate(b));
+ assume $RefToDelegateMultiset(c) == MultisetMinus($RefToDelegateMultiset(a), $RefToDelegateMultiset(b));
+ assume $RefToDelegateMultiset(c)[$RefToDelegate(c)] > 0;
}
}
procedure {:inline 1} DelegateCreate(d: Delegate) returns (c: Ref)
{
call c := Alloc();
- assume $Delegate(c) == MultisetSingleton(d);
+ assume $RefToDelegate(c) == d;
+ assume $RefToDelegateMultiset(c) == MultisetSingleton(d);
}
procedure {:inline 1} System.String.op_Equality$System.String$System.String(a$in: Ref, b$in: Ref) returns ($result: bool);
@@ -477,46 +525,15 @@ implementation System.String.op_Inequality$System.String$System.String(a$in: Ref
$result := (a$in != b$in);
}
-// SILVERLIGHT CONTROL SPECIFIC CODE
-var isControlEnabled: [Ref]bool;
-var isControlChecked: [Ref]bool;
-
-procedure {:inline 1} System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool);
-implementation System.Windows.Controls.Control.set_IsEnabled$System.Boolean($this: Ref, value$in: bool) {
- $Exception:=null;
- isControlEnabled[$this] := value$in;
-}
-
-procedure {:inline 1} System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref);
-implementation System.Windows.Controls.Control.get_IsEnabled($this: Ref) returns ($result: Ref) {
- var enabledness: bool;
- $Exception:=null;
- enabledness := isControlEnabled[$this];
- $result := Box2Ref(Bool2Box(enabledness));
-}
-
-procedure {:inline 1} System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref);
-implementation System.Windows.Controls.Primitives.ToggleButton.set_IsChecked$System.Nullable$System.Boolean$($this: Ref, value$in: Ref) {
- var check: bool;
- $Exception:=null;
- check := Box2Bool(Ref2Box(value$in));
- isControlChecked[$this] := check;
-}
-
-procedure {:inline 1} System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref);
-implementation System.Windows.Controls.Primitives.ToggleButton.get_IsChecked($this: Ref) returns ($result: Ref) {
- var isChecked: bool;
- $Exception:=null;
- isChecked := isControlChecked[$this];
- $result := Box2Ref(Bool2Box(isChecked));
-}
-
";
- [RepresentationFor("$Delegate", "function $Delegate(Ref): DelegateMultiset;")]
- public Bpl.Function Delegate = null;
+ [RepresentationFor("$RefToDelegate", "function $RefToDelegate(Ref): Delegate;")]
+ public Bpl.Function RefToDelegate = null;
+
+ [RepresentationFor("$RefToDelegateMultiset", "function $RefToDelegateMultiset(Ref): DelegateMultiset;")]
+ public Bpl.Function RefToDelegateMultiset = null;
- [RepresentationFor("$DelegateCons", "function {:constructor} $DelegateCons($Method: int, $Receiver: Ref, $TypeParameters: Type): Delegate;")]
+ [RepresentationFor("$RefToDelegateMultisetCons", "function {:constructor} $RefToDelegateMultisetCons($Method: int, $Receiver: Ref, $TypeParameters: Type): Delegate;")]
public Bpl.DatatypeConstructor DelegateCons = null;
public Bpl.Function DelegateMethod {
diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs
index 5217df14..22b64dca 100644
--- a/BCT/BytecodeTranslator/Program.cs
+++ b/BCT/BytecodeTranslator/Program.cs
@@ -174,12 +174,11 @@ namespace BytecodeTranslator {
var fileName = assemblyNames[0];
fileName = Path.GetFileNameWithoutExtension(fileName);
string outputFileName = fileName + ".bpl";
- Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter(outputFileName);
+ Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter("_" + outputFileName);
Prelude.Emit(writer);
pgm.Emit(writer);
writer.Close();
- return 0; // success
-
+ return Inline(outputFileName);
} catch (Exception e) { // swallow everything and just return an error code
Console.WriteLine("The byte-code translator failed: {0}", e.Message);
// Console.WriteLine("Stack trace: {0}", e.StackTrace);
@@ -189,6 +188,59 @@ namespace BytecodeTranslator {
private static List<IModule> modules;
+ public static int Inline(string bplFileName) {
+ Bpl.CommandLineOptions options = new Bpl.CommandLineOptions();
+ Bpl.CommandLineOptions.Install(options);
+ Bpl.CommandLineOptions.Clo.DoModSetAnalysis = true;
+ Bpl.Program program;
+ string _bplFileName = "_" + bplFileName;
+
+ Bpl.Parser.Parse(_bplFileName, new List<string>(), out program);
+ int errorCount = program.Resolve();
+ if (errorCount != 0) {
+ Console.WriteLine("{0} name resolution errors detected in {1}", errorCount, _bplFileName);
+ return -1;
+ }
+ errorCount = program.Typecheck();
+ if (errorCount != 0) {
+ Console.WriteLine("{0} type checking errors detected in {1}", errorCount, _bplFileName);
+ return -1;
+ }
+ bool inline = false;
+ foreach (var d in program.TopLevelDeclarations) {
+ if (d.FindExprAttribute("inline") != null) {
+ inline = true;
+ }
+ }
+ if (inline) {
+ foreach (var d in program.TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null) {
+ impl.OriginalBlocks = impl.Blocks;
+ impl.OriginalLocVars = impl.LocVars;
+ }
+ }
+ foreach (var d in program.TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null && !impl.SkipVerification) {
+ Bpl.Inliner.ProcessImplementation(program, impl);
+ }
+ }
+ foreach (var d in program.TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null) {
+ impl.OriginalBlocks = null;
+ impl.OriginalLocVars = null;
+ }
+ }
+ }
+ Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter(bplFileName);
+ options.PrintInstrumented = true;
+ program.Emit(writer);
+ writer.Close();
+ return 0;
+ }
+
public static int TranslateAssemblyAndWriteOutput(List<string> assemblyNames, HeapFactory heapFactory, Options options, List<Regex> exemptionList, bool whiteList) {
Contract.Requires(assemblyNames != null);
Contract.Requires(heapFactory != null);
@@ -565,11 +617,11 @@ namespace BytecodeTranslator {
Bpl.Expr rexpr = Bpl.Expr.Ident(rvar);
if (rtype == ltype) {
// do nothing
- } else if (ltype == sink.Heap.BoxType) {
- rexpr = sink.Heap.Box(Bpl.Token.NoToken, rtype, rexpr);
+ } else if (ltype == sink.Heap.UnionType) {
+ rexpr = sink.Heap.ToUnion(Bpl.Token.NoToken, rtype, rexpr);
}
- else if (rtype == sink.Heap.BoxType) {
- rexpr = sink.Heap.Unbox(Bpl.Token.NoToken, ltype, rexpr);
+ else if (rtype == sink.Heap.UnionType) {
+ rexpr = sink.Heap.FromUnion(Bpl.Token.NoToken, ltype, rexpr);
}
else {
System.Diagnostics.Debug.Assert(false);
@@ -578,6 +630,19 @@ namespace BytecodeTranslator {
}
}
+ private static void GenerateInAndOutExprs(Bpl.Expr e, Bpl.VariableSeq invars, Bpl.VariableSeq outvars, out Bpl.ExprSeq inExprs, out Bpl.IdentifierExprSeq outExprs) {
+ inExprs = new Bpl.ExprSeq();
+ inExprs.Add(e);
+ for (int i = 1; i < invars.Length; i++) {
+ Bpl.Variable f = invars[i];
+ inExprs.Add(Bpl.Expr.Ident(f));
+ }
+ outExprs = new Bpl.IdentifierExprSeq();
+ foreach (Bpl.Formal f in outvars) {
+ outExprs.Add(Bpl.Expr.Ident(f));
+ }
+ }
+
private static void CreateDispatchMethod(Sink sink, ITypeDefinition type, HashSet<IMethodDefinition> delegates) {
Contract.Assert(type.IsDelegate);
IMethodDefinition invokeMethod = null;
@@ -693,6 +758,7 @@ namespace BytecodeTranslator {
if (tempInputs.Count > 0) {
BuildAssignment(sink, ifStmtBuilder, tempInputs, dispatchProcInExprs);
}
+ ifStmtBuilder.Add(EmitDummySourceContext());
ifStmtBuilder.Add(new Bpl.CallCmd(token, delegateProcedure.Name, ins, outs));
System.Diagnostics.Debug.Assert(tempOutputs.Count == dispatchProcOutExprs.Count);
if (tempOutputs.Count > 0) {
@@ -721,27 +787,29 @@ namespace BytecodeTranslator {
dispatchImpl.Proc = dispatchProcedure;
sink.TranslatedProgram.TopLevelDeclarations.Add(dispatchImpl);
+ Bpl.ExprSeq inExprs;
+ Bpl.IdentifierExprSeq outExprs;
+
Bpl.LocalVariable iter = new Bpl.LocalVariable(token, new Bpl.TypedIdent(token, "iter", sink.Heap.DelegateMultisetType));
Bpl.LocalVariable d = new Bpl.LocalVariable(token, new Bpl.TypedIdent(token, "d", sink.Heap.DelegateType));
Bpl.LocalVariable all = new Bpl.LocalVariable(token, new Bpl.TypedIdent(token, "all", sink.Heap.DelegateMultisetType));
Bpl.StmtListBuilder implStmtBuilder = new Bpl.StmtListBuilder();
- implStmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(all), sink.ReadDelegate(Bpl.Expr.Ident(invars[0]))));
- implStmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(iter), Bpl.Expr.Ident(sink.Heap.MultisetEmpty)));
+ implStmtBuilder.Add(new Bpl.AssumeCmd(Bpl.Token.NoToken, Bpl.Expr.Neq(Bpl.Expr.Ident(invars[0]), Bpl.Expr.Ident(sink.Heap.NullRef))));
+ GenerateInAndOutExprs(sink.ReadDelegate(Bpl.Expr.Ident(invars[0])), invars, outvars, out inExprs, out outExprs);
+ implStmtBuilder.Add(new Bpl.CallCmd(token, dispatchProcedure.Name, inExprs, outExprs));
+ implStmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(all), sink.ReadDelegateMultiset(Bpl.Expr.Ident(invars[0]))));
+ implStmtBuilder.Add(
+ TranslationHelper.BuildAssignCmd(
+ Bpl.Expr.Ident(iter),
+ new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(sink.Heap.MultisetSingleton), new Bpl.ExprSeq(sink.ReadDelegate(Bpl.Expr.Ident(invars[0]))))));
Bpl.StmtListBuilder whileStmtBuilder = new Bpl.StmtListBuilder();
whileStmtBuilder.Add(BuildReturnCmd(Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, Bpl.Expr.Ident(iter), Bpl.Expr.Ident(all))));
whileStmtBuilder.Add(new Bpl.AssumeCmd(Bpl.Token.NoToken, Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Gt, Bpl.Expr.Select(new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(sink.Heap.MultisetMinus), new Bpl.ExprSeq(Bpl.Expr.Ident(all), Bpl.Expr.Ident(iter))), Bpl.Expr.Ident(d)), new Bpl.LiteralExpr(Bpl.Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(0)))));
- Bpl.ExprSeq inExprs = new Bpl.ExprSeq();
- inExprs.Add(Bpl.Expr.Ident(d));
- for (int i = 1; i < invars.Length; i++) {
- Bpl.Variable f = invars[i];
- inExprs.Add(Bpl.Expr.Ident(f));
- }
- Bpl.IdentifierExprSeq outExprs = new Bpl.IdentifierExprSeq();
- foreach (Bpl.Formal f in outvars) {
- outExprs.Add(Bpl.Expr.Ident(f));
- }
+
+ whileStmtBuilder.Add(EmitDummySourceContext());
+ GenerateInAndOutExprs(Bpl.Expr.Ident(d), invars, outvars, out inExprs, out outExprs);
whileStmtBuilder.Add(new Bpl.CallCmd(token, dispatchProcedure.Name, inExprs, outExprs));
whileStmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(iter), new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(sink.Heap.MultisetPlus), new Bpl.ExprSeq(Bpl.Expr.Ident(iter), new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(sink.Heap.MultisetSingleton), new Bpl.ExprSeq(Bpl.Expr.Ident(d)))))));
whileStmtBuilder.Add(new Bpl.HavocCmd(Bpl.Token.NoToken, new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(d))));
@@ -769,6 +837,15 @@ namespace BytecodeTranslator {
}
}
+ private static Bpl.AssertCmd EmitDummySourceContext() {
+ string fileName = "BCTAutoGenerated";
+ int lineNumber = 0;
+ var tok = Bpl.Token.NoToken;
+ var attrib = new Bpl.QKeyValue(tok, "sourceLine", new List<object> { Bpl.Expr.Literal((int)lineNumber) }, null);
+ attrib = new Bpl.QKeyValue(tok, "sourceFile", new List<object> { fileName }, attrib);
+ return new Bpl.AssertCmd(tok, Bpl.Expr.True, attrib);
+ }
+
private class RewriteUnitReferences : MetadataRewriter {
private UnitIdentity sourceUnitIdentity = null;
internal IAssembly/*?*/ targetAssembly = null;
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index 4499f11e..b1a8f1a4 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -100,8 +100,12 @@ namespace BytecodeTranslator {
public readonly string DelegateAddName = "DelegateAdd";
public readonly string DelegateRemoveName = "DelegateRemove";
+ public Bpl.Expr ReadDelegateMultiset(Bpl.Expr delegateReference) {
+ return new Bpl.NAryExpr(delegateReference.tok, new Bpl.FunctionCall(Heap.RefToDelegateMultiset), new Bpl.ExprSeq(delegateReference));
+ }
+
public Bpl.Expr ReadDelegate(Bpl.Expr delegateReference) {
- return new Bpl.NAryExpr(delegateReference.tok, new Bpl.FunctionCall(Heap.Delegate), new Bpl.ExprSeq(delegateReference));
+ return new Bpl.NAryExpr(delegateReference.tok, new Bpl.FunctionCall(Heap.RefToDelegate), new Bpl.ExprSeq(delegateReference));
}
public Bpl.Expr ReadMethod(Bpl.Expr delegateExpr) {
@@ -144,7 +148,7 @@ namespace BytecodeTranslator {
if (TypeHelper.TypesAreEquivalent(c, type.PlatformType.SystemValueType)) continue;
return CciTypeToBoogie(c);
}
- return heap.BoxType;
+ return heap.UnionType;
} else
return heap.RefType;
}
@@ -319,6 +323,9 @@ namespace BytecodeTranslator {
}
public Bpl.Constant FindOrCreateConstant(string str) {
+ str = str.Replace("\n", "\\n");
+ str = str.Replace("\r", "\\r");
+ str = str.Replace("\"", "\\\"");
Bpl.Constant c;
if (!this.declaredStringConstants.TryGetValue(str, out c)) {
var tok = Bpl.Token.NoToken;
@@ -326,6 +333,8 @@ 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);
+ var attrib = new Bpl.QKeyValue(Bpl.Token.NoToken, "value", new List<object> { str, }, null);
+ c.Attributes = attrib;
this.declaredStringConstants.Add(str, c);
this.TranslatedProgram.TopLevelDeclarations.Add(c);
}
diff --git a/BCT/BytecodeTranslator/StatementTraverser.cs b/BCT/BytecodeTranslator/StatementTraverser.cs
index c36608b6..feca0559 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;
}
@@ -122,11 +123,14 @@ namespace BytecodeTranslator
foreach (var sloc in slocs) {
fileName = sloc.Document.Location;
lineNumber = sloc.StartLine;
+
+ this.parent.lastSourceLocation = sloc;
break;
}
if (fileName != null) {
var attrib = new Bpl.QKeyValue(tok, "sourceLine", new List<object> { Bpl.Expr.Literal((int)lineNumber) }, null);
attrib = new Bpl.QKeyValue(tok, "sourceFile", new List<object> { fileName }, attrib);
+ attrib = new Bpl.QKeyValue(tok, "first", new List<object>(), attrib);
this.parent.StmtBuilder.Add(
new Bpl.AssertCmd(tok, Bpl.Expr.True, attrib)
);
@@ -237,6 +241,7 @@ namespace BytecodeTranslator
}
private static int counter = 0;
+ public IPrimarySourceLocation lastSourceLocation;
internal int NextUniqueNumber() {
return counter++;
}
@@ -336,14 +341,16 @@ namespace BytecodeTranslator
// then a struct value of type S is being assigned: "lhs := s"
// model this as the statement "call lhs := S..#copy_ctor(s)" that does the bit-wise copying
if (isStruct) {
- var defaultValue = new DefaultValue() {
- DefaultValueType = typ,
- Locations = new List<ILocation>(localDeclarationStatement.Locations),
- Type = typ,
- };
- var e2 = ExpressionFor(defaultValue);
- StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, boogieLocalExpr, e2));
- if (structCopy) {
+ if (!structCopy) {
+ var defaultValue = new DefaultValue() {
+ DefaultValueType = typ,
+ Locations = new List<ILocation>(localDeclarationStatement.Locations),
+ Type = typ,
+ };
+ var e2 = ExpressionFor(defaultValue);
+ StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, boogieLocalExpr, e2));
+ } else
+ /*if (structCopy) */{
var proc = this.sink.FindOrCreateProcedureForStructCopy(typ);
e = ExpressionFor(initVal);
StmtBuilder.Add(new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { e, }, new List<Bpl.IdentifierExpr>{ boogieLocalExpr, }));
@@ -453,6 +460,9 @@ namespace BytecodeTranslator
throw new TranslationException("For statements are not handled");
}
+ public override void TraverseChildren(IDoUntilStatement doUntilStatement) {
+ throw new TranslationException("DoUntil statements are not handled");
+ }
#endregion
public void GenerateDispatchContinuation(ITryCatchFinallyStatement tryCatchFinallyStatement) {
diff --git a/BCT/BytecodeTranslator/WholeProgram.cs b/BCT/BytecodeTranslator/WholeProgram.cs
index bd297451..73e882e0 100644
--- a/BCT/BytecodeTranslator/WholeProgram.cs
+++ b/BCT/BytecodeTranslator/WholeProgram.cs
@@ -140,7 +140,7 @@ namespace BytecodeTranslator {
List<Bpl.Expr> inexpr;
List<Bpl.IdentifierExpr> outvars;
Bpl.IdentifierExpr thisExpr;
- Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toBoxed;
var proc = TranslateArgumentsAndReturnProcedure(token, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
diff --git a/Chalice/build.sbt b/Chalice/build.sbt
index 65b12413..3fa72ec5 100644
--- a/Chalice/build.sbt
+++ b/Chalice/build.sbt
@@ -6,3 +6,5 @@ version := "1.0"
scalaVersion := "2.8.1"
scalacOptions += "-deprecation"
+
+libraryDependencies += "org.scalatest" %% "scalatest" % "1.7.1" % "test"
diff --git a/Chalice/chalice.bat b/Chalice/chalice.bat
index e4bbf5da..6400ca7b 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=
@@ -36,6 +36,7 @@ set CHALICE_MAIN=chalice.Chalice
REM Chalice command line options
set CHALICE_OPTS=
set CHALICE_OPTS=%CHALICE_OPTS% /boogieOpt:nologo
+set CHALICE_OPTS=%CHALICE_OPTS% /boogieOpt:noinfer
set CHALICE_OPTS=%CHALICE_OPTS% %*
REM Assemble main command
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/Boogie.scala b/Chalice/src/main/scala/Boogie.scala
index acc061ad..900ad6d1 100644
--- a/Chalice/src/main/scala/Boogie.scala
+++ b/Chalice/src/main/scala/Boogie.scala
@@ -222,13 +222,17 @@ object Boogie {
indent + "assert " + "{:msg \"" + pos + assert.message + "\"}" + (assert.subsumption match {case Some(n) => "{:subsumption " + n + "}"; case None => ""}) + " " + PrintExpr(e) + ";" + nl
case Assume(e) => indent + "assume " + PrintExpr(e) + ";" + nl
case If(guard, thn, els) =>
+ if (thn == Nil && els == Nil) "" else
indent + "if (" +
(if (guard == null) "*" else PrintExpr(guard)) +
") {" + nl +
IndentMore { Print(thn, "", PrintStmt) } +
- indent + "} else {" + nl +
- IndentMore { Print(els, "", PrintStmt) } +
- indent + "}" + nl
+ indent + "}" +
+ (if (els == Nil) nl else
+ " else {" + nl +
+ IndentMore { Print(els, "", PrintStmt) } +
+ indent + "}" + nl
+ )
case Assign(lhs, rhs) =>
indent + PrintExpr(lhs) + " := " + PrintExpr(rhs) + ";" + nl
case AssignMap(lhs, index, rhs) =>
diff --git a/Chalice/src/main/scala/Chalice.scala b/Chalice/src/main/scala/Chalice.scala
index cc06ad7b..077e5c46 100644
--- a/Chalice/src/main/scala/Chalice.scala
+++ b/Chalice/src/main/scala/Chalice.scala
@@ -55,6 +55,8 @@ object Chalice {
val boogieArgs: String
val gen: Boolean
val showFullStackTrace: Boolean
+ val noBplFile: Boolean
+ val bplFile: String
def getHelp(): String
}
@@ -68,7 +70,9 @@ object Chalice {
var aPrintProgram = false
var aDoTypecheck = true
var aDoTranslate = true
- var aBoogieArgs = " ";
+ var aNoBplFile = true
+ var aBplFile = "out.bpl"
+ var aBoogieArgs = " "
var aGen = false;
var aShowFullStackTrace = false
@@ -76,7 +80,8 @@ object Chalice {
"help" -> (
{() => },
"print this message"),
- "print" -> ({() => aPrintProgram = true},"print intermediate versions of the Chalice program"),
+ "print" -> ({() => aNoBplFile = false},"output the Boogie program used for verification to 'out.bpl'"),
+ "printIntermediate" -> ({() => aPrintProgram = true},"print intermediate versions of the Chalice program"),
"noTranslate" -> (
{() => aDoTranslate = false},
"do not translate the program to Boogie (only parse and typecheck)"),
@@ -126,6 +131,7 @@ object Chalice {
// help text for options with arguments
val nonBooleanOptions = ListMap(
"boogie:<file>" -> "use the executable of Boogie at <file>",
+ "print:<file>" -> "print the Boogie program used for verification into file <file>",
"defaults:<level>" -> ("defaults to reduce specification overhead\n"+
"level 0 or below: no defaults\n"+
"level 1: unfold predicates with receiver this in pre and postconditions\n"+
@@ -152,6 +158,7 @@ object Chalice {
for (a <- args) {
if (a == "/help" || a == "-help") {Console.out.println(help); return None}
else if ((a.startsWith("-") || a.startsWith("/")) && (options contains a.substring(1))) options(a.substring(1))._1()
+ else if (a.startsWith("/print:") || a.startsWith("-print:")) {aBplFile = a.substring(7); aNoBplFile = false}
else if (a.startsWith("/boogie:") || a.startsWith("-boogie:")) aBoogiePath = a.substring(8)
else if (a.startsWith("/defaults:") || a.startsWith("-defaults:")) {
try {
@@ -216,6 +223,8 @@ object Chalice {
val boogieArgs = aBoogieArgs
val gen = aGen
val showFullStackTrace = aShowFullStackTrace
+ val noBplFile = aNoBplFile
+ val bplFile = aBplFile
def getHelp(): String = help
})
}
@@ -274,43 +283,94 @@ 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 params.bplFile)
+ if (!params.noBplFile) writeFile(bplFilename, bplText);
+ // run Boogie.exe on out.bpl
+ val boogie = Runtime.getRuntime.exec(boogiePath + " /errorTrace:0 " + boogieArgs + "stdin.bpl");
+ 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 +379,7 @@ object Chalice {
return
}
case e:NotSupportedException => {
- if (showFullStackTrace) {
+ if (params.showFullStackTrace) {
e.printStackTrace()
Console.err.println()
Console.err.println()
@@ -328,60 +388,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..e802b7e7 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) {
@@ -781,6 +790,9 @@ object Resolver {
case c:Class if (c.IsNormalClass) =>
p = MonitorEpsilon(Some(exp))
p.pos = a.pos
+ case null =>
+ // ignore, found error earlier
+ p = Star
case _ =>
context.Error(a.pos, "type " + typ.FullName + " of variable " + id + " is not supported inside a rd expression.")
p = Star
@@ -900,6 +912,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 +1251,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..bd4f3e10 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,105 @@ 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
+
+ def isOldEtran = {
+ Heap match {
+ case Boogie.Old(_) => true
+ case _ => false
+ }
+ }
+
+ /** 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 +1564,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 +1599,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,41 +1613,49 @@ 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 o = Tr(obj)
+ val (flagV, flag) = Boogie.NewBVar("predFlag", tbool, true)
- val receiverOk = isDefined(obj) ::: prove(nonNull(Tr(obj)), obj.pos, "Receiver might be null.");
+ val receiverOk = isDefined(obj) ::: prove(nonNull(o), obj.pos, "Receiver might be null.");
val definition = scaleExpressionByPermission(SubstThis(DefinitionOf(pred.predicate), obj), perm, unfolding.pos)
// pick new k
val (unfoldingKV, unfoldingK) = Boogie.NewBVar("unfoldingK", tint, true)
- Comment("unfolding") ::
+ val res = Comment("unfolding") ::
BLocal(unfoldingKV) :: bassume(0 < unfoldingK && 1000*unfoldingK < percentPermission(1)) ::
+ BLocal(flagV) :: (flag := true) ::
// 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) :::
+ // remove secondary permissions (if any), and add them again
+ (if (isOldEtran) Nil else
+ UpdateSecMaskDuringUnfold(pred.predicate, Tr(obj), Heap.select(Tr(obj), pred.predicate.FullName), perm, unfoldingK) :::
+ TransferPermissionToSecMask(pred.predicate, obj, perm, unfolding.pos)) :::
// check definedness of e in state where the predicate is unfolded
tmpTranslator.isDefined(e)
+
+ // record folded predicate
+ val version = Heap.select(o, pred.predicate.FullName)
+ if (!isOldEtran) fpi.addFoldedPredicate(FoldedPredicate(pred.predicate, o, version, fpi.currentConditions, flag))
+
+ res
case Iff(e0,e1) =>
isDefined(e0) ::: isDefined(e1)
case Implies(e0,e1) =>
@@ -1607,8 +1707,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 +1725,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 +1740,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 +1748,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 +1757,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 +1789,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 +1817,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 +1899,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)
+ //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)
- 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 +1918,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 +1943,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 +1955,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 +1990,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 +2004,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 +2018,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,43 +2060,191 @@ 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 := Heap.select(o, pred.predicate.FullName)) ::
+ (if(check) isDefined(uf)(true) else
+ if (isOldEtran) Nil else
+ // remove secondary permissions (if any), and add them again
+ UpdateSecMaskDuringUnfold(pred.predicate, o, Heap.select(o, pred.predicate.FullName), perm, currentK) :::
+ TransferPermissionToSecMask(pred.predicate, BoogieExpr(receiver), perm, uf.pos)
+ ) :::
+ bassume(Tr(uf))
+
+ // record folded predicate
+ if (!isOldEtran) fpi.addFoldedPredicate(FoldedPredicate(pred.predicate, receiver, version, 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.") ::
- DecPermissionBoth(obj, memberName, f, n, em, error, pos, exactchecking)
+ (if (isUpdatingSecMask) DecPermissionBoth2(obj, memberName, f, n, em, error, pos, exactchecking)
+ else DecPermissionBoth(obj, memberName, f, n, em, error, pos, exactchecking))
case PermissionType.Epsilons =>
bassert(n > 0, error.pos, error.message + " The permission at " + pos + " might not be positive.") ::
- DecPermissionEpsilon(obj, memberName, n, em, error, pos)
+ (if (isUpdatingSecMask) DecPermissionEpsilon2(obj, memberName, n, em, error, pos)
+ else DecPermissionEpsilon(obj, memberName, n, em, error, pos))
case PermissionType.Fraction =>
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) DecPermission2(obj, memberName, f, em, error, pos, exactchecking)
+ else 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 +2276,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 +2288,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 +2296,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 +2346,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 +2357,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 +2373,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 +2390,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 +2478,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 +2506,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 +2525,13 @@ 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 CanReadForSure2(obj: Boogie.Expr, field: Boogie.Expr): Boogie.Expr = new Boogie.FunctionApp("CanReadForSure", List(SecMask, obj, 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 +2545,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 +2563,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,9 +2572,31 @@ 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 DecPermission2(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr, mask: Boogie.Expr, error: ErrorMessage, pos: Position, exactchecking: Boolean): List[Boogie.Stmt] = {
+ DecPermission(obj, field, howMuch, mask, error, pos, exactchecking) :::
+ Boogie.If(new Boogie.MapSelect(mask, obj, field, "perm$R") < 0,
+ MapUpdate3(mask, obj, field, "perm$R", 0),
+ Nil)
+ }
+ def DecPermissionEpsilon2(obj: Boogie.Expr, field: String, epsilons: Boogie.Expr, mask: Boogie.Expr, error: ErrorMessage, pos: Position): List[Boogie.Stmt] = {
+ DecPermissionEpsilon(obj, field, epsilons, mask, error, pos) :::
+ Boogie.If(new Boogie.MapSelect(mask, obj, field, "perm$N") < 0,
+ MapUpdate3(mask, obj, field, "perm$N", 0),
+ Nil)
}
+ def DecPermissionBoth2(obj: Boogie.Expr, field: String, howMuch: Boogie.Expr, epsilons: Boogie.Expr, mask: Boogie.Expr, error: ErrorMessage, pos: Position, exactchecking: Boolean): List[Boogie.Stmt] = {
+ DecPermissionBoth(obj, field, howMuch, epsilons, mask, error, pos, exactchecking) :::
+ Boogie.If(new Boogie.MapSelect(mask, obj, field, "perm$R") < 0,
+ MapUpdate3(mask, obj, field, "perm$R", 0),
+ Nil) ::
+ Boogie.If(new Boogie.MapSelect(mask, obj, field, "perm$N") < 0,
+ MapUpdate3(mask, obj, field, "perm$N", 0),
+ Nil) :: Nil
+ }
+
def MapUpdate3(m: Boogie.Expr, arg0: Boogie.Expr, arg1: String, arg2: String, rhs: Boogie.Expr) = {
// m[a,b,c] := rhs
@@ -2406,6 +2728,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 +2744,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 +2770,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 +2883,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 +2935,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 +3088,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 +3254,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..f457c481
--- /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
+ }
+
+ 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..ae84772b
--- /dev/null
+++ b/Chalice/tests/predicates/aux-info.output.txt
@@ -0,0 +1,4 @@
+Verification of aux-info.chalice using parameters=""
+
+
+Boogie program verifier finished with 0 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/framing-fields.chalice b/Chalice/tests/predicates/framing-fields.chalice
new file mode 100644
index 00000000..ce168f26
--- /dev/null
+++ b/Chalice/tests/predicates/framing-fields.chalice
@@ -0,0 +1,24 @@
+class List
+{
+ var value:int;
+ var next:List;
+ predicate valid { acc(value) && acc(next) && (next!=null ==> next.valid) }
+
+ method set(x:int, y:int) requires valid; ensures valid; {}
+}
+
+class C
+{
+ method M (x:List, y:List)
+ requires x!=null && y!=null && x!=y && x.valid && y.valid;
+ requires unfolding x.valid in x.next!=y;
+ requires unfolding y.valid in y.next!=x;
+ // the two requirements above are needed, otherwise Chalice cannot prove that the two lists are disjoint
+ {
+ var i: int := unfolding x.valid in x.value;
+ var j: int := unfolding y.valid in y.value;
+ call y.set(0,10);
+ assert unfolding x.valid in (i == x.value); // succeeds
+ assert unfolding y.valid in (j == y.value); // correctly fails to verify
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/framing-fields.output.txt b/Chalice/tests/predicates/framing-fields.output.txt
new file mode 100644
index 00000000..3a7ea2ba
--- /dev/null
+++ b/Chalice/tests/predicates/framing-fields.output.txt
@@ -0,0 +1,5 @@
+Verification of framing-fields.chalice using parameters=""
+
+ 22.5: Assertion might not hold. The expression at 22.12 might not evaluate to true.
+
+Boogie program verifier finished with 1 errors and 0 smoke test warnings.
diff --git a/Chalice/tests/predicates/framing-functions.chalice b/Chalice/tests/predicates/framing-functions.chalice
new file mode 100644
index 00000000..8b66a473
--- /dev/null
+++ b/Chalice/tests/predicates/framing-functions.chalice
@@ -0,0 +1,25 @@
+class List
+{
+ var value:int;
+ var next:List;
+ predicate valid { acc(value) && acc(next) && (next!=null ==> next.valid) }
+
+ method set(x:int, y:int) requires valid; ensures valid; {}
+
+ function itemAt(i: int): int
+ requires valid && 0 <= i;
+ { unfolding valid in i == 0 || next == null ? value : next.itemAt(i-1) }
+}
+
+class C
+{
+ method M (x:List, y:List)
+ requires x!=null && y!=null && x!=y && x.valid && y.valid;
+ {
+ var i: int := x.itemAt(0);
+ var j: int := y.itemAt(0);
+ call y.set(0,10);
+ assert i==x.itemAt(0); // succeeds
+ assert j==y.itemAt(0); // correctly fails to verify
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/framing-functions.output.txt b/Chalice/tests/predicates/framing-functions.output.txt
new file mode 100644
index 00000000..01bdd7bb
--- /dev/null
+++ b/Chalice/tests/predicates/framing-functions.output.txt
@@ -0,0 +1,5 @@
+Verification of framing-functions.chalice using parameters=""
+
+ 23.5: Assertion might not hold. The expression at 23.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/setset.chalice b/Chalice/tests/predicates/setset.chalice
new file mode 100644
index 00000000..512c65c1
--- /dev/null
+++ b/Chalice/tests/predicates/setset.chalice
@@ -0,0 +1,57 @@
+class Node {
+ var value: int;
+
+ method init(v: int)
+ requires acc(value)
+ ensures valid
+ {
+ value := v
+ fold this.valid
+ }
+
+ function get():int requires valid { unfolding valid in value }
+
+ method set(v: int)
+ requires valid
+ ensures valid && get() == v
+ {
+ unfold valid
+ value := v
+ fold valid
+ }
+
+ predicate valid {
+ acc(value)
+ }
+
+ method main(x: Node, y: Node)
+ requires x != null && y != null
+ requires x.valid && y.valid
+ {
+ call x.set(3)
+ call y.set(3)
+ call x.set(3)
+ call y.set(3)
+ call x.set(3)
+ call y.set(3)
+ call x.set(3)
+ unfold x.valid
+ x.value := 3
+ fold x.valid
+ call y.set(3)
+ call x.set(3)
+ call y.set(3)
+ unfold x.valid
+ x.value := 3
+ fold x.valid
+ unfold x.valid
+ x.value := 3
+ fold x.valid
+ call x.set(3)
+ call y.set(3)
+ call x.set(4)
+
+ assert y.get() == 3
+ assert x.get() == 3 // error: should fail
+ }
+} \ No newline at end of file
diff --git a/Chalice/tests/predicates/setset.output.txt b/Chalice/tests/predicates/setset.output.txt
new file mode 100644
index 00000000..c20911f0
--- /dev/null
+++ b/Chalice/tests/predicates/setset.output.txt
@@ -0,0 +1,8 @@
+Verification of setset.chalice using parameters=""
+
+ 55.5: Assertion might not hold. The expression at 55.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.
+ 27.3: The end of method main is unreachable.
+
+Boogie program verifier finished with 1 errors and 1 smoke test warnings.
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/predicates/unfolding.chalice b/Chalice/tests/predicates/unfolding.chalice
new file mode 100644
index 00000000..f01b237d
--- /dev/null
+++ b/Chalice/tests/predicates/unfolding.chalice
@@ -0,0 +1,31 @@
+class Cell {
+ var value: int;
+
+ predicate p { acc(value) }
+
+ method test()
+ requires p
+ {
+ var tmp: int := unfolding p in value;
+ var tmp2: int := unfolding p in value;
+ call void()
+ assert tmp == unfolding p in value // ERROR: should fail
+ }
+
+ method test2()
+ requires p
+ {
+ var tmp: int := unfolding p in value;
+ var tmp2: int := unfolding p in value;
+ call v()
+ assert tmp == unfolding p in value
+ }
+
+ method v() requires true {}
+
+ method void()
+ requires p
+ ensures p
+ {}
+
+}
diff --git a/Chalice/tests/predicates/unfolding.output.txt b/Chalice/tests/predicates/unfolding.output.txt
new file mode 100644
index 00000000..4a1ebbde
--- /dev/null
+++ b/Chalice/tests/predicates/unfolding.output.txt
@@ -0,0 +1,5 @@
+Verification of unfolding.chalice using parameters=""
+
+ 12.5: Assertion might not hold. The expression at 12.12 might not evaluate to true.
+
+Boogie program verifier finished with 1 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/internal-bug-2.chalice b/Chalice/tests/regressions/internal-bug-2.chalice
new file mode 100644
index 00000000..ac6b5a09
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-2.chalice
@@ -0,0 +1,13 @@
+class Lala {
+ var x;
+
+ predicate inv { acc(x) }
+
+ method koko()
+ requires inv
+ {
+ x := x + 1;
+ assert (unfolding inv in x) == old(unfolding inv in x)
+ }
+}
+
diff --git a/Chalice/tests/regressions/internal-bug-2.output.txt b/Chalice/tests/regressions/internal-bug-2.output.txt
new file mode 100644
index 00000000..3b763659
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-2.output.txt
@@ -0,0 +1,8 @@
+Verification of internal-bug-2.chalice using parameters=""
+
+ 9.9: Location might not be writable
+
+The program did not fully verify; the smoke warnings might be misleading if contradictions are introduced by failing proof attempts of the verification.
+ 6.5: The end of method koko is unreachable.
+
+Boogie program verifier finished with 1 errors and 1 smoke test warnings.
diff --git a/Chalice/tests/regressions/internal-bug-3.chalice b/Chalice/tests/regressions/internal-bug-3.chalice
new file mode 100644
index 00000000..17b6dd25
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-3.chalice
@@ -0,0 +1,8 @@
+class C
+{
+ var f: int
+ method M ()
+ requires acc(f, 100-rd(non_existing_field))
+ {
+ }
+}
diff --git a/Chalice/tests/regressions/internal-bug-3.output.txt b/Chalice/tests/regressions/internal-bug-3.output.txt
new file mode 100644
index 00000000..5f5ebd08
--- /dev/null
+++ b/Chalice/tests/regressions/internal-bug-3.output.txt
@@ -0,0 +1,4 @@
+Verification of internal-bug-3.chalice using parameters=""
+
+The program did not typecheck.
+5.28: undeclared member non_existing_field in class C
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..eb26d4ec 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
@@ -26,7 +26,7 @@ for %%f in (examples permission-model general-tests regressions) do (
REM Run refinement regression tests
cd refinements
-call test.bat
+REM call test.bat
cd ..
if !nosummary!==0 (
diff --git a/Jennisys/Jennisys.sln b/Jennisys/Jennisys.sln
index af8d8f4a..3f213e27 100644
--- a/Jennisys/Jennisys.sln
+++ b/Jennisys/Jennisys.sln
@@ -2,6 +2,9 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Jennisys", "Jennisys\Jennisys.fsproj", "{F2FF4B3A-2FE8-474A-88DF-6950F7D78908}"
+ ProjectSection(ProjectDependencies) = postProject
+ {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83} = {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "..\Source\Model\Model.csproj", "{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}"
EndProject
diff --git a/Jennisys/Jennisys/Analyzer.fs b/Jennisys/Jennisys/Analyzer.fs
index 8172718b..db4887ed 100644
--- a/Jennisys/Jennisys/Analyzer.fs
+++ b/Jennisys/Jennisys/Analyzer.fs
@@ -406,7 +406,7 @@ let FindClauses trueOnly resolverFunc heapInst expr =
let exprAllResolved = EvalFull heapInst expr
match exprAllResolved with
| BoolLiteral(true) -> acc @ (exprEval |> SplitIntoConjunts)
- | BoolLiteral(false) -> if trueOnly then acc else acc @ (UnaryNot exprEval |> SplitIntoConjunts)
+ | BoolLiteral(false) -> acc //if trueOnly then acc else acc @ (UnaryNot exprEval |> SplitIntoConjunts)
| _ -> acc
with
| _ -> acc
@@ -416,24 +416,6 @@ let FindClauses trueOnly resolverFunc heapInst expr =
/// Descends down a given expression and returns all sub-expressions that evaluate to TrueLiteral
let FindTrueClauses resolverFunc heapInst expr =
FindClauses true resolverFunc heapInst expr
-// let MyFun expr acc =
-// try
-// match expr with
-// // skip binary logical operators because we want to find smallest sub-expressions
-// | BinaryExpr(_,op,_,_) when IsLogicalOp op -> acc
-// | _ ->
-// let exprEval = EvalAndCheckTrue heapInst resolverFunc expr
-// match exprEval with
-// | _ when exprEval = TrueLiteral -> acc
-// | _ ->
-// let exprAllResolved = EvalFull heapInst expr
-// match exprAllResolved with
-// | BoolLiteral(true) -> acc @ [exprEval]
-// | _ -> acc
-// with
-// | _ -> acc
-// (* --- function body starts here --- *)
-// DescendExpr2 MyFun expr []
/// Returns a list of boolean expressions obtained by combining (in some way)
/// the two given list of conditions conditions
@@ -456,6 +438,42 @@ let GetAllPossibleConditions specConds argConds aliasingConds =
allConds |> List.filter (fun e -> not (e = TrueLiteral))
|> Utils.ListDeduplicate
+// check whther a given solution (in the form of heapInst) verifies assuming a given guard
+let rec CheckGuard prog comp m candCond indent idt heapInst callGraph =
+ let rec __MinGuard guard idx m2 sol =
+ let conjs = SplitIntoConjunts guard
+ let len = List.length conjs
+ if idx >= 0 && idx < len && len > 1 then
+ let guard' = conjs |> Utils.ListRemoveIdx (len - idx - 1) |> List.fold BinaryAnd TrueLiteral
+ match CheckGuard prog comp m guard' indent idt heapInst callGraph with
+ | Some(x) -> x
+ | None -> __MinGuard guard (idx+1) m2 sol
+ else
+ guard, m2, sol
+
+ let m2 = AddPrecondition m candCond
+ let sol = MakeModular (indent+2) prog comp m2 candCond heapInst callGraph
+ Logger.Info (idt + " - verifying partial solution ... ")
+ let verified =
+ if Options.CONFIG.verifyPartialSolutions then
+ VerifySolution prog sol Options.CONFIG.genRepr
+ else
+ true
+ if verified then
+ if Options.CONFIG.verifyPartialSolutions then Logger.InfoLine "VERIFIED" else Logger.InfoLine "SKIPPED"
+ if Options.CONFIG.minimizeGuards then
+ Logger.InfoLine(idt + " - minimizing guard ... " + (PrintExpr 0 candCond))
+ Some(__MinGuard candCond 0 m2 sol)
+ else
+ Some(candCond,m2,sol)
+ else
+ Logger.InfoLine ("NOT VERIFIED")
+ None
+
+// iteratively tries to remove conjunts and check whether the solutions still verifies
+//let MinimizeGuard guard prog comp m heapInst callGraph indent =
+
+
// ============================================================================
/// Attempts to synthesize the initialization code for the given constructor "m"
///
@@ -733,32 +751,6 @@ and TryInferConditionals indent prog comp m unifs heapInst callGraph premises =
let loggerFunc = fun e -> Logger.TraceLine (sprintf "%s --> %s" idt (PrintExpr 0 e))
let methodArgs = GetMethodInArgs m
- /// Tries to minimize the guard for a given (already verified) solution
- let rec __MinimizeGuard oldGuard guard c m sol i =
- let guardList = SplitIntoConjunts guard
- Logger.TraceLine (sprintf "Minimizing guard: %s [%i]" (PrintExpr 0 guard) i)
- let ___ReplaceGuard newGuard sol =
- let lst = sol |> Map.find (c,m)
- let newLst = lst |> List.map (fun (g,hInst) -> if g = guard then (newGuard,hInst) else (g,hInst))
- if newLst = lst then
- Logger.TraceLine "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa lst aaaaaaaaaaaaaaaaaaaaaaa" else ()
- let newMeth = SetPrecondition m (BinaryAnd oldGuard newGuard)
- let newSol = sol |> Utils.MapReplaceKey (c,m) (c,newMeth) newLst
- if newSol = sol then Logger.TraceLine "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa sol aaaaaaaaaaaaaaaaaaaaaaaaaa" else ()
- newMeth,newSol
- if i >= List.length guardList || List.length guardList <= 1 then
- guard,m,sol
- else
- let newGuardList = Utils.ListRemoveNth i guardList
- let newGuard = newGuardList |> List.fold BinaryAnd TrueLiteral
- let m',sol' = ___ReplaceGuard newGuard sol
- let verified = VerifySolution prog sol' Options.CONFIG.genRepr
- if verified then
- Logger.TraceLine (sprintf "clause %s successfully removed" (PrintExpr 0 (List.nth guardList i)))
- __MinimizeGuard oldGuard newGuard c m' sol' 0
- else
- __MinimizeGuard oldGuard guard c m sol (i+1)
-
/// Iterates through a given list of boolean conditions and checks
/// which one suffices. If it finds such a condition, it returns
/// the following three things:
@@ -777,30 +769,9 @@ and TryInferConditionals indent prog comp m unifs heapInst callGraph premises =
Logger.InfoLine (sprintf "%s candidate pre-condition: %s" idt (PrintExpr 0 candCond))
Logger.InfoLine (sprintf "%s ------------------------" idt)
let idt = idt + " "
- let oldPrecondition = GetMethodPre m
- let m2 = AddPrecondition m candCond
- let sol = MakeModular (indent+2) prog comp m2 candCond heapInst callGraph
- Logger.Info (idt + " - verifying partial solution ... ")
- let verified =
- if Options.CONFIG.verifyPartialSolutions then
- VerifySolution prog sol Options.CONFIG.genRepr
- else
- true
- if verified then
- if Options.CONFIG.verifyPartialSolutions then
- Logger.InfoLine "VERIFIED"
- let g',m',sol' =
- if Options.CONFIG.minimizeGuards then
- __MinimizeGuard oldPrecondition candCond comp m2 sol 0
- else
- candCond,m2,sol
- Some(g',m',sol')
- else
- Logger.InfoLine "SKIPPED"
- Some(candCond,m2,sol)
- else
- Logger.InfoLine "NOT VERIFIED"
- __TryOutConditions heapInst rest
+ match CheckGuard prog comp m candCond indent idt heapInst callGraph with
+ | Some(guard, m2, sol) -> Some(guard, m2, sol)
+ | None -> __TryOutConditions heapInst rest
if IsSolution1stLevelOnly heapInst then
// try to find a non-recursive solution
@@ -828,6 +799,7 @@ and TryInferConditionals indent prog comp m unifs heapInst callGraph premises =
match __TryOutConditions heapInst allConds with
| Some(candCond,m2,sol) ->
+ Logger.InfoLine (idt + " - guard found: " + (PrintExpr 0 candCond))
let solThis = match TryFindExistingAndConvertToSolution indent comp m2 candCond callGraph with
| Some(sol2) -> sol2
| None -> sol
diff --git a/Jennisys/Jennisys/AstUtils.fs b/Jennisys/Jennisys/AstUtils.fs
index 28b84ab9..11189ebb 100644
--- a/Jennisys/Jennisys/AstUtils.fs
+++ b/Jennisys/Jennisys/AstUtils.fs
@@ -613,11 +613,11 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| SequenceExpr(elist) -> IntLiteral(List.length elist)
| _ -> SeqLength(e')
| SequenceExpr(elist) ->
- let elist' = elist |> List.fold (fun acc e -> (__EvalSym resolverFunc returnFunc ctx e) :: acc) [] |> List.rev
+ let elist' = elist |> List.map (__EvalSym resolverFunc returnFunc ctx) // List.fold (fun acc e -> (__EvalSym resolverFunc returnFunc ctx e) :: acc) [] |> List.rev
SequenceExpr(elist')
| SetExpr(elist) ->
- let eset' = elist |> List.fold (fun acc e -> Set.add (__EvalSym resolverFunc returnFunc ctx e) acc) Set.empty
- SetExpr(Set.toList eset')
+ let elist' = elist |> List.map (__EvalSym resolverFunc returnFunc ctx) //List.fold (fun acc e -> Set.add (__EvalSym resolverFunc returnFunc ctx e) acc) Set.empty
+ SetExpr(elist' |> Set.ofList |> Set.toList)
| MethodOutSelect(e,name) ->
MethodOutSelect(__EvalSym resolverFunc returnFunc ctx e, name)
| MethodCall(rcv,cname, mname,aparams) ->
@@ -670,8 +670,6 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| "<" ->
match e1'.Force(), e2'.Force() with
| IntLiteral(n1), IntLiteral(n2) -> BoolLiteral(n1 < n2)
- | SetExpr(s1), SetExpr(s2) -> BoolLiteral((List.length s1) < (List.length s2))
- | SequenceExpr(s1), SequenceExpr(s2) -> BoolLiteral((List.length s1) < (List.length s2))
| _ -> recomposed.Force()
| "<=" ->
let e1'' = e1'.Force()
@@ -681,14 +679,10 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| Some(true) -> TrueLiteral
| _ -> match e1'', e2'' with
| IntLiteral(n1), IntLiteral(n2) -> BoolLiteral(n1 <= n2)
- | SetExpr(s1), SetExpr(s2) -> BoolLiteral((List.length s1) <= (List.length s2))
- | SequenceExpr(s1), SequenceExpr(s2) -> BoolLiteral((List.length s1) <= (List.length s2))
| _ -> recomposed.Force()
| ">" ->
match e1'.Force(), e2'.Force() with
| IntLiteral(n1), IntLiteral(n2) -> BoolLiteral(n1 > n2)
- | SetExpr(s1), SetExpr(s2) -> BoolLiteral((List.length s1) > (List.length s2))
- | SequenceExpr(s1), SequenceExpr(s2) -> BoolLiteral((List.length s1) > (List.length s2))
| _ -> recomposed.Force()
| ">=" ->
let e1'' = e1'.Force()
@@ -698,8 +692,6 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| Some(true) -> TrueLiteral
| _ -> match e1'', e2'' with
| IntLiteral(n1), IntLiteral(n2) -> BoolLiteral(n1 >= n2)
- | SetExpr(s1), SetExpr(s2) -> BoolLiteral((List.length s1) >= (List.length s2))
- | SequenceExpr(s1), SequenceExpr(s2) -> BoolLiteral((List.length s1) >= (List.length s2))
| _ -> recomposed.Force()
| ".." ->
let e1'' = e1'.Force()
@@ -764,7 +756,6 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| BoolLiteral(false) -> BoolLiteral(false)
| _ ->
match e1'.Force(), e2'.Force() with
- | BoolLiteral(false), _ -> BoolLiteral(false)
| _, BoolLiteral(false) -> BoolLiteral(false)
| BoolLiteral(b1), BoolLiteral(b2) -> BoolLiteral(b1 && b2)
| _ -> BinaryAnd (e1'.Force()) (e2'.Force())
@@ -774,7 +765,6 @@ let EvalSym2 fullResolverFunc otherResolverFunc returnFunc ctx expr =
| BoolLiteral(true) -> BoolLiteral(true)
| _ ->
match e1'.Force(), e2'.Force() with
- | BoolLiteral(true), _ -> BoolLiteral(true)
| _, BoolLiteral(true) -> BoolLiteral(true)
| BoolLiteral(b1), BoolLiteral(b2) -> BoolLiteral(b1 || b2)
| _ -> BinaryOr (e1'.Force()) (e2'.Force())
diff --git a/Jennisys/Jennisys/CodeGen.fs b/Jennisys/Jennisys/CodeGen.fs
index 7ec8d33e..8df4ca60 100644
--- a/Jennisys/Jennisys/CodeGen.fs
+++ b/Jennisys/Jennisys/CodeGen.fs
@@ -9,6 +9,7 @@ open TypeChecker
open PrintUtils
open DafnyPrinter
open DafnyModelUtils
+open Options
let validFuncName = "Valid()"
let validSelfFuncName = "Valid_self()"
@@ -48,19 +49,22 @@ let GetFieldValidExpr flds validFunName numUnrolls =
// add the recursive definition as well
let recExprs =
if not (validFunName = validFuncName) && Options.CONFIG.recursiveValid then
- flds |> List.map (fun var ->
+ flds //|> List.filter (fun var -> not ((GetExtVarName var).StartsWith("_back_"))) //don't use back pointers
+ |> List.map (fun var ->
let name = GetExtVarName var
BinaryImplies (BinaryNeq (IdLiteral(name)) NullLiteral) (Dot(IdLiteral(name), validFuncName)))
else
[]
recExprs @ unrolledExprs
-let GetFieldsForValidExpr allFields prog : VarDecl list =
+let GetFieldsForValidExpr allFields prog comp : VarDecl list =
+ let frameVars = GetFrameFields comp
allFields |> List.filter (fun var -> IsUserType prog (GetVarType var))
+ |> List.filter (fun var -> Utils.ListContains var frameVars)
let GetFieldsValidExprList clsName allFields prog : Expr list =
- let fields = GetFieldsForValidExpr allFields prog
- let fieldsByType = GroupFieldsByType fields
+ let fields = GetFieldsForValidExpr allFields prog (FindComponent prog clsName |> ExtractOption)
+ let fieldsByType = GroupFieldsByType fields
fieldsByType |> Map.fold (fun acc t varSet ->
let validFunName, numUnrolls =
match t with
@@ -234,26 +238,48 @@ let PrintReprAssignments prog heapInst indent =
|> Set.toList
|> Utils.TopSort __FollowsFunc
|> List.rev
+ let rec __GetReprConcrete obj =
+ let expr = SetExpr([ObjLiteral(obj.name)])
+ let builder = CascadingBuilder<_>(expr)
+ builder {
+ let typeName = GetTypeShortName obj.objType
+ let! comp = FindComponent prog typeName
+ let vars = GetFrameFields comp
+ let nonNullVars = vars |> List.choose (fun v ->
+ let lst = heapInst.assignments |> List.choose (function FieldAssignment(x,y) -> Some(x,y) | _ -> None)
+ match Utils.ListMapTryFind (obj,v) lst with
+ | Some(ObjLiteral(n)) when not (n = "null" || n = obj.name) -> Some(v,n)
+ | _ -> None)
+ return nonNullVars |> List.map (fun (var,objName) -> var,(Map.find objName heapInst.objs))
+ |> List.fold (fun acc (var,varValObj) ->
+ if Options.CONFIG.genMod then
+ BinaryAdd acc (Dot(Dot(ObjLiteral(obj.name), (GetVarName var)), "Repr"))
+ else
+ BinaryAdd acc (__GetReprConcrete varValObj)
+ ) expr
+ }
+
let reprGetsList = objs |> List.fold (fun acc obj ->
- let expr = SetExpr([ObjLiteral(obj.name)])
- let builder = CascadingBuilder<_>(expr)
- let fullRhs = builder {
- let typeName = GetTypeShortName obj.objType
- let! comp = FindComponent prog typeName
- let vars = GetFrameFields comp
- let nonNullVars = vars |> List.filter (fun v ->
- let lst = heapInst.assignments |> List.choose (function FieldAssignment(x,y) -> Some(x,y) | _ -> None)
- match Utils.ListMapTryFind (obj,v) lst with
- | Some(ObjLiteral(n)) when not (n = "null") -> true
- | _ -> false)
- return nonNullVars |> List.fold (fun a v ->
- BinaryAdd a (Dot(Dot(ObjLiteral(obj.name), (GetVarName v)), "Repr"))
- ) expr
- }
- let fullReprExpr = BinaryGets (Dot(ObjLiteral(obj.name), "Repr")) fullRhs
- fullReprExpr :: acc
+ let objStmt = BinaryGets (Dot(ObjLiteral(obj.name), "Repr")) (__GetReprConcrete obj)
+ objStmt :: acc
+// let expr = SetExpr([ObjLiteral(obj.name)])
+// let builder = CascadingBuilder<_>(expr)
+// let fullRhs = builder {
+// let typeName = GetTypeShortName obj.objType
+// let! comp = FindComponent prog typeName
+// let vars = GetFrameFields comp
+// let nonNullVars = vars |> List.filter (fun v ->
+// let lst = heapInst.assignments |> List.choose (function FieldAssignment(x,y) -> Some(x,y) | _ -> None)
+// match Utils.ListMapTryFind (obj,v) lst with
+// | Some(ObjLiteral(n)) when not (n = "null") -> true
+// | _ -> false)
+// return nonNullVars |> List.fold (fun a v ->
+// BinaryAdd a (Dot(Dot(ObjLiteral(obj.name), (GetVarName v)), "Repr"))
+// ) expr
+// }
+// let fullReprExpr = BinaryGets (Dot(ObjLiteral(obj.name), "Repr")) fullRhs
+// fullReprExpr :: acc
) []
- let reprValidExpr = GetAllocObjects heapInst |> Set.fold (fun acc obj -> BinaryAnd acc (Dot(ObjLiteral(obj.name), validFuncName))) TrueLiteral
let reprStr = if not (reprGetsList = []) then
idt + "// repr stuff" + newline +
@@ -261,6 +287,8 @@ let PrintReprAssignments prog heapInst indent =
else
""
+ let reprValidExpr = GetAllocObjects heapInst |> Set.fold (fun acc obj -> BinaryAnd acc (Dot(ObjLiteral(obj.name), validFuncName))) TrueLiteral
+
let assertValidStr = if not (reprValidExpr = TrueLiteral) then
idt + "// assert repr objects are valid (helps verification)" + newline +
(PrintStmt (ExprStmt(AssertExpr(reprValidExpr))) indent true)
diff --git a/Jennisys/Jennisys/DafnyModelUtils.fs b/Jennisys/Jennisys/DafnyModelUtils.fs
index 1588da57..50d5f2c5 100644
--- a/Jennisys/Jennisys/DafnyModelUtils.fs
+++ b/Jennisys/Jennisys/DafnyModelUtils.fs
@@ -39,16 +39,6 @@ let GetElemFullName (elem: Model.Element) =
elem.Names |> Seq.filter (fun ft -> ft.Func.Arity = 0)
|> Seq.choose (fun ft -> Some(ft.Func.Name))
|> Utils.SeqToOption
-
-let GetElemName (elem: Model.Element) =
- let fullNameOpt = GetElemFullName elem
- match fullNameOpt with
- | Some(fullName) ->
- let dotIdx = fullName.LastIndexOf(".")
- let fldName = fullName.Substring(dotIdx + 1)
- let clsName = if dotIdx = -1 then "" else fullName.Substring(0, dotIdx)
- Some(clsName, fldName)
- | None -> None
let GetRefName (ref: Model.Element) =
match ref with
@@ -73,13 +63,20 @@ let GetBool (elem: Model.Element) =
| :? Model.Boolean as bval -> bval.Value
| _ -> failwith ("not a bool element: " + elem.ToString())
+let LastDotSplit (str: string) =
+ let dotIdx = str.LastIndexOf(".")
+ let s1 = if dotIdx = -1 then "" else str.Substring(0, dotIdx)
+ let s2 = str.Substring(dotIdx + 1)
+ s1,s2
+
let GetType (e: Model.Element) prog =
let fNameOpt = GetElemFullName e
match fNameOpt with
| Some(fname) -> match fname with
| "intType" -> Some(IntType)
| Prefix "class." clsName ->
- match FindComponent prog clsName with
+ let _,shortClsName = LastDotSplit clsName
+ match FindComponent prog shortClsName with
| Some(comp) -> Some(GetClassType comp)
| None -> None
| _ -> None
@@ -155,9 +152,8 @@ let ReadHeap (model: Microsoft.Boogie.Model) prog =
let fld = ft.Args.[2]
assert (Seq.length fld.Names = 1)
let fldFullName = (Seq.nth 0 fld.Names).Func.Name
- let dotIdx = fldFullName.LastIndexOf(".")
- let fldName = fldFullName.Substring(dotIdx + 1)
- let clsName = if dotIdx = -1 then "" else fldFullName.Substring(0, dotIdx)
+ let pfix,fldName = LastDotSplit fldFullName
+ let _,clsName = LastDotSplit pfix
let refVal = ft.Result
let refObj = Unresolved(GetRefName ref)
let nonebuilder = CascadingBuilder<_>(None)
diff --git a/Jennisys/Jennisys/FixpointSolver.fs b/Jennisys/Jennisys/FixpointSolver.fs
index efb09485..b2ce1fac 100644
--- a/Jennisys/Jennisys/FixpointSolver.fs
+++ b/Jennisys/Jennisys/FixpointSolver.fs
@@ -208,7 +208,7 @@ let rec ComputeClosure heapInst expandExprFunc premises =
let lenExpr = SeqLength(lst)
match lst with
| BinaryExpr(_,"+",lhs,rhs) ->
- BinaryAdd (__fff lhs) (__fff rhs)
+ BinaryAdd (__fff lhs) (__fff rhs) //TODO: this ought to be incorrect!
| SequenceExpr(elist) ->
IntLiteral(List.length elist)
| _ -> lenExpr
@@ -216,7 +216,7 @@ let rec ComputeClosure heapInst expandExprFunc premises =
let BinaryInCombiner lhs rhs =
// distribute the "in" operation if possible
- let rec __fff lhs rhs =
+ let __fff lhs rhs =
//Logger.TraceLine ("In fff for " + (PrintExpr 0 lhs) + " and " + (PrintExpr 0 rhs))
let binInExpr = BinaryIn lhs rhs
// match rhs with
diff --git a/Jennisys/Jennisys/Jennisys.fsproj b/Jennisys/Jennisys/Jennisys.fsproj
index 38c444f9..f9bbc289 100644
--- a/Jennisys/Jennisys/Jennisys.fsproj
+++ b/Jennisys/Jennisys/Jennisys.fsproj
@@ -23,7 +23,7 @@
<WarningLevel>3</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<DocumentationFile>bin\Debug\Language.XML</DocumentationFile>
- <StartArguments>examples/List.jen /method:Node.Find</StartArguments>
+ <StartArguments>examples/DList.jen /method:DNode.Init /noGenMod</StartArguments>
<StartWorkingDirectory>C:\boogie\Jennisys\Jennisys\</StartWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
@@ -80,6 +80,9 @@
<Compile Include="Jennisys.fs" />
</ItemGroup>
<ItemGroup>
+ <Reference Include="Boogie">
+ <HintPath>..\..\Binaries\Boogie.exe</HintPath>
+ </Reference>
<Reference Include="FSharp.PowerPack">
<HintPath>C:\Program Files\FSharpPowerPack-1.9.9.9\bin\FSharp.PowerPack.dll</HintPath>
</Reference>
diff --git a/Jennisys/Jennisys/Options.fs b/Jennisys/Jennisys/Options.fs
index 66aa5b85..41ad91e5 100644
--- a/Jennisys/Jennisys/Options.fs
+++ b/Jennisys/Jennisys/Options.fs
@@ -76,6 +76,7 @@ let cfgOptions = [
{ optionName = "noRecValid"; optionType = "bool"; optionSetter = (fun v (cfg: Config) -> {cfg with recursiveValid = not (CheckBool v "noRecValid")}); descr = "unroll Valid() function"; }
{ optionName = "break"; optionType = "bool"; optionSetter = (fun v (cfg: Config) -> {cfg with breakIntoDebugger = CheckBool v "break"}); descr = "launches debugger upon start-up"; }
{ optionName = "minGuards"; optionType = "bool"; optionSetter = (fun v (cfg: Config) -> {cfg with minimizeGuards = CheckBool v "minGuards"}); descr = "tries to remove unnecessary clauses from the inferred guards"; }
+ { optionName = "noMinGuards"; optionType = "bool"; optionSetter = (fun v (cfg: Config) -> {cfg with minimizeGuards = not (CheckBool v "noMinGuards")}); descr = "don't minimize guards"; }
]
let cfgOptMap = cfgOptions |> List.fold (fun acc o -> acc |> Map.add o.optionName o) Map.empty
diff --git a/Jennisys/Jennisys/Utils.fs b/Jennisys/Jennisys/Utils.fs
index 469e5e5a..56b6b779 100644
--- a/Jennisys/Jennisys/Utils.fs
+++ b/Jennisys/Jennisys/Utils.fs
@@ -207,11 +207,11 @@ let ListContains elem lst =
let ListRemove elem lst =
lst |> List.choose (fun e -> if e = elem then None else Some(e))
-let rec ListRemoveNth n lst =
- if n = 0 then
+let rec ListRemoveIdx idx lst =
+ if idx = 0 then
List.tail lst
- else
- List.head lst :: ListRemoveNth (n-1) (List.tail lst)
+ else
+ List.head lst :: ListRemoveIdx (idx - 1) (List.tail lst)
// ===============================================================
/// ensures: |ret| = max(|lst| - cnt, 0)
diff --git a/Jennisys/Jennisys/examples/DList.jen b/Jennisys/Jennisys/examples/DList.jen
new file mode 100644
index 00000000..47c74dc1
--- /dev/null
+++ b/Jennisys/Jennisys/examples/DList.jen
@@ -0,0 +1,63 @@
+interface DList[T] {
+ var list: seq[T]
+
+ constructor Empty()
+ ensures list = []
+
+ constructor Singleton(t: T)
+ ensures list = [t]
+
+ constructor Double(p: T, q: T)
+ ensures list = [p q]
+}
+
+datamodel DList[T] {
+ var root: DNode[T]
+
+ frame
+ root
+
+ invariant
+ root = null ==> |list| = 0
+ root != null ==> list = root.list
+}
+
+interface DNode[T] {
+ var list: seq[T]
+
+ invariant
+ |list| > 0
+
+ constructor Init(t: T)
+ ensures list = [t]
+
+ constructor Double(p: T, q: T)
+ ensures list = [p q]
+
+ method List() returns (ret: seq[T])
+ ensures ret = list
+
+ method Size() returns (ret: int)
+ ensures ret = |list|
+
+ method Get(idx: int) returns (ret: T)
+ requires idx >= 0 && idx < |list|
+ ensures ret = list[idx]
+
+ method Find(n: T) returns (ret: bool)
+ ensures ret = (n in list)
+}
+
+datamodel DNode[T] {
+ var data: T
+ var next: DNode[T]
+ var prev: DNode[T]
+
+ frame
+ next
+
+ invariant
+ next = null ==> list = [data]
+ next != null ==> (list = [data] + next.list && next.prev = this)
+ prev != null ==> prev.next = this
+}
diff --git a/Jennisys/Jennisys/examples/mod2/jennisys-synth_DList.dfy b/Jennisys/Jennisys/examples/mod2/jennisys-synth_DList.dfy
new file mode 100644
index 00000000..3e1aa99f
--- /dev/null
+++ b/Jennisys/Jennisys/examples/mod2/jennisys-synth_DList.dfy
@@ -0,0 +1,255 @@
+class DList<T> {
+ ghost var Repr: set<object>;
+ ghost var list: seq<T>;
+
+ var root: DNode<T>;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (root != null ==> root in Repr && root.Repr <= Repr && this !in root.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (root == null ==> |list| == 0) &&
+ (root != null ==> list == root.list)
+ }
+
+ function Valid(): bool
+ reads *;
+ {
+ this.Valid_self() &&
+ (root != null ==> root.Valid())
+ }
+
+
+ method Double(p: T, q: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p, q];
+ ensures list[0] == p;
+ ensures list[1] == q;
+ ensures |list| == 2;
+ {
+ var gensym79 := new DNode<T>;
+ var gensym85 := new DNode<T>;
+ this.list := [p, q];
+ this.root := gensym79;
+ gensym79.data := p;
+ gensym79.list := [p, q];
+ gensym79.next := gensym85;
+ gensym79.prev := null;
+ gensym85.data := q;
+ gensym85.list := [q];
+ gensym85.next := null;
+ gensym85.prev := gensym79;
+
+ // repr stuff
+ gensym85.Repr := {gensym85};
+ gensym79.Repr := {gensym79} + {gensym85};
+ this.Repr := {this} + ({gensym79} + {gensym85});
+ // assert repr objects are valid (helps verification)
+ assert gensym79.Valid() && gensym85.Valid();
+ }
+
+
+ method Empty()
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [];
+ ensures |list| == 0;
+ {
+ this.list := [];
+ this.root := null;
+
+ // repr stuff
+ this.Repr := {this};
+ }
+
+
+ method Singleton(t: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [t];
+ ensures list[0] == t;
+ ensures |list| == 1;
+ {
+ var gensym78 := new DNode<T>;
+ this.list := [t];
+ this.root := gensym78;
+ gensym78.data := t;
+ gensym78.list := [t];
+ gensym78.next := null;
+ gensym78.prev := null;
+
+ // repr stuff
+ gensym78.Repr := {gensym78};
+ this.Repr := {this} + {gensym78};
+ // assert repr objects are valid (helps verification)
+ assert gensym78.Valid();
+ }
+
+}
+
+class DNode<T> {
+ ghost var Repr: set<object>;
+ ghost var list: seq<T>;
+
+ var data: T;
+ var next: DNode<T>;
+ var prev: DNode<T>;
+
+ function Valid_repr(): bool
+ reads *;
+ {
+ this in Repr &&
+ null !in Repr &&
+ (next != null ==> next in Repr && next.Repr <= Repr && this !in next.Repr)
+ }
+
+ function Valid_self(): bool
+ reads *;
+ {
+ Valid_repr() &&
+ (next == null ==> (list == [data] && list[0] == data) && |list| == 1) &&
+ (next != null ==> list == [data] + next.list && next.prev == this) &&
+ (prev != null ==> prev.next == this) &&
+ (|list| > 0)
+ }
+
+ function Valid(): bool
+ reads *;
+ decreases Repr;
+ {
+ this.Valid_self() &&
+ (next != null ==> next.Valid()) &&
+ (next != null ==> next.Valid_self()) &&
+ (next != null && next.next != null ==> next.next.Valid_self())
+ }
+
+
+ method Double(p: T, q: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [p, q];
+ ensures list[0] == p;
+ ensures list[1] == q;
+ ensures |list| == 2;
+ {
+ var gensym95 := new DNode<T>;
+ this.data := p;
+ this.list := [p, q];
+ this.next := gensym95;
+ this.prev := null;
+ gensym95.data := q;
+ gensym95.list := [q];
+ gensym95.next := null;
+ gensym95.prev := this;
+
+ // repr stuff
+ this.Repr := {this} + {gensym95};
+ gensym95.Repr := {gensym95};
+ // assert repr objects are valid (helps verification)
+ assert gensym95.Valid();
+ }
+
+
+ method Find(n: T) returns (ret: bool)
+ requires Valid();
+ ensures fresh(Repr - old(Repr));
+ ensures Valid();
+ ensures ret == (n in list);
+ decreases Repr;
+ {
+ if (this.next == null) {
+ ret := n == this.data;
+ } else {
+ var x_5 := this.next.Find(n);
+ ret := n == this.data || x_5;
+ }
+ }
+
+
+ method Get(idx: int) returns (ret: T)
+ requires Valid();
+ requires idx >= 0;
+ requires idx < |list|;
+ ensures fresh(Repr - old(Repr));
+ ensures Valid();
+ ensures ret == list[idx];
+ decreases Repr;
+ {
+ if (this.next == null) {
+ ret := this.data;
+ } else {
+ if (idx == 0) {
+ ret := this.data;
+ } else {
+ var x_6 := this.next.Get(idx - 1);
+ ret := x_6;
+ }
+ }
+ }
+
+
+ method Init(t: T)
+ modifies this;
+ ensures fresh(Repr - {this});
+ ensures Valid();
+ ensures list == [t];
+ ensures list[0] == t;
+ ensures |list| == 1;
+ {
+ this.data := t;
+ this.list := [t];
+ this.next := null;
+ this.prev := null;
+
+ // repr stuff
+ this.Repr := {this};
+ }
+
+
+ method List() returns (ret: seq<T>)
+ requires Valid();
+ ensures fresh(Repr - old(Repr));
+ ensures Valid();
+ ensures ret == list;
+ decreases Repr;
+ {
+ if (this.next == null) {
+ ret := [this.data];
+ } else {
+ var x_7 := this.next.List();
+ ret := [this.data] + x_7;
+ }
+ }
+
+
+ method Size() returns (ret: int)
+ requires Valid();
+ ensures fresh(Repr - old(Repr));
+ ensures Valid();
+ ensures ret == |list|;
+ decreases Repr;
+ {
+ if (this.next == null) {
+ ret := 1;
+ } else {
+ var x_8 := this.next.Size();
+ ret := 1 + x_8;
+ }
+ }
+
+}
+
+
diff --git a/Source/Boogie.sln b/Source/Boogie.sln
index 53130382..955dfb46 100644
--- a/Source/Boogie.sln
+++ b/Source/Boogie.sln
@@ -9,12 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Isabelle", "Provers\Isabell
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbsInt", "AbsInt\AbsInt.csproj", "{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}"
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}") = "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}") = "VCExpr", "VCExpr\VCExpr.csproj", "{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}"
@@ -37,8 +33,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelper\ParserHelper.csproj", "{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TPTP", "Provers\TPTP\TPTP.csproj", "{A598ED5A-93AD-4125-A555-3921A2F936FA}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}"
EndProject
Global
@@ -136,31 +130,6 @@ Global
{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU
{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Checked|.NET.ActiveCfg = Checked|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|.NET.ActiveCfg = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.Debug|.NET.Build.0 = Debug|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|.NET.ActiveCfg = Release|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|.NET.ActiveCfg = z3apidebug|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 = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.Checked|.NET.ActiveCfg = Checked|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
@@ -186,31 +155,6 @@ Global
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Checked|.NET.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|.NET.ActiveCfg = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.Debug|.NET.Build.0 = Debug|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|.NET.ActiveCfg = Release|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|.NET.ActiveCfg = z3apidebug|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 = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
{E1F10180-C7B9-4147-B51F-FA1B701966DC}.Checked|.NET.ActiveCfg = Checked|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
@@ -473,30 +417,6 @@ Global
{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU
{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU
{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}.z3apidebug|x86.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.Checked|.NET.ActiveCfg = Checked|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|.NET.ActiveCfg = Debug|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|.NET.ActiveCfg = Release|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|.NET.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Any CPU.Build.0 = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU
- {A598ED5A-93AD-4125-A555-3921A2F936FA}.z3apidebug|x86.ActiveCfg = Release|Any CPU
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|.NET.ActiveCfg = Release|Any CPU
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.ActiveCfg = Release|Any CPU
{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.Checked|Any CPU.Build.0 = Release|Any CPU
@@ -527,10 +447,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{435D5BD0-6F62-49F8-BB24-33E2257519AD} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
- {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
{9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
- {FEE9F01B-9722-4A76-A24B-72A4016DFA8E} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
{966DD87B-A29D-4F3C-9406-F680A61DC0E0} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
- {A598ED5A-93AD-4125-A555-3921A2F936FA} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D}
EndGlobalSection
EndGlobal
diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs
index d5a98913..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,14 +606,41 @@ namespace Microsoft.Boogie {
return PipelineOutcome.Done;
}
- #region Verify each implementation
+ #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
-#if ROB_DEBUG
- string now = DateTime.Now.ToString().Replace(' ','-').Replace('/','-').Replace(':','-');
- System.IO.StreamWriter w = new System.IO.StreamWriter(@"\temp\batch_"+now+".bpl");
- program.Emit(new TokenTextWriter(w));
- w.Close();
-#endif
+ #region Verify each implementation
ConditionGeneration vcgen = null;
try {
@@ -548,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);
+ }
+ 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) {
+ }
+ }
+ 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) {
@@ -593,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);
}
@@ -725,6 +736,7 @@ namespace Microsoft.Boogie {
}
}
}
+
vcgen.Close();
cce.NonNull(CommandLineOptions.Clo.TheProverFactory).Close();
@@ -733,6 +745,5 @@ namespace Microsoft.Boogie {
return PipelineOutcome.VerificationCompleted;
}
-
}
}
diff --git a/Source/BoogieDriver/BoogieDriver.csproj b/Source/BoogieDriver/BoogieDriver.csproj
index 52714dc9..9b6e329b 100644
--- a/Source/BoogieDriver/BoogieDriver.csproj
+++ b/Source/BoogieDriver/BoogieDriver.csproj
@@ -184,22 +184,10 @@
<Project>{435D5BD0-6F62-49F8-BB24-33E2257519AD}</Project>
<Name>Isabelle</Name>
</ProjectReference>
- <ProjectReference Include="..\Provers\Simplify\Simplify.csproj">
- <Project>{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}</Project>
- <Name>Simplify</Name>
- </ProjectReference>
<ProjectReference Include="..\Provers\SMTLib\SMTLib.csproj">
<Project>{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}</Project>
<Name>SMTLib</Name>
</ProjectReference>
- <ProjectReference Include="..\Provers\TPTP\TPTP.csproj">
- <Project>{A598ED5A-93AD-4125-A555-3921A2F936FA}</Project>
- <Name>TPTP</Name>
- </ProjectReference>
- <ProjectReference Include="..\Provers\Z3\Z3.csproj">
- <Project>{BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}</Project>
- <Name>Z3</Name>
- </ProjectReference>
<ProjectReference Include="..\VCGeneration\VCGeneration.csproj">
<Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
<Name>VCGeneration</Name>
diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs
index 76eaf661..274ed534 100644
--- a/Source/Core/Absy.cs
+++ b/Source/Core/Absy.cs
@@ -1803,13 +1803,37 @@ namespace Microsoft.Boogie {
{
selectors = new List<DatatypeSelector>();
}
+
+ public override void Resolve(ResolutionContext rc) {
+ HashSet<string> selectorNames = new HashSet<string>();
+ foreach (DatatypeSelector selector in selectors) {
+ if (selector.Name.StartsWith("#")) {
+ rc.Error(selector.tok, "The selector must be a non-empty string");
+ }
+ else {
+ if (selectorNames.Contains(selector.Name))
+ rc.Error(this.tok, "The selectors for a constructor must be distinct strings");
+ else
+ selectorNames.Add(selector.Name);
+ }
+ }
+ base.Resolve(rc);
+ }
+
+ public override void Typecheck(TypecheckingContext tc) {
+ CtorType outputType = this.OutParams[0].TypedIdent.Type as CtorType;
+ if (outputType == null || !outputType.IsDatatype()) {
+ tc.Error(tok, "The output type of a constructor must be a datatype");
+ }
+ base.Typecheck(tc);
+ }
}
public class DatatypeSelector : Function {
public Function constructor;
public int index;
public DatatypeSelector(Function constructor, int index)
- : base(constructor.tok,
+ : base(constructor.InParams[index].tok,
constructor.InParams[index].Name + "#" + constructor.Name,
new VariableSeq(new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.OutParams[0].TypedIdent.Type), true)),
new Formal(constructor.tok, new TypedIdent(constructor.tok, "", constructor.InParams[index].TypedIdent.Type), false))
@@ -1817,6 +1841,7 @@ namespace Microsoft.Boogie {
this.constructor = constructor;
this.index = index;
}
+
public override void Emit(TokenTextWriter stream, int level) { }
}
@@ -1830,8 +1855,8 @@ namespace Microsoft.Boogie {
{
this.constructor = constructor;
}
- public override void Emit(TokenTextWriter stream, int level) {
- }
+
+ public override void Emit(TokenTextWriter stream, int level) { }
}
public class Function : DeclWithFormals {
diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs
index e96c3fd1..62ebc77f 100644
--- a/Source/Core/AbsyCmd.cs
+++ b/Source/Core/AbsyCmd.cs
@@ -749,6 +749,7 @@ namespace Microsoft.Boogie {
} else {
stream.Write(level + 1, "invariant ");
}
+ Cmd.EmitAttributes(stream, inv.Attributes);
inv.Expr.Emit(stream);
stream.WriteLine(";");
}
diff --git a/Source/Core/AbsyType.cs b/Source/Core/AbsyType.cs
index 84703a7c..a22ece7d 100644
--- a/Source/Core/AbsyType.cs
+++ b/Source/Core/AbsyType.cs
@@ -2820,6 +2820,10 @@ Contract.Requires(that != null);
this.Arguments = arguments;
}
+ public bool IsDatatype() {
+ return QKeyValue.FindBoolAttribute(Decl.Attributes, "datatype");
+ }
+
//----------- Cloning ----------------------------------
// We implement our own clone-method, because bound type variables
// have to be created in the right way. It is /not/ ok to just clone
diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg
index 33172e7f..aed741d8 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();
@@ -66,6 +70,7 @@ Contract.Requires(cce.NonNullElements(defines,true));
if (parser.errors.count == 0)
{
program = Pgm;
+ program.ProcessDatatypeConstructors();
return 0;
}
else
@@ -111,10 +116,13 @@ CHARACTERS
cr = '\r'.
lf = '\n'.
tab = '\t'.
-
+
space = ' '.
quote = '"'.
+ newLine = cr + lf.
+ regularStringChar = ANY - quote - newLine.
+
nondigit = letter + special.
nonquote = letter + digit + space + glyph.
@@ -124,7 +132,9 @@ TOKENS
ident = [ '\\' ] nondigit {nondigit | digit}.
bvlit = digit {digit} 'b' 'v' digit {digit}.
digits = digit {digit}.
- string = quote {nonquote} quote.
+
+ string = quote { regularStringChar | "\\\"" } quote.
+
float = digit {digit} '.' {digit}.
COMMENTS FROM "/*" TO "*/" NESTED
@@ -776,6 +786,7 @@ WhileCmd<out WhileCmd/*!*/ wcmd>
Expr guard; Expr/*!*/ e; bool isFree;
List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
StmtList/*!*/ body;
+ QKeyValue kv = null;
.)
"while" (. x = t; .)
Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
@@ -783,10 +794,11 @@ WhileCmd<out WhileCmd/*!*/ wcmd>
[ "free" (. isFree = true; .)
]
"invariant"
+ { Attribute<ref kv> }
Expression<out e> (. if (isFree) {
- invariants.Add(new AssumeCmd(z, e));
+ invariants.Add(new AssumeCmd(z, e, kv));
} else {
- invariants.Add(new AssertCmd(z, e));
+ invariants.Add(new AssertCmd(z, e, kv));
}
.)
";"
diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs
index 9413cf30..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;
@@ -447,6 +448,7 @@ namespace Microsoft.Boogie {
public int EnhancedErrorMessages = 0;
public bool ForceBplErrors = false; // if true, boogie error is shown even if "msg" attribute is present
public bool UseArrayTheory = false;
+ public bool UseLabels = true;
public bool MonomorphicArrays {
get {
return UseArrayTheory || TypeEncodingMethod == TypeEncoding.Monomorphic;
@@ -561,6 +563,7 @@ namespace Microsoft.Boogie {
public int StratifiedInlining = 0;
public int StratifiedInliningOption = 0;
public bool StratifiedInliningWithoutModels = false; // disable model generation for SI
+ public int StratifiedInliningVerbose = 0; // verbosity level
public bool UseUnsatCoreForInlining = false;
public int RecursionBound = 500;
public string inferLeastForUnsat = null;
@@ -828,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;
@@ -1005,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]));
@@ -1222,7 +1225,10 @@ namespace Microsoft.Boogie {
ps.CheckBooleanFlag("z3multipleErrors", ref z3AtFlag, false) ||
ps.CheckBooleanFlag("monomorphize", ref Monomorphize) ||
ps.CheckBooleanFlag("useArrayTheory", ref UseArrayTheory) ||
- ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis)
+ ps.CheckBooleanFlag("doModSetAnalysis", ref DoModSetAnalysis) ||
+ 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..5a6f8098 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();
@@ -1089,6 +1093,7 @@ out VariableSeq/*!*/ ins, out VariableSeq/*!*/ outs, out QKeyValue kv) {
Expr guard; Expr/*!*/ e; bool isFree;
List<PredicateCmd/*!*/> invariants = new List<PredicateCmd/*!*/>();
StmtList/*!*/ body;
+ QKeyValue kv = null;
Expect(40);
x = t;
@@ -1101,11 +1106,14 @@ out VariableSeq/*!*/ ins, out VariableSeq/*!*/ outs, out QKeyValue kv) {
isFree = true;
}
Expect(41);
+ while (la.kind == 25) {
+ Attribute(ref kv);
+ }
Expression(out e);
if (isFree) {
- invariants.Add(new AssumeCmd(z, e));
+ invariants.Add(new AssumeCmd(z, e, kv));
} else {
- invariants.Add(new AssertCmd(z, e));
+ invariants.Add(new AssertCmd(z, e, kv));
}
Expect(7);
diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs
index e3d131e0..cfef86c7 100644
--- a/Source/Core/Scanner.cs
+++ b/Source/Core/Scanner.cs
@@ -259,39 +259,39 @@ public class Scanner {
for (int i = 48; i <= 57; ++i) start[i] = 9;
for (int i = 34; i <= 34; ++i) start[i] = 6;
start[92] = 1;
- start[59] = 10;
- start[40] = 11;
- start[41] = 12;
- start[58] = 47;
- start[44] = 13;
- start[91] = 14;
- start[93] = 15;
- start[60] = 48;
- start[62] = 49;
- start[123] = 16;
- start[125] = 50;
- start[61] = 51;
- start[42] = 17;
- start[8660] = 20;
- start[8658] = 22;
- start[8656] = 23;
- start[38] = 24;
- start[8743] = 26;
- start[124] = 52;
- start[8744] = 28;
- start[33] = 53;
- start[8800] = 32;
- start[8804] = 33;
- start[8805] = 34;
- start[43] = 54;
- start[45] = 36;
- start[47] = 37;
- start[37] = 38;
- start[172] = 39;
- start[8704] = 42;
- start[8707] = 43;
- start[955] = 44;
- start[8226] = 46;
+ start[59] = 12;
+ start[40] = 13;
+ start[41] = 14;
+ start[58] = 49;
+ start[44] = 15;
+ start[91] = 16;
+ start[93] = 17;
+ start[60] = 50;
+ start[62] = 51;
+ start[123] = 18;
+ start[125] = 52;
+ start[61] = 53;
+ start[42] = 19;
+ start[8660] = 22;
+ start[8658] = 24;
+ start[8656] = 25;
+ start[38] = 26;
+ start[8743] = 28;
+ start[124] = 54;
+ start[8744] = 30;
+ start[33] = 55;
+ start[8800] = 34;
+ start[8804] = 35;
+ start[8805] = 36;
+ start[43] = 56;
+ start[45] = 38;
+ start[47] = 39;
+ start[37] = 40;
+ start[172] = 41;
+ start[8704] = 44;
+ start[8707] = 45;
+ start[955] = 46;
+ start[8226] = 48;
start[Buffer.EOF] = -1;
}
@@ -576,7 +576,8 @@ public class Scanner {
else {t.kind = 2; break;}
case 6:
if (ch == '"') {AddCh(); goto case 7;}
- else if (ch >= ' ' && ch <= '!' || ch >= '#' && ch <= '~') {AddCh(); goto case 6;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 10;}
else {goto case 0;}
case 7:
{t.kind = 4; break;}
@@ -591,125 +592,136 @@ public class Scanner {
else if (ch == '.') {AddCh(); goto case 8;}
else {t.kind = 3; break;}
case 10:
- {t.kind = 7; break;}
+ if (ch == '"') {AddCh(); goto case 11;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 10;}
+ else {goto case 0;}
case 11:
- {t.kind = 8; break;}
+ recEnd = pos; recKind = 4;
+ if (ch == '"') {AddCh(); goto case 7;}
+ else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}
+ else if (ch == 92) {AddCh(); goto case 10;}
+ else {t.kind = 4; break;}
case 12:
- {t.kind = 9; break;}
+ {t.kind = 7; break;}
case 13:
- {t.kind = 11; break;}
+ {t.kind = 8; break;}
case 14:
- {t.kind = 15; break;}
+ {t.kind = 9; break;}
case 15:
- {t.kind = 16; break;}
+ {t.kind = 11; break;}
case 16:
- {t.kind = 25; break;}
+ {t.kind = 15; break;}
case 17:
- {t.kind = 42; break;}
+ {t.kind = 16; break;}
case 18:
- {t.kind = 47; break;}
+ {t.kind = 25; break;}
case 19:
- {t.kind = 50; break;}
+ {t.kind = 42; break;}
case 20:
- {t.kind = 51; break;}
+ {t.kind = 47; break;}
case 21:
- {t.kind = 52; break;}
+ {t.kind = 50; break;}
case 22:
- {t.kind = 53; break;}
+ {t.kind = 51; break;}
case 23:
- {t.kind = 55; break;}
+ {t.kind = 52; break;}
case 24:
- if (ch == '&') {AddCh(); goto case 25;}
- else {goto case 0;}
+ {t.kind = 53; break;}
case 25:
- {t.kind = 56; break;}
+ {t.kind = 55; break;}
case 26:
- {t.kind = 57; break;}
+ if (ch == '&') {AddCh(); goto case 27;}
+ else {goto case 0;}
case 27:
- {t.kind = 58; break;}
+ {t.kind = 56; break;}
case 28:
- {t.kind = 59; break;}
+ {t.kind = 57; break;}
case 29:
- {t.kind = 62; break;}
+ {t.kind = 58; break;}
case 30:
- {t.kind = 63; break;}
+ {t.kind = 59; break;}
case 31:
- {t.kind = 64; break;}
+ {t.kind = 62; break;}
case 32:
- {t.kind = 65; break;}
+ {t.kind = 63; break;}
case 33:
- {t.kind = 66; break;}
+ {t.kind = 64; break;}
case 34:
- {t.kind = 67; break;}
+ {t.kind = 65; break;}
case 35:
- {t.kind = 68; break;}
+ {t.kind = 66; break;}
case 36:
- {t.kind = 70; break;}
+ {t.kind = 67; break;}
case 37:
- {t.kind = 71; break;}
+ {t.kind = 68; break;}
case 38:
- {t.kind = 72; break;}
+ {t.kind = 70; break;}
case 39:
- {t.kind = 74; break;}
+ {t.kind = 71; break;}
case 40:
- {t.kind = 78; break;}
+ {t.kind = 72; break;}
case 41:
- {t.kind = 79; break;}
+ {t.kind = 74; break;}
case 42:
- {t.kind = 81; break;}
+ {t.kind = 78; break;}
case 43:
- {t.kind = 83; break;}
+ {t.kind = 79; break;}
case 44:
- {t.kind = 85; break;}
+ {t.kind = 81; break;}
case 45:
- {t.kind = 86; break;}
+ {t.kind = 83; break;}
case 46:
- {t.kind = 87; break;}
+ {t.kind = 85; break;}
case 47:
+ {t.kind = 86; break;}
+ case 48:
+ {t.kind = 87; break;}
+ case 49:
recEnd = pos; recKind = 10;
- if (ch == '=') {AddCh(); goto case 18;}
- else if (ch == ':') {AddCh(); goto case 45;}
+ if (ch == '=') {AddCh(); goto case 20;}
+ else if (ch == ':') {AddCh(); goto case 47;}
else {t.kind = 10; break;}
- case 48:
+ case 50:
recEnd = pos; recKind = 17;
- if (ch == '=') {AddCh(); goto case 55;}
- else if (ch == ':') {AddCh(); goto case 31;}
+ if (ch == '=') {AddCh(); goto case 57;}
+ else if (ch == ':') {AddCh(); goto case 33;}
else {t.kind = 17; break;}
- case 49:
+ case 51:
recEnd = pos; recKind = 18;
- if (ch == '=') {AddCh(); goto case 29;}
+ if (ch == '=') {AddCh(); goto case 31;}
else {t.kind = 18; break;}
- case 50:
+ case 52:
recEnd = pos; recKind = 26;
- if (ch == '|') {AddCh(); goto case 41;}
+ if (ch == '|') {AddCh(); goto case 43;}
else {t.kind = 26; break;}
- case 51:
+ case 53:
recEnd = pos; recKind = 29;
- if (ch == '=') {AddCh(); goto case 56;}
+ if (ch == '=') {AddCh(); goto case 58;}
else {t.kind = 29; break;}
- case 52:
- if (ch == '|') {AddCh(); goto case 27;}
- else if (ch == '{') {AddCh(); goto case 40;}
+ case 54:
+ if (ch == '|') {AddCh(); goto case 29;}
+ else if (ch == '{') {AddCh(); goto case 42;}
else {goto case 0;}
- case 53:
+ case 55:
recEnd = pos; recKind = 73;
- if (ch == '=') {AddCh(); goto case 30;}
+ if (ch == '=') {AddCh(); goto case 32;}
else {t.kind = 73; break;}
- case 54:
+ case 56:
recEnd = pos; recKind = 69;
- if (ch == '+') {AddCh(); goto case 35;}
+ if (ch == '+') {AddCh(); goto case 37;}
else {t.kind = 69; break;}
- case 55:
+ case 57:
recEnd = pos; recKind = 61;
- if (ch == '=') {AddCh(); goto case 57;}
+ if (ch == '=') {AddCh(); goto case 59;}
else {t.kind = 61; break;}
- case 56:
+ case 58:
recEnd = pos; recKind = 60;
- if (ch == '>') {AddCh(); goto case 21;}
+ if (ch == '>') {AddCh(); goto case 23;}
else {t.kind = 60; break;}
- case 57:
+ case 59:
recEnd = pos; recKind = 54;
- if (ch == '>') {AddCh(); goto case 19;}
+ if (ch == '>') {AddCh(); goto case 21;}
else {t.kind = 54; break;}
}
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index caf3df24..454b47be 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");
@@ -706,40 +710,11 @@ namespace Microsoft.Dafny {
Contract.Requires(stmt != null);
if (stmt is AssumeStmt) {
Error("an assume statement cannot be compiled (line {0})", stmt.Tok.line);
- } else if (stmt is BlockStmt) {
- foreach (Statement s in ((BlockStmt)stmt).Body) {
- CheckHasNoAssumes(s);
- }
- } else if (stmt is IfStmt) {
- IfStmt s = (IfStmt)stmt;
- CheckHasNoAssumes(s.Thn);
- if (s.Els != null) {
- CheckHasNoAssumes(s.Els);
- }
- } else if (stmt is AlternativeStmt) {
- foreach (var alternative in ((AlternativeStmt)stmt).Alternatives) {
- foreach (Statement s in alternative.Body) {
- CheckHasNoAssumes(s);
- }
- }
- } else if (stmt is WhileStmt) {
- WhileStmt s = (WhileStmt)stmt;
- CheckHasNoAssumes(s.Body);
- } else if (stmt is AlternativeLoopStmt) {
- foreach (var alternative in ((AlternativeLoopStmt)stmt).Alternatives) {
- foreach (Statement s in alternative.Body) {
- CheckHasNoAssumes(s);
- }
- }
- } else if (stmt is ParallelStmt) {
- var s = (ParallelStmt)stmt;
- CheckHasNoAssumes(s.Body);
- } else if (stmt is MatchStmt) {
- MatchStmt s = (MatchStmt)stmt;
- foreach (MatchCaseStmt mc in s.Cases) {
- foreach (Statement bs in mc.Body) {
- CheckHasNoAssumes(bs);
- }
+ } else if (stmt is AssignSuchThatStmt) {
+ Error("an assign-such-that statement cannot be compiled (line {0})", stmt.Tok.line);
+ } else {
+ foreach (var ss in stmt.SubStatements) {
+ CheckHasNoAssumes(ss);
}
}
}
@@ -1216,7 +1191,7 @@ namespace Microsoft.Dafny {
} else {
if (rhs is ExprRhs) {
SpillLetVariableDecls(((ExprRhs)rhs).Expr, indent);
- } else if (tRhs != null) {
+ } else if (tRhs != null && tRhs.ArrayDimensions != null) {
foreach (Expression dim in tRhs.ArrayDimensions) {
SpillLetVariableDecls(dim, indent);
}
@@ -1582,7 +1557,11 @@ namespace Microsoft.Dafny {
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
Contract.Assert(dtv.Ctor != null); // since dtv has been successfully resolved
- wr.Write("new {0}(new {1}", dtv.DatatypeName, DtCtorName(dtv.Ctor));
+ wr.Write("new {0}", dtv.DatatypeName);
+ if (dtv.InferredTypeArgs.Count != 0) {
+ wr.Write("<{0}>", TypeNames(dtv.InferredTypeArgs));
+ }
+ wr.Write("(new {0}", DtCtorName(dtv.Ctor));
if (dtv.InferredTypeArgs.Count != 0) {
wr.Write("<{0}>", TypeNames(dtv.InferredTypeArgs));
}
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index 5b9689b4..c6609b4c 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,8 +374,9 @@ 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;
IToken bodyEnd = Token.NoToken;
.)
@@ -391,18 +401,24 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
.)
{ Attribute<ref attrs> }
Ident<out id>
- [ GenericParameters<typeArgs> ]
- Formals<true, !mmod.IsGhost, ins, out openParen>
- [ "returns" (. if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); } .)
- Formals<false, !mmod.IsGhost, outs, out openParen>
- ]
+ (
+ [ GenericParameters<typeArgs> ]
+ Formals<true, !mmod.IsGhost, ins, out openParen>
+ [ "returns" (. if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); } .)
+ Formals<false, !mmod.IsGhost, outs, out openParen>
+ ]
+ | "..." (. 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, req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs);
- else
- m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs);
+ (. if (isConstructor) {
+ m = new Constructor(id, id.val, typeArgs, ins,
+ req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureOmitted);
+ } else {
+ m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs,
+ req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureOmitted);
+ }
m.BodyStartTok = bodyStart;
m.BodyEndTok = bodyEnd;
.)
@@ -519,12 +535,13 @@ 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;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ bool signatureOmitted = false;
.)
/* ----- function ----- */
( "function"
@@ -534,10 +551,14 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
.)
{ Attribute<ref attrs> }
Ident<out id>
- [ GenericParameters<typeArgs> ]
- Formals<true, isFunctionMethod, formals, out openParen>
- ":"
- Type<out returnType>
+ (
+ [ GenericParameters<typeArgs> ]
+ Formals<true, isFunctionMethod, formals, out openParen>
+ ":"
+ Type<out returnType>
+ | "..." (. signatureOmitted = true;
+ openParen = Token.NoToken; .)
+ )
/* ----- predicate ----- */
| "predicate" (. isPredicate = true; .)
@@ -547,20 +568,26 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
.)
{ Attribute<ref attrs> }
Ident<out id>
- [ GenericParameters<typeArgs> ]
- [ Formals<true, isFunctionMethod, formals, out openParen>
- [ ":" (. SemErr(t, "predicates do not have an explicitly declared return type; it is always bool"); .)
+ (
+ [ GenericParameters<typeArgs> ]
+ [ Formals<true, isFunctionMethod, formals, out openParen>
+ [ ":" (. SemErr(t, "predicates do not have an explicitly declared return type; it is always bool"); .)
+ ]
]
- ]
+ | "..." (. signatureOmitted = true;
+ openParen = Token.NoToken; .)
+ )
)
{ 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, reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs);
+ f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals,
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs, signatureOmitted);
} else {
- f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals, returnType, reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs);
+ f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals, returnType,
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureOmitted);
}
f.BodyStartTok = bodyStart;
f.BodyEndTok = bodyEnd;
@@ -616,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/*!*/>();
.)
@@ -634,12 +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;
.)
- /* This list does not contain BlockStmt, see comment above in Stmt production. */
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>
@@ -660,6 +687,8 @@ OneStmt<out Statement/*!*/ s>
SYNC
";" (. s = label != null ? new BreakStmt(x, label) : new BreakStmt(x, breakCount); .)
| ReturnStmt<out s>
+ | "..." (. s = new SkeletonStatement(t); .)
+ ";"
)
.
ReturnStmt<out Statement/*!*/ s>
@@ -683,21 +712,30 @@ UpdateStmt<out Statement/*!*/ s>
Expression lhs0;
IToken x;
Attributes attrs = null;
+ Expression suchThat = null;
.)
Lhs<out e> (. x = e.tok; .)
- ( { IF(IsAttribute()) Attribute<ref attrs> }
+ ( { Attribute<ref attrs> }
";" (. rhss.Add(new ExprRhs(e, attrs)); .)
| (. lhss.Add(e); lhs0 = e; .)
{ "," Lhs<out e> (. lhss.Add(e); .)
}
- ":=" (. x = t; .)
- Rhs<out r, lhs0> (. rhss.Add(r); .)
- { "," Rhs<out r, lhs0> (. rhss.Add(r); .)
- }
+ ( ":=" (. x = t; .)
+ Rhs<out r, lhs0> (. rhss.Add(r); .)
+ { "," Rhs<out r, lhs0> (. rhss.Add(r); .)
+ }
+ | ":|" (. x = t; .)
+ Expression<out suchThat>
+ )
";"
| ":" (. SemErr(t, "invalid statement (did you forget the 'label' keyword?)"); .)
)
- (. s = new UpdateStmt(x, lhss, rhss); .)
+ (. if (suchThat != null) {
+ s = new AssignSuchThatStmt(x, lhss, suchThat);
+ } else {
+ s = new UpdateStmt(x, lhss, rhss);
+ }
+ .)
.
Rhs<out AssignmentRhs r, Expression receiverForInitCall>
= (. IToken/*!*/ x, newToken; Expression/*!*/ e;
@@ -733,7 +771,7 @@ Rhs<out AssignmentRhs r, Expression receiverForInitCall>
| "*" (. r = new HavocRhs(t); .)
| Expression<out e> (. r = new ExprRhs(e); .)
)
- { IF(IsAttribute()) Attribute<ref attrs> } (. r.Attributes = attrs; .)
+ { Attribute<ref attrs> } (. r.Attributes = attrs; .)
.
VarDeclStatement<.out Statement/*!*/ s.>
= (. IToken x = null, assignTok = null; bool isGhost = false;
@@ -741,6 +779,7 @@ VarDeclStatement<.out Statement/*!*/ s.>
AssignmentRhs r; IdentifierExpr lhs0;
List<VarDecl> lhss = new List<VarDecl>();
List<AssignmentRhs> rhss = new List<AssignmentRhs>();
+ Expression suchThat = null;
.)
[ "ghost" (. isGhost = true; x = t; .)
]
@@ -756,10 +795,18 @@ VarDeclStatement<.out Statement/*!*/ s.>
Rhs<out r, lhs0> (. rhss.Add(r); .)
{ "," Rhs<out r, lhs0> (. rhss.Add(r); .)
}
+ | ":|" (. assignTok = t; .)
+ Expression<out suchThat>
]
";"
- (. UpdateStmt update;
- if (rhss.Count == 0) {
+ (. ConcreteUpdateStatement update;
+ if (suchThat != null) {
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new AssignSuchThatStmt(assignTok, ies, suchThat);
+ } else if (rhss.Count == 0) {
update = null;
} else {
var ies = new List<Expression>();
@@ -773,8 +820,9 @@ VarDeclStatement<.out Statement/*!*/ s.>
.
IfStmt<out Statement/*!*/ ifStmt>
= (. Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;
- Expression guard;
- Statement/*!*/ thn;
+ Expression guard = null; bool guardOmitted = false;
+ BlockStmt/*!*/ thn;
+ BlockStmt/*!*/ bs;
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
@@ -783,14 +831,21 @@ IfStmt<out Statement/*!*/ ifStmt>
.)
"if" (. x = t; .)
(
- Guard<out guard>
+ ( Guard<out guard>
+ | "..." (. guardOmitted = true; .)
+ )
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; .)
)
]
- (. ifStmt = new IfStmt(x, guard, thn, els); .)
+ (. if (guardOmitted) {
+ ifStmt = new SkeletonStatement(new IfStmt(x, guard, thn, els), true, false);
+ } else {
+ ifStmt = new IfStmt(x, guard, thn, els);
+ }
+ .)
|
AlternativeBlock<out alternatives>
(. ifStmt = new AlternativeStmt(x, alternatives); .)
@@ -814,23 +869,43 @@ AlternativeBlock<.out List<GuardedAlternative> alternatives.>
.
WhileStmt<out Statement/*!*/ stmt>
= (. Contract.Ensures(Contract.ValueAtReturn(out stmt) != null); IToken/*!*/ x;
- Expression guard;
+ Expression guard = null; bool guardOmitted = false;
List<MaybeFreeExpression/*!*/> invariants = new List<MaybeFreeExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
Attributes decAttrs = null;
Attributes modAttrs = null;
List<FrameExpression/*!*/> mod = null;
- Statement/*!*/ body;
- IToken bodyStart, bodyEnd;
+ BlockStmt/*!*/ body = null; bool bodyOmitted = false;
+ IToken bodyStart = null, bodyEnd = null;
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
.)
"while" (. x = t; .)
(
- Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
+ ( Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
+ | "..." (. guardOmitted = true; .)
+ )
LoopSpec<out invariants, out decreases, out mod, ref decAttrs, ref modAttrs>
- BlockStmt<out body, out bodyStart, out bodyEnd>
- (. stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body); .)
+ ( BlockStmt<out body, out bodyStart, out bodyEnd>
+ | "..." (. bodyOmitted = true; .)
+ )
+ (.
+ if (guardOmitted || bodyOmitted) {
+ if (decreases.Count != 0) {
+ SemErr(decreases[0].tok, "'decreases' clauses are not allowed on refining loops");
+ }
+ if (mod != null) {
+ SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
+ }
+ if (body == 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);
+ } else {
+ stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
+ }
+ .)
|
LoopSpec<out invariants, out decreases, out mod, ref decAttrs, ref modAttrs>
AlternativeBlock<out alternatives>
@@ -846,12 +921,15 @@ LoopSpec<.out List<MaybeFreeExpression/*!*/> invariants, out List<Expression/*!*
.)
{
Invariant<out invariant> SYNC ";" (. invariants.Add(invariant); .)
- | SYNC "decreases" { IF(IsAttribute()) Attribute<ref decAttrs> } DecreasesList<decreases, true> SYNC ";"
- | SYNC "modifies" { IF(IsAttribute()) Attribute<ref modAttrs> } (. mod = mod ?? new List<FrameExpression>(); .)
- [ FrameExpression<out fe> (. mod.Add(fe); .)
- { "," FrameExpression<out fe> (. mod.Add(fe); .)
- }
- ] SYNC ";"
+ | SYNC "decreases"
+ { IF(IsAttribute()) Attribute<ref decAttrs> }
+ DecreasesList<decreases, true> SYNC ";"
+ | SYNC "modifies"
+ { IF(IsAttribute()) Attribute<ref modAttrs> } (. mod = mod ?? new List<FrameExpression>(); .)
+ [ FrameExpression<out fe> (. mod.Add(fe); .)
+ { "," FrameExpression<out fe> (. mod.Add(fe); .)
+ }
+ ] SYNC ";"
}
.
Invariant<out MaybeFreeExpression/*!*/ invariant>
@@ -917,10 +995,21 @@ CaseStatement<out MatchCaseStmt/*!*/ c>
.
/*------------------------------------------------------------------------*/
AssertStmt<out Statement/*!*/ s>
-= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; Attributes attrs = null; .)
+= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;
+ Expression/*!*/ e = null; Attributes attrs = null;
+ .)
"assert" (. x = t; s = null;.)
- { IF(IsAttribute()) Attribute<ref attrs> } Expression<out e> (. s = new AssertStmt(x, e, attrs); .)
+ { IF(IsAttribute()) Attribute<ref attrs> }
+ ( Expression<out e>
+ | "..."
+ )
";"
+ (. if (e == null) {
+ s = new SkeletonStatement(new AssertStmt(x, new LiteralExpr(x, true), attrs), true, false);
+ } else {
+ s = new AssertStmt(x, e, attrs);
+ }
+ .)
.
AssumeStmt<out Statement/*!*/ s>
= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; .)
@@ -947,7 +1036,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 b410b37d..f5955d11 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() {
@@ -101,7 +101,40 @@ namespace Microsoft.Dafny {
Prev = prev;
}
- public class Argument {
+ public static bool Contains(Attributes attrs, string nm) {
+ Contract.Requires(nm != null);
+ for (; attrs != null; attrs = attrs.Prev) {
+ if (attrs.Name == nm) {
+ return true;
+ }
+ }
+ 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;
public readonly string S;
public readonly Expression E;
@@ -314,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
@@ -610,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() {
@@ -618,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);
@@ -631,6 +675,7 @@ namespace Microsoft.Dafny {
ImportNames.Add(nm);
}
}
+ IsGhost = isGhost;
}
public virtual bool IsDefaultModule {
get {
@@ -640,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 {
@@ -1055,7 +1100,8 @@ 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() {
Contract.Invariant(cce.NonNullElements(TypeArgs));
@@ -1070,7 +1116,7 @@ namespace Microsoft.Dafny {
public Function(IToken tok, string name, bool isStatic, bool isGhost, bool isUnlimited,
List<TypeParameter> typeArgs, IToken openParen, List<Formal> formals, Type resultType,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
- Expression body, Attributes attributes)
+ Expression body, Attributes attributes, bool signatureOmitted)
: base(tok, name, isStatic, attributes) {
Contract.Requires(tok != null);
@@ -1093,6 +1139,7 @@ namespace Microsoft.Dafny {
this.Ens = ens;
this.Decreases = decreases;
this.Body = body;
+ this.SignatureIsOmitted = signatureOmitted;
}
}
@@ -1102,8 +1149,8 @@ namespace Microsoft.Dafny {
public Predicate(IToken tok, string name, bool isStatic, bool isGhost, bool isUnlimited,
List<TypeParameter> typeArgs, IToken openParen, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
- Expression body, bool bodyIsExtended, Attributes attributes)
- : base(tok, name, isStatic, isGhost, isUnlimited, typeArgs, openParen, formals, new BoolType(), req, reads, ens, decreases, body, attributes) {
+ Expression body, bool bodyIsExtended, Attributes attributes, bool signatureOmitted)
+ : base(tok, name, isStatic, isGhost, isUnlimited, typeArgs, openParen, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureOmitted) {
Contract.Requires(!bodyIsExtended || body != null);
BodyIsExtended = bodyIsExtended;
}
@@ -1112,6 +1159,7 @@ namespace Microsoft.Dafny {
public class Method : MemberDecl, TypeParameter.ParentType
{
public readonly bool IsGhost;
+ public readonly bool SignatureIsOmitted;
public readonly List<TypeParameter/*!*/>/*!*/ TypeArgs;
public readonly List<Formal/*!*/>/*!*/ Ins;
public readonly List<Formal/*!*/>/*!*/ Outs;
@@ -1119,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() {
@@ -1140,7 +1188,7 @@ namespace Microsoft.Dafny {
[Captured] List<MaybeFreeExpression/*!*/>/*!*/ ens,
[Captured] Specification<Expression>/*!*/ decreases,
[Captured] BlockStmt body,
- Attributes attributes)
+ Attributes attributes, bool signatureOmitted)
: base(tok, name, isStatic, attributes) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
@@ -1160,6 +1208,7 @@ namespace Microsoft.Dafny {
this.Ens = ens;
this.Decreases = decreases;
this.Body = body;
+ this.SignatureIsOmitted = signatureOmitted;
}
}
@@ -1172,8 +1221,8 @@ namespace Microsoft.Dafny {
[Captured] List<MaybeFreeExpression/*!*/>/*!*/ ens,
[Captured] Specification<Expression>/*!*/ decreases,
[Captured] BlockStmt body,
- Attributes attributes)
- : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, body, attributes) {
+ Attributes attributes, bool signatureOmitted)
+ : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, body, attributes, signatureOmitted) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -1223,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
@@ -1497,18 +1553,22 @@ namespace Microsoft.Dafny {
public ConcreteSyntaxStatement(IToken tok)
: base(tok) {
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get { return ResolvedStatements; }
+ }
}
public class VarDeclStmt : ConcreteSyntaxStatement
{
public readonly List<VarDecl> Lhss;
- public readonly UpdateStmt Update;
+ public readonly ConcreteUpdateStatement Update;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(cce.NonNullElements(Lhss));
}
- public VarDeclStmt(IToken tok, List<VarDecl> lhss, UpdateStmt update)
+ public VarDeclStmt(IToken tok, List<VarDecl> lhss, ConcreteUpdateStatement update)
: base(tok)
{
Contract.Requires(lhss != null);
@@ -1518,9 +1578,35 @@ namespace Microsoft.Dafny {
}
}
- public class UpdateStmt : ConcreteSyntaxStatement
+ /// <summary>
+ /// Common superclass of UpdateStmt and AssignSuchThatStmt.
+ /// </summary>
+ public abstract class ConcreteUpdateStatement : ConcreteSyntaxStatement
{
public readonly List<Expression> Lhss;
+ public ConcreteUpdateStatement(IToken tok, List<Expression> lhss)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(lhss));
+ Lhss = lhss;
+ }
+ }
+
+ public class AssignSuchThatStmt : ConcreteUpdateStatement
+ {
+ public readonly AssumeStmt Assume;
+ public AssignSuchThatStmt(IToken tok, List<Expression> lhss, Expression expr)
+ : base(tok, lhss) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(lhss));
+ Contract.Requires(lhss.Count != 0);
+ Contract.Requires(expr != null);
+ Assume = new AssumeStmt(tok, expr);
+ }
+ }
+
+ public class UpdateStmt : ConcreteUpdateStatement
+ {
public readonly List<AssignmentRhs> Rhss;
public readonly bool CanMutateKnownState;
[ContractInvariantMethod]
@@ -1529,24 +1615,22 @@ namespace Microsoft.Dafny {
Contract.Invariant(cce.NonNullElements(Rhss));
}
public UpdateStmt(IToken tok, List<Expression> lhss, List<AssignmentRhs> rhss)
- : base(tok)
+ : base(tok, lhss)
{
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(lhss));
Contract.Requires(cce.NonNullElements(rhss));
Contract.Requires(lhss.Count != 0 || rhss.Count == 1);
- Lhss = lhss;
Rhss = rhss;
CanMutateKnownState = false;
}
public UpdateStmt(IToken tok, List<Expression> lhss, List<AssignmentRhs> rhss, bool mutate)
- : base(tok)
+ : base(tok, lhss)
{
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(lhss));
Contract.Requires(cce.NonNullElements(rhss));
Contract.Requires(lhss.Count != 0 || rhss.Count == 1);
- Lhss = lhss;
Rhss = rhss;
CanMutateKnownState = mutate;
}
@@ -1569,6 +1653,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 {
@@ -1669,20 +1762,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);
@@ -1691,6 +1787,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
@@ -1728,6 +1832,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
@@ -1758,7 +1871,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);
@@ -1766,13 +1879,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
@@ -1790,6 +1909,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
@@ -1865,6 +1993,12 @@ namespace Microsoft.Dafny {
}
}
}
+
+ public override IEnumerable<Statement> SubStatements {
+ get {
+ yield return Body;
+ }
+ }
}
public class MatchStmt : Statement
@@ -1887,7 +2021,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;
+ }
+ }
+ }
}
}
@@ -1911,6 +2054,53 @@ namespace Microsoft.Dafny {
}
}
+ /// <summary>
+ /// The class represents several possible scenarios:
+ /// * ...;
+ /// S == null
+ /// * assert ...
+ /// ConditionOmitted == true
+ /// * if ... { Stmt }
+ /// if ... { Stmt } else ElseStmt
+ /// ConditionOmitted == true
+ /// * while ... invariant J;
+ /// ConditionOmitted == true && BodyOmitted == true
+ /// * while ... invariant J; { Stmt }
+ /// ConditionOmitted == true && BodyOmitted == false
+ /// </summary>
+ public class SkeletonStatement : Statement
+ {
+ public readonly Statement S;
+ public readonly bool ConditionOmitted;
+ public readonly bool BodyOmitted;
+ public SkeletonStatement(IToken tok)
+ : base(tok)
+ {
+ Contract.Requires(tok != null);
+ }
+ public SkeletonStatement(Statement s, bool conditionOmitted, bool bodyOmitted)
+ : base(s.Tok)
+ {
+ Contract.Requires(s != null);
+ S = s;
+ 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;
+ }
+ }
+ }
+ }
+ }
+
// ------------------------------------------------------------------------------------------------------
public abstract class TokenWrapper : IToken
@@ -2551,6 +2741,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 18415db0..8e0d2e31 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -21,12 +21,12 @@ public class Parser {
public const int _colon = 5;
public const int _lbrace = 6;
public const int _rbrace = 7;
- public const int maxT = 104;
+ public const int maxT = 106;
const bool T = true;
const bool x = false;
const int minErrDist = 2;
-
+
public Scanner/*!*/ scanner;
public Errors/*!*/ errors;
@@ -131,10 +131,10 @@ bool IsAttribute() {
if (errDist >= minErrDist) errors.SemErr(t, msg);
errDist = 0;
}
-
- public void SemErr(IToken/*!*/ tok, string/*!*/ msg) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
+
+ public void SemErr(IToken/*!*/ tok, string/*!*/ msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
errors.SemErr(tok, msg);
}
@@ -147,15 +147,15 @@ bool IsAttribute() {
la = t;
}
}
-
+
void Expect (int n) {
if (la.kind==n) Get(); else { SynErr(n); }
}
-
+
bool StartOf (int s) {
return set[s, la.kind];
}
-
+
void ExpectWeak (int n, int follow) {
if (la.kind == n) Get();
else {
@@ -179,7 +179,7 @@ bool IsAttribute() {
}
}
-
+
void Dafny() {
ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; ArbitraryTypeDecl at;
Attributes attrs; IToken/*!*/ id; List<string/*!*/> theImports;
@@ -189,19 +189,25 @@ bool IsAttribute() {
// to support multiple files, create a default module only if theModules doesn't already contain one
DefaultModuleDecl defaultModule = null;
foreach (ModuleDecl mdecl in theModules) {
- defaultModule = mdecl as DefaultModuleDecl;
- if (defaultModule != null) { break; }
+ defaultModule = mdecl as DefaultModuleDecl;
+ if (defaultModule != null) { break; }
}
bool defaultModuleCreatedHere = false;
if (defaultModule == null) {
- defaultModuleCreatedHere = true;
- defaultModule = new DefaultModuleDecl();
+ defaultModuleCreatedHere = true;
+ 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,38 +238,41 @@ 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(107);
}
if (defaultModuleCreatedHere) {
defaultModule.TopLevelDecls.Add(new DefaultClassDecl(defaultModule, membersDefaultClass));
theModules.Add(defaultModule);
} else {
- // find the default class in the default module, then append membersDefaultClass to its member list
- foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
- DefaultClassDecl defaultClass = topleveldecl as DefaultClassDecl;
- if (defaultClass != null) {
- defaultClass.Members.AddRange(membersDefaultClass);
- break;
- }
- }
+ // find the default class in the default module, then append membersDefaultClass to its member list
+ foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
+ DefaultClassDecl defaultClass = topleveldecl as DefaultClassDecl;
+ if (defaultClass != null) {
+ defaultClass.Members.AddRange(membersDefaultClass);
+ break;
+ }
+ }
}
Expect(0);
@@ -301,8 +310,8 @@ bool IsAttribute() {
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
- while (!(la.kind == 0 || la.kind == 11)) {SynErr(105); Get();}
- Expect(11);
+ while (!(la.kind == 0 || la.kind == 12)) {SynErr(108); 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(106); Get();}
+ while (!(la.kind == 0 || la.kind == 15)) {SynErr(109); 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(107); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(110); 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(108); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(111); 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) {
@@ -389,13 +399,13 @@ bool IsAttribute() {
}
if (la.kind == 19) {
FieldDecl(mmod, mm);
- } else if (la.kind == 41 || la.kind == 42) {
+ } else if (la.kind == 42 || la.kind == 43) {
FunctionDecl(mmod, out f);
mm.Add(f);
} else if (la.kind == 24 || la.kind == 25) {
MethodDecl(mmod, allowConstructors, out m);
mm.Add(m);
- } else SynErr(109);
+ } else SynErr(112);
}
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(110); Get();}
+ while (!(la.kind == 0 || la.kind == 19)) {SynErr(113); 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(111); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(114); Get();}
Expect(18);
}
@@ -447,14 +457,15 @@ 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;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ bool signatureOmitted = false;
- if (la.kind == 41) {
+ if (la.kind == 42) {
Get();
if (la.kind == 24) {
Get();
@@ -466,13 +477,19 @@ bool IsAttribute() {
Attribute(ref attrs);
}
Ident(out id);
- if (la.kind == 22) {
- GenericParameters(typeArgs);
- }
- Formals(true, isFunctionMethod, formals, out openParen);
- Expect(5);
- Type(out returnType);
- } else if (la.kind == 42) {
+ if (la.kind == 22 || la.kind == 33) {
+ if (la.kind == 22) {
+ GenericParameters(typeArgs);
+ }
+ Formals(true, isFunctionMethod, formals, out openParen);
+ Expect(5);
+ Type(out returnType);
+ } else if (la.kind == 27) {
+ Get();
+ signatureOmitted = true;
+ openParen = Token.NoToken;
+ } else SynErr(115);
+ } else if (la.kind == 43) {
Get();
isPredicate = true;
if (la.kind == 24) {
@@ -485,28 +502,35 @@ bool IsAttribute() {
Attribute(ref attrs);
}
Ident(out id);
- if (la.kind == 22) {
- GenericParameters(typeArgs);
- }
- if (la.kind == 32) {
- Formals(true, isFunctionMethod, formals, out openParen);
- if (la.kind == 5) {
- Get();
- SemErr(t, "predicates do not have an explicitly declared return type; it is always bool");
+ if (StartOf(4)) {
+ if (la.kind == 22) {
+ GenericParameters(typeArgs);
}
- }
- } else SynErr(112);
- while (StartOf(4)) {
+ if (la.kind == 33) {
+ Formals(true, isFunctionMethod, formals, out openParen);
+ if (la.kind == 5) {
+ Get();
+ SemErr(t, "predicates do not have an explicitly declared return type; it is always bool");
+ }
+ }
+ } else if (la.kind == 27) {
+ Get();
+ signatureOmitted = true;
+ openParen = Token.NoToken;
+ } else SynErr(116);
+ } else SynErr(117);
+ 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, reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs);
+ f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals,
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs, signatureOmitted);
} else {
- f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals, returnType, reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs);
+ f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, openParen, formals, returnType,
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureOmitted);
}
f.BodyStartTok = bodyStart;
f.BodyEndTok = bodyEnd;
@@ -527,12 +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(113); Get();}
+ while (!(la.kind == 0 || la.kind == 24 || la.kind == 25)) {SynErr(118); Get();}
if (la.kind == 24) {
Get();
} else if (la.kind == 25) {
@@ -540,44 +565,51 @@ bool IsAttribute() {
if (allowConstructor) {
isConstructor = true;
} else {
- SemErr(t, "constructors are only allowed in classes");
+ SemErr(t, "constructors are only allowed in classes");
}
- } else SynErr(114);
+ } else SynErr(119);
if (mmod.IsUnlimited) { SemErr(t, "methods cannot be declared 'unlimited'"); }
if (isConstructor) {
- if (mmod.IsGhost) {
- SemErr(t, "constructors cannot be declared 'ghost'");
- }
- if (mmod.IsStatic) {
- SemErr(t, "constructors cannot be declared 'static'");
- }
+ if (mmod.IsGhost) {
+ SemErr(t, "constructors cannot be declared 'ghost'");
+ }
+ if (mmod.IsStatic) {
+ SemErr(t, "constructors cannot be declared 'static'");
+ }
}
while (la.kind == 6) {
Attribute(ref attrs);
}
Ident(out id);
- if (la.kind == 22) {
- GenericParameters(typeArgs);
- }
- Formals(true, !mmod.IsGhost, ins, out openParen);
- if (la.kind == 26) {
+ if (la.kind == 22 || la.kind == 33) {
+ if (la.kind == 22) {
+ GenericParameters(typeArgs);
+ }
+ Formals(true, !mmod.IsGhost, ins, out openParen);
+ if (la.kind == 26) {
+ Get();
+ if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); }
+ Formals(false, !mmod.IsGhost, outs, out openParen);
+ }
+ } else if (la.kind == 27) {
Get();
- if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); }
- Formals(false, !mmod.IsGhost, outs, out openParen);
- }
- while (StartOf(5)) {
+ signatureOmitted = true; openParen = Token.NoToken;
+ } else SynErr(120);
+ 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,
+ req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureOmitted);
+ } else {
+ m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs,
+ req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureOmitted);
}
- if (isConstructor)
- m = new Constructor(id, id.val, typeArgs, ins, req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs);
- else
- m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs);
m.BodyStartTok = bodyStart;
m.BodyEndTok = bodyEnd;
@@ -593,7 +625,7 @@ bool IsAttribute() {
Attribute(ref attrs);
}
Ident(out id);
- if (la.kind == 32) {
+ if (la.kind == 33) {
FormalsOptionalIds(formals);
}
ctors.Add(new DatatypeCtor(id, id.val, formals, attrs));
@@ -601,8 +633,8 @@ bool IsAttribute() {
void FormalsOptionalIds(List<Formal/*!*/>/*!*/ formals) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost;
- Expect(32);
- if (StartOf(6)) {
+ Expect(33);
+ if (StartOf(7)) {
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
while (la.kind == 20) {
@@ -611,7 +643,7 @@ bool IsAttribute() {
formals.Add(new Formal(id, name, ty, true, isGhost));
}
}
- Expect(33);
+ Expect(34);
}
void IdentType(out IToken/*!*/ id, out Type/*!*/ ty) {
@@ -625,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"); }
}
@@ -666,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;
}
@@ -675,9 +707,9 @@ bool IsAttribute() {
Get();
UserDefinedType udt = ty as UserDefinedType;
if (udt != null && udt.TypeArgs.Count == 0) {
- name = udt.Name;
+ name = udt.Name;
} else {
- SemErr(id, "invalid formal-parameter name in datatype constructor");
+ SemErr(id, "invalid formal-parameter name in datatype constructor");
}
Type(out ty);
@@ -685,7 +717,7 @@ bool IsAttribute() {
if (name != null) {
identName = name;
} else {
- identName = "#" + anonymousIds++;
+ identName = "#" + anonymousIds++;
}
}
@@ -695,22 +727,22 @@ bool IsAttribute() {
List<Type/*!*/>/*!*/ gt;
switch (la.kind) {
- case 34: {
+ case 35: {
Get();
tok = t;
break;
}
- case 35: {
+ case 36: {
Get();
tok = t; ty = new NatType();
break;
}
- case 36: {
+ case 37: {
Get();
tok = t; ty = new IntType();
break;
}
- case 37: {
+ case 38: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -721,7 +753,7 @@ bool IsAttribute() {
break;
}
- case 38: {
+ case 39: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -732,7 +764,7 @@ bool IsAttribute() {
break;
}
- case 39: {
+ case 40: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -743,19 +775,19 @@ bool IsAttribute() {
break;
}
- case 1: case 3: case 40: {
+ case 1: case 3: case 41: {
ReferenceType(out tok, out ty);
break;
}
- default: SynErr(115); break;
+ default: SynErr(121); break;
}
}
void Formals(bool incoming, bool allowGhostKeyword, List<Formal/*!*/>/*!*/ formals, out IToken openParen) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; bool isGhost;
- Expect(32);
+ 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) {
@@ -764,7 +796,7 @@ bool IsAttribute() {
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
}
}
- Expect(33);
+ Expect(34);
}
void MethodSpec(List<MaybeFreeExpression/*!*/>/*!*/ req, List<FrameExpression/*!*/>/*!*/ mod, List<MaybeFreeExpression/*!*/>/*!*/ ens,
@@ -772,13 +804,13 @@ 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(7))) {SynErr(116); Get();}
- if (la.kind == 27) {
+ while (!(StartOf(8))) {SynErr(122); Get();}
+ if (la.kind == 28) {
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
}
- if (StartOf(8)) {
+ if (StartOf(9)) {
FrameExpression(out fe);
mod.Add(fe);
while (la.kind == 20) {
@@ -787,47 +819,47 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(117); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(123); Get();}
Expect(18);
- } else if (la.kind == 28 || la.kind == 29 || la.kind == 30) {
- if (la.kind == 28) {
+ } else if (la.kind == 29 || la.kind == 30 || la.kind == 31) {
+ if (la.kind == 29) {
Get();
isFree = true;
}
- if (la.kind == 29) {
+ if (la.kind == 30) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(118); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(124); Get();}
Expect(18);
req.Add(new MaybeFreeExpression(e, isFree));
- } else if (la.kind == 30) {
+ } else if (la.kind == 31) {
Get();
while (IsAttribute()) {
Attribute(ref ensAttrs);
}
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(119); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(125); Get();}
Expect(18);
ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));
- } else SynErr(120);
- } else if (la.kind == 31) {
+ } else SynErr(126);
+ } else if (la.kind == 32) {
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(121); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(127); Get();}
Expect(18);
- } else SynErr(122);
+ } else SynErr(128);
}
- 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/*!*/>();
Expect(6);
bodyStart = t;
- while (StartOf(9)) {
+ while (StartOf(10)) {
Stmt(body);
}
Expect(7);
@@ -838,7 +870,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void FrameExpression(out FrameExpression/*!*/ fe) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null;
Expression(out e);
- if (la.kind == 45) {
+ if (la.kind == 46) {
Get();
Ident(out id);
fieldName = id.val;
@@ -856,7 +888,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (!allowWildcard && e is WildcardExpr) {
SemErr(e.tok, "'decreases *' is only allowed on loops");
} else {
- decreases.Add(e);
+ decreases.Add(e);
}
while (la.kind == 20) {
@@ -865,7 +897,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (!allowWildcard && e is WildcardExpr) {
SemErr(e.tok, "'decreases *' is only allowed on loops");
} else {
- decreases.Add(e);
+ decreases.Add(e);
}
}
@@ -889,7 +921,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/
List<Type/*!*/>/*!*/ gt;
- if (la.kind == 40) {
+ if (la.kind == 41) {
Get();
tok = t; ty = new ObjectType();
} else if (la.kind == 3) {
@@ -901,7 +933,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
int dims = 1;
if (tok.val.Length != 5) {
- dims = int.Parse(tok.val.Substring(5));
+ dims = int.Parse(tok.val.Substring(5));
}
ty = theBuiltIns.ArrayType(tok, dims, gt[0], true);
@@ -912,22 +944,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
GenericInstantiation(gt);
}
ty = new UserDefinedType(tok, tok.val, gt);
- } else SynErr(123);
+ } else SynErr(129);
}
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 == 29) {
- while (!(la.kind == 0 || la.kind == 29)) {SynErr(124); Get();}
+ if (la.kind == 30) {
+ while (!(la.kind == 0 || la.kind == 30)) {SynErr(130); Get();}
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(125); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(131); Get();}
Expect(18);
reqs.Add(e);
- } else if (la.kind == 43) {
+ } else if (la.kind == 44) {
Get();
- if (StartOf(10)) {
+ if (StartOf(11)) {
PossiblyWildFrameExpression(out fe);
reads.Add(fe);
while (la.kind == 20) {
@@ -936,20 +968,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
reads.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(126); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(132); Get();}
Expect(18);
- } else if (la.kind == 30) {
+ } else if (la.kind == 31) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(127); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(133); Get();}
Expect(18);
ens.Add(e);
- } else if (la.kind == 31) {
+ } else if (la.kind == 32) {
Get();
DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(128); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(134); Get();}
Expect(18);
- } else SynErr(129);
+ } else SynErr(135);
}
void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) {
@@ -963,23 +995,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void PossiblyWildFrameExpression(out FrameExpression/*!*/ fe) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr;
- if (la.kind == 44) {
+ if (la.kind == 45) {
Get();
fe = new FrameExpression(new WildcardExpr(t), null);
- } else if (StartOf(8)) {
+ } else if (StartOf(9)) {
FrameExpression(out fe);
- } else SynErr(130);
+ } else SynErr(136);
}
void PossiblyWildExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e)!=null);
e = dummyExpr;
- if (la.kind == 44) {
+ if (la.kind == 45) {
Get();
e = new WildcardExpr(t);
- } else if (StartOf(8)) {
+ } else if (StartOf(9)) {
Expression(out e);
- } else SynErr(131);
+ } else SynErr(137);
}
void Stmt(List<Statement/*!*/>/*!*/ ss) {
@@ -992,52 +1024,54 @@ 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(11))) {SynErr(132); Get();}
+ while (!(StartOf(12))) {SynErr(138); Get();}
switch (la.kind) {
case 6: {
- BlockStmt(out s, out bodyStart, out bodyEnd);
+ BlockStmt(out bs, out bodyStart, out bodyEnd);
+ s = bs;
break;
}
- case 62: {
+ case 64: {
AssertStmt(out s);
break;
}
- case 63: {
+ case 65: {
AssumeStmt(out s);
break;
}
- case 64: {
+ case 66: {
PrintStmt(out s);
break;
}
- case 1: case 2: case 17: case 32: case 89: case 90: case 91: case 92: case 93: case 94: case 95: {
+ case 1: case 2: case 17: case 33: case 91: case 92: case 93: case 94: case 95: case 96: case 97: {
UpdateStmt(out s);
break;
}
- case 12: case 19: {
+ case 8: case 19: {
VarDeclStatement(out s);
break;
}
- case 55: {
+ case 57: {
IfStmt(out s);
break;
}
- case 59: {
+ case 61: {
WhileStmt(out s);
break;
}
- case 61: {
+ case 63: {
MatchStmt(out s);
break;
}
- case 65: {
+ case 67: {
ParallelStmt(out s);
break;
}
- case 46: {
+ case 47: {
Get();
x = t;
Ident(out id);
@@ -1046,46 +1080,63 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
s.Labels = new LabelNode(x, id.val, s.Labels);
break;
}
- case 47: {
+ case 48: {
Get();
x = t; breakCount = 1; label = null;
if (la.kind == 1) {
Ident(out id);
label = id.val;
- } else if (la.kind == 18 || la.kind == 47) {
- while (la.kind == 47) {
+ } else if (la.kind == 18 || la.kind == 48) {
+ while (la.kind == 48) {
Get();
breakCount++;
}
- } else SynErr(133);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(134); Get();}
+ } else SynErr(139);
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(140); Get();}
Expect(18);
s = label != null ? new BreakStmt(x, label) : new BreakStmt(x, breakCount);
break;
}
- case 48: {
+ case 49: {
ReturnStmt(out s);
break;
}
- default: SynErr(135); break;
+ case 27: {
+ Get();
+ s = new SkeletonStatement(t);
+ Expect(18);
+ break;
+ }
+ default: SynErr(141); break;
}
}
void AssertStmt(out Statement/*!*/ s) {
- Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; Attributes attrs = null;
- Expect(62);
+ Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;
+ Expression/*!*/ e = null; Attributes attrs = null;
+
+ Expect(64);
x = t; s = null;
while (IsAttribute()) {
Attribute(ref attrs);
}
- Expression(out e);
- s = new AssertStmt(x, e, attrs);
+ if (StartOf(9)) {
+ Expression(out e);
+ } else if (la.kind == 27) {
+ Get();
+ } else SynErr(142);
Expect(18);
+ if (e == null) {
+ s = new SkeletonStatement(new AssertStmt(x, new LiteralExpr(x, true), attrs), true, false);
+ } else {
+ s = new AssertStmt(x, e, attrs);
+ }
+
}
void AssumeStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e;
- Expect(63);
+ Expect(65);
x = t;
Expression(out e);
Expect(18);
@@ -1096,7 +1147,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Attributes.Argument/*!*/ arg;
List<Attributes.Argument/*!*/> args = new List<Attributes.Argument/*!*/>();
- Expect(64);
+ Expect(66);
x = t;
AttributeArg(out arg);
args.Add(arg);
@@ -1116,37 +1167,49 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression lhs0;
IToken x;
Attributes attrs = null;
+ Expression suchThat = null;
Lhs(out e);
x = e.tok;
if (la.kind == 6 || la.kind == 18) {
- while (IsAttribute()) {
+ while (la.kind == 6) {
Attribute(ref attrs);
}
Expect(18);
rhss.Add(new ExprRhs(e, attrs));
- } else if (la.kind == 20 || la.kind == 49) {
+ } else if (la.kind == 20 || la.kind == 50 || la.kind == 51) {
lhss.Add(e); lhs0 = e;
while (la.kind == 20) {
Get();
Lhs(out e);
lhss.Add(e);
}
- Expect(49);
- x = t;
- Rhs(out r, lhs0);
- rhss.Add(r);
- while (la.kind == 20) {
+ if (la.kind == 50) {
Get();
+ x = t;
Rhs(out r, lhs0);
rhss.Add(r);
- }
+ while (la.kind == 20) {
+ Get();
+ Rhs(out r, lhs0);
+ rhss.Add(r);
+ }
+ } else if (la.kind == 51) {
+ Get();
+ x = t;
+ Expression(out suchThat);
+ } else SynErr(143);
Expect(18);
} else if (la.kind == 5) {
Get();
SemErr(t, "invalid statement (did you forget the 'label' keyword?)");
- } else SynErr(136);
- s = new UpdateStmt(x, lhss, rhss);
+ } else SynErr(144);
+ if (suchThat != null) {
+ s = new AssignSuchThatStmt(x, lhss, suchThat);
+ } else {
+ s = new UpdateStmt(x, lhss, rhss);
+ }
+
}
void VarDeclStatement(out Statement/*!*/ s) {
@@ -1155,8 +1218,9 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
AssignmentRhs r; IdentifierExpr lhs0;
List<VarDecl> lhss = new List<VarDecl>();
List<AssignmentRhs> rhss = new List<AssignmentRhs>();
+ Expression suchThat = null;
- if (la.kind == 12) {
+ if (la.kind == 8) {
Get();
isGhost = true; x = t;
}
@@ -1169,30 +1233,42 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
LocalIdentTypeOptional(out d, isGhost);
lhss.Add(d);
}
- if (la.kind == 49) {
- Get();
- assignTok = t;
- lhs0 = new IdentifierExpr(lhss[0].Tok, lhss[0].Name);
- lhs0.Var = lhss[0]; lhs0.Type = lhss[0].OptionalType; // resolve here
-
- Rhs(out r, lhs0);
- rhss.Add(r);
- while (la.kind == 20) {
+ if (la.kind == 50 || la.kind == 51) {
+ if (la.kind == 50) {
Get();
+ assignTok = t;
+ lhs0 = new IdentifierExpr(lhss[0].Tok, lhss[0].Name);
+ lhs0.Var = lhss[0]; lhs0.Type = lhss[0].OptionalType; // resolve here
+
Rhs(out r, lhs0);
rhss.Add(r);
+ while (la.kind == 20) {
+ Get();
+ Rhs(out r, lhs0);
+ rhss.Add(r);
+ }
+ } else {
+ Get();
+ assignTok = t;
+ Expression(out suchThat);
}
}
Expect(18);
- UpdateStmt update;
- if (rhss.Count == 0) {
- update = null;
+ ConcreteUpdateStatement update;
+ if (suchThat != null) {
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new AssignSuchThatStmt(assignTok, ies, suchThat);
+ } else if (rhss.Count == 0) {
+ update = null;
} else {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
- }
- update = new UpdateStmt(assignTok, ies, rhss);
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new UpdateStmt(assignTok, ies, rhss);
}
s = new VarDeclStmt(x, lhss, update);
@@ -1200,73 +1276,109 @@ 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;
- Statement/*!*/ thn;
+ Expression guard = null; bool guardOmitted = false;
+ BlockStmt/*!*/ thn;
+ BlockStmt/*!*/ bs;
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
List<GuardedAlternative> alternatives;
ifStmt = dummyStmt; // to please the compiler
- Expect(55);
+ Expect(57);
x = t;
- if (la.kind == 32) {
- Guard(out guard);
+ if (la.kind == 27 || la.kind == 33) {
+ if (la.kind == 33) {
+ Guard(out guard);
+ } else {
+ Get();
+ guardOmitted = true;
+ }
BlockStmt(out thn, out bodyStart, out bodyEnd);
- if (la.kind == 56) {
+ if (la.kind == 58) {
Get();
- if (la.kind == 55) {
+ if (la.kind == 57) {
IfStmt(out s);
els = s;
} else if (la.kind == 6) {
- BlockStmt(out s, out bodyStart, out bodyEnd);
- els = s;
- } else SynErr(137);
+ BlockStmt(out bs, out bodyStart, out bodyEnd);
+ els = bs;
+ } else SynErr(145);
}
- ifStmt = new IfStmt(x, guard, thn, els);
+ if (guardOmitted) {
+ ifStmt = new SkeletonStatement(new IfStmt(x, guard, thn, els), true, false);
+ } else {
+ ifStmt = new IfStmt(x, guard, thn, els);
+ }
+
} else if (la.kind == 6) {
AlternativeBlock(out alternatives);
ifStmt = new AlternativeStmt(x, alternatives);
- } else SynErr(138);
+ } else SynErr(146);
}
void WhileStmt(out Statement/*!*/ stmt) {
Contract.Ensures(Contract.ValueAtReturn(out stmt) != null); IToken/*!*/ x;
- Expression guard;
+ Expression guard = null; bool guardOmitted = false;
List<MaybeFreeExpression/*!*/> invariants = new List<MaybeFreeExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
Attributes decAttrs = null;
Attributes modAttrs = null;
List<FrameExpression/*!*/> mod = null;
- Statement/*!*/ body;
- IToken bodyStart, bodyEnd;
+ BlockStmt/*!*/ body = null; bool bodyOmitted = false;
+ IToken bodyStart = null, bodyEnd = null;
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
- Expect(59);
+ Expect(61);
x = t;
- if (la.kind == 32) {
- Guard(out guard);
- Contract.Assume(guard == null || cce.Owner.None(guard));
+ if (la.kind == 27 || la.kind == 33) {
+ if (la.kind == 33) {
+ Guard(out guard);
+ Contract.Assume(guard == null || cce.Owner.None(guard));
+ } else {
+ Get();
+ guardOmitted = true;
+ }
LoopSpec(out invariants, out decreases, out mod, ref decAttrs, ref modAttrs);
- BlockStmt(out body, out bodyStart, out bodyEnd);
- stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
- } else if (StartOf(12)) {
+ if (la.kind == 6) {
+ BlockStmt(out body, out bodyStart, out bodyEnd);
+ } else if (la.kind == 27) {
+ Get();
+ bodyOmitted = true;
+ } else SynErr(147);
+ if (guardOmitted || bodyOmitted) {
+ if (decreases.Count != 0) {
+ SemErr(decreases[0].tok, "'decreases' clauses are not allowed on refining loops");
+ }
+ if (mod != null) {
+ SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
+ }
+ if (body == 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);
+ } else {
+ stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
+ }
+
+ } else if (StartOf(13)) {
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(139);
+ } else SynErr(148);
}
void MatchStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x; Expression/*!*/ e; MatchCaseStmt/*!*/ c;
List<MatchCaseStmt/*!*/> cases = new List<MatchCaseStmt/*!*/>();
- Expect(61);
+ Expect(63);
x = t;
Expression(out e);
Expect(6);
- while (la.kind == 57) {
+ while (la.kind == 59) {
CaseStatement(out c);
cases.Add(c);
}
@@ -1283,12 +1395,12 @@ 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(65);
+ Expect(67);
x = t;
- Expect(32);
+ Expect(33);
if (la.kind == 1) {
List<BoundVar/*!*/> bvarsX; Attributes attrsX; Expression rangeX;
QuantifierDomain(out bvarsX, out attrsX, out rangeX);
@@ -1298,14 +1410,14 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (bvars == null) { bvars = new List<BoundVar>(); }
if (range == null) { range = new LiteralExpr(x, true); }
- Expect(33);
- while (la.kind == 28 || la.kind == 30) {
+ Expect(34);
+ while (la.kind == 29 || la.kind == 31) {
isFree = false;
- if (la.kind == 28) {
+ if (la.kind == 29) {
Get();
isFree = true;
}
- Expect(30);
+ Expect(31);
Expression(out e);
Expect(18);
ens.Add(new MaybeFreeExpression(e, isFree));
@@ -1319,9 +1431,9 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<AssignmentRhs> rhss = null;
AssignmentRhs r;
- Expect(48);
+ Expect(49);
returnTok = t;
- if (StartOf(13)) {
+ if (StartOf(14)) {
Rhs(out r, null);
rhss = new List<AssignmentRhs>(); rhss.Add(r);
while (la.kind == 20) {
@@ -1343,27 +1455,27 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
r = null; // to please compiler
Attributes attrs = null;
- if (la.kind == 50) {
+ if (la.kind == 52) {
Get();
newToken = t;
TypeAndToken(out x, out ty);
- if (la.kind == 51 || la.kind == 53) {
- if (la.kind == 51) {
+ if (la.kind == 53 || la.kind == 55) {
+ if (la.kind == 53) {
Get();
ee = new List<Expression>();
Expressions(ee);
- Expect(52);
+ Expect(54);
UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true);
} else {
Get();
Ident(out x);
- Expect(32);
+ Expect(33);
args = new List<Expression/*!*/>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(33);
+ Expect(34);
initCall = new CallStmt(x, new List<Expression>(),
receiverForInitCall, x.val, args);
}
@@ -1371,22 +1483,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (ee != null) {
r = new TypeRhs(newToken, ty, ee);
} else {
- r = new TypeRhs(newToken, ty, initCall);
+ r = new TypeRhs(newToken, ty, initCall);
}
- } else if (la.kind == 54) {
+ } else if (la.kind == 56) {
Get();
x = t;
Expression(out e);
r = new ExprRhs(new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e));
- } else if (la.kind == 44) {
+ } else if (la.kind == 45) {
Get();
r = new HavocRhs(t);
- } else if (StartOf(8)) {
+ } else if (StartOf(9)) {
Expression(out e);
r = new ExprRhs(e);
- } else SynErr(140);
- while (IsAttribute()) {
+ } else SynErr(149);
+ while (la.kind == 6) {
Attribute(ref attrs);
}
r.Attributes = attrs;
@@ -1397,16 +1509,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 1) {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 51 || la.kind == 53) {
+ while (la.kind == 53 || la.kind == 55) {
Suffix(ref e);
}
- } else if (StartOf(14)) {
+ } else if (StartOf(15)) {
ConstAtomExpression(out e);
Suffix(ref e);
- while (la.kind == 51 || la.kind == 53) {
+ while (la.kind == 53 || la.kind == 55) {
Suffix(ref e);
}
- } else SynErr(141);
+ } else SynErr(150);
}
void Expressions(List<Expression/*!*/>/*!*/ args) {
@@ -1422,15 +1534,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void Guard(out Expression e) {
Expression/*!*/ ee; e = null;
- Expect(32);
- if (la.kind == 44) {
+ Expect(33);
+ if (la.kind == 45) {
Get();
e = null;
- } else if (StartOf(8)) {
+ } else if (StartOf(9)) {
Expression(out ee);
e = ee;
- } else SynErr(142);
- Expect(33);
+ } else SynErr(151);
+ Expect(34);
}
void AlternativeBlock(out List<GuardedAlternative> alternatives) {
@@ -1440,13 +1552,13 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Statement> body;
Expect(6);
- while (la.kind == 57) {
+ while (la.kind == 59) {
Get();
x = t;
Expression(out e);
- Expect(58);
+ Expect(60);
body = new List<Statement>();
- while (StartOf(9)) {
+ while (StartOf(10)) {
Stmt(body);
}
alternatives.Add(new GuardedAlternative(x, e, body));
@@ -1461,29 +1573,29 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
decreases = new List<Expression/*!*/>();
mod = null;
- while (StartOf(15)) {
- if (la.kind == 28 || la.kind == 60) {
+ while (StartOf(16)) {
+ if (la.kind == 29 || la.kind == 62) {
Invariant(out invariant);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(143); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(152); Get();}
Expect(18);
invariants.Add(invariant);
- } else if (la.kind == 31) {
- while (!(la.kind == 0 || la.kind == 31)) {SynErr(144); Get();}
+ } else if (la.kind == 32) {
+ while (!(la.kind == 0 || la.kind == 32)) {SynErr(153); Get();}
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, true);
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(145); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(154); Get();}
Expect(18);
} else {
- while (!(la.kind == 0 || la.kind == 27)) {SynErr(146); Get();}
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(155); Get();}
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
}
mod = mod ?? new List<FrameExpression>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
FrameExpression(out fe);
mod.Add(fe);
while (la.kind == 20) {
@@ -1492,7 +1604,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 18)) {SynErr(147); Get();}
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(156); Get();}
Expect(18);
}
}
@@ -1500,12 +1612,12 @@ 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 == 28 || la.kind == 60)) {SynErr(148); Get();}
- if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 29 || la.kind == 62)) {SynErr(157); Get();}
+ if (la.kind == 29) {
Get();
isFree = true;
}
- Expect(60);
+ Expect(62);
while (IsAttribute()) {
Attribute(ref attrs);
}
@@ -1520,10 +1632,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BoundVar/*!*/ bv;
List<Statement/*!*/> body = new List<Statement/*!*/>();
- Expect(57);
+ Expect(59);
x = t;
Ident(out id);
- if (la.kind == 32) {
+ if (la.kind == 33) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
@@ -1532,10 +1644,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out bv);
arguments.Add(bv);
}
- Expect(33);
+ Expect(34);
}
- Expect(58);
- while (StartOf(9)) {
+ Expect(60);
+ while (StartOf(10)) {
Stmt(body);
}
c = new MatchCaseStmt(x, id.val, arguments, body);
@@ -1546,10 +1658,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 4) {
Get();
arg = new Attributes.Argument(t, t.val.Substring(1, t.val.Length-2));
- } else if (StartOf(8)) {
+ } else if (StartOf(9)) {
Expression(out e);
arg = new Attributes.Argument(t, e);
- } else SynErr(149);
+ } else SynErr(158);
}
void QuantifierDomain(out List<BoundVar/*!*/> bvars, out Attributes attrs, out Expression range) {
@@ -1577,7 +1689,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void EquivExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
ImpliesExpression(out e0);
- while (la.kind == 66 || la.kind == 67) {
+ while (la.kind == 68 || la.kind == 69) {
EquivOp();
x = t;
ImpliesExpression(out e1);
@@ -1588,7 +1700,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void ImpliesExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
LogicalExpression(out e0);
- if (la.kind == 68 || la.kind == 69) {
+ if (la.kind == 70 || la.kind == 71) {
ImpliesOp();
x = t;
ImpliesExpression(out e1);
@@ -1597,23 +1709,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void EquivOp() {
- if (la.kind == 66) {
+ if (la.kind == 68) {
Get();
- } else if (la.kind == 67) {
+ } else if (la.kind == 69) {
Get();
- } else SynErr(150);
+ } else SynErr(159);
}
void LogicalExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
RelationalExpression(out e0);
- if (StartOf(16)) {
- if (la.kind == 70 || la.kind == 71) {
+ if (StartOf(17)) {
+ if (la.kind == 72 || la.kind == 73) {
AndOp();
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1);
- while (la.kind == 70 || la.kind == 71) {
+ while (la.kind == 72 || la.kind == 73) {
AndOp();
x = t;
RelationalExpression(out e1);
@@ -1624,7 +1736,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1);
- while (la.kind == 72 || la.kind == 73) {
+ while (la.kind == 74 || la.kind == 75) {
OrOp();
x = t;
RelationalExpression(out e1);
@@ -1635,11 +1747,11 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void ImpliesOp() {
- if (la.kind == 68) {
+ if (la.kind == 70) {
Get();
- } else if (la.kind == 69) {
+ } else if (la.kind == 71) {
Get();
- } else SynErr(151);
+ } else SynErr(160);
}
void RelationalExpression(out Expression/*!*/ e) {
@@ -1648,23 +1760,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Expression> chain = null;
List<BinaryExpr.Opcode> ops = null;
int kind = 0; // 0 ("uncommitted") indicates chain of ==, possibly with one !=
- // 1 ("ascending") indicates chain of ==, <, <=, possibly with one !=
- // 2 ("descending") indicates chain of ==, >, >=, possibly with one !=
- // 3 ("illegal") indicates illegal chain
- // 4 ("disjoint") indicates chain of disjoint set operators
+ // 1 ("ascending") indicates chain of ==, <, <=, possibly with one !=
+ // 2 ("descending") indicates chain of ==, >, >=, possibly with one !=
+ // 3 ("illegal") indicates illegal chain
+ // 4 ("disjoint") indicates chain of disjoint set operators
bool hasSeenNeq = false;
Term(out e0);
e = e0;
- if (StartOf(17)) {
+ if (StartOf(18)) {
RelOp(out x, out op);
firstOpTok = x;
Term(out e1);
e = new BinaryExpr(x, op, e0, e1);
if (op == BinaryExpr.Opcode.Disjoint)
- acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, e0, e1); // accumulate first two operands.
+ acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, e0, e1); // accumulate first two operands.
- while (StartOf(17)) {
+ while (StartOf(18)) {
if (chain == null) {
chain = new List<Expression>();
ops = new List<BinaryExpr.Opcode>();
@@ -1718,11 +1830,11 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Term(out e1);
ops.Add(op); chain.Add(e1);
if (op == BinaryExpr.Opcode.Disjoint) {
- e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, acc, e1));
- acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, acc, e1); //e0 has already been added.
+ e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, acc, e1));
+ acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, acc, e1); //e0 has already been added.
}
else
- e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, e0, e1));
+ e = new BinaryExpr(x, BinaryExpr.Opcode.And, e, new BinaryExpr(x, op, e0, e1));
}
}
@@ -1733,25 +1845,25 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void AndOp() {
- if (la.kind == 70) {
+ if (la.kind == 72) {
Get();
- } else if (la.kind == 71) {
+ } else if (la.kind == 73) {
Get();
- } else SynErr(152);
+ } else SynErr(161);
}
void OrOp() {
- if (la.kind == 72) {
+ if (la.kind == 74) {
Get();
- } else if (la.kind == 73) {
+ } else if (la.kind == 75) {
Get();
- } else SynErr(153);
+ } else SynErr(162);
}
void Term(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
Factor(out e0);
- while (la.kind == 84 || la.kind == 85) {
+ while (la.kind == 86 || la.kind == 87) {
AddOp(out x, out op);
Factor(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -1764,7 +1876,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken y;
switch (la.kind) {
- case 74: {
+ case 76: {
Get();
x = t; op = BinaryExpr.Opcode.Eq;
break;
@@ -1779,72 +1891,72 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = t; op = BinaryExpr.Opcode.Gt;
break;
}
- case 75: {
+ case 77: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 76: {
+ case 78: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- case 77: {
+ case 79: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
break;
}
- case 78: {
+ case 80: {
Get();
x = t; op = BinaryExpr.Opcode.Disjoint;
break;
}
- case 79: {
+ case 81: {
Get();
x = t; op = BinaryExpr.Opcode.In;
break;
}
- case 80: {
+ case 82: {
Get();
x = t; y = Token.NoToken;
- if (la.kind == 79) {
+ if (la.kind == 81) {
Get();
y = t;
}
if (y == Token.NoToken) {
SemErr(x, "invalid RelOp");
} else if (y.pos != x.pos + 1) {
- SemErr(x, "invalid RelOp (perhaps you intended \"!in\" with no intervening whitespace?)");
+ SemErr(x, "invalid RelOp (perhaps you intended \"!in\" with no intervening whitespace?)");
} else {
- x.val = "!in";
- op = BinaryExpr.Opcode.NotIn;
+ x.val = "!in";
+ op = BinaryExpr.Opcode.NotIn;
}
break;
}
- case 81: {
+ case 83: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
break;
}
- case 82: {
+ case 84: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 83: {
+ case 85: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- default: SynErr(154); break;
+ default: SynErr(163); break;
}
}
void Factor(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
UnaryExpression(out e0);
- while (la.kind == 44 || la.kind == 86 || la.kind == 87) {
+ while (la.kind == 45 || la.kind == 88 || la.kind == 89) {
MulOp(out x, out op);
UnaryExpression(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -1853,82 +1965,82 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void AddOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 84) {
+ if (la.kind == 86) {
Get();
x = t; op = BinaryExpr.Opcode.Add;
- } else if (la.kind == 85) {
+ } else if (la.kind == 87) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(155);
+ } else SynErr(164);
}
void UnaryExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr;
switch (la.kind) {
- case 85: {
+ case 87: {
Get();
x = t;
UnaryExpression(out e);
e = new BinaryExpr(x, BinaryExpr.Opcode.Sub, new LiteralExpr(x, 0), e);
break;
}
- case 80: case 88: {
+ case 82: case 90: {
NegOp();
x = t;
UnaryExpression(out e);
e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e);
break;
}
- case 19: case 37: case 55: case 61: case 62: case 63: case 98: case 99: case 100: case 101: {
+ case 19: case 38: case 57: case 63: case 64: case 65: case 100: case 101: case 102: case 103: {
EndlessExpression(out e);
break;
}
case 1: {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 51 || la.kind == 53) {
+ while (la.kind == 53 || la.kind == 55) {
Suffix(ref e);
}
break;
}
- case 6: case 51: {
+ case 6: case 53: {
DisplayExpr(out e);
break;
}
- case 38: {
+ case 39: {
MultiSetExpr(out e);
break;
}
- case 2: case 17: case 32: case 89: case 90: case 91: case 92: case 93: case 94: case 95: {
+ case 2: case 17: case 33: case 91: case 92: case 93: case 94: case 95: case 96: case 97: {
ConstAtomExpression(out e);
- while (la.kind == 51 || la.kind == 53) {
+ while (la.kind == 53 || la.kind == 55) {
Suffix(ref e);
}
break;
}
- default: SynErr(156); break;
+ default: SynErr(165); break;
}
}
void MulOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 44) {
+ if (la.kind == 45) {
Get();
x = t; op = BinaryExpr.Opcode.Mul;
- } else if (la.kind == 86) {
+ } else if (la.kind == 88) {
Get();
x = t; op = BinaryExpr.Opcode.Div;
- } else if (la.kind == 87) {
+ } else if (la.kind == 89) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(157);
+ } else SynErr(166);
}
void NegOp() {
- if (la.kind == 80) {
+ if (la.kind == 82) {
Get();
- } else if (la.kind == 88) {
+ } else if (la.kind == 90) {
Get();
- } else SynErr(158);
+ } else SynErr(167);
}
void EndlessExpression(out Expression e) {
@@ -1939,30 +2051,30 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<BoundVar> letVars; List<Expression> letRHSs;
switch (la.kind) {
- case 55: {
+ case 57: {
Get();
x = t;
Expression(out e);
- Expect(96);
+ Expect(98);
Expression(out e0);
- Expect(56);
+ Expect(58);
Expression(out e1);
e = new ITEExpr(x, e, e0, e1);
break;
}
- case 61: {
+ case 63: {
MatchExpression(out e);
break;
}
- case 98: case 99: case 100: case 101: {
+ case 100: case 101: case 102: case 103: {
QuantifierGuts(out e);
break;
}
- case 37: {
+ case 38: {
ComprehensionExpr(out e);
break;
}
- case 62: {
+ case 64: {
Get();
x = t;
Expression(out e0);
@@ -1971,7 +2083,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new AssertExpr(x, e0, e1);
break;
}
- case 63: {
+ case 65: {
Get();
x = t;
Expression(out e0);
@@ -1992,7 +2104,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out d);
letVars.Add(d);
}
- Expect(49);
+ Expect(50);
Expression(out e);
letRHSs.Add(e);
while (la.kind == 20) {
@@ -2005,7 +2117,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new LetExpr(x, letVars, letRHSs, e);
break;
}
- default: SynErr(159); break;
+ default: SynErr(168); break;
}
}
@@ -2016,18 +2128,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Ident(out id);
idents.Add(id);
- while (la.kind == 53) {
+ while (la.kind == 55) {
Get();
Ident(out id);
idents.Add(id);
}
- if (la.kind == 32) {
+ if (la.kind == 33) {
Get();
openParen = t; args = new List<Expression>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(33);
+ Expect(34);
}
e = new IdentifierSequence(idents, openParen, args);
}
@@ -2038,37 +2150,37 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Expression> multipleIndices = null;
bool func = false;
- if (la.kind == 53) {
+ if (la.kind == 55) {
Get();
Ident(out id);
- if (la.kind == 32) {
+ if (la.kind == 33) {
Get();
IToken openParen = t; args = new List<Expression/*!*/>(); func = true;
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(33);
+ Expect(34);
e = new FunctionCallExpr(id, id.val, e, openParen, args);
}
if (!func) { e = new ExprDotName(id, e, id.val); }
- } else if (la.kind == 51) {
+ } else if (la.kind == 53) {
Get();
x = t;
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expression(out ee);
e0 = ee;
- if (la.kind == 97) {
+ if (la.kind == 99) {
Get();
anyDots = true;
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expression(out ee);
e1 = ee;
}
- } else if (la.kind == 49) {
+ } else if (la.kind == 50) {
Get();
Expression(out ee);
e1 = ee;
- } else if (la.kind == 20 || la.kind == 52) {
+ } else if (la.kind == 20 || la.kind == 54) {
while (la.kind == 20) {
Get();
Expression(out ee);
@@ -2079,39 +2191,39 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
multipleIndices.Add(ee);
}
- } else SynErr(160);
- } else if (la.kind == 97) {
+ } else SynErr(169);
+ } else if (la.kind == 99) {
Get();
anyDots = true;
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expression(out ee);
e1 = ee;
}
- } else SynErr(161);
+ } else SynErr(170);
if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
// make sure an array class with this dimensionality exists
UserDefinedType tmp = theBuiltIns.ArrayType(x, multipleIndices.Count, new IntType(), true);
} else {
- if (!anyDots && e0 == null) {
- /* a parsing error occurred */
- e0 = dummyExpr;
- }
- Contract.Assert(anyDots || e0 != null);
- if (anyDots) {
- //Contract.Assert(e0 != null || e1 != null);
- e = new SeqSelectExpr(x, false, e, e0, e1);
- } else if (e1 == null) {
- Contract.Assert(e0 != null);
- e = new SeqSelectExpr(x, true, e, e0, null);
- } else {
- Contract.Assert(e0 != null);
- e = new SeqUpdateExpr(x, e, e0, e1);
- }
+ if (!anyDots && e0 == null) {
+ /* a parsing error occurred */
+ e0 = dummyExpr;
+ }
+ Contract.Assert(anyDots || e0 != null);
+ if (anyDots) {
+ //Contract.Assert(e0 != null || e1 != null);
+ e = new SeqSelectExpr(x, false, e, e0, e1);
+ } else if (e1 == null) {
+ Contract.Assert(e0 != null);
+ e = new SeqSelectExpr(x, true, e, e0, null);
+ } else {
+ Contract.Assert(e0 != null);
+ e = new SeqUpdateExpr(x, e, e0, e1);
+ }
}
- Expect(52);
- } else SynErr(162);
+ Expect(54);
+ } else SynErr(171);
}
void DisplayExpr(out Expression e) {
@@ -2122,20 +2234,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 6) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(elements);
}
e = new SetDisplayExpr(x, elements);
Expect(7);
- } else if (la.kind == 51) {
+ } else if (la.kind == 53) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(elements);
}
e = new SeqDisplayExpr(x, elements);
- Expect(52);
- } else SynErr(163);
+ Expect(54);
+ } else SynErr(172);
}
void MultiSetExpr(out Expression e) {
@@ -2143,25 +2255,25 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
e = dummyExpr;
- Expect(38);
+ Expect(39);
x = t;
if (la.kind == 6) {
Get();
elements = new List<Expression/*!*/>();
- if (StartOf(8)) {
+ if (StartOf(9)) {
Expressions(elements);
}
e = new MultiSetDisplayExpr(x, elements);
Expect(7);
- } else if (la.kind == 32) {
+ } else if (la.kind == 33) {
Get();
x = t; elements = new List<Expression/*!*/>();
Expression(out e);
e = new MultiSetFormingExpr(x, e);
- Expect(33);
- } else if (StartOf(18)) {
+ Expect(34);
+ } else if (StartOf(19)) {
SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses.");
- } else SynErr(164);
+ } else SynErr(173);
}
void ConstAtomExpression(out Expression/*!*/ e) {
@@ -2170,17 +2282,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
switch (la.kind) {
- case 89: {
+ case 91: {
Get();
e = new LiteralExpr(t, false);
break;
}
- case 90: {
+ case 92: {
Get();
e = new LiteralExpr(t, true);
break;
}
- case 91: {
+ case 93: {
Get();
e = new LiteralExpr(t);
break;
@@ -2190,35 +2302,35 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new LiteralExpr(t, n);
break;
}
- case 92: {
+ case 94: {
Get();
e = new ThisExpr(t);
break;
}
- case 93: {
+ case 95: {
Get();
x = t;
- Expect(32);
- Expression(out e);
Expect(33);
+ Expression(out e);
+ Expect(34);
e = new FreshExpr(x, e);
break;
}
- case 94: {
+ case 96: {
Get();
x = t;
- Expect(32);
- Expression(out e);
Expect(33);
+ Expression(out e);
+ Expect(34);
e = new AllocatedExpr(x, e);
break;
}
- case 95: {
+ case 97: {
Get();
x = t;
- Expect(32);
- Expression(out e);
Expect(33);
+ Expression(out e);
+ Expect(34);
e = new OldExpr(x, e);
break;
}
@@ -2230,15 +2342,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(17);
break;
}
- case 32: {
+ case 33: {
Get();
x = t;
Expression(out e);
e = new ParensExpression(x, e);
- Expect(33);
+ Expect(34);
break;
}
- default: SynErr(165); break;
+ default: SynErr(174); break;
}
}
@@ -2247,8 +2359,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
try {
n = BigInteger.Parse(t.val);
} catch (System.FormatException) {
- SemErr("incorrectly formatted number");
- n = BigInteger.Zero;
+ SemErr("incorrectly formatted number");
+ n = BigInteger.Zero;
}
}
@@ -2257,10 +2369,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; MatchCaseExpr/*!*/ c;
List<MatchCaseExpr/*!*/> cases = new List<MatchCaseExpr/*!*/>();
- Expect(61);
+ Expect(63);
x = t;
Expression(out e);
- while (la.kind == 57) {
+ while (la.kind == 59) {
CaseExpression(out c);
cases.Add(c);
}
@@ -2275,20 +2387,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression range;
Expression/*!*/ body;
- if (la.kind == 98 || la.kind == 99) {
+ if (la.kind == 100 || la.kind == 101) {
Forall();
x = t; univ = true;
- } else if (la.kind == 100 || la.kind == 101) {
+ } else if (la.kind == 102 || la.kind == 103) {
Exists();
x = t;
- } else SynErr(166);
+ } else SynErr(175);
QuantifierDomain(out bvars, out attrs, out range);
QSep();
Expression(out body);
if (univ) {
q = new ForallExpr(x, bvars, range, body, attrs);
} else {
- q = new ExistsExpr(x, bvars, range, body, attrs);
+ q = new ExistsExpr(x, bvars, range, body, attrs);
}
}
@@ -2301,7 +2413,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression/*!*/ range;
Expression body = null;
- Expect(37);
+ Expect(38);
x = t;
IdentTypeOptional(out bv);
bvars.Add(bv);
@@ -2312,7 +2424,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
Expect(17);
Expression(out range);
- if (la.kind == 102 || la.kind == 103) {
+ if (la.kind == 104 || la.kind == 105) {
QSep();
Expression(out body);
}
@@ -2327,10 +2439,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BoundVar/*!*/ bv;
Expression/*!*/ body;
- Expect(57);
+ Expect(59);
x = t;
Ident(out id);
- if (la.kind == 32) {
+ if (la.kind == 33) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
@@ -2339,35 +2451,35 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out bv);
arguments.Add(bv);
}
- Expect(33);
+ Expect(34);
}
- Expect(58);
+ Expect(60);
Expression(out body);
c = new MatchCaseExpr(x, id.val, arguments, body);
}
void Forall() {
- if (la.kind == 98) {
+ if (la.kind == 100) {
Get();
- } else if (la.kind == 99) {
+ } else if (la.kind == 101) {
Get();
- } else SynErr(167);
+ } else SynErr(176);
}
void Exists() {
- if (la.kind == 100) {
+ if (la.kind == 102) {
Get();
- } else if (la.kind == 101) {
+ } else if (la.kind == 103) {
Get();
- } else SynErr(168);
+ } else SynErr(177);
}
void QSep() {
- if (la.kind == 102) {
+ if (la.kind == 104) {
Get();
- } else if (la.kind == 103) {
+ } else if (la.kind == 105) {
Get();
- } else SynErr(169);
+ } else SynErr(178);
}
void AttributeBody(ref Attributes attrs) {
@@ -2378,7 +2490,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(5);
Expect(1);
aName = t.val;
- if (StartOf(19)) {
+ if (StartOf(20)) {
AttributeArg(out aArg);
aArgs.Add(aArg);
while (la.kind == 20) {
@@ -2394,34 +2506,36 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
public void Parse() {
la = new Token();
- la.val = "";
+ la.val = "";
Get();
Dafny();
+ Expect(0);
- Expect(0);
+ Expect(0);
}
-
+
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,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,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,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,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,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,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,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, 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,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, 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,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,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, 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, 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},
- {x,x,x,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,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,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,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,T,T, x,x,x,x, x,x,x,x, x,T,T,x, T,x,T,T, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, T,T,x,x, x,T,x,x, T,x,x,x, T,T,T,x, x,x,x,x, x,x,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, T,T,x,x, x,x,T,T, x,x},
- {x,T,T,x, T,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, 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}
+ {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, 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,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,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,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,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,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},
+ {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,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},
+ {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, 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, 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, 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, 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, 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, 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,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,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,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, 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,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,x,x,x, 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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,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,T,T, x,x,x,x, x,x,x,x, x,T,T,x, T,x,T,T, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, x,x,T,x, x,x,T,T, T,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,x, x,x,x,x, x,x,T,T, x,x,x,x, T,T,x,x},
+ {x,T,T,x, T,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, 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}
};
} // end Parser
@@ -2430,18 +2544,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
public class Errors {
public int count = 0; // number of errors detected
public System.IO.TextWriter/*!*/ errorStream = Console.Out; // error messages go to this stream
- public string errMsgFormat = "{0}({1},{2}): error: {3}"; // 0=filename, 1=line, 2=column, 3=text
- public string warningMsgFormat = "{0}({1},{2}): warning: {3}"; // 0=filename, 1=line, 2=column, 3=text
-
+ public string errMsgFormat = "{0}({1},{2}): error: {3}"; // 0=filename, 1=line, 2=column, 3=text
+ public string warningMsgFormat = "{0}({1},{2}): warning: {3}"; // 0=filename, 1=line, 2=column, 3=text
+
public void SynErr(string filename, int line, int col, int n) {
- SynErr(filename, line, col, GetSyntaxErrorString(n));
- }
- public virtual void SynErr(string filename, int line, int col, string msg) {
- Contract.Requires(msg != null);
+ SynErr(filename, line, col, GetSyntaxErrorString(n));
+ }
+
+ public virtual void SynErr(string filename, int line, int col, string/*!*/ msg) {
+ Contract.Requires(msg != null);
errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
count++;
- }
- string GetSyntaxErrorString(int n) {
+ }
+
+ string GetSyntaxErrorString(int n) {
string s;
switch (n) {
case 0: s = "EOF expected"; break;
@@ -2452,11 +2568,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;
@@ -2471,153 +2587,162 @@ public class Errors {
case 24: s = "\"method\" expected"; break;
case 25: s = "\"constructor\" expected"; break;
case 26: s = "\"returns\" expected"; break;
- case 27: s = "\"modifies\" expected"; break;
- case 28: s = "\"free\" expected"; break;
- case 29: s = "\"requires\" expected"; break;
- case 30: s = "\"ensures\" expected"; break;
- case 31: s = "\"decreases\" expected"; break;
- case 32: s = "\"(\" expected"; break;
- case 33: s = "\")\" expected"; break;
- case 34: s = "\"bool\" expected"; break;
- case 35: s = "\"nat\" expected"; break;
- case 36: s = "\"int\" expected"; break;
- case 37: s = "\"set\" expected"; break;
- case 38: s = "\"multiset\" expected"; break;
- case 39: s = "\"seq\" expected"; break;
- case 40: s = "\"object\" expected"; break;
- case 41: s = "\"function\" expected"; break;
- case 42: s = "\"predicate\" expected"; break;
- case 43: s = "\"reads\" expected"; break;
- case 44: s = "\"*\" expected"; break;
- case 45: s = "\"`\" expected"; break;
- case 46: s = "\"label\" expected"; break;
- case 47: s = "\"break\" expected"; break;
- case 48: s = "\"return\" expected"; break;
- case 49: s = "\":=\" expected"; break;
- case 50: s = "\"new\" expected"; break;
- case 51: s = "\"[\" expected"; break;
- case 52: s = "\"]\" expected"; break;
- case 53: s = "\".\" expected"; break;
- case 54: s = "\"choose\" expected"; break;
- case 55: s = "\"if\" expected"; break;
- case 56: s = "\"else\" expected"; break;
- case 57: s = "\"case\" expected"; break;
- case 58: s = "\"=>\" expected"; break;
- case 59: s = "\"while\" expected"; break;
- case 60: s = "\"invariant\" expected"; break;
- case 61: s = "\"match\" expected"; break;
- case 62: s = "\"assert\" expected"; break;
- case 63: s = "\"assume\" expected"; break;
- case 64: s = "\"print\" expected"; break;
- case 65: s = "\"parallel\" expected"; break;
- case 66: s = "\"<==>\" expected"; break;
- case 67: s = "\"\\u21d4\" expected"; break;
- case 68: s = "\"==>\" expected"; break;
- case 69: s = "\"\\u21d2\" expected"; break;
- case 70: s = "\"&&\" expected"; break;
- case 71: s = "\"\\u2227\" expected"; break;
- case 72: s = "\"||\" expected"; break;
- case 73: s = "\"\\u2228\" expected"; break;
- case 74: s = "\"==\" expected"; break;
- case 75: s = "\"<=\" expected"; break;
- case 76: s = "\">=\" expected"; break;
- case 77: s = "\"!=\" expected"; break;
- case 78: s = "\"!!\" expected"; break;
- case 79: s = "\"in\" expected"; break;
- case 80: s = "\"!\" expected"; break;
- case 81: s = "\"\\u2260\" expected"; break;
- case 82: s = "\"\\u2264\" expected"; break;
- case 83: s = "\"\\u2265\" expected"; break;
- case 84: s = "\"+\" expected"; break;
- case 85: s = "\"-\" expected"; break;
- case 86: s = "\"/\" expected"; break;
- case 87: s = "\"%\" expected"; break;
- case 88: s = "\"\\u00ac\" expected"; break;
- case 89: s = "\"false\" expected"; break;
- case 90: s = "\"true\" expected"; break;
- case 91: s = "\"null\" expected"; break;
- case 92: s = "\"this\" expected"; break;
- case 93: s = "\"fresh\" expected"; break;
- case 94: s = "\"allocated\" expected"; break;
- case 95: s = "\"old\" expected"; break;
- case 96: s = "\"then\" expected"; break;
- case 97: s = "\"..\" expected"; break;
- case 98: s = "\"forall\" expected"; break;
- case 99: s = "\"\\u2200\" expected"; break;
- case 100: s = "\"exists\" expected"; break;
- case 101: s = "\"\\u2203\" expected"; break;
- case 102: s = "\"::\" expected"; break;
- case 103: s = "\"\\u2022\" expected"; break;
- case 104: s = "??? expected"; break;
- case 105: s = "this symbol not expected in ClassDecl"; break;
- case 106: s = "this symbol not expected in DatatypeDecl"; break;
- case 107: s = "this symbol not expected in DatatypeDecl"; break;
- case 108: s = "this symbol not expected in ArbitraryTypeDecl"; break;
- case 109: s = "invalid ClassMemberDecl"; break;
- case 110: s = "this symbol not expected in FieldDecl"; break;
- case 111: s = "this symbol not expected in FieldDecl"; break;
- case 112: s = "invalid FunctionDecl"; break;
- case 113: s = "this symbol not expected in MethodDecl"; break;
- case 114: s = "invalid MethodDecl"; break;
- case 115: s = "invalid TypeAndToken"; break;
- case 116: s = "this symbol not expected in MethodSpec"; break;
- case 117: s = "this symbol not expected in MethodSpec"; break;
- case 118: s = "this symbol not expected in MethodSpec"; break;
- case 119: s = "this symbol not expected in MethodSpec"; break;
- case 120: s = "invalid MethodSpec"; break;
- case 121: s = "this symbol not expected in MethodSpec"; break;
- case 122: s = "invalid MethodSpec"; break;
- case 123: s = "invalid ReferenceType"; break;
- case 124: s = "this symbol not expected in FunctionSpec"; break;
- case 125: s = "this symbol not expected in FunctionSpec"; break;
- case 126: s = "this symbol not expected in FunctionSpec"; break;
- case 127: s = "this symbol not expected in FunctionSpec"; break;
- case 128: s = "this symbol not expected in FunctionSpec"; break;
- case 129: s = "invalid FunctionSpec"; break;
- case 130: s = "invalid PossiblyWildFrameExpression"; break;
- case 131: s = "invalid PossiblyWildExpression"; break;
- case 132: s = "this symbol not expected in OneStmt"; break;
- case 133: s = "invalid OneStmt"; break;
- case 134: s = "this symbol not expected in OneStmt"; break;
- case 135: s = "invalid OneStmt"; break;
- case 136: s = "invalid UpdateStmt"; break;
- case 137: s = "invalid IfStmt"; break;
- case 138: s = "invalid IfStmt"; break;
- case 139: s = "invalid WhileStmt"; break;
- case 140: s = "invalid Rhs"; break;
- case 141: s = "invalid Lhs"; break;
- case 142: s = "invalid Guard"; break;
- case 143: s = "this symbol not expected in LoopSpec"; break;
- case 144: s = "this symbol not expected in LoopSpec"; break;
- case 145: s = "this symbol not expected in LoopSpec"; break;
- case 146: s = "this symbol not expected in LoopSpec"; break;
- case 147: s = "this symbol not expected in LoopSpec"; break;
- case 148: s = "this symbol not expected in Invariant"; break;
- case 149: s = "invalid AttributeArg"; break;
- case 150: s = "invalid EquivOp"; break;
- case 151: s = "invalid ImpliesOp"; break;
- case 152: s = "invalid AndOp"; break;
- case 153: s = "invalid OrOp"; break;
- case 154: s = "invalid RelOp"; break;
- case 155: s = "invalid AddOp"; break;
- case 156: s = "invalid UnaryExpression"; break;
- case 157: s = "invalid MulOp"; break;
- case 158: s = "invalid NegOp"; break;
- case 159: s = "invalid EndlessExpression"; break;
- case 160: s = "invalid Suffix"; break;
- case 161: s = "invalid Suffix"; break;
- case 162: s = "invalid Suffix"; break;
- case 163: s = "invalid DisplayExpr"; break;
- case 164: s = "invalid MultiSetExpr"; break;
- case 165: s = "invalid ConstAtomExpression"; break;
- case 166: s = "invalid QuantifierGuts"; break;
- case 167: s = "invalid Forall"; break;
- case 168: s = "invalid Exists"; break;
- case 169: s = "invalid QSep"; break;
+ case 27: s = "\"...\" expected"; break;
+ case 28: s = "\"modifies\" expected"; break;
+ case 29: s = "\"free\" expected"; break;
+ case 30: s = "\"requires\" expected"; break;
+ case 31: s = "\"ensures\" expected"; break;
+ case 32: s = "\"decreases\" expected"; break;
+ case 33: s = "\"(\" expected"; break;
+ case 34: s = "\")\" expected"; break;
+ case 35: s = "\"bool\" expected"; break;
+ case 36: s = "\"nat\" expected"; break;
+ case 37: s = "\"int\" expected"; break;
+ case 38: s = "\"set\" expected"; break;
+ case 39: s = "\"multiset\" expected"; break;
+ case 40: s = "\"seq\" expected"; break;
+ case 41: s = "\"object\" expected"; break;
+ case 42: s = "\"function\" expected"; break;
+ case 43: s = "\"predicate\" expected"; break;
+ case 44: s = "\"reads\" expected"; break;
+ case 45: s = "\"*\" expected"; break;
+ case 46: s = "\"`\" expected"; break;
+ case 47: s = "\"label\" expected"; break;
+ case 48: s = "\"break\" expected"; break;
+ case 49: s = "\"return\" expected"; break;
+ case 50: s = "\":=\" expected"; break;
+ case 51: s = "\":|\" expected"; break;
+ case 52: s = "\"new\" expected"; break;
+ case 53: s = "\"[\" expected"; break;
+ case 54: s = "\"]\" expected"; break;
+ case 55: s = "\".\" expected"; break;
+ case 56: s = "\"choose\" expected"; break;
+ case 57: s = "\"if\" expected"; break;
+ case 58: s = "\"else\" expected"; break;
+ case 59: s = "\"case\" expected"; break;
+ case 60: s = "\"=>\" expected"; break;
+ case 61: s = "\"while\" expected"; break;
+ case 62: s = "\"invariant\" expected"; break;
+ case 63: s = "\"match\" expected"; break;
+ case 64: s = "\"assert\" expected"; break;
+ case 65: s = "\"assume\" expected"; break;
+ case 66: s = "\"print\" expected"; break;
+ case 67: s = "\"parallel\" expected"; break;
+ case 68: s = "\"<==>\" expected"; break;
+ case 69: s = "\"\\u21d4\" expected"; break;
+ case 70: s = "\"==>\" expected"; break;
+ case 71: s = "\"\\u21d2\" expected"; break;
+ case 72: s = "\"&&\" expected"; break;
+ case 73: s = "\"\\u2227\" expected"; break;
+ case 74: s = "\"||\" expected"; break;
+ case 75: s = "\"\\u2228\" expected"; break;
+ case 76: s = "\"==\" expected"; break;
+ case 77: s = "\"<=\" expected"; break;
+ case 78: s = "\">=\" expected"; break;
+ case 79: s = "\"!=\" expected"; break;
+ case 80: s = "\"!!\" expected"; break;
+ case 81: s = "\"in\" expected"; break;
+ case 82: s = "\"!\" expected"; break;
+ case 83: s = "\"\\u2260\" expected"; break;
+ case 84: s = "\"\\u2264\" expected"; break;
+ case 85: s = "\"\\u2265\" expected"; break;
+ case 86: s = "\"+\" expected"; break;
+ case 87: s = "\"-\" expected"; break;
+ case 88: s = "\"/\" expected"; break;
+ case 89: s = "\"%\" expected"; break;
+ case 90: s = "\"\\u00ac\" expected"; break;
+ case 91: s = "\"false\" expected"; break;
+ case 92: s = "\"true\" expected"; break;
+ case 93: s = "\"null\" expected"; break;
+ case 94: s = "\"this\" expected"; break;
+ case 95: s = "\"fresh\" expected"; break;
+ case 96: s = "\"allocated\" expected"; break;
+ case 97: s = "\"old\" expected"; break;
+ case 98: s = "\"then\" expected"; break;
+ case 99: s = "\"..\" expected"; break;
+ case 100: s = "\"forall\" expected"; break;
+ case 101: s = "\"\\u2200\" expected"; break;
+ case 102: s = "\"exists\" expected"; break;
+ case 103: s = "\"\\u2203\" expected"; break;
+ case 104: s = "\"::\" expected"; break;
+ case 105: s = "\"\\u2022\" expected"; break;
+ case 106: s = "??? expected"; break;
+ case 107: s = "invalid Dafny"; break;
+ case 108: s = "this symbol not expected in ClassDecl"; break;
+ case 109: s = "this symbol not expected in DatatypeDecl"; break;
+ case 110: s = "this symbol not expected in DatatypeDecl"; break;
+ case 111: s = "this symbol not expected in ArbitraryTypeDecl"; break;
+ case 112: s = "invalid ClassMemberDecl"; break;
+ case 113: s = "this symbol not expected in FieldDecl"; break;
+ case 114: s = "this symbol not expected in FieldDecl"; break;
+ case 115: s = "invalid FunctionDecl"; break;
+ case 116: s = "invalid FunctionDecl"; break;
+ case 117: s = "invalid FunctionDecl"; break;
+ case 118: s = "this symbol not expected in MethodDecl"; break;
+ case 119: s = "invalid MethodDecl"; break;
+ case 120: s = "invalid MethodDecl"; break;
+ case 121: s = "invalid TypeAndToken"; break;
+ case 122: s = "this symbol not expected in MethodSpec"; break;
+ case 123: s = "this symbol not expected in MethodSpec"; break;
+ case 124: s = "this symbol not expected in MethodSpec"; break;
+ case 125: s = "this symbol not expected in MethodSpec"; break;
+ case 126: s = "invalid MethodSpec"; break;
+ case 127: s = "this symbol not expected in MethodSpec"; break;
+ case 128: s = "invalid MethodSpec"; break;
+ case 129: s = "invalid ReferenceType"; 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 = "this symbol not expected in FunctionSpec"; break;
+ case 134: s = "this symbol not expected in FunctionSpec"; break;
+ case 135: s = "invalid FunctionSpec"; break;
+ case 136: s = "invalid PossiblyWildFrameExpression"; break;
+ case 137: s = "invalid PossiblyWildExpression"; break;
+ case 138: s = "this symbol not expected in OneStmt"; break;
+ case 139: s = "invalid OneStmt"; break;
+ case 140: s = "this symbol not expected in OneStmt"; break;
+ case 141: s = "invalid OneStmt"; break;
+ case 142: s = "invalid AssertStmt"; break;
+ case 143: s = "invalid UpdateStmt"; break;
+ case 144: s = "invalid UpdateStmt"; break;
+ case 145: s = "invalid IfStmt"; break;
+ case 146: s = "invalid IfStmt"; break;
+ case 147: s = "invalid WhileStmt"; break;
+ case 148: s = "invalid WhileStmt"; break;
+ case 149: s = "invalid Rhs"; break;
+ case 150: s = "invalid Lhs"; break;
+ case 151: s = "invalid Guard"; 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 LoopSpec"; break;
+ case 155: s = "this symbol not expected in LoopSpec"; break;
+ case 156: s = "this symbol not expected in LoopSpec"; break;
+ case 157: s = "this symbol not expected in Invariant"; break;
+ case 158: s = "invalid AttributeArg"; break;
+ case 159: s = "invalid EquivOp"; break;
+ case 160: s = "invalid ImpliesOp"; break;
+ case 161: s = "invalid AndOp"; break;
+ case 162: s = "invalid OrOp"; break;
+ case 163: s = "invalid RelOp"; break;
+ case 164: s = "invalid AddOp"; break;
+ case 165: s = "invalid UnaryExpression"; break;
+ case 166: s = "invalid MulOp"; break;
+ case 167: s = "invalid NegOp"; break;
+ case 168: s = "invalid EndlessExpression"; break;
+ case 169: s = "invalid Suffix"; break;
+ case 170: s = "invalid Suffix"; break;
+ case 171: s = "invalid Suffix"; break;
+ case 172: s = "invalid DisplayExpr"; break;
+ case 173: s = "invalid MultiSetExpr"; break;
+ case 174: s = "invalid ConstAtomExpression"; break;
+ case 175: s = "invalid QuantifierGuts"; break;
+ case 176: s = "invalid Forall"; break;
+ case 177: s = "invalid Exists"; break;
+ case 178: s = "invalid QSep"; break;
default: s = "error " + n; break;
}
- return s;
+ return s;
}
public void SemErr(IToken/*!*/ tok, string/*!*/ msg) { // semantic errors
@@ -2625,8 +2750,9 @@ public class Errors {
Contract.Requires(msg != null);
SemErr(tok.filename, tok.line, tok.col, msg);
}
+
public virtual void SemErr(string filename, int line, int col, string/*!*/ msg) {
- Contract.Requires(msg != null);
+ Contract.Requires(msg != null);
errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
count++;
}
@@ -2642,4 +2768,5 @@ public class FatalError: Exception {
public FatalError(string m): base(m) {}
}
+
} \ No newline at end of file
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index 9bd29da0..015bd490 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -226,16 +226,20 @@ namespace Microsoft.Dafny {
if (f.IsStatic) { k = "static " + k; }
if (!f.IsGhost) { k += " method"; }
PrintClassMethodHelper(k, f.Attributes, f.Name, f.TypeArgs);
- if (f.OpenParen != null) {
- PrintFormals(f.Formals);
+ if (f.SignatureIsOmitted) {
+ wr.WriteLine(" ...");
} else {
- Contract.Assert(isPredicate);
- }
- if (!isPredicate) {
- wr.Write(": ");
- PrintType(f.ResultType);
+ if (f.OpenParen != null) {
+ PrintFormals(f.Formals);
+ } else {
+ Contract.Assert(isPredicate);
+ }
+ if (!isPredicate) {
+ wr.Write(": ");
+ PrintType(f.ResultType);
+ }
+ wr.WriteLine();
}
- wr.WriteLine();
int ind = indent + IndentAmount;
PrintSpec("requires", f.Req, ind);
@@ -272,18 +276,22 @@ namespace Microsoft.Dafny {
if (method.IsStatic) { k = "static " + k; }
if (method.IsGhost) { k = "ghost " + k; }
PrintClassMethodHelper(k, method.Attributes, method.Name, method.TypeArgs);
- PrintFormals(method.Ins);
- if (method.Outs.Count != 0) {
- if (method.Ins.Count + method.Outs.Count <= 3) {
- wr.Write(" returns ");
- } else {
- wr.WriteLine();
- Indent(3 * IndentAmount);
- wr.Write("returns ");
+ if (method.SignatureIsOmitted) {
+ wr.WriteLine(" ...");
+ } else {
+ PrintFormals(method.Ins);
+ if (method.Outs.Count != 0) {
+ if (method.Ins.Count + method.Outs.Count <= 3) {
+ wr.Write(" returns ");
+ } else {
+ wr.WriteLine();
+ Indent(3 * IndentAmount);
+ wr.Write("returns ");
+ }
+ PrintFormals(method.Outs);
}
- PrintFormals(method.Outs);
+ wr.WriteLine();
}
- wr.WriteLine();
int ind = indent + IndentAmount;
PrintSpec("requires", method.Req, ind);
@@ -339,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())
@@ -352,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);
@@ -520,22 +528,7 @@ namespace Microsoft.Dafny {
} else if (stmt is IfStmt) {
IfStmt s = (IfStmt)stmt;
- while (true) {
- wr.Write("if (");
- PrintGuard(s.Guard);
- wr.Write(") ");
- PrintStatement(s.Thn, indent);
- if (s.Els == null) {
- break;
- }
- wr.Write(" else ");
- if (s.Els is IfStmt) {
- s = (IfStmt)s.Els;
- } else {
- PrintStatement(s.Els, indent);
- break;
- }
- }
+ PrintIfStatement(indent, s, false);
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
@@ -546,18 +539,7 @@ namespace Microsoft.Dafny {
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
- wr.Write("while (");
- PrintGuard(s.Guard);
- wr.WriteLine(")");
-
- PrintSpec("invariant", s.Invariants, indent + IndentAmount);
- PrintDecreasesSpec(s.Decreases, indent + IndentAmount);
- if (s.Mod.Expressions != null)
- {
- PrintFrameSpecLine("modifies", s.Mod.Expressions, indent + IndentAmount, s.Mod.HasAttributes() ? s.Mod.Attributes : null);
- }
- Indent(indent);
- PrintStatement(s.Body, indent);
+ PrintWhileStatement(indent, s, false, false);
} else if (stmt is AlternativeLoopStmt) {
var s = (AlternativeLoopStmt)stmt;
@@ -613,23 +595,15 @@ namespace Microsoft.Dafny {
Indent(indent);
wr.Write("}");
- } else if (stmt is UpdateStmt) {
- var s = (UpdateStmt)stmt;
+ } else if (stmt is ConcreteUpdateStatement) {
+ var s = (ConcreteUpdateStatement)stmt;
string sep = "";
foreach (var lhs in s.Lhss) {
wr.Write(sep);
PrintExpression(lhs);
sep = ", ";
}
- if (s.Lhss.Count != 0) {
- sep = " := ";
- }
- foreach (var rhs in s.Rhss) {
- wr.Write(sep);
- PrintRhs(rhs);
- sep = ", ";
- }
-
+ PrintUpdateRHS(s);
wr.Write(";");
} else if (stmt is VarDeclStmt) {
@@ -645,21 +619,100 @@ namespace Microsoft.Dafny {
sep = ", ";
}
if (s.Update != null) {
- wr.Write(" := ");
- sep = "";
- foreach (var rhs in s.Update.Rhss) {
- wr.Write(sep);
- PrintRhs(rhs);
- sep = ", ";
- }
+ PrintUpdateRHS(s.Update);
}
wr.Write(";");
+ } else if (stmt is SkeletonStatement) {
+ var s = (SkeletonStatement)stmt;
+ if (s.S == null) {
+ wr.Write("...;");
+ } else if (s.S is AssertStmt) {
+ Contract.Assert(s.ConditionOmitted);
+ wr.Write("assert ...;");
+ } else if (s.S is IfStmt) {
+ PrintIfStatement(indent, (IfStmt)s.S, s.ConditionOmitted);
+ } else if (s.S is WhileStmt) {
+ PrintWhileStatement(indent, (WhileStmt)s.S, s.ConditionOmitted, s.BodyOmitted);
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected skeleton statement
+ }
+
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
}
}
+ /// <summary>
+ /// Does not print LHS
+ /// </summary>
+ void PrintUpdateRHS(ConcreteUpdateStatement s) {
+ Contract.Requires(s != null);
+ if (s is UpdateStmt) {
+ var update = (UpdateStmt)s;
+ if (update.Lhss.Count != 0) {
+ wr.Write(" := ");
+ }
+ var sep = "";
+ foreach (var rhs in update.Rhss) {
+ wr.Write(sep);
+ PrintRhs(rhs);
+ sep = ", ";
+ }
+ } else if (s is AssignSuchThatStmt) {
+ var update = (AssignSuchThatStmt)s;
+ wr.Write(" :| ");
+ PrintExpression(update.Assume.Expr);
+ } else {
+ Contract.Assert(s == null); // otherwise, unknown type
+ }
+ }
+
+ void PrintIfStatement(int indent, IfStmt s, bool omitGuard) {
+ while (true) {
+ if (omitGuard) {
+ wr.Write("if ... ");
+ } else {
+ wr.Write("if (");
+ PrintGuard(s.Guard);
+ wr.Write(") ");
+ }
+ PrintStatement(s.Thn, indent);
+ if (s.Els == null) {
+ break;
+ }
+ wr.Write(" else ");
+ if (s.Els is IfStmt) {
+ s = (IfStmt)s.Els;
+ } else {
+ PrintStatement(s.Els, indent);
+ break;
+ }
+ }
+ }
+
+ void PrintWhileStatement(int indent, WhileStmt s, bool omitGuard, bool omitBody) {
+ if (omitGuard) {
+ wr.WriteLine("while ...");
+ } else {
+ wr.Write("while (");
+ PrintGuard(s.Guard);
+ wr.WriteLine(")");
+ }
+
+ PrintSpec("invariant", s.Invariants, indent + IndentAmount);
+ PrintDecreasesSpec(s.Decreases, indent + IndentAmount);
+ if (s.Mod.Expressions != null) {
+ PrintFrameSpecLine("modifies", s.Mod.Expressions, indent + IndentAmount, s.Mod.HasAttributes() ? s.Mod.Attributes : null);
+ }
+ Indent(indent);
+ if (omitBody) {
+ wr.WriteLine("...;");
+ } else {
+ PrintStatement(s.Body, indent);
+ }
+ }
+
void PrintAlternatives(int indent, List<GuardedAlternative> alternatives) {
int caseInd = indent + IndentAmount;
foreach (var alternative in alternatives) {
diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs
index ffa54826..a10cb4bf 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;
@@ -473,13 +473,17 @@ namespace Microsoft.Dafny {
r = new MatchStmt(Tok(s.Tok), CloneExpr(s.Source),
s.Cases.ConvertAll(c => new MatchCaseStmt(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), c.Body.ConvertAll(CloneStmt))));
+ } else if (stmt is AssignSuchThatStmt) {
+ var s = (AssignSuchThatStmt)stmt;
+ r = new AssignSuchThatStmt(Tok(s.Tok), s.Lhss.ConvertAll(CloneExpr), CloneExpr(s.Assume.Expr));
+
} else if (stmt is UpdateStmt) {
var s = (UpdateStmt)stmt;
r = new UpdateStmt(Tok(s.Tok), s.Lhss.ConvertAll(CloneExpr), s.Rhss.ConvertAll(CloneRHS), s.CanMutateKnownState);
} else if (stmt is VarDeclStmt) {
var s = (VarDeclStmt)stmt;
- r = new VarDeclStmt(Tok(s.Tok), s.Lhss.ConvertAll(c => (VarDecl)CloneStmt(c)), (UpdateStmt)CloneStmt(s.Update));
+ r = new VarDeclStmt(Tok(s.Tok), s.Lhss.ConvertAll(c => (VarDecl)CloneStmt(c)), (ConcreteUpdateStatement)CloneStmt(s.Update));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
@@ -494,7 +498,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);
+ }
}
}
@@ -535,10 +543,10 @@ namespace Microsoft.Dafny {
if (f is Predicate) {
return new Predicate(tok, f.Name, f.IsStatic, isGhost, f.IsUnlimited, tps, f.OpenParen, formals,
- req, reads, ens, decreases, body, moreBody != null, null);
+ req, reads, ens, decreases, body, moreBody != null, null, false);
} else {
return new Function(tok, f.Name, f.IsStatic, isGhost, f.IsUnlimited, tps, f.OpenParen, formals, CloneType(f.ResultType),
- req, reads, ens, decreases, body, null);
+ req, reads, ens, decreases, body, null, false);
}
}
@@ -562,10 +570,10 @@ namespace Microsoft.Dafny {
var body = replacementBody ?? CloneBlockStmt(m.Body);
if (m is Constructor) {
return new Constructor(Tok(m.tok), m.Name, tps, ins,
- req, mod, ens, decreases, body, null);
+ req, mod, ens, decreases, body, null, false);
} else {
return new Method(Tok(m.tok), m.Name, m.IsStatic, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, null);
+ req, mod, ens, decreases, body, null, false);
}
}
@@ -620,10 +628,15 @@ namespace Microsoft.Dafny {
} else if (prevFunction.IsGhost && !f.IsGhost && prevFunction.Body != null) {
reporter.Error(f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name);
}
- CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function");
- CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter");
- if (!TypesAreEqual(prevFunction.ResultType, f.ResultType)) {
- reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
+ if (f.SignatureIsOmitted) {
+ Contract.Assert(f.TypeArgs.Count == 0);
+ Contract.Assert(f.Formals.Count == 0);
+ } else {
+ CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function");
+ CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter");
+ if (!TypesAreEqual(prevFunction.ResultType, f.ResultType)) {
+ reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
+ }
}
Expression moreBody = null;
@@ -662,17 +675,22 @@ namespace Microsoft.Dafny {
} else if (!prevMethod.IsGhost && m.IsGhost) {
reporter.Error(m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name);
}
- CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, "method");
- CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter");
- CheckAgreement_Parameters(m.tok, prevMethod.Outs, m.Outs, m.Name, "method", "out-parameter");
+ if (m.SignatureIsOmitted) {
+ Contract.Assert(m.TypeArgs.Count == 0);
+ Contract.Assert(m.Ins.Count == 0);
+ Contract.Assert(m.Outs.Count == 0);
+ } else {
+ CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, "method");
+ CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter");
+ CheckAgreement_Parameters(m.tok, prevMethod.Outs, m.Outs, m.Name, "method", "out-parameter");
+ }
var replacementBody = m.Body;
if (replacementBody != null) {
if (prevMethod.Body == null) {
// cool
} else {
- reporter.Error(m, "body of refining method is not yet supported"); // TODO (merge the new body into the old)
- replacementBody = null;
+ replacementBody = MergeBlockStmt(replacementBody, prevMethod.Body);
}
}
nw.Members[index] = CloneMethod(prevMethod, m.Ens, replacementBody);
@@ -735,6 +753,356 @@ namespace Microsoft.Dafny {
return t.ToString() == u.ToString();
}
+ BlockStmt MergeBlockStmt(BlockStmt skeleton, BlockStmt oldStmt) {
+ Contract.Requires(skeleton != null);
+ Contract.Requires(oldStmt != null);
+
+ var body = new List<Statement>();
+ int i = 0, j = 0;
+ while (i < skeleton.Body.Count) {
+ var cur = skeleton.Body[i];
+ if (j == oldStmt.Body.Count) {
+ if (!(cur is SkeletonStatement)) {
+ MergeAddStatement(cur, body);
+ } else if (((SkeletonStatement)cur).S == null) {
+ // the "..." matches the empty statement sequence
+ } else {
+ reporter.Error(cur.Tok, "skeleton statement does not match old statement");
+ }
+ i++;
+ } else {
+ var oldS = oldStmt.Body[j];
+ /* See how the two statements match up.
+ * cur oldS result
+ * ------ ------ ------
+ * assert ...; assume E; assert E;
+ * assert ...; assert E; assert E;
+ * assert E; assert E;
+ *
+ * var x := E; var x; var x := E;
+ * var x := E; var x := *; var x := E;
+ * var x := E1; var x :| E0; var x := E1; assert E0;
+ * var VarProduction; var VarProduction;
+ *
+ * x := E; x := *; x := E;
+ *
+ * if ... Then else Else if (G) Then' else Else' if (G) Merge(Then,Then') else Merge(Else,Else')
+ * if (G) Then else Else if (*) Then' else Else' if (G) Merge(Then,Then') else Merge(Else,Else')
+ *
+ * while ... LoopSpec ... while (G) LoopSpec' Body while (G) Merge(LoopSpec,LoopSpec') Body
+ * while ... LoopSpec Body while (G) LoopSpec' Body' while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')
+ * while (G) LoopSpec ... while (*) LoopSpec' Body while (G) Merge(LoopSpec,LoopSpec') Body
+ * while (G) LoopSpec Body while (*) LoopSpec' Body' while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')
+ *
+ * ...; S StmtThatDoesNotMatchS; S' StatementThatDoesNotMatchS; Merge( ...;S , S')
+ *
+ * Note, LoopSpec must contain only invariant declarations (as the parser ensures for the first three cases).
+ * Note, there is an implicit "...;" at the end of every block in a skeleton.
+ *
+ * TODO: should also handle labels and some form of new "replace" statement
+ */
+ if (cur is SkeletonStatement) {
+ 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 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(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;
+ bool doMerge = false;
+ Expression addedAssert = null;
+ if (cOld != null && cNew.Lhss.Count == 1 && cOld.Lhss.Count == 1 && cNew.Lhss[0].Name == cOld.Lhss[0].Name) {
+ var update = cNew.Update as UpdateStmt;
+ if (update != null && update.Rhss.Count == 1 && update.Rhss[0] is ExprRhs) {
+ // Note, we allow switching between ghost and non-ghost, since that seems unproblematic.
+ if (cOld.Update == null) {
+ doMerge = true;
+ } else if (cOld.Update is AssignSuchThatStmt) {
+ doMerge = true;
+ addedAssert = CloneExpr(((AssignSuchThatStmt)cOld.Update).Assume.Expr);
+ } else {
+ var updateOld = (UpdateStmt)cOld.Update; // if cast fails, there are more ConcreteUpdateStatement subclasses than expected
+ if (updateOld.Rhss.Count == 1 && updateOld.Rhss[0] is HavocRhs) {
+ doMerge = true;
+ }
+ }
+ }
+ }
+ if (doMerge) {
+ // Go ahead with the merge:
+ body.Add(cNew);
+ i++; j++;
+ if (addedAssert != null) {
+ body.Add(new AssertStmt(addedAssert.tok, addedAssert));
+ }
+ } else {
+ MergeAddStatement(cur, body);
+ i++;
+ }
+
+ } else if (cur is AssignStmt) {
+ var cNew = (AssignStmt)cur;
+ var cOld = oldS as AssignStmt;
+ if (cOld == null && oldS is UpdateStmt) {
+ var us = (UpdateStmt)oldS;
+ if (us.ResolvedStatements.Count == 1) {
+ cOld = us.ResolvedStatements[0] as AssignStmt;
+ }
+ }
+ bool doMerge = false;
+ if (cOld != null && cNew.Lhs.Resolved is IdentifierExpr && cOld.Lhs.Resolved is IdentifierExpr) {
+ if (((IdentifierExpr)cNew.Lhs.Resolved).Name == ((IdentifierExpr)cOld.Lhs.Resolved).Name) {
+ if (!(cNew.Rhs is TypeRhs) && cOld.Rhs is HavocRhs) {
+ doMerge = true;
+ }
+ }
+ }
+ if (doMerge) {
+ // Go ahead with the merge:
+ body.Add(cNew);
+ i++; j++;
+ } else {
+ MergeAddStatement(cur, body);
+ i++;
+ }
+
+ } 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++) {
+ 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 "...", 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);
+ 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 {
+ 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();
+ }
+ }
+
// ---------------------- additional methods -----------------------------------------------------------------------------
public static bool ContainsChange(Expression expr, ModuleDecl m) {
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index 116ca201..adf530aa 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
@@ -419,7 +423,7 @@ namespace Microsoft.Dafny {
foreach (MemberDecl member in cl.Members) {
member.EnclosingClass = cl;
if (member is Field) {
- ResolveType(member.tok, ((Field)member).Type);
+ ResolveType(member.tok, ((Field)member).Type, null, false);
} else if (member is Function) {
Function f = (Function)member;
@@ -490,7 +494,7 @@ namespace Microsoft.Dafny {
ctor.EnclosingDatatype = dt;
allTypeParameters.PushMarker();
- ResolveCtorSignature(ctor);
+ ResolveCtorSignature(ctor, dt.TypeArgs);
allTypeParameters.PopMarker();
foreach (Formal p in ctor.Formals) {
@@ -623,13 +627,17 @@ namespace Microsoft.Dafny {
void ResolveFunctionSignature(Function f) {
Contract.Requires(f != null);
scope.PushMarker();
+ if (f.SignatureIsOmitted) {
+ Error(f, "function signature can be omitted only in refining functions");
+ }
+ var defaultTypeArguments = f.TypeArgs.Count == 0 ? f.TypeArgs : null;
foreach (Formal p in f.Formals) {
if (!scope.Push(p.Name, p)) {
Error(p, "Duplicate parameter name: {0}", p.Name);
}
- ResolveType(p.tok, p.Type);
+ ResolveType(p.tok, p.Type, defaultTypeArguments, true);
}
- ResolveType(f.tok, f.ResultType);
+ ResolveType(f.tok, f.ResultType, defaultTypeArguments, true);
scope.PopMarker();
}
@@ -726,19 +734,23 @@ namespace Microsoft.Dafny {
void ResolveMethodSignature(Method m) {
Contract.Requires(m != null);
scope.PushMarker();
+ if (m.SignatureIsOmitted) {
+ Error(m, "method signature can be omitted only in refining methods");
+ }
+ var defaultTypeArguments = m.TypeArgs.Count == 0 ? m.TypeArgs : null;
// resolve in-parameters
foreach (Formal p in m.Ins) {
if (!scope.Push(p.Name, p)) {
Error(p, "Duplicate parameter name: {0}", p.Name);
}
- ResolveType(p.tok, p.Type);
+ ResolveType(p.tok, p.Type, defaultTypeArguments, true);
}
// resolve out-parameters
foreach (Formal p in m.Outs) {
if (!scope.Push(p.Name, p)) {
Error(p, "Duplicate parameter name: {0}", p.Name);
}
- ResolveType(p.tok, p.Type);
+ ResolveType(p.tok, p.Type, defaultTypeArguments, true);
}
scope.PopMarker();
}
@@ -806,28 +818,40 @@ namespace Microsoft.Dafny {
scope.PopMarker(); // for the in-parameters
}
- void ResolveCtorSignature(DatatypeCtor ctor) {
+ void ResolveCtorSignature(DatatypeCtor ctor, List<TypeParameter> dtTypeArguments) {
Contract.Requires(ctor != null);
+ Contract.Requires(dtTypeArguments != null);
foreach (Formal p in ctor.Formals) {
- ResolveType(p.tok, p.Type);
+ ResolveType(p.tok, p.Type, dtTypeArguments, false);
}
}
- public void ResolveType(IToken tok, Type type) {
+ /// <summary>
+ /// If ResolveType encounters a type "T" that takes type arguments but wasn't given any, then:
+ /// * If "defaultTypeArguments" is non-null and "defaultTypeArgument.Count" equals the number
+ /// of type arguments that "T" expects, then use these default type arguments as "T"'s arguments.
+ /// * If "allowAutoTypeArguments" is true, then infer "T"'s arguments.
+ /// * If "defaultTypeArguments" is non-null AND "allowAutoTypeArguments" is true, then enough
+ /// type parameters will be added to "defaultTypeArguments" to have at least as many type
+ /// parameters as "T" expects, and then a prefix of the "defaultTypeArguments" will be supplied
+ /// as arguments to "T".
+ /// </summary>
+ public void ResolveType(IToken tok, Type type, List<TypeParameter> defaultTypeArguments, bool allowAutoTypeArguments) {
+ Contract.Requires(tok != null);
Contract.Requires(type != null);
if (type is BasicType) {
// nothing to resolve
} else if (type is CollectionType) {
var t = (CollectionType)type;
var argType = t.Arg;
- ResolveType(tok, argType);
+ ResolveType(tok, argType, defaultTypeArguments, allowAutoTypeArguments);
if (argType.IsSubrangeType) {
Error(tok, "sorry, cannot instantiate collection type with a subrange type");
}
} else if (type is UserDefinedType) {
UserDefinedType t = (UserDefinedType)type;
foreach (Type tt in t.TypeArgs) {
- ResolveType(t.tok, tt);
+ ResolveType(t.tok, tt, defaultTypeArguments, allowAutoTypeArguments);
if (tt.IsSubrangeType) {
Error(t.tok, "sorry, cannot instantiate type parameter with a subrange type");
}
@@ -845,19 +869,47 @@ namespace Microsoft.Dafny {
Error(t.tok, "Undeclared top-level type or type parameter: {0} (did you forget a module import?)", t.Name);
} else if (d is AmbiguousTopLevelDecl) {
Error(t.tok, "The name {0} ambiguously refers to a type in one of the modules {1}", t.Name, ((AmbiguousTopLevelDecl)d).ModuleNames());
- } else if (d.TypeArgs.Count != t.TypeArgs.Count) {
- Error(t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to class/datatype: {2}", t.TypeArgs.Count, d.TypeArgs.Count, t.Name);
} else if (d is ArbitraryTypeDecl) {
- t.ResolvedParam = ((ArbitraryTypeDecl)d).TheType; // resolve as type parameter
+ t.ResolvedParam = ((ArbitraryTypeDecl)d).TheType; // resolve like a type parameter
} else {
+ // d is a class or datatype, and it may have type parameters
t.ResolvedClass = d;
+ if (d.TypeArgs.Count != t.TypeArgs.Count && t.TypeArgs.Count == 0) {
+ if (allowAutoTypeArguments && defaultTypeArguments == null) {
+ // add type arguments that will be inferred
+ for (int i = 0; i < d.TypeArgs.Count; i++) {
+ t.TypeArgs.Add(new InferredTypeProxy());
+ }
+ } else if (defaultTypeArguments != null) {
+ // add specific type arguments, drawn from defaultTypeArguments (which may have to be extended)
+ if (allowAutoTypeArguments) {
+ // add to defaultTypeArguments the necessary number of arguments
+ for (int i = defaultTypeArguments.Count; i < d.TypeArgs.Count; i++) {
+ defaultTypeArguments.Add(new TypeParameter(t.tok, "T$" + i));
+ }
+ }
+ if (allowAutoTypeArguments || d.TypeArgs.Count == defaultTypeArguments.Count) {
+ Contract.Assert(d.TypeArgs.Count <= defaultTypeArguments.Count);
+ // automatically supply a prefix of the arguments from defaultTypeArguments
+ for (int i = 0; i < d.TypeArgs.Count; i++) {
+ var typeArg = new UserDefinedType(t.tok, defaultTypeArguments[i].Name, new List<Type>());
+ typeArg.ResolvedParam = defaultTypeArguments[i]; // resolve "typeArg" here
+ t.TypeArgs.Add(typeArg);
+ }
+ }
+ }
+ }
+ // defaults and auto have been applied; check if we now have the right number of arguments
+ if (d.TypeArgs.Count != t.TypeArgs.Count) {
+ Error(t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to class/datatype: {2}", t.TypeArgs.Count, d.TypeArgs.Count, t.Name);
+ }
}
}
} else if (type is TypeProxy) {
TypeProxy t = (TypeProxy)type;
if (t.T != null) {
- ResolveType(tok, t.T);
+ ResolveType(tok, t.T, defaultTypeArguments, allowAutoTypeArguments);
}
} else {
@@ -1256,8 +1308,8 @@ namespace Microsoft.Dafny {
else {// this is a regular return statement.
s.hiddenUpdate = null;
}
- } else if (stmt is UpdateStmt) {
- ResolveUpdateStmt((UpdateStmt)stmt, specContextOnly, method);
+ } else if (stmt is ConcreteUpdateStatement) {
+ ResolveUpdateStmt((ConcreteUpdateStatement)stmt, specContextOnly, method);
} else if (stmt is VarDeclStmt) {
var s = (VarDeclStmt)stmt;
foreach (var vd in s.Lhss) {
@@ -1382,7 +1434,7 @@ namespace Microsoft.Dafny {
} else if (stmt is VarDecl) {
VarDecl s = (VarDecl)stmt;
if (s.OptionalType != null) {
- ResolveType(stmt.Tok, s.OptionalType);
+ ResolveType(stmt.Tok, s.OptionalType, null, true);
s.type = s.OptionalType;
}
// now that the declaration has been processed, add the name to the scope
@@ -1506,7 +1558,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate bound-variable name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
}
ResolveExpression(s.Range, true);
Contract.Assert(s.Range.Type != null); // follows from postcondition of ResolveExpression
@@ -1631,7 +1683,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate parameter name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
if (ctor != null && i < ctor.Formals.Count) {
Formal formal = ctor.Formals[i];
Type st = SubstType(formal.Type, subst);
@@ -1661,12 +1713,19 @@ namespace Microsoft.Dafny {
}
+ } else if (stmt is SkeletonStatement) {
+ var s = (SkeletonStatement)stmt;
+ Error(s.Tok, "skeleton statements are allowed only in refining methods");
+ // nevertheless, resolve the underlying statement; hey, why not
+ if (s.S != null) {
+ ResolveStatement(s.S, specContextOnly, method);
+ }
} else {
Contract.Assert(false); throw new cce.UnreachableException();
}
}
- private void ResolveUpdateStmt(UpdateStmt s, bool specContextOnly, Method method)
+ private void ResolveUpdateStmt(ConcreteUpdateStatement s, bool specContextOnly, Method method)
{
int prevErrorCount = ErrorCount;
// First, resolve all LHS's and expression-looking RHS's.
@@ -1678,39 +1737,44 @@ namespace Microsoft.Dafny {
if (arrayRangeLhs == null && !sse.SelectOne) {
arrayRangeLhs = sse;
}
- }
- else {
+ } else {
ResolveExpression(lhs, true);
}
}
IToken firstEffectfulRhs = null;
CallRhs callRhs = null;
+ var update = s as UpdateStmt;
// Resolve RHSs
- foreach (var rhs in s.Rhss) {
- bool isEffectful;
- if (rhs is TypeRhs) {
- var tr = (TypeRhs)rhs;
- ResolveTypeRhs(tr, s, specContextOnly, method);
- isEffectful = tr.InitCall != null;
- } else if (rhs is HavocRhs) {
- isEffectful = false;
- } else {
- var er = (ExprRhs)rhs;
- if (er.Expr is IdentifierSequence) {
- var cRhs = ResolveIdentifierSequence((IdentifierSequence)er.Expr, true, true);
- isEffectful = cRhs != null;
- callRhs = callRhs ?? cRhs;
- } else if (er.Expr is FunctionCallExpr) {
- var cRhs = ResolveFunctionCallExpr((FunctionCallExpr)er.Expr, true, true);
- isEffectful = cRhs != null;
- callRhs = callRhs ?? cRhs;
- } else {
- ResolveExpression(er.Expr, true);
+ if (update == null) {
+ var suchThat = (AssignSuchThatStmt)s; // this is the other possible subclass
+ s.ResolvedStatements.Add(suchThat.Assume);
+ } else {
+ foreach (var rhs in update.Rhss) {
+ bool isEffectful;
+ if (rhs is TypeRhs) {
+ var tr = (TypeRhs)rhs;
+ ResolveTypeRhs(tr, s, specContextOnly, method);
+ isEffectful = tr.InitCall != null;
+ } else if (rhs is HavocRhs) {
isEffectful = false;
+ } else {
+ var er = (ExprRhs)rhs;
+ if (er.Expr is IdentifierSequence) {
+ var cRhs = ResolveIdentifierSequence((IdentifierSequence)er.Expr, true, true);
+ isEffectful = cRhs != null;
+ callRhs = callRhs ?? cRhs;
+ } else if (er.Expr is FunctionCallExpr) {
+ var cRhs = ResolveFunctionCallExpr((FunctionCallExpr)er.Expr, true, true);
+ isEffectful = cRhs != null;
+ callRhs = callRhs ?? cRhs;
+ } else {
+ ResolveExpression(er.Expr, true);
+ isEffectful = false;
+ }
+ }
+ if (isEffectful && firstEffectfulRhs == null) {
+ firstEffectfulRhs = rhs.Tok;
}
- }
- if (isEffectful && firstEffectfulRhs == null) {
- firstEffectfulRhs = rhs.Tok;
}
}
// check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification)
@@ -1726,67 +1790,69 @@ namespace Microsoft.Dafny {
}
}
- // figure out what kind of UpdateStmt this is
- if (firstEffectfulRhs == null) {
- if (s.Lhss.Count == 0) {
- Contract.Assert(s.Rhss.Count == 1); // guaranteed by the parser
- Error(s, "expected method call, found expression");
- } else if (s.Lhss.Count != s.Rhss.Count) {
- Error(s, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, s.Rhss.Count);
- } else if (arrayRangeLhs != null && s.Lhss.Count != 1) {
- Error(arrayRangeLhs, "array-range may not be used as LHS of multi-assignment; use separate assignment statements for each array-range assignment");
- } else if (ErrorCount == prevErrorCount) {
- // add the statements here in a sequence, but don't use that sequence later for translation (instead, should translated properly as multi-assignment)
- for (int i = 0; i < s.Lhss.Count; i++) {
- var a = new AssignStmt(s.Tok, s.Lhss[i].Resolved, s.Rhss[i]);
- s.ResolvedStatements.Add(a);
- }
- }
-
- } else if (s.CanMutateKnownState) {
- if (1 < s.Rhss.Count) {
- Error(firstEffectfulRhs, "cannot have effectful parameter in multi-return statement.");
- } else { // it might be ok, if it is a TypeRhs
- Contract.Assert(s.Rhss.Count == 1);
- if (callRhs != null) {
- Error(callRhs.Tok, "cannot have method call in return statement.");
- } else {
- // we have a TypeRhs
- Contract.Assert(s.Rhss[0] is TypeRhs);
- var tr = (TypeRhs)s.Rhss[0];
- Contract.Assert(tr.InitCall != null); // there were effects, so this must have been a call.
- if (tr.CanAffectPreviouslyKnownExpressions) {
- Error(tr.Tok, "can only have initialization methods which modify at most 'this'.");
+ if (update != null) {
+ // figure out what kind of UpdateStmt this is
+ if (firstEffectfulRhs == null) {
+ if (s.Lhss.Count == 0) {
+ Contract.Assert(update.Rhss.Count == 1); // guaranteed by the parser
+ Error(s, "expected method call, found expression");
+ } else if (s.Lhss.Count != update.Rhss.Count) {
+ Error(s, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, update.Rhss.Count);
+ } else if (arrayRangeLhs != null && s.Lhss.Count != 1) {
+ Error(arrayRangeLhs, "array-range may not be used as LHS of multi-assignment; use separate assignment statements for each array-range assignment");
+ } else if (ErrorCount == prevErrorCount) {
+ // add the statements here in a sequence, but don't use that sequence later for translation (instead, should translated properly as multi-assignment)
+ for (int i = 0; i < s.Lhss.Count; i++) {
+ var a = new AssignStmt(s.Tok, s.Lhss[i].Resolved, update.Rhss[i]);
+ s.ResolvedStatements.Add(a);
}
- var a = new AssignStmt(s.Tok, s.Lhss[0].Resolved, tr);
- s.ResolvedStatements.Add(a);
}
- }
- } else {
- // if there was an effectful RHS, that must be the only RHS
- if (s.Rhss.Count != 1) {
- Error(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS");
- } else if (arrayRangeLhs != null) {
- Error(arrayRangeLhs, "Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable");
- } else if (callRhs == null) {
- // must be a single TypeRhs
- if (s.Lhss.Count != 1) {
- Contract.Assert(2 <= s.Lhss.Count); // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs)
- Error(s.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, s.Rhss.Count);
- } else if (ErrorCount == prevErrorCount) {
- var a = new AssignStmt(s.Tok, s.Lhss[0].Resolved, s.Rhss[0]);
- s.ResolvedStatements.Add(a);
+ } else if (update.CanMutateKnownState) {
+ if (1 < update.Rhss.Count) {
+ Error(firstEffectfulRhs, "cannot have effectful parameter in multi-return statement.");
+ } else { // it might be ok, if it is a TypeRhs
+ Contract.Assert(update.Rhss.Count == 1);
+ if (callRhs != null) {
+ Error(callRhs.Tok, "cannot have method call in return statement.");
+ } else {
+ // we have a TypeRhs
+ Contract.Assert(update.Rhss[0] is TypeRhs);
+ var tr = (TypeRhs)update.Rhss[0];
+ Contract.Assert(tr.InitCall != null); // there were effects, so this must have been a call.
+ if (tr.CanAffectPreviouslyKnownExpressions) {
+ Error(tr.Tok, "can only have initialization methods which modify at most 'this'.");
+ }
+ var a = new AssignStmt(s.Tok, s.Lhss[0].Resolved, tr);
+ s.ResolvedStatements.Add(a);
+ }
}
+
} else {
- // a call statement
- if (ErrorCount == prevErrorCount) {
- var resolvedLhss = new List<Expression>();
- foreach (var ll in s.Lhss) {
- resolvedLhss.Add(ll.Resolved);
+ // if there was an effectful RHS, that must be the only RHS
+ if (update.Rhss.Count != 1) {
+ Error(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS");
+ } else if (arrayRangeLhs != null) {
+ Error(arrayRangeLhs, "Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable");
+ } else if (callRhs == null) {
+ // must be a single TypeRhs
+ if (s.Lhss.Count != 1) {
+ Contract.Assert(2 <= s.Lhss.Count); // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs)
+ Error(s.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, update.Rhss.Count);
+ } else if (ErrorCount == prevErrorCount) {
+ var a = new AssignStmt(s.Tok, s.Lhss[0].Resolved, update.Rhss[0]);
+ s.ResolvedStatements.Add(a);
+ }
+ } else {
+ // a call statement
+ if (ErrorCount == prevErrorCount) {
+ var resolvedLhss = new List<Expression>();
+ foreach (var ll in s.Lhss) {
+ resolvedLhss.Add(ll.Resolved);
+ }
+ var a = new CallStmt(callRhs.Tok, resolvedLhss, callRhs.Receiver, callRhs.MethodName, callRhs.Args);
+ s.ResolvedStatements.Add(a);
}
- var a = new CallStmt(callRhs.Tok, resolvedLhss, callRhs.Receiver, callRhs.MethodName, callRhs.Args);
- s.ResolvedStatements.Add(a);
}
}
}
@@ -2031,6 +2097,11 @@ namespace Microsoft.Dafny {
// this case is checked already in the first pass through the parallel body, by doing so from an empty set of labeled statements and resetting the loop-stack
} else if (stmt is ReturnStmt) {
Error(stmt, "return statement is not allowed inside a parallel statement");
+ } else if (stmt is AssignSuchThatStmt) {
+ var s = (AssignSuchThatStmt)stmt;
+ foreach (var lhs in s.Lhss) {
+ CheckParallelBodyLhs(s.Tok, lhs.Resolved, kind);
+ }
} else if (stmt is ConcreteSyntaxStatement) {
var s = (ConcreteSyntaxStatement)stmt;
foreach (var ss in s.ResolvedStatements) {
@@ -2038,14 +2109,7 @@ namespace Microsoft.Dafny {
}
} else if (stmt is AssignStmt) {
var s = (AssignStmt)stmt;
- var idExpr = s.Lhs.Resolved as IdentifierExpr;
- if (idExpr != null) {
- if (scope.ContainsDecl(idExpr.Var)) {
- Error(stmt, "body of parallel statement is attempting to update a variable declared outside the parallel statement");
- }
- } else if (kind != ParallelStmt.ParBodyKind.Assign) {
- Error(stmt, "the body of the enclosing parallel statement is not allowed to update heap locations");
- }
+ CheckParallelBodyLhs(s.Tok, s.Lhs.Resolved, kind);
var rhs = s.Rhs; // ExprRhs and HavocRhs are fine, but TypeRhs is not
if (rhs is TypeRhs) {
if (kind == ParallelStmt.ParBodyKind.Assign) {
@@ -2148,6 +2212,17 @@ namespace Microsoft.Dafny {
}
}
+ void CheckParallelBodyLhs(IToken tok, Expression lhs, ParallelStmt.ParBodyKind kind) {
+ var idExpr = lhs as IdentifierExpr;
+ if (idExpr != null) {
+ if (scope.ContainsDecl(idExpr.Var)) {
+ Error(tok, "body of parallel statement is attempting to update a variable declared outside the parallel statement");
+ }
+ } else if (kind != ParallelStmt.ParBodyKind.Assign) {
+ Error(tok, "the body of the enclosing parallel statement is not allowed to update heap locations");
+ }
+ }
+
Type ResolveTypeRhs(TypeRhs rr, Statement stmt, bool specContextOnly, Method method) {
Contract.Requires(rr != null);
Contract.Requires(stmt != null);
@@ -2155,7 +2230,7 @@ namespace Microsoft.Dafny {
Contract.Ensures(Contract.Result<Type>() != null);
if (rr.Type == null) {
- ResolveType(stmt.Tok, rr.EType);
+ ResolveType(stmt.Tok, rr.EType, null, true);
if (rr.ArrayDimensions == null) {
if (!rr.EType.IsRefType) {
Error(stmt, "new can be applied only to reference types (got {0})", rr.EType);
@@ -2423,7 +2498,7 @@ namespace Microsoft.Dafny {
subst.Add(dt.TypeArgs[i], t);
}
expr.Type = new UserDefinedType(dtv.tok, dtv.DatatypeName, gt);
- ResolveType(expr.tok, expr.Type);
+ ResolveType(expr.tok, expr.Type, null, true);
DatatypeCtor ctor;
if (!datatypeCtors[dt].TryGetValue(dtv.MemberName, out ctor)) {
@@ -2771,7 +2846,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate let-variable name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
if (i < e.RHSs.Count && !UnifyTypes(v.Type, e.RHSs[i].Type)) {
Error(e.RHSs[i].tok, "type of RHS ({0}) does not match type of bound variable ({1})", e.RHSs[i].Type, v.Type);
}
@@ -2789,7 +2864,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate bound-variable name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
}
if (e.Range != null) {
ResolveExpression(e.Range, twoState);
@@ -2825,7 +2900,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate bound-variable name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
}
ResolveExpression(e.Range, twoState);
Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
@@ -2949,7 +3024,7 @@ namespace Microsoft.Dafny {
if (!scope.Push(v.Name, v)) {
Error(v, "Duplicate parameter name: {0}", v.Name);
}
- ResolveType(v.tok, v.Type);
+ ResolveType(v.tok, v.Type, null, true);
if (ctor != null && i < ctor.Formals.Count) {
Formal formal = ctor.Formals[i];
Type st = SubstType(formal.Type, subst);
diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs
new file mode 100644
index 00000000..26ec496e
--- /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 ConcreteUpdateStatement) {
+ var ss = (ConcreteUpdateStatement)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 7c3831a7..ca2ae13c 100644
--- a/Source/Dafny/Scanner.cs
+++ b/Source/Dafny/Scanner.cs
@@ -19,7 +19,7 @@ public class Buffer {
// a) whole stream in buffer
// b) part of stream in buffer
// 2) non seekable stream (network, console)
-
+
public const int EOF = 65535 + 1; // char.MaxValue + 1;
const int MIN_BUFFER_LENGTH = 1024; // 1KB
const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB
@@ -31,15 +31,17 @@ public class Buffer {
Stream/*!*/ stream; // input stream (seekable)
bool isUserStream; // was the stream opened by the user?
-[ContractInvariantMethod]
-void ObjectInvariant(){
- Contract.Invariant(buf != null);
- Contract.Invariant(stream != null);}
- [NotDelayed]
- public Buffer (Stream/*!*/ s, bool isUserStream) :base() {
+ [ContractInvariantMethod]
+ void ObjectInvariant(){
+ Contract.Invariant(buf != null);
+ Contract.Invariant(stream != null);
+ }
+
+// [NotDelayed]
+ public Buffer (Stream/*!*/ s, bool isUserStream) : base() {
Contract.Requires(s != null);
stream = s; this.isUserStream = isUserStream;
-
+
int fl, bl;
if (s.CanSeek) {
fl = (int) s.Length;
@@ -51,12 +53,12 @@ void ObjectInvariant(){
buf = new byte[(bl>0) ? bl : MIN_BUFFER_LENGTH];
fileLen = fl; bufLen = bl;
-
+
if (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)
else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
if (bufLen == fileLen && s.CanSeek) Close();
}
-
+
protected Buffer(Buffer/*!*/ b) { // called in UTF8Buffer constructor
Contract.Requires(b != null);
buf = b.buf;
@@ -73,14 +75,14 @@ void ObjectInvariant(){
}
~Buffer() { Close(); }
-
+
protected void Close() {
if (!isUserStream && stream != null) {
stream.Close();
//stream = null;
}
}
-
+
public virtual int Read () {
if (bufPos < bufLen) {
return buf[bufPos++];
@@ -100,7 +102,7 @@ void ObjectInvariant(){
Pos = curPos;
return ch;
}
-
+
public string/*!*/ GetString (int beg, int end) {
Contract.Ensures(Contract.Result<string>() != null);
int len = 0;
@@ -139,7 +141,7 @@ void ObjectInvariant(){
}
}
}
-
+
// Read the next chunk of bytes from the stream, increases the buffer
// if needed and updates the fields fileLen and bufLen.
// Returns the number of bytes read.
@@ -209,26 +211,28 @@ public class UTF8Buffer: Buffer {
public class Scanner {
const char EOL = '\n';
const int eofSym = 0; /* pdt */
- const int maxT = 104;
- const int noSym = 104;
-
-
-[ContractInvariantMethod]
-void objectInvariant(){
- Contract.Invariant(buffer!=null);
- Contract.Invariant(t != null);
- Contract.Invariant(start != null);
- Contract.Invariant(tokens != null);
- Contract.Invariant(pt != null);
- Contract.Invariant(tval != null);
- Contract.Invariant(Filename != null);
- Contract.Invariant(errorHandler != null);
-}
+ const int maxT = 106;
+ const int noSym = 106;
+
+
+ [ContractInvariantMethod]
+ void objectInvariant(){
+ Contract.Invariant(buffer!=null);
+ Contract.Invariant(t != null);
+ Contract.Invariant(start != null);
+ Contract.Invariant(tokens != null);
+ Contract.Invariant(pt != null);
+ Contract.Invariant(tval != null);
+ Contract.Invariant(Filename != null);
+ Contract.Invariant(errorHandler != null);
+ }
+
public Buffer/*!*/ buffer; // scanner buffer
-
+
Token/*!*/ t; // current token
int ch; // current input character
int pos; // byte position of current character
+ int charPos;
int col; // column number of current character
int line; // line number of current character
int oldEols; // EOLs that appeared in a comment;
@@ -236,13 +240,13 @@ void objectInvariant(){
Token/*!*/ tokens; // list of tokens already peeked (first token is a dummy)
Token/*!*/ pt; // current peek token
-
+
char[]/*!*/ tval = new char[128]; // text of current token
int tlen; // length of current token
-
+
private string/*!*/ Filename;
private Errors/*!*/ errorHandler;
-
+
static Scanner() {
start = new Hashtable(128);
for (int i = 39; i <= 39; ++i) start[i] = 1;
@@ -254,45 +258,45 @@ void objectInvariant(){
for (int i = 48; i <= 57; ++i) start[i] = 7;
for (int i = 34; i <= 34; ++i) start[i] = 8;
start[97] = 12;
- start[58] = 55;
+ start[58] = 56;
start[123] = 10;
start[125] = 11;
- start[61] = 56;
- start[124] = 57;
+ start[61] = 57;
+ start[124] = 58;
start[59] = 19;
start[44] = 20;
- start[60] = 58;
- start[62] = 59;
- start[40] = 21;
- start[41] = 22;
- start[42] = 23;
- start[96] = 24;
- start[91] = 26;
- start[93] = 27;
- start[46] = 60;
- start[8660] = 31;
- start[8658] = 33;
- start[38] = 34;
- start[8743] = 36;
- start[8744] = 38;
- start[33] = 61;
- start[8800] = 42;
- start[8804] = 43;
- start[8805] = 44;
- start[43] = 45;
- start[45] = 46;
- start[47] = 47;
- start[37] = 48;
- start[172] = 49;
- start[8704] = 51;
- start[8707] = 52;
- start[8226] = 54;
+ start[60] = 59;
+ start[62] = 60;
+ start[46] = 61;
+ start[40] = 22;
+ start[41] = 23;
+ start[42] = 24;
+ start[96] = 25;
+ start[91] = 28;
+ start[93] = 29;
+ start[8660] = 33;
+ start[8658] = 35;
+ start[38] = 36;
+ start[8743] = 38;
+ start[8744] = 40;
+ start[33] = 62;
+ start[8800] = 44;
+ start[8804] = 45;
+ start[8805] = 46;
+ start[43] = 47;
+ start[45] = 48;
+ start[47] = 49;
+ start[37] = 50;
+ start[172] = 51;
+ start[8704] = 52;
+ start[8707] = 53;
+ start[8226] = 55;
start[Buffer.EOF] = -1;
}
-
- [NotDelayed]
- public Scanner (string/*!*/ fileName, Errors/*!*/ errorHandler) :base(){
+
+// [NotDelayed]
+ public Scanner (string/*!*/ fileName, Errors/*!*/ errorHandler) : base() {
Contract.Requires(fileName != null);
Contract.Requires(errorHandler != null);
this.errorHandler = errorHandler;
@@ -302,15 +306,14 @@ void objectInvariant(){
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
buffer = new Buffer(stream, false);
Filename = fileName;
-
Init();
} catch (IOException) {
throw new FatalError("Cannot open file " + fileName);
}
}
-
- [NotDelayed]
- public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fileName) :base(){
+
+// [NotDelayed]
+ public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fileName) : base() {
Contract.Requires(s != null);
Contract.Requires(errorHandler != null);
Contract.Requires(fileName != null);
@@ -319,10 +322,9 @@ void objectInvariant(){
buffer = new Buffer(s, true);
this.errorHandler = errorHandler;
this.Filename = fileName;
-
Init();
}
-
+
void Init() {
pos = -1; line = 1; col = 0;
oldEols = 0;
@@ -343,11 +345,11 @@ void objectInvariant(){
Contract.Ensures(Contract.Result<string>() != null);
int p = buffer.Pos;
int ch = buffer.Read();
- // replace isolated '\r' by '\n' in order to make
+ // replace isolated '\r' by '\n' in order to make
// eol handling uniform across Windows, Unix and Mac
if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
while (ch != EOL && ch != Buffer.EOF){
- ch = buffer.Read();
+ ch = buffer.Read();
// replace isolated '\r' by '\n' in order to make
// eol handling uniform across Windows, Unix and Mac
if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
@@ -358,7 +360,7 @@ void objectInvariant(){
}
void NextCh() {
- if (oldEols > 0) { ch = EOL; oldEols--; }
+ if (oldEols > 0) { ch = EOL; oldEols--; }
else {
// pos = buffer.Pos;
// ch = buffer.Read(); col++;
@@ -366,9 +368,9 @@ void objectInvariant(){
// // eol handling uniform across Windows, Unix and Mac
// if (ch == '\r' && buffer.Peek() != '\n') ch = EOL;
// if (ch == EOL) { line++; col = 0; }
-
+
while (true) {
- pos = buffer.Pos;
+ pos = buffer.Pos;
ch = buffer.Read(); col++;
// replace isolated '\r' by '\n' in order to make
// eol handling uniform across Windows, Unix and Mac
@@ -418,7 +420,7 @@ void objectInvariant(){
return;
}
-
+
}
}
@@ -438,7 +440,7 @@ void objectInvariant(){
bool Comment0() {
- int level = 1, pos0 = pos, line0 = line, col0 = col;
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
NextCh();
if (ch == '/') {
NextCh();
@@ -451,13 +453,13 @@ void objectInvariant(){
else NextCh();
}
} else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0;
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
}
return false;
}
bool Comment1() {
- int level = 1, pos0 = pos, line0 = line, col0 = col;
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
NextCh();
if (ch == '*') {
NextCh();
@@ -478,7 +480,7 @@ void objectInvariant(){
else NextCh();
}
} else {
- buffer.Pos = pos0; NextCh(); line = line0; col = col0;
+ buffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;
}
return false;
}
@@ -486,11 +488,11 @@ void objectInvariant(){
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;
@@ -499,47 +501,47 @@ void objectInvariant(){
case "method": t.kind = 24; break;
case "constructor": t.kind = 25; break;
case "returns": t.kind = 26; break;
- case "modifies": t.kind = 27; break;
- case "free": t.kind = 28; break;
- case "requires": t.kind = 29; break;
- case "ensures": t.kind = 30; break;
- case "decreases": t.kind = 31; break;
- case "bool": t.kind = 34; break;
- case "nat": t.kind = 35; break;
- case "int": t.kind = 36; break;
- case "set": t.kind = 37; break;
- case "multiset": t.kind = 38; break;
- case "seq": t.kind = 39; break;
- case "object": t.kind = 40; break;
- case "function": t.kind = 41; break;
- case "predicate": t.kind = 42; break;
- case "reads": t.kind = 43; break;
- case "label": t.kind = 46; break;
- case "break": t.kind = 47; break;
- case "return": t.kind = 48; break;
- case "new": t.kind = 50; break;
- case "choose": t.kind = 54; break;
- case "if": t.kind = 55; break;
- case "else": t.kind = 56; break;
- case "case": t.kind = 57; break;
- case "while": t.kind = 59; break;
- case "invariant": t.kind = 60; break;
- case "match": t.kind = 61; break;
- case "assert": t.kind = 62; break;
- case "assume": t.kind = 63; break;
- case "print": t.kind = 64; break;
- case "parallel": t.kind = 65; break;
- case "in": t.kind = 79; break;
- case "false": t.kind = 89; break;
- case "true": t.kind = 90; break;
- case "null": t.kind = 91; break;
- case "this": t.kind = 92; break;
- case "fresh": t.kind = 93; break;
- case "allocated": t.kind = 94; break;
- case "old": t.kind = 95; break;
- case "then": t.kind = 96; break;
- case "forall": t.kind = 98; break;
- case "exists": t.kind = 100; break;
+ case "modifies": t.kind = 28; break;
+ case "free": t.kind = 29; break;
+ case "requires": t.kind = 30; break;
+ case "ensures": t.kind = 31; break;
+ case "decreases": t.kind = 32; break;
+ case "bool": t.kind = 35; break;
+ case "nat": t.kind = 36; break;
+ case "int": t.kind = 37; break;
+ case "set": t.kind = 38; break;
+ case "multiset": t.kind = 39; break;
+ case "seq": t.kind = 40; break;
+ case "object": t.kind = 41; break;
+ case "function": t.kind = 42; break;
+ case "predicate": t.kind = 43; break;
+ case "reads": t.kind = 44; break;
+ case "label": t.kind = 47; break;
+ case "break": t.kind = 48; break;
+ case "return": t.kind = 49; break;
+ case "new": t.kind = 52; break;
+ case "choose": t.kind = 56; break;
+ case "if": t.kind = 57; break;
+ case "else": t.kind = 58; break;
+ case "case": t.kind = 59; break;
+ case "while": t.kind = 61; break;
+ case "invariant": t.kind = 62; break;
+ case "match": t.kind = 63; break;
+ case "assert": t.kind = 64; break;
+ case "assume": t.kind = 65; break;
+ case "print": t.kind = 66; break;
+ case "parallel": t.kind = 67; break;
+ case "in": t.kind = 81; break;
+ case "false": t.kind = 91; break;
+ case "true": t.kind = 92; break;
+ case "null": t.kind = 93; break;
+ case "this": t.kind = 94; break;
+ case "fresh": t.kind = 95; break;
+ case "allocated": t.kind = 96; break;
+ case "old": t.kind = 97; break;
+ case "then": t.kind = 98; break;
+ case "forall": t.kind = 100; break;
+ case "exists": t.kind = 102; break;
default: break;
}
}
@@ -556,10 +558,13 @@ void objectInvariant(){
t.pos = pos; t.col = col; t.line = line;
t.filename = this.Filename;
int state;
- if (start.ContainsKey(ch)) { state = (int) cce.NonNull( start[ch]); }
+ if (start.ContainsKey(ch)) {
+ Contract.Assert(start[ch] != null);
+ state = (int) start[ch];
+ }
else { state = 0; }
tlen = 0; AddCh();
-
+
switch (state) {
case -1: { t.kind = eofSym; break; } // NextCh already done
case 0: {
@@ -646,53 +651,53 @@ void objectInvariant(){
case 20:
{t.kind = 20; break;}
case 21:
- {t.kind = 32; break;}
+ {t.kind = 27; break;}
case 22:
{t.kind = 33; break;}
case 23:
- {t.kind = 44; break;}
+ {t.kind = 34; break;}
case 24:
{t.kind = 45; break;}
case 25:
- {t.kind = 49; break;}
+ {t.kind = 46; break;}
case 26:
- {t.kind = 51; break;}
+ {t.kind = 50; break;}
case 27:
- {t.kind = 52; break;}
+ {t.kind = 51; break;}
case 28:
- {t.kind = 58; break;}
+ {t.kind = 53; break;}
case 29:
- if (ch == '>') {AddCh(); goto case 30;}
- else {goto case 0;}
+ {t.kind = 54; break;}
case 30:
- {t.kind = 66; break;}
+ {t.kind = 60; break;}
case 31:
- {t.kind = 67; break;}
+ if (ch == '>') {AddCh(); goto case 32;}
+ else {goto case 0;}
case 32:
{t.kind = 68; break;}
case 33:
{t.kind = 69; break;}
case 34:
- if (ch == '&') {AddCh(); goto case 35;}
- else {goto case 0;}
- case 35:
{t.kind = 70; break;}
- case 36:
+ case 35:
{t.kind = 71; break;}
+ case 36:
+ if (ch == '&') {AddCh(); goto case 37;}
+ else {goto case 0;}
case 37:
{t.kind = 72; break;}
case 38:
{t.kind = 73; break;}
case 39:
- {t.kind = 76; break;}
+ {t.kind = 74; break;}
case 40:
- {t.kind = 77; break;}
+ {t.kind = 75; break;}
case 41:
{t.kind = 78; break;}
case 42:
- {t.kind = 81; break;}
+ {t.kind = 79; break;}
case 43:
- {t.kind = 82; break;}
+ {t.kind = 80; break;}
case 44:
{t.kind = 83; break;}
case 45:
@@ -706,67 +711,74 @@ void objectInvariant(){
case 49:
{t.kind = 88; break;}
case 50:
- {t.kind = 97; break;}
+ {t.kind = 89; break;}
case 51:
- {t.kind = 99; break;}
+ {t.kind = 90; break;}
case 52:
{t.kind = 101; break;}
case 53:
- {t.kind = 102; break;}
- case 54:
{t.kind = 103; break;}
+ case 54:
+ {t.kind = 104; break;}
case 55:
+ {t.kind = 105; break;}
+ case 56:
recEnd = pos; recKind = 5;
- if (ch == '=') {AddCh(); goto case 25;}
- else if (ch == ':') {AddCh(); goto case 53;}
+ if (ch == '=') {AddCh(); goto case 26;}
+ else if (ch == '|') {AddCh(); goto case 27;}
+ else if (ch == ':') {AddCh(); goto case 54;}
else {t.kind = 5; break;}
- case 56:
+ case 57:
recEnd = pos; recKind = 16;
- if (ch == '>') {AddCh(); goto case 28;}
- else if (ch == '=') {AddCh(); goto case 62;}
+ if (ch == '>') {AddCh(); goto case 30;}
+ else if (ch == '=') {AddCh(); goto case 63;}
else {t.kind = 16; break;}
- case 57:
+ case 58:
recEnd = pos; recKind = 17;
- if (ch == '|') {AddCh(); goto case 37;}
+ if (ch == '|') {AddCh(); goto case 39;}
else {t.kind = 17; break;}
- case 58:
+ case 59:
recEnd = pos; recKind = 22;
- if (ch == '=') {AddCh(); goto case 63;}
+ if (ch == '=') {AddCh(); goto case 64;}
else {t.kind = 22; break;}
- case 59:
+ case 60:
recEnd = pos; recKind = 23;
- if (ch == '=') {AddCh(); goto case 39;}
+ if (ch == '=') {AddCh(); goto case 41;}
else {t.kind = 23; break;}
- case 60:
- recEnd = pos; recKind = 53;
- if (ch == '.') {AddCh(); goto case 50;}
- else {t.kind = 53; break;}
case 61:
- recEnd = pos; recKind = 80;
- if (ch == '=') {AddCh(); goto case 40;}
- else if (ch == '!') {AddCh(); goto case 41;}
- else {t.kind = 80; break;}
+ recEnd = pos; recKind = 55;
+ if (ch == '.') {AddCh(); goto case 65;}
+ else {t.kind = 55; break;}
case 62:
- recEnd = pos; recKind = 74;
- if (ch == '>') {AddCh(); goto case 32;}
- else {t.kind = 74; break;}
+ recEnd = pos; recKind = 82;
+ if (ch == '=') {AddCh(); goto case 42;}
+ else if (ch == '!') {AddCh(); goto case 43;}
+ else {t.kind = 82; break;}
case 63:
- recEnd = pos; recKind = 75;
- if (ch == '=') {AddCh(); goto case 29;}
- else {t.kind = 75; break;}
+ recEnd = pos; recKind = 76;
+ if (ch == '>') {AddCh(); goto case 34;}
+ else {t.kind = 76; break;}
+ case 64:
+ recEnd = pos; recKind = 77;
+ if (ch == '=') {AddCh(); goto case 31;}
+ else {t.kind = 77; break;}
+ case 65:
+ recEnd = pos; recKind = 99;
+ if (ch == '.') {AddCh(); goto case 21;}
+ else {t.kind = 99; break;}
}
t.val = new String(tval, 0, tlen);
return t;
}
-
+
private void SetScannerBehindT() {
buffer.Pos = t.pos;
NextCh();
line = t.line; col = t.col;
for (int i = 0; i < tlen; i++) NextCh();
}
-
+
// get the next token (possibly a token already seen during peeking)
public Token/*!*/ Scan () {
Contract.Ensures(Contract.Result<Token>() != null);
@@ -787,7 +799,7 @@ void objectInvariant(){
}
pt = pt.next;
} while (pt.kind > maxT); // skip pragmas
-
+
return pt;
}
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index 8135a61a..29632ea4 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;
@@ -3276,14 +3287,20 @@ namespace Microsoft.Dafny {
AddComment(builder, stmt, "assert statement");
PredicateStmt s = (PredicateStmt)stmt;
TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);
+ IToken enclosingToken = null;
+ if (Attributes.Contains(stmt.Attributes, "prependAssertToken")) {
+ enclosingToken = stmt.Tok;
+ }
bool splitHappened;
var ss = TrSplitExpr(s.Expr, etran, out splitHappened);
if (!splitHappened) {
- builder.Add(Assert(s.Expr.tok, etran.TrExpr(s.Expr), "assertion violation"));
+ var tok = enclosingToken == null ? s.Expr.tok : new NestedToken(enclosingToken, s.Expr.tok);
+ builder.Add(Assert(tok, etran.TrExpr(s.Expr), "assertion violation"));
} else {
foreach (var split in ss) {
if (!split.IsFree) {
- builder.Add(AssertNS(split.E.tok, split.E, "assertion violation"));
+ var tok = enclosingToken == null ? split.E.tok : new NestedToken(enclosingToken, split.E.tok);
+ builder.Add(AssertNS(tok, split.E, "assertion violation"));
}
}
builder.Add(new Bpl.AssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));
@@ -3314,6 +3331,25 @@ namespace Microsoft.Dafny {
TrStmt(s.hiddenUpdate, builder, locals, etran);
}
builder.Add(new Bpl.ReturnCmd(stmt.Tok));
+ } else if (stmt is AssignSuchThatStmt) {
+ var s = (AssignSuchThatStmt)stmt;
+ AddComment(builder, s, "assign-such-that statement");
+ // treat like a parallel havoc, followed by an assume
+ // Here comes the havoc part
+ var lhss = new List<Expression>();
+ var havocRhss = new List<AssignmentRhs>();
+ foreach (var lhs in s.Lhss) {
+ lhss.Add(lhs.Resolved);
+ havocRhss.Add(new HavocRhs(lhs.tok)); // note, a HavocRhs is constructed as already resolved
+ }
+ List<AssignToLhs> lhsBuilder;
+ List<Bpl.IdentifierExpr> bLhss;
+ ProcessLhss(lhss, false, builder, locals, etran, out lhsBuilder, out bLhss);
+ ProcessRhss(lhsBuilder, bLhss, lhss, havocRhss, builder, locals, etran);
+ // End by doing the assume
+ TrStmt(s.Assume, builder, locals, etran);
+ builder.Add(CaptureState(s.Tok)); // just do one capture state--here, at the very end (that is, don't do one before the assume)
+
} else if (stmt is UpdateStmt) {
var s = (UpdateStmt)stmt;
// This UpdateStmt can be single-target assignment, a multi-assignment, a call statement, or
@@ -7055,7 +7091,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..71d3e482
--- /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, 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_IMPLIES))
+ {
+ return Expr.Imp(MakeReadHasOccurred(node, call, READ_IMPLIES), VisitExpr(node.Args[0]));
+ }
+
+ if (MatchesIntrinsic(call.Func, WRITE_IMPLIES))
+ {
+ return Expr.Imp(MakeWriteHasOccurred(node, call, WRITE_IMPLIES), VisitExpr(node.Args[0]));
+ }
+
+ 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))
+ {
+ return MakeReadHasOccurred(node, call, READ);
+ }
+
+ if (MatchesIntrinsic(call.Func, WRITE))
+ {
+ return MakeWriteHasOccurred(node, call, WRITE);
+ }
+
+ }
+
+ 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/CommandLineOptions.cs b/Source/GPUVerify/CommandLineOptions.cs
index f2842d8f..59d2fd89 100644
--- a/Source/GPUVerify/CommandLineOptions.cs
+++ b/Source/GPUVerify/CommandLineOptions.cs
@@ -16,8 +16,9 @@ namespace GPUVerify
public static string outputFile = null;
public static bool OnlyDivergence = false;
- public static bool FullAbstraction;
- public static bool Inference;
+ public static bool FullAbstraction = false;
+ public static bool Inference = false;
+ public static bool ArrayEqualities = false;
public static string invariantsFile = null;
public static bool DividedArray = false;
public static string ArrayToCheck = null;
@@ -29,6 +30,16 @@ namespace GPUVerify
public static bool ShowStages = false;
+ public static bool AddDivergenceCandidatesOnlyIfModified = true;
+ public static bool AddDivergenceCandidatesOnlyToBarrierLoops = true;
+
+ public static bool ShowUniformityAnalysis = false;
+ public static bool DoUniformityAnalysis = true;
+
+ public static bool ShowMayBeTidAnalysis = false;
+ public static bool ShowMayBePowerOfTwoAnalysis = false;
+ public static bool ShowMayBeTidPlusConstantAnalysis = false;
+
public static int Parse(string[] args)
{
for (int i = 0; i < args.Length; i++)
@@ -129,6 +140,41 @@ namespace GPUVerify
break;
+ case "-arrayEqualities":
+ case "/arrayEqualities":
+ ArrayEqualities = true;
+ break;
+
+ case "-alwaysAddDivergenceCandidates":
+ AddDivergenceCandidatesOnlyIfModified = false;
+ AddDivergenceCandidatesOnlyToBarrierLoops = false;
+ break;
+
+ case "-showUniformityAnalysis":
+ case "/showUniformityAnalysis":
+ ShowUniformityAnalysis = true;
+ break;
+
+ case "-noUniformityAnalysis":
+ case "/noUniformityAnalysis":
+ DoUniformityAnalysis = false;
+ break;
+
+ case "-showMayBeTidAnalysis":
+ case "/showMayBeTidAnalysis":
+ ShowMayBeTidAnalysis = true;
+ break;
+
+ case "-showMayBePowerOfTwoAnalysis":
+ case "/showMayBePowerOfTwoAnalysis":
+ ShowMayBePowerOfTwoAnalysis = true;
+ break;
+
+ case "-showMayBeTidPlusConstantAnalysis":
+ case "/showMayBeTidPlusConstantAnalysis":
+ ShowMayBeTidPlusConstantAnalysis = true;
+ break;
+
default:
inputFiles.Add(args[i]);
break;
diff --git a/Source/GPUVerify/CrossThreadInvariantProcessor.cs b/Source/GPUVerify/CrossThreadInvariantProcessor.cs
new file mode 100644
index 00000000..4d215f24
--- /dev/null
+++ b/Source/GPUVerify/CrossThreadInvariantProcessor.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class CrossThreadInvariantProcessor : StandardVisitor
+ {
+ private GPUVerifier verifier;
+ private string procName;
+
+ public CrossThreadInvariantProcessor(GPUVerifier verifier, string procName)
+ {
+ this.verifier = verifier;
+ this.procName = procName;
+ }
+
+ 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, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).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, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr));
+ }
+
+ if (call.Func.Name.Equals("__all"))
+ {
+ return Expr.And(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr));
+ }
+
+ if (call.Func.Name.Equals("__at_most_one"))
+ {
+ return Expr.Not(Expr.And(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(node.Args[0].Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName)
+ .VisitExpr(node.Args[0].Clone() as Expr)));
+ }
+
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+
+ internal EnsuresSeq ProcessCrossThreadInvariants(EnsuresSeq ensuresSeq)
+ {
+ EnsuresSeq result = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq)
+ {
+ result.Add(new Ensures(e.Free, VisitExpr(e.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ internal RequiresSeq ProcessCrossThreadInvariants(RequiresSeq requiresSeq)
+ {
+ RequiresSeq result = new RequiresSeq();
+ foreach (Requires r in requiresSeq)
+ {
+ result.Add(new Requires(r.Free, VisitExpr(r.Condition.Clone() as Expr)));
+ }
+ return result;
+ }
+
+ internal 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, VisitExpr((c as AssertCmd).Expr.Clone() as Expr)));
+ }
+ else if (c is AssumeCmd)
+ {
+ newCommands.Add(new AssumeCmd(c.tok, 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, VisitExpr(p.Expr)));
+ }
+ whileCmd.Invariants = newInvariants;
+ ProcessCrossThreadInvariants(whileCmd.Body);
+ }
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs b/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
index 84624e5d..91b1edb6 100644
--- a/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
+++ b/Source/GPUVerify/ElementEncodingRaceInstrumenter.cs
@@ -111,7 +111,6 @@ namespace GPUVerify
{
MapType mt = v.TypedIdent.Type as MapType;
Debug.Assert(mt.Arguments.Length == 1);
- Debug.Assert(GPUVerifier.IsIntOrBv32(mt.Arguments[0]));
Variable AccessOffsetX = GPUVerifier.MakeOffsetXVariable(v, ReadOrWrite);
@@ -173,8 +172,10 @@ namespace GPUVerify
protected override void SetNoAccessOccurred(IToken tok, BigBlock bb, Variable v, string AccessType)
{
- IdentifierExpr AccessOccurred1 = new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, AccessType)));
- IdentifierExpr AccessOccurred2 = new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, AccessType)));
+ IdentifierExpr AccessOccurred1 = new IdentifierExpr(tok,
+ new VariableDualiser(1, null, null).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, AccessType)));
+ IdentifierExpr AccessOccurred2 = new IdentifierExpr(tok,
+ new VariableDualiser(2, null, null).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, AccessType)));
List<AssignLhs> lhss = new List<AssignLhs>();
List<Expr> rhss = new List<Expr>();
@@ -191,46 +192,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, null, null).VisitVariable(MakeReadOrWriteHasOccurredVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).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, null, null).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).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, null, null).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).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, null, null).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, FirstAccessType))),
+ new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, SecondAccessType)))
));
}
@@ -247,16 +248,15 @@ namespace GPUVerify
private static Expr MakeWrittenIndex(Variable v, int OneOrTwo)
{
- Expr result = new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo).VisitVariable(v.Clone() as Variable));
+ Expr result = new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo, null, null).VisitVariable(v.Clone() as Variable));
if (v.TypedIdent.Type is MapType)
{
MapType mt = v.TypedIdent.Type as MapType;
Debug.Assert(mt.Arguments.Length == 1);
- Debug.Assert(GPUVerifier.IsIntOrBv32(mt.Arguments[0]));
result = Expr.Select(result,
- new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, "WRITE"))) });
+ new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo, null, null).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, "WRITE"))) });
if (mt.Result is MapType)
{
@@ -265,7 +265,7 @@ namespace GPUVerify
Debug.Assert(GPUVerifier.IsIntOrBv32(mt2.Arguments[0]));
result = Expr.Select(result,
- new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, "WRITE"))) });
+ new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo, null, null).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, "WRITE"))) });
if (mt2.Result is MapType)
{
@@ -275,7 +275,7 @@ namespace GPUVerify
Debug.Assert(!(mt3.Result is MapType));
result = Expr.Select(result,
- new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, "WRITE"))) });
+ new Expr[] { new IdentifierExpr(v.tok, new VariableDualiser(OneOrTwo, null, null).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, "WRITE"))) });
}
}
@@ -292,10 +292,10 @@ namespace GPUVerify
protected override void AddRequiresNoPendingAccess(Variable v)
{
- IdentifierExpr ReadAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "READ")));
- IdentifierExpr ReadAccessOccurred2 = new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "READ")));
- IdentifierExpr WriteAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "WRITE")));
- IdentifierExpr WriteAccessOccurred2 = new IdentifierExpr(v.tok, new VariableDualiser(2).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "WRITE")));
+ IdentifierExpr ReadAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "READ")));
+ IdentifierExpr ReadAccessOccurred2 = new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "READ")));
+ IdentifierExpr WriteAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "WRITE")));
+ IdentifierExpr WriteAccessOccurred2 = new IdentifierExpr(v.tok, new VariableDualiser(2, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, "WRITE")));
if (CommandLineOptions.Symmetry)
{
@@ -346,8 +346,8 @@ namespace GPUVerify
if (GPUVerifier.HasZDimension(v) && verifier.KernelHasIdZ() && GPUVerifier.IndexTypeOfZDimension(v).Equals(verifier.GetTypeOfIdZ()))
{
expr = Expr.Imp(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
- Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "Z", Thread))));
+ new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
+ Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetZVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "Z", Thread))));
}
return expr;
}
@@ -367,8 +367,8 @@ namespace GPUVerify
if (GPUVerifier.HasYDimension(v) && verifier.KernelHasIdY() && GPUVerifier.IndexTypeOfYDimension(v).Equals(verifier.GetTypeOfIdY()))
{
expr = Expr.Imp(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
- Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "Y", Thread))));
+ new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
+ Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetYVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "Y", Thread))));
}
return expr;
}
@@ -388,8 +388,8 @@ namespace GPUVerify
if (GPUVerifier.HasXDimension(v) && GPUVerifier.IndexTypeOfXDimension(v).Equals(verifier.GetTypeOfIdX()))
{
expr = Expr.Imp(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
- Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "X", Thread))));
+ new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(ElementEncodingRaceInstrumenter.MakeReadOrWriteHasOccurredVariable(v, ReadOrWrite))),
+ Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetXVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "X", Thread))));
}
return expr;
}
diff --git a/Source/GPUVerify/EnabledToPredicateVisitor.cs b/Source/GPUVerify/EnabledToPredicateVisitor.cs
new file mode 100644
index 00000000..e004004f
--- /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(Expr currentPredicate)
+ {
+ this.currentPredicate = currentPredicate;
+
+ }
+
+ private Expr 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 currentPredicate;
+ }
+
+ }
+
+ return base.VisitNAryExpr(node);
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/EnsureDisabledThreadHasNoEffectInstrumenter.cs b/Source/GPUVerify/EnsureDisabledThreadHasNoEffectInstrumenter.cs
new file mode 100644
index 00000000..32dde507
--- /dev/null
+++ b/Source/GPUVerify/EnsureDisabledThreadHasNoEffectInstrumenter.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class EnsureDisabledThreadHasNoEffectInstrumenter
+ {
+
+ private GPUVerifier verifier;
+ private Implementation Impl;
+
+ public EnsureDisabledThreadHasNoEffectInstrumenter(GPUVerifier verifier, Implementation Impl)
+ {
+ this.verifier = verifier;
+ this.Impl = Impl;
+ }
+
+ internal void instrument()
+ {
+
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name))
+ {
+ return;
+ }
+
+ foreach (IdentifierExpr iex in Impl.Proc.Modifies)
+ {
+ // For some reason, this does not work well with maps
+ if (iex.Decl.TypedIdent.Type is MapType)
+ {
+ continue;
+ }
+
+ Expr NoEffectExpr = Expr.Imp(
+ Expr.Not(new IdentifierExpr(iex.tok, new LocalVariable(iex.tok, new TypedIdent(iex.tok, "_P$" +
+ GPUVerifier.GetThreadSuffix(iex.Name), Microsoft.Boogie.Type.Bool)))),
+ Expr.Eq(iex, new OldExpr(iex.tok, iex))
+ );
+
+ Impl.Proc.Ensures.Add(new Ensures(false,
+ NoEffectExpr
+ ));
+
+ GPUVerifier.AddInvariantToAllLoops(NoEffectExpr, Impl.StructuredStmts);
+
+ }
+
+ AddEnablednessInvariantToAllLoops(Impl.StructuredStmts);
+ }
+
+ private void AddEnablednessInvariantToAllLoops(StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ AddEnablednessInvariantToAllLoops(bb);
+ }
+ }
+
+ private void AddEnablednessInvariantToAllLoops(BigBlock bb)
+ {
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ Debug.Assert(wc.Guard is NAryExpr);
+ Debug.Assert((wc.Guard as NAryExpr).Fun is BinaryOperator);
+ Debug.Assert((wc.Guard as NAryExpr).Args[0] is IdentifierExpr);
+ string LoopPredicate = ((wc.Guard as NAryExpr).Args[0] as IdentifierExpr).Name;
+ LoopPredicate = GPUVerifier.StripThreadIdentifier(LoopPredicate);
+
+ wc.Invariants.Add(
+ new AssertCmd(wc.tok,
+ Expr.Imp(
+ Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, "_P$1", Microsoft.Boogie.Type.Bool)))),
+ Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Bool))))
+ )));
+
+ wc.Invariants.Add(
+ new AssertCmd(wc.tok,
+ Expr.Imp(
+ Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, "_P$2", Microsoft.Boogie.Type.Bool)))),
+ Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Bool))))
+ )));
+
+ AddEnablednessInvariantToAllLoops(wc.Body);
+ }
+
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs
index a0ea0543..61643f80 100644
--- a/Source/GPUVerify/GPUVerifier.cs
+++ b/Source/GPUVerify/GPUVerifier.cs
@@ -29,40 +29,46 @@ namespace GPUVerify
private int TempCounter = 0;
private int invariantGenerationCounter;
- private Constant _X = null;
- private Constant _Y = null;
- private Constant _Z = null;
+ private const string LOCAL_ID_X_STRING = "local_id_x";
+ private const string LOCAL_ID_Y_STRING = "local_id_y";
+ private const string LOCAL_ID_Z_STRING = "local_id_z";
- private const string _X_name = "_X";
- private const string _Y_name = "_Y";
- private const string _Z_name = "_Z";
+ internal static Constant _X = null;
+ internal static Constant _Y = null;
+ internal static Constant _Z = null;
private Constant _GROUP_SIZE_X = null;
private Constant _GROUP_SIZE_Y = null;
private Constant _GROUP_SIZE_Z = null;
- private const string _GROUP_SIZE_X_name = "_GROUP_SIZE_X";
- private const string _GROUP_SIZE_Y_name = "_GROUP_SIZE_Y";
- private const string _GROUP_SIZE_Z_name = "_GROUP_SIZE_Z";
+ private const string GROUP_SIZE_X_STRING = "group_size_x";
+ private const string GROUP_SIZE_Y_STRING = "group_size_y";
+ private const string GROUP_SIZE_Z_STRING = "group_size_z";
private Constant _GROUP_X = null;
private Constant _GROUP_Y = null;
private Constant _GROUP_Z = null;
- private const string _GROUP_X_name = "_GROUP_X";
- private const string _GROUP_Y_name = "_GROUP_Y";
- private const string _GROUP_Z_name = "_GROUP_Z";
+ private const string GROUP_ID_X_STRING = "group_id_x";
+ private const string GROUP_ID_Y_STRING = "group_id_y";
+ private const string GROUP_ID_Z_STRING = "group_id_z";
private Constant _NUM_GROUPS_X = null;
private Constant _NUM_GROUPS_Y = null;
private Constant _NUM_GROUPS_Z = null;
- private const string _NUM_GROUPS_X_name = "_NUM_GROUPS_X";
- private const string _NUM_GROUPS_Y_name = "_NUM_GROUPS_Y";
- private const string _NUM_GROUPS_Z_name = "_NUM_GROUPS_Z";
+ private const string NUM_GROUPS_X_STRING = "num_groups_x";
+ private const string NUM_GROUPS_Y_STRING = "num_groups_y";
+ private const string NUM_GROUPS_Z_STRING = "num_groups_z";
public IRaceInstrumenter RaceInstrumenter;
+ public UniformityAnalyser uniformityAnalyser;
+ public MayBeTidAnalyser mayBeTidAnalyser;
+ public MayBeTidPlusConstantAnalyser mayBeTidPlusConstantAnalyser;
+ public MayBePowerOfTwoAnalyser mayBePowerOfTwoAnalyser;
+ public LiveVariableAnalyser liveVariableAnalyser;
+
public GPUVerifier(string filename, Program program, IRaceInstrumenter raceInstrumenter) : this(filename, program, raceInstrumenter, false)
{
}
@@ -155,8 +161,35 @@ namespace GPUVerify
}
}
- private void FindNonLocalVariables(Program program)
+
+ private void ReportMultipleAttributeError(string attribute, IToken first, IToken second)
+ {
+ Error(
+ second,
+ "Can only have one {0} attribute, but previously saw this attribute at ({1}, {2})",
+ attribute,
+ first.filename,
+ first.line, first.col - 1);
+ }
+
+ private bool setConstAttributeField(Constant constInProgram, string attr, ref Constant constFieldRef)
+ {
+ if (QKeyValue.FindBoolAttribute(constInProgram.Attributes, attr))
+ {
+ if (constFieldRef != null)
+ {
+ ReportMultipleAttributeError(attr, constFieldRef.tok, constInProgram.tok);
+ return false;
+ }
+ CheckSpecialConstantType(constInProgram);
+ constFieldRef = constInProgram;
+ }
+ return true;
+ }
+
+ private bool FindNonLocalVariables(Program program)
{
+ bool success = true;
foreach (Declaration D in program.TopLevelDeclarations)
{
if (D is Variable && (D as Variable).IsMutable)
@@ -176,69 +209,28 @@ namespace GPUVerify
else if (D is Constant)
{
Constant C = D as Constant;
- if (C.Name.Equals(_X_name))
- {
- CheckSpecialConstantType(C);
- _X = C;
- }
- if (C.Name.Equals(_Y_name))
- {
- CheckSpecialConstantType(C);
- _Y = C;
- }
- if (C.Name.Equals(_Z_name))
- {
- CheckSpecialConstantType(C);
- _Z = C;
- }
- if (C.Name.Equals(_GROUP_SIZE_X_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_SIZE_X = C;
- }
- if (C.Name.Equals(_GROUP_SIZE_Y_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_SIZE_Y = C;
- }
- if (C.Name.Equals(_GROUP_SIZE_Z_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_SIZE_Z = C;
- }
- if (C.Name.Equals(_GROUP_X_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_X = C;
- }
- if (C.Name.Equals(_GROUP_Y_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_Y = C;
- }
- if (C.Name.Equals(_GROUP_Z_name))
- {
- CheckSpecialConstantType(C);
- _GROUP_Z = C;
- }
- if (C.Name.Equals(_NUM_GROUPS_X_name))
- {
- CheckSpecialConstantType(C);
- _NUM_GROUPS_X = C;
- }
- if (C.Name.Equals(_NUM_GROUPS_Y_name))
- {
- CheckSpecialConstantType(C);
- _NUM_GROUPS_Y = C;
- }
- if (C.Name.Equals(_NUM_GROUPS_Z_name))
- {
- CheckSpecialConstantType(C);
- _NUM_GROUPS_Z = C;
- }
+
+ success &= setConstAttributeField(C, LOCAL_ID_X_STRING, ref _X);
+ success &= setConstAttributeField(C, LOCAL_ID_Y_STRING, ref _Y);
+ success &= setConstAttributeField(C, LOCAL_ID_Z_STRING, ref _Z);
+
+ success &= setConstAttributeField(C, GROUP_SIZE_X_STRING, ref _GROUP_SIZE_X);
+ success &= setConstAttributeField(C, GROUP_SIZE_Y_STRING, ref _GROUP_SIZE_Y);
+ success &= setConstAttributeField(C, GROUP_SIZE_Z_STRING, ref _GROUP_SIZE_Z);
+
+ success &= setConstAttributeField(C, GROUP_ID_X_STRING, ref _GROUP_X);
+ success &= setConstAttributeField(C, GROUP_ID_Y_STRING, ref _GROUP_Y);
+ success &= setConstAttributeField(C, GROUP_ID_Z_STRING, ref _GROUP_Z);
+
+ success &= setConstAttributeField(C, NUM_GROUPS_X_STRING, ref _NUM_GROUPS_X);
+ success &= setConstAttributeField(C, NUM_GROUPS_Y_STRING, ref _NUM_GROUPS_Y);
+ success &= setConstAttributeField(C, NUM_GROUPS_Z_STRING, ref _NUM_GROUPS_Z);
+
}
}
+
+ return success;
}
private void CheckSpecialConstantType(Constant C)
@@ -312,8 +304,25 @@ namespace GPUVerify
internal void doit()
{
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_original");
+ }
+
preProcess();
+ DoLiveVariableAnalysis();
+
+ DoUniformityAnalysis();
+
+ DoMayBeTidAnalysis();
+
+ DoMayBeTidPlusConstantAnalysis();
+
+ DoMayBePowerOfTwoAnalysis();
+
+ DoArrayControlFlowAnalysis();
+
if (CommandLineOptions.ShowStages)
{
emitProgram(outputFilename + "_preprocessed");
@@ -324,6 +333,8 @@ namespace GPUVerify
return;
}
+ ProcessAccessInvariants();
+
if (CommandLineOptions.ShowStages)
{
emitProgram(outputFilename + "_instrumented");
@@ -350,6 +361,13 @@ namespace GPUVerify
emitProgram(outputFilename + "_dualised");
}
+ ProcessCrossThreadInvariants();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_cross_thread_invariants");
+ }
+
if (CommandLineOptions.Eager)
{
AddEagerRaceChecking();
@@ -357,7 +375,7 @@ namespace GPUVerify
GenerateBarrierImplementation();
- GenerateKernelPrecondition();
+ GenerateStandardKernelContract();
if (CommandLineOptions.ShowStages)
{
@@ -413,6 +431,160 @@ namespace GPUVerify
}
+ private void DoMayBePowerOfTwoAnalysis()
+ {
+ mayBePowerOfTwoAnalyser = new MayBePowerOfTwoAnalyser(this);
+ mayBePowerOfTwoAnalyser.Analyse();
+ }
+
+ private void DoMayBeTidAnalysis()
+ {
+ mayBeTidAnalyser = new MayBeTidAnalyser(this);
+ mayBeTidAnalyser.Analyse();
+ }
+
+ private void DoMayBeTidPlusConstantAnalysis()
+ {
+ mayBeTidPlusConstantAnalyser = new MayBeTidPlusConstantAnalyser(this);
+ mayBeTidPlusConstantAnalyser.Analyse();
+ }
+
+ private void DoArrayControlFlowAnalysis()
+ {
+ // TODO
+ }
+
+ private void DoUniformityAnalysis()
+ {
+ uniformityAnalyser = new UniformityAnalyser(this);
+ uniformityAnalyser.Analyse();
+ }
+
+ private void DoLiveVariableAnalysis()
+ {
+ liveVariableAnalyser = new LiveVariableAnalyser(this);
+ liveVariableAnalyser.Analyse();
+ }
+
+
+ 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 = new CrossThreadInvariantProcessor(this, p.Name).ProcessCrossThreadInvariants(p.Requires);
+ p.Ensures = new CrossThreadInvariantProcessor(this, p.Name).ProcessCrossThreadInvariants(p.Ensures);
+ }
+ if (d is Implementation)
+ {
+ Implementation i = d as Implementation;
+ new CrossThreadInvariantProcessor(this, i.Name).ProcessCrossThreadInvariants(i.StructuredStmts);
+ }
+
+ }
+ }
+
+
private void emitProgram(string filename)
{
using (TokenTextWriter writer = new TokenTextWriter(filename + ".bpl"))
@@ -437,7 +609,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)
@@ -470,24 +642,7 @@ namespace GPUVerify
List<Expr> UserSuppliedInvariants = GetUserSuppliedInvariants(Impl.Name);
- HashSet<string> LocalNames = new HashSet<string>();
- foreach (Variable v in Impl.LocVars)
- {
- string basicName = StripThreadIdentifier(v.Name);
- LocalNames.Add(basicName);
- }
- foreach (Variable v in Impl.InParams)
- {
- string basicName = StripThreadIdentifier(v.Name);
- LocalNames.Add(basicName);
- }
- foreach (Variable v in Impl.OutParams)
- {
- string basicName = StripThreadIdentifier(v.Name);
- LocalNames.Add(basicName);
- }
-
- AddCandidateInvariants(Impl.StructuredStmts, LocalNames, UserSuppliedInvariants, Impl);
+ new LoopInvariantGenerator(this, Impl).instrument(UserSuppliedInvariants);
Procedure Proc = Impl.Proc;
@@ -572,8 +727,8 @@ namespace GPUVerify
new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, "_P$2", Microsoft.Boogie.Type.Bool)))
),
Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable))
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
)
));
}
@@ -582,8 +737,8 @@ namespace GPUVerify
{
AddCandidateRequires(Proc,
Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable))
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
)
);
}
@@ -592,8 +747,8 @@ namespace GPUVerify
{
AddCandidateEnsures(Proc,
Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable))
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
));
}
@@ -701,97 +856,20 @@ namespace GPUVerify
return result;
}
- private void AddCandidateInvariants(StmtList stmtList, HashSet<string> LocalNames, List<Expr> UserSuppliedInvariants, Implementation Impl)
- {
- foreach (BigBlock bb in stmtList.BigBlocks)
- {
- AddCandidateInvariants(bb, LocalNames, UserSuppliedInvariants, Impl);
- }
- }
-
- private void AddCandidateInvariants(BigBlock bb, HashSet<string> LocalNames, List<Expr> UserSuppliedInvariants, Implementation Impl)
+ internal bool ContainsNamedVariable(HashSet<Variable> variables, string name)
{
- if (bb.ec is WhileCmd)
+ foreach(Variable v in variables)
{
- WhileCmd wc = bb.ec as WhileCmd;
-
- Debug.Assert(wc.Guard is NAryExpr);
- Debug.Assert((wc.Guard as NAryExpr).Args.Length == 2);
- Debug.Assert((wc.Guard as NAryExpr).Args[0] is IdentifierExpr);
- string LoopPredicate = ((wc.Guard as NAryExpr).Args[0] as IdentifierExpr).Name;
-
- LoopPredicate = LoopPredicate.Substring(0, LoopPredicate.IndexOf('$'));
-
- AddCandidateInvariant(wc, Expr.Eq(
- // Int type used here, but it doesn't matter as we will print and then re-parse the program
- new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
- new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
- ));
-
- foreach (string lv in LocalNames)
+ if(StripThreadIdentifier(v.Name) == name)
{
- if (IsPredicateOrTemp(lv))
- {
- continue;
- }
-
- AddEqualityCandidateInvariant(wc, LoopPredicate, new LocalVariable(wc.tok, new TypedIdent(wc.tok, lv, Microsoft.Boogie.Type.Int)));
-
- if (Impl != KernelImplementation)
- {
- AddPredicatedEqualityCandidateInvariant(wc, LoopPredicate, new LocalVariable(wc.tok, new TypedIdent(wc.tok, lv, Microsoft.Boogie.Type.Int)));
- }
- }
-
- if (!CommandLineOptions.FullAbstraction)
- {
- foreach (Variable v in NonLocalState.getAllNonLocalVariables())
- {
- AddEqualityCandidateInvariant(wc, LoopPredicate, v);
- }
+ return true;
}
-
- RaceInstrumenter.AddRaceCheckingCandidateInvariants(wc);
-
- AddUserSuppliedInvariants(wc, UserSuppliedInvariants, Impl);
-
- AddCandidateInvariants(wc.Body, LocalNames, UserSuppliedInvariants, Impl);
}
- else if (bb.ec is IfCmd)
- {
- // We should have done predicated execution by now, so we won't have any if statements
- Debug.Assert(false);
- }
- else
- {
- Debug.Assert(bb.ec == null);
- }
- }
-
- private void AddEqualityCandidateInvariant(WhileCmd wc, string LoopPredicate, Variable v)
- {
- AddCandidateInvariant(wc,
- Expr.Eq(
- new IdentifierExpr(wc.tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(wc.tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable))
- ));
- }
-
- private void AddPredicatedEqualityCandidateInvariant(WhileCmd wc, string LoopPredicate, Variable v)
- {
- AddCandidateInvariant(wc, Expr.Imp(
- Expr.And(
- new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
- new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
- ),
- Expr.Eq(
- new IdentifierExpr(wc.tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(wc.tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable))
- )));
+ return false;
}
- private bool IsPredicateOrTemp(string lv)
+ internal static bool IsPredicateOrTemp(string lv)
{
return (lv.Length >= 2 && lv.Substring(0,2).Equals("_P")) ||
(lv.Length > 3 && lv.Substring(0,3).Equals("_LC")) ||
@@ -800,21 +878,8 @@ namespace GPUVerify
- private void AddUserSuppliedInvariants(WhileCmd wc, List<Expr> UserSuppliedInvariants, Implementation Impl)
- {
- foreach (Expr e in UserSuppliedInvariants)
- {
- wc.Invariants.Add(new AssertCmd(wc.tok, e));
- bool OK = ProgramIsOK(Impl);
- wc.Invariants.RemoveAt(wc.Invariants.Count - 1);
- if (OK)
- {
- AddCandidateInvariant(wc, e);
- }
- }
- }
- private bool ProgramIsOK(Declaration d)
+ internal bool ProgramIsOK(Declaration d)
{
Debug.Assert(d is Procedure || d is Implementation);
TokenTextWriter writer = new TokenTextWriter("temp_out.bpl");
@@ -950,27 +1015,7 @@ 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);
- IdentifierExpr ExistentialBoolean = new IdentifierExpr(wc.tok, ExistentialBooleanConstant);
- wc.Invariants.Add(new AssertCmd(wc.tok, Expr.Imp(ExistentialBoolean, e)));
- Program.TopLevelDeclarations.Add(ExistentialBooleanConstant);
- }
-
- private Constant MakeExistentialBoolean(IToken tok)
+ internal Constant MakeExistentialBoolean(IToken tok)
{
Constant ExistentialBooleanConstant = new Constant(tok, new TypedIdent(tok, "_b" + invariantGenerationCounter, Microsoft.Boogie.Type.Bool), false);
invariantGenerationCounter++;
@@ -978,9 +1023,13 @@ namespace GPUVerify
return ExistentialBooleanConstant;
}
- private string StripThreadIdentifier(string p)
+ internal static string StripThreadIdentifier(string p)
{
- return p.Substring(0, p.IndexOf("$"));
+ if (p.Contains("$"))
+ {
+ return p.Substring(0, p.IndexOf("$"));
+ }
+ return p;
}
private void AddStartAndEndBarriers()
@@ -988,6 +1037,9 @@ namespace GPUVerify
CallCmd FirstBarrier = new CallCmd(KernelImplementation.tok, BarrierProcedure.Name, new ExprSeq(), new IdentifierExprSeq());
CallCmd LastBarrier = new CallCmd(KernelImplementation.tok, BarrierProcedure.Name, new ExprSeq(), new IdentifierExprSeq());
+ FirstBarrier.Proc = KernelProcedure;
+ LastBarrier.Proc = KernelProcedure;
+
CmdSeq newCommands = new CmdSeq();
newCommands.Add(FirstBarrier);
foreach (Cmd c in KernelImplementation.StructuredStmts.BigBlocks[0].simpleCmds)
@@ -1003,7 +1055,7 @@ namespace GPUVerify
KernelImplementation.StructuredStmts.BigBlocks.Add(bb);
}
- private void GenerateKernelPrecondition()
+ private void GenerateStandardKernelContract()
{
RaceInstrumenter.AddKernelPrecondition();
@@ -1033,6 +1085,21 @@ namespace GPUVerify
Proc.Requires.Add(new Requires(false, AssumeDistinctThreads));
Proc.Requires.Add(new Requires(false, AssumeThreadIdsInRange));
+
+ if (Proc != KernelProcedure)
+ {
+ RaceInstrumenter.AddNoRaceContract(Proc);
+ }
+ else
+ {
+ for (int i = 0; i < Proc.InParams.Length / 2; i++)
+ {
+ Proc.Requires.Add(new Requires(false,
+ Expr.Eq(new IdentifierExpr(Proc.InParams[i].tok, Proc.InParams[i]),
+ new IdentifierExpr(Proc.InParams[i + Proc.InParams.Length / 2].tok, Proc.InParams[i + Proc.InParams.Length / 2]))));
+ }
+ }
+
}
}
else
@@ -1047,6 +1114,9 @@ namespace GPUVerify
continue;
}
Implementation Impl = D as Implementation;
+
+ RaceInstrumenter.AddNoRaceInvariants(Impl);
+
if (QKeyValue.FindIntAttribute(Impl.Proc.Attributes, "inline", -1) == 1)
{
continue;
@@ -1056,77 +1126,13 @@ namespace GPUVerify
continue;
}
- EnsureDisabledThreadHasNoEffect(Impl);
-
- }
-
- }
-
- private void EnsureDisabledThreadHasNoEffect(Implementation Impl)
- {
- foreach (IdentifierExpr iex in Impl.Proc.Modifies)
- {
- // For some reason, this does not work well with maps
- if (iex.Decl.TypedIdent.Type is MapType)
- {
- continue;
- }
-
- Expr NoEffectExpr = Expr.Imp(
- Expr.Not(new IdentifierExpr(iex.tok, new LocalVariable(iex.tok, new TypedIdent(iex.tok, "_P$" + GetThreadSuffix(iex.Name), Microsoft.Boogie.Type.Bool)))),
- Expr.Eq(iex, new OldExpr(iex.tok, iex))
- );
-
- Impl.Proc.Ensures.Add(new Ensures(false,
- NoEffectExpr
- ));
-
- AddInvariantToAllLoops(NoEffectExpr, Impl.StructuredStmts);
+ new EnsureDisabledThreadHasNoEffectInstrumenter(this, Impl).instrument();
}
- AddEnablednessInvariantToAllLoops(Impl.StructuredStmts);
}
- private void AddEnablednessInvariantToAllLoops(StmtList stmtList)
- {
- foreach (BigBlock bb in stmtList.BigBlocks)
- {
- AddEnablednessInvariantToAllLoops(bb);
- }
- }
-
- private void AddEnablednessInvariantToAllLoops(BigBlock bb)
- {
- if (bb.ec is WhileCmd)
- {
- WhileCmd wc = bb.ec as WhileCmd;
- Debug.Assert(wc.Guard is NAryExpr);
- Debug.Assert((wc.Guard as NAryExpr).Fun is BinaryOperator);
- Debug.Assert((wc.Guard as NAryExpr).Args[0] is IdentifierExpr);
- string LoopPredicate = ((wc.Guard as NAryExpr).Args[0] as IdentifierExpr).Name;
- LoopPredicate = StripThreadIdentifier(LoopPredicate);
-
- wc.Invariants.Add(
- new AssertCmd(wc.tok,
- Expr.Imp(
- Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, "_P$1", Microsoft.Boogie.Type.Bool)))),
- Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Bool))))
- )));
-
- wc.Invariants.Add(
- new AssertCmd(wc.tok,
- Expr.Imp(
- Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, "_P$2", Microsoft.Boogie.Type.Bool)))),
- Expr.Not(new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Bool))))
- )));
-
- AddEnablednessInvariantToAllLoops(wc.Body);
- }
-
- }
-
- private void AddInvariantToAllLoops(Expr Invariant, StmtList stmtList)
+ internal static void AddInvariantToAllLoops(Expr Invariant, StmtList stmtList)
{
foreach (BigBlock bb in stmtList.BigBlocks)
{
@@ -1134,7 +1140,7 @@ namespace GPUVerify
}
}
- private void AddInvariantToAllLoops(Expr Invariant, BigBlock bb)
+ internal static void AddInvariantToAllLoops(Expr Invariant, BigBlock bb)
{
if (bb.ec is WhileCmd)
{
@@ -1145,78 +1151,75 @@ namespace GPUVerify
Debug.Assert(!(bb.ec is IfCmd));
}
- private int GetThreadSuffix(string p)
+ internal static int GetThreadSuffix(string p)
{
return Int32.Parse(p.Substring(p.IndexOf("$") + 1, p.Length - (p.IndexOf("$") + 1)));
}
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)
+ internal static Expr MakeBitVectorBinaryBoolean(string functionName, Expr lhs, Expr rhs)
{
return new NAryExpr(lhs.tok, new FunctionCall(new Function(lhs.tok, functionName, new VariableSeq(new Variable[] {
new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg1", Microsoft.Boogie.Type.GetBvType(32))),
@@ -1248,12 +1251,11 @@ namespace GPUVerify
{
Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
string name = null;
- if (dimension.Equals("X")) name = _X_name;
- if (dimension.Equals("Y")) name = _Y_name;
- if (dimension.Equals("Z")) name = _Z_name;
+ if (dimension.Equals("X")) name = _X.Name;
+ if (dimension.Equals("Y")) name = _Y.Name;
+ if (dimension.Equals("Z")) name = _Z.Name;
Debug.Assert(name != null);
- name = name + "$" + number;
- return new Constant(tok, new TypedIdent(tok, "_" + dimension + "$" + number, GetTypeOfId(dimension)));
+ return new Constant(tok, new TypedIdent(tok, name + "$" + number, GetTypeOfId(dimension)));
}
private Constant GetGroupId(string dimension)
@@ -1358,16 +1360,13 @@ namespace GPUVerify
private void HavocAndAssumeEquality(IToken tok, BigBlock bb, Variable v)
{
- IdentifierExpr v1 = new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(v.Clone() as Variable));
- IdentifierExpr v2 = new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(v.Clone() as Variable));
+ IdentifierExpr v1 = new IdentifierExpr(tok, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable));
+ IdentifierExpr v2 = new IdentifierExpr(tok, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable));
IdentifierExprSeq ModifiedVars = new IdentifierExprSeq(new IdentifierExpr[] { v1, v2 });
bb.simpleCmds.Add(new HavocCmd(tok, ModifiedVars));
bb.simpleCmds.Add(new AssumeCmd(tok, Expr.Eq(v1, v2)));
- HashSet<string> MayCallBarrier = GetProceduresThatIndirectlyCallProcedure(BarrierProcedure.Name);
- ExtendModifiesSetOfProcedures(ModifiedVars, MayCallBarrier);
-
}
internal static bool ModifiesSetContains(IdentifierExprSeq Modifies, IdentifierExpr v)
@@ -1535,7 +1534,8 @@ namespace GPUVerify
if (bb.ec is WhileCmd)
{
WhileCmd WhileCommand = bb.ec as WhileCmd;
- result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, PerformFullSharedStateAbstraction(WhileCommand.Body));
+ result.ec =
+ new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, PerformFullSharedStateAbstraction(WhileCommand.Body));
}
else if (bb.ec is IfCmd)
{
@@ -1778,7 +1778,9 @@ namespace GPUVerify
}
- result.simpleCmds.Add(new CallCmd(call.tok, call.callee, newIns, call.Outs));
+ CallCmd newCall = new CallCmd(call.tok, call.callee, newIns, call.Outs);
+ newCall.Proc = call.Proc;
+ result.simpleCmds.Add(newCall);
}
else if (c is AssignCmd)
{
@@ -1898,32 +1900,9 @@ namespace GPUVerify
if (d is Procedure)
{
- // DuplicateParameters
- Procedure proc = d as Procedure;
-
- bool HalfDualise = HalfDualisedProcedureNames.Contains(proc.Name);
+ new KernelDualiser(this).DualiseProcedure(d as Procedure);
- proc.InParams = DualiseVariableSequence(proc.InParams, HalfDualise);
- proc.OutParams = DualiseVariableSequence(proc.OutParams, HalfDualise);
- IdentifierExprSeq NewModifies = new IdentifierExprSeq();
- foreach (IdentifierExpr v in proc.Modifies)
- {
- NewModifies.Add(new VariableDualiser(1).VisitIdentifierExpr((IdentifierExpr)v.Clone()));
- }
-
- if (!HalfDualise)
- {
- foreach (IdentifierExpr v in proc.Modifies)
- {
- if (!CommandLineOptions.Symmetry || !HalfDualisedVariableNames.Contains(v.Name))
- {
- NewModifies.Add(new VariableDualiser(2).VisitIdentifierExpr((IdentifierExpr)v.Clone()));
- }
- }
- }
- proc.Modifies = NewModifies;
-
- NewTopLevelDeclarations.Add(proc);
+ NewTopLevelDeclarations.Add(d as Procedure);
continue;
@@ -1931,17 +1910,10 @@ namespace GPUVerify
if (d is Implementation)
{
- // DuplicateParameters
- Implementation impl = d as Implementation;
-
- bool HalfDualise = HalfDualisedProcedureNames.Contains(impl.Name);
- impl.InParams = DualiseVariableSequence(impl.InParams, HalfDualise);
- impl.OutParams = DualiseVariableSequence(impl.OutParams, HalfDualise);
- MakeDualLocalVariables(impl, HalfDualise);
- impl.StructuredStmts = MakeDual(impl.StructuredStmts, HalfDualise);
+ new KernelDualiser(this).DualiseImplementation(d as Implementation);
- NewTopLevelDeclarations.Add(impl);
+ NewTopLevelDeclarations.Add(d as Implementation);
continue;
@@ -1949,11 +1921,11 @@ namespace GPUVerify
if (d is Variable && ((d as Variable).IsMutable || IsThreadLocalIdConstant(d as Variable)))
{
- NewTopLevelDeclarations.Add(new VariableDualiser(1).VisitVariable((Variable)d.Clone()));
+ NewTopLevelDeclarations.Add(new VariableDualiser(1, null, null).VisitVariable((Variable)d.Clone()));
if (!HalfDualisedVariableNames.Contains((d as Variable).Name))
{
- NewTopLevelDeclarations.Add(new VariableDualiser(2).VisitVariable((Variable)d.Clone()));
+ NewTopLevelDeclarations.Add(new VariableDualiser(2, null, null).VisitVariable((Variable)d.Clone()));
}
continue;
@@ -1967,220 +1939,58 @@ namespace GPUVerify
}
- private static VariableSeq DualiseVariableSequence(VariableSeq seq, bool HalfDualise)
- {
- VariableSeq result = new VariableSeq();
- foreach (Variable v in seq)
- {
- result.Add(new VariableDualiser(1).VisitVariable((Variable)v.Clone()));
- }
-
- if (!HalfDualise)
- {
- foreach (Variable v in seq)
- {
- result.Add(new VariableDualiser(2).VisitVariable((Variable)v.Clone()));
- }
- }
- return result;
- }
-
private void MakeKernelPredicated()
{
foreach (Declaration d in Program.TopLevelDeclarations)
{
if (d is Procedure)
{
- if (d != KernelProcedure)
+ Procedure proc = d as Procedure;
+ IdentifierExpr enabled = new IdentifierExpr(proc.tok,
+ new LocalVariable(proc.tok, new TypedIdent(proc.tok, "_P", Microsoft.Boogie.Type.Bool)));
+ Expr predicateExpr;
+ if (!uniformityAnalyser.IsUniform(proc.Name))
{
// 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)));
+ NewIns.Add(enabled.Decl);
foreach (Variable v in proc.InParams)
{
NewIns.Add(v);
}
proc.InParams = NewIns;
+ predicateExpr = enabled;
}
-
- }
- else if (d is Implementation)
- {
- new Predicator(d != KernelImplementation).transform(d as Implementation);
-
- //MakePredicated(d as Implementation, d != KernelImplementation);
- }
- }
-
- }
-
- private StmtList MakeDual(StmtList stmtList, bool HalfDualise)
- {
- Contract.Requires(stmtList != null);
-
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
-
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(MakeDual(bodyBlock, HalfDualise));
- }
-
- return result;
- }
-
- private BigBlock MakeDual(BigBlock bb, bool HalfDualise)
- {
- // Not sure what to do about the transfer command
-
- BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
-
- foreach (Cmd c in bb.simpleCmds)
- {
- if (c is CallCmd)
- {
- CallCmd Call = c as CallCmd;
-
- List<Expr> newIns = new List<Expr>();
- foreach (Expr e in Call.Ins)
- {
- newIns.Add(new VariableDualiser(1).VisitExpr(e));
- }
- if (!HalfDualise && !HalfDualisedProcedureNames.Contains(Call.callee))
- {
- foreach (Expr e in Call.Ins)
- {
- newIns.Add(new VariableDualiser(2).VisitExpr(e));
- }
- }
-
- List<IdentifierExpr> newOuts = new List<IdentifierExpr>();
- foreach (IdentifierExpr ie in Call.Outs)
- {
- newOuts.Add(new VariableDualiser(1).VisitIdentifierExpr(ie.Clone() as IdentifierExpr) as IdentifierExpr);
- }
- if (!HalfDualise && !HalfDualisedProcedureNames.Contains(Call.callee))
+ else
{
- foreach (IdentifierExpr ie in Call.Outs)
- {
- newOuts.Add(new VariableDualiser(2).VisitIdentifierExpr(ie.Clone() as IdentifierExpr) as IdentifierExpr);
- }
+ predicateExpr = Expr.True;
}
- CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, newIns, newOuts);
-
- result.simpleCmds.Add(NewCallCmd);
- }
- else if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
-
- Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
-
- List<AssignLhs> newLhss = new List<AssignLhs>();
-
- newLhss.Add(new VariableDualiser(1).Visit(assign.Lhss.ElementAt(0).Clone() as AssignLhs) as AssignLhs);
-
- if (!HalfDualise)
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in proc.Requires)
{
- newLhss.Add(new VariableDualiser(2).Visit(assign.Lhss.ElementAt(0).Clone() as AssignLhs) as AssignLhs);
+ newRequires.Add(new Requires(r.Free, Predicator.ProcessEnabledIntrinsics(r.Condition, predicateExpr)));
}
+ proc.Requires = newRequires;
- List<Expr> newRhss = new List<Expr>();
-
- newRhss.Add(new VariableDualiser(1).VisitExpr(assign.Rhss.ElementAt(0).Clone() as Expr));
-
- if (!HalfDualise)
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in proc.Ensures)
{
- newRhss.Add(new VariableDualiser(2).VisitExpr(assign.Rhss.ElementAt(0).Clone() as Expr));
+ newEnsures.Add(new Ensures(e.Free, Predicator.ProcessEnabledIntrinsics(e.Condition, predicateExpr)));
}
+ proc.Ensures = newEnsures;
- AssignCmd newAssign = new AssignCmd(assign.tok, newLhss, newRhss);
-
- result.simpleCmds.Add(newAssign);
- }
- else if (c is HavocCmd)
- {
- HavocCmd havoc = c as HavocCmd;
- Debug.Assert(havoc.Vars.Length == 1);
-
- HavocCmd newHavoc;
-
- if (HalfDualise)
- {
- newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
- (IdentifierExpr)(new VariableDualiser(1).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr))
- }));
- }
- else
- {
- newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
- (IdentifierExpr)(new VariableDualiser(1).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr)),
- (IdentifierExpr)(new VariableDualiser(2).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr))
- }));
- }
- result.simpleCmds.Add(newHavoc);
- }
- else if (c is AssertCmd)
- {
- AssertCmd ass = c as AssertCmd;
- if (HalfDualise)
- {
- result.simpleCmds.Add(new AssertCmd(c.tok, new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr)));
- }
- else
- {
- result.simpleCmds.Add(new AssertCmd(c.tok, Expr.And(new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr), new VariableDualiser(2).VisitExpr(ass.Expr.Clone() as Expr))));
- }
}
- else if (c is AssumeCmd)
- {
- AssumeCmd ass = c as AssumeCmd;
- if (HalfDualise)
- {
- result.simpleCmds.Add(new AssumeCmd(c.tok, new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr)));
- }
- else
- {
- result.simpleCmds.Add(new AssumeCmd(c.tok, Expr.And(new VariableDualiser(1).VisitExpr(ass.Expr.Clone() as Expr), new VariableDualiser(2).VisitExpr(ass.Expr.Clone() as Expr))));
- }
- }
- else
- {
- Debug.Assert(false);
- }
- }
-
- 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));
- }
- else
- {
- Debug.Assert(bb.ec == null);
- }
-
- return result;
-
- }
-
- private void MakeDualLocalVariables(Implementation impl, bool HalfDualise)
- {
- VariableSeq NewLocalVars = new VariableSeq();
-
- foreach (LocalVariable v in impl.LocVars)
- {
- NewLocalVars.Add(new LocalVariable(v.tok, new TypedIdent(v.tok, v.Name + "$1", v.TypedIdent.Type)));
- if (!HalfDualise)
+ else if (d is Implementation)
{
- NewLocalVars.Add(new LocalVariable(v.tok, new TypedIdent(v.tok, v.Name + "$2", v.TypedIdent.Type)));
+ Implementation impl = d as Implementation;
+ new Predicator(this, !uniformityAnalyser.IsUniform(impl.Name)).transform
+ (impl);
}
}
- impl.LocVars = NewLocalVars;
}
-
private void CheckKernelParameters()
{
if (KernelProcedure.OutParams.Length != 0)
@@ -2210,189 +2020,171 @@ namespace GPUVerify
Error(BarrierProcedure, "Barrier procedure must not return any results");
}
- FindNonLocalVariables(Program);
+ if (!FindNonLocalVariables(Program))
+ {
+ return ErrorCount;
+ }
CheckKernelImplementation();
if (!KernelHasIdX())
{
- Error(KernelProcedure.tok, "Kernel must declare global constant '" + _X_name + "'");
+ MissingKernelAttributeError(LOCAL_ID_X_STRING);
}
if (!KernelHasGroupSizeX())
{
- Error(KernelProcedure.tok, "Kernel must declare global constant '" + _GROUP_SIZE_X_name + "'");
+ MissingKernelAttributeError(GROUP_SIZE_X_STRING);
}
if (!KernelHasNumGroupsX())
{
- Error(KernelProcedure.tok, "Kernel must declare global constant '" + _NUM_GROUPS_X_name + "'");
+ MissingKernelAttributeError(NUM_GROUPS_X_STRING);
}
if (!KernelHasGroupIdX())
{
- Error(KernelProcedure.tok, "Kernel must declare global constant '" + _GROUP_X_name + "'");
+ MissingKernelAttributeError(GROUP_ID_X_STRING);
}
- if (KernelHasIdY() || KernelHasGroupSizeY() || KernelHasNumGroupsY() || KernelHasGroupIdY())
+ if (!KernelHasIdY())
{
+ MissingKernelAttributeError(LOCAL_ID_Y_STRING);
+ }
- if (!KernelHasIdY())
- {
- Error(KernelProcedure.tok, "2D kernel must declare global constant '" + _Y_name + "'");
- }
-
- if (!KernelHasGroupSizeY())
- {
- Error(KernelProcedure.tok, "2D kernel must declare global constant '" + _GROUP_SIZE_Y_name + "'");
- }
-
- if (!KernelHasNumGroupsY())
- {
- Error(KernelProcedure.tok, "2D kernel must declare global constant '" + _NUM_GROUPS_Y_name + "'");
- }
-
- if (!KernelHasGroupIdY())
- {
- Error(KernelProcedure.tok, "2D kernel must declare global constant '" + _GROUP_Y_name + "'");
- }
-
+ if (!KernelHasGroupSizeY())
+ {
+ MissingKernelAttributeError(GROUP_SIZE_Y_STRING);
}
- if (KernelHasIdZ() || KernelHasGroupSizeZ() || KernelHasNumGroupsZ() || KernelHasGroupIdZ())
+ if (!KernelHasNumGroupsY())
{
+ MissingKernelAttributeError(NUM_GROUPS_Y_STRING);
+ }
- if (!KernelHasIdY())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _Y_name + "'");
- }
+ if (!KernelHasGroupIdY())
+ {
+ MissingKernelAttributeError(GROUP_ID_Y_STRING);
+ }
- if (!KernelHasGroupSizeY())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _GROUP_SIZE_Y_name + "'");
- }
+ if (!KernelHasIdY())
+ {
+ MissingKernelAttributeError(LOCAL_ID_Y_STRING);
+ }
- if (!KernelHasNumGroupsY())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _NUM_GROUPS_Y_name + "'");
- }
+ if (!KernelHasGroupSizeY())
+ {
+ MissingKernelAttributeError(GROUP_SIZE_Y_STRING);
+ }
- if (!KernelHasGroupIdY())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _GROUP_Y_name + "'");
- }
+ if (!KernelHasNumGroupsY())
+ {
+ MissingKernelAttributeError(NUM_GROUPS_Y_STRING);
+ }
- if (!KernelHasIdZ())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _Z_name + "'");
- }
+ if (!KernelHasGroupIdY())
+ {
+ MissingKernelAttributeError(GROUP_ID_Y_STRING);
+ }
- if (!KernelHasGroupSizeZ())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _GROUP_SIZE_Z_name + "'");
- }
+ if (!KernelHasIdZ())
+ {
+ MissingKernelAttributeError(LOCAL_ID_Z_STRING);
+ }
- if (!KernelHasNumGroupsZ())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _NUM_GROUPS_Z_name + "'");
- }
+ if (!KernelHasGroupSizeZ())
+ {
+ MissingKernelAttributeError(GROUP_SIZE_Z_STRING);
+ }
- if (!KernelHasGroupIdZ())
- {
- Error(KernelProcedure.tok, "3D kernel must declare global constant '" + _GROUP_Z_name + "'");
- }
+ if (!KernelHasNumGroupsZ())
+ {
+ MissingKernelAttributeError(NUM_GROUPS_Z_STRING);
+ }
+ if (!KernelHasGroupIdZ())
+ {
+ MissingKernelAttributeError(GROUP_ID_Z_STRING);
}
return ErrorCount;
}
+ private void MissingKernelAttributeError(string attribute)
+ {
+ Error(KernelProcedure.tok, "Kernel must declare global constant marked with attribute ':" + attribute + "'");
+ }
+
public static bool IsThreadLocalIdConstant(Variable variable)
{
- return variable is Constant && (variable.Name.Equals(_X_name) || variable.Name.Equals(_Y_name) || variable.Name.Equals(_Z_name));
+ return variable is Constant && (
+ QKeyValue.FindBoolAttribute(variable.Attributes, LOCAL_ID_X_STRING) ||
+ QKeyValue.FindBoolAttribute(variable.Attributes, LOCAL_ID_Y_STRING) ||
+ QKeyValue.FindBoolAttribute(variable.Attributes, LOCAL_ID_Z_STRING));
}
- internal HashSet<string> GetProceduresThatIndirectlyCallProcedure(string Name)
+ internal void AddCandidateInvariant(WhileCmd wc, Expr e)
{
- HashSet<string> MayCallProc = new HashSet<string>();
- MayCallProc.Add(Name);
- bool changed = true;
- while (changed)
+ Constant ExistentialBooleanConstant = MakeExistentialBoolean(wc.tok);
+ IdentifierExpr ExistentialBoolean = new IdentifierExpr(wc.tok, ExistentialBooleanConstant);
+ wc.Invariants.Add(new AssertCmd(wc.tok, Expr.Imp(ExistentialBoolean, e)));
+ Program.TopLevelDeclarations.Add(ExistentialBooleanConstant);
+ }
+
+ internal Implementation GetImplementation(string procedureName)
+ {
+ foreach (Declaration D in Program.TopLevelDeclarations)
{
- changed = false;
- foreach (Declaration d in Program.TopLevelDeclarations)
+ if (D is Implementation && ((D as Implementation).Name == procedureName))
{
- if (d is Implementation && !MayCallProc.Contains((d as Implementation).Name))
- {
- HashSet<string> CalledProcedures = GetCalledProcedures(d as Implementation);
- foreach (string p in CalledProcedures)
- {
- if (MayCallProc.Contains(p))
- {
- changed = true;
- MayCallProc.Add((d as Implementation).Name);
- break;
- }
- }
- }
+ return D as Implementation;
}
}
- return MayCallProc;
+ Debug.Assert(false);
+ return null;
}
- private HashSet<string> GetCalledProcedures(Implementation impl)
- {
- HashSet<string> result = new HashSet<string>();
- return GetCalledProcedures(impl.StructuredStmts, result);
- }
- private HashSet<string> GetCalledProcedures(StmtList statements, HashSet<string> result)
+ internal bool ContainsBarrierCall(StmtList stmtList)
{
- foreach (BigBlock bb in statements.BigBlocks)
+ foreach (BigBlock bb in stmtList.BigBlocks)
{
- foreach (Cmd c in bb.simpleCmds)
+ if (ContainsBarrierCall(bb))
{
- if (c is CallCmd)
- {
- result.Add((c as CallCmd).callee);
- }
+ return true;
}
+ }
+ return false;
+ }
- if (bb.ec is WhileCmd)
- {
- result = GetCalledProcedures((bb.ec as WhileCmd).Body, result);
- }
- else if (bb.ec is IfCmd)
+ private bool ContainsBarrierCall(BigBlock bb)
+ {
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is CallCmd && ((c as CallCmd).Proc == BarrierProcedure))
{
- result = GetCalledProcedures((bb.ec as IfCmd).thn, result);
- Debug.Assert((bb.ec as IfCmd).elseIf == null);
- if ((bb.ec as IfCmd).elseBlock != null)
- {
- result = GetCalledProcedures((bb.ec as IfCmd).elseBlock, result);
- }
+ return true;
}
}
- return result;
- }
+ if (bb.ec is WhileCmd)
+ {
+ return ContainsBarrierCall((bb.ec as WhileCmd).Body);
+ }
- internal void ExtendModifiesSetOfProcedures(IdentifierExprSeq ModifiedVariables, HashSet<string> Procedures)
- {
- foreach (Declaration d in Program.TopLevelDeclarations)
+ if (bb.ec is IfCmd)
{
- if (d is Procedure && Procedures.Contains((d as Procedure).Name))
+ Debug.Assert((bb.ec as IfCmd).elseIf == null);
+ if (ContainsBarrierCall((bb.ec as IfCmd).thn))
{
- Procedure P = d as Procedure;
- foreach (IdentifierExpr e in ModifiedVariables)
- {
- if (!GPUVerifier.ModifiesSetContains(P.Modifies, e))
- {
- P.Modifies.Add(e);
- }
- }
+ return true;
}
+ return (bb.ec as IfCmd).elseBlock != null && ContainsBarrierCall((bb.ec as IfCmd).elseBlock);
}
+
+ return false;
}
+
}
}
diff --git a/Source/GPUVerify/GPUVerify.csproj b/Source/GPUVerify/GPUVerify.csproj
index 6956b973..1109ebb7 100644
--- a/Source/GPUVerify/GPUVerify.csproj
+++ b/Source/GPUVerify/GPUVerify.csproj
@@ -104,7 +104,19 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AccessCollector.cs" />
+ <Compile Include="AccessInvariantProcessor.cs" />
<Compile Include="AccessRecord.cs" />
+ <Compile Include="AsymmetricExpressionFinder.cs" />
+ <Compile Include="EnsureDisabledThreadHasNoEffectInstrumenter.cs" />
+ <Compile Include="KernelDualiser.cs" />
+ <Compile Include="LiveVariableAnalyser.cs" />
+ <Compile Include="LoopInvariantGenerator.cs" />
+ <Compile Include="MayBePowerOfTwoAnalyser.cs" />
+ <Compile Include="MayBeTidAnalyser.cs" />
+ <Compile Include="MayBeTidPlusConstantAnalyser.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" />
@@ -121,7 +133,10 @@
<Compile Include="RaceInstrumenterBase.cs" />
<Compile Include="ReadCollector.cs" />
<Compile Include="SetEncodingRaceInstrumenter.cs" />
+ <Compile Include="UniformExpressionAnalysisVisitor.cs" />
+ <Compile Include="UniformityAnalyser.cs" />
<Compile Include="VariableDualiser.cs" />
+ <Compile Include="VariablesOccurringInExpressionVisitor.cs" />
<Compile Include="WriteCollector.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/Source/GPUVerify/IRaceInstrumenter.cs b/Source/GPUVerify/IRaceInstrumenter.cs
index 9a1c0d8c..f1b877a5 100644
--- a/Source/GPUVerify/IRaceInstrumenter.cs
+++ b/Source/GPUVerify/IRaceInstrumenter.cs
@@ -8,7 +8,7 @@ namespace GPUVerify
{
interface IRaceInstrumenter
{
- void AddRaceCheckingCandidateInvariants(WhileCmd wc);
+ void AddRaceCheckingCandidateInvariants(Implementation impl, WhileCmd wc);
void AddKernelPrecondition();
// Summary:
@@ -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/KernelDualiser.cs b/Source/GPUVerify/KernelDualiser.cs
new file mode 100644
index 00000000..6f6d7184
--- /dev/null
+++ b/Source/GPUVerify/KernelDualiser.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class KernelDualiser
+ {
+ private GPUVerifier verifier;
+
+ public KernelDualiser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ }
+
+ private string procName = null;
+
+ internal void DualiseProcedure(Microsoft.Boogie.Procedure proc)
+ {
+ procName = proc.Name;
+
+ bool HalfDualise = verifier.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();
+ foreach (IdentifierExpr v in proc.Modifies)
+ {
+ NewModifies.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr((IdentifierExpr)v.Clone()));
+ }
+
+ if (!HalfDualise)
+ {
+ foreach (IdentifierExpr v in proc.Modifies)
+ {
+ if (!CommandLineOptions.Symmetry || !verifier.HalfDualisedVariableNames.Contains(v.Name))
+ {
+ NewModifies.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr((IdentifierExpr)v.Clone()));
+ }
+ }
+ }
+ proc.Modifies = NewModifies;
+
+ procName = null;
+ }
+
+ private RequiresSeq DualiseRequires(RequiresSeq requiresSeq)
+ {
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in requiresSeq)
+ {
+ newRequires.Add(new Requires(r.Free, new VariableDualiser(1, verifier.uniformityAnalyser, procName).
+ VisitExpr(r.Condition.Clone() as Expr)));
+
+ if ((!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(r.Condition))
+ && !verifier.uniformityAnalyser.IsUniform(procName, r.Condition))
+ {
+ newRequires.Add(new Requires(r.Free, new VariableDualiser(2, verifier.uniformityAnalyser, procName).
+ VisitExpr(r.Condition.Clone() as Expr)));
+ }
+ }
+ return newRequires;
+ }
+
+ private EnsuresSeq DualiseEnsures(EnsuresSeq ensuresSeq)
+ {
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq)
+ {
+ newEnsures.Add(new Ensures(e.Free, new VariableDualiser(1, verifier.uniformityAnalyser, procName).
+ VisitExpr(e.Condition.Clone() as Expr)));
+ if ((!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(e.Condition))
+ && !verifier.uniformityAnalyser.IsUniform(procName, e.Condition))
+ {
+ newEnsures.Add(new Ensures(e.Free, new VariableDualiser(2, verifier.uniformityAnalyser, procName).
+ VisitExpr(e.Condition.Clone() as Expr)));
+ }
+ }
+ return newEnsures;
+ }
+
+
+ private StmtList MakeDual(StmtList stmtList, bool HalfDualise)
+ {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks)
+ {
+ result.BigBlocks.Add(MakeDual(bodyBlock, HalfDualise));
+ }
+
+ return result;
+ }
+
+ private BigBlock MakeDual(BigBlock bb, bool HalfDualise)
+ {
+ // Not sure what to do about the transfer command
+
+ BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is CallCmd)
+ {
+ CallCmd Call = c as CallCmd;
+
+ List<Expr> uniformNewIns = new List<Expr>();
+ List<Expr> nonUniformNewIns = new List<Expr>();
+ for (int i = 0; i < Call.Ins.Count; i++)
+ {
+ if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i)))
+ {
+ uniformNewIns.Add(Call.Ins[i]);
+ }
+ else
+ {
+ nonUniformNewIns.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
+ }
+ }
+ if (!HalfDualise && !verifier.HalfDualisedProcedureNames.Contains(Call.callee))
+ {
+ for (int i = 0; i < Call.Ins.Count; i++)
+ {
+ if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i))))
+ {
+ nonUniformNewIns.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
+ }
+ }
+ }
+
+ List<Expr> newIns = uniformNewIns;
+ newIns.AddRange(nonUniformNewIns);
+
+ List<IdentifierExpr> uniformNewOuts = new List<IdentifierExpr>();
+ List<IdentifierExpr> nonUniformNewOuts = new List<IdentifierExpr>();
+ for (int i = 0; i < Call.Outs.Count; i++)
+ {
+ if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i)))
+ {
+ uniformNewOuts.Add(Call.Outs[i]);
+ }
+ else
+ {
+ nonUniformNewOuts.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
+ }
+
+ }
+ if (!HalfDualise && !verifier.HalfDualisedProcedureNames.Contains(Call.callee))
+ {
+ for (int i = 0; i < Call.Outs.Count; i++)
+ {
+ if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i))))
+ {
+ nonUniformNewOuts.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
+ }
+ }
+ }
+
+ List<IdentifierExpr> newOuts = uniformNewOuts;
+ newOuts.AddRange(nonUniformNewOuts);
+
+ CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, newIns, newOuts);
+
+ NewCallCmd.Proc = Call.Proc;
+
+ result.simpleCmds.Add(NewCallCmd);
+ }
+ else if (c is AssignCmd)
+ {
+ AssignCmd assign = c as AssignCmd;
+
+ Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
+
+ if (assign.Lhss[0] is SimpleAssignLhs &&
+ verifier.uniformityAnalyser.IsUniform(procName, (assign.Lhss[0] as SimpleAssignLhs).AssignedVariable.Name))
+ {
+ result.simpleCmds.Add(assign);
+ }
+ else
+ {
+ List<AssignLhs> newLhss = new List<AssignLhs>();
+ List<Expr> newRhss = new List<Expr>();
+
+ newLhss.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).Visit(assign.Lhss.ElementAt(0).Clone() as AssignLhs) as AssignLhs);
+
+ if (!HalfDualise)
+ {
+ newLhss.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).Visit(assign.Lhss.ElementAt(0).Clone() as AssignLhs) as AssignLhs);
+ }
+
+ newRhss.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(assign.Rhss.ElementAt(0).Clone() as Expr));
+
+ if (!HalfDualise)
+ {
+ newRhss.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(assign.Rhss.ElementAt(0).Clone() as Expr));
+ }
+
+ AssignCmd newAssign = new AssignCmd(assign.tok, newLhss, newRhss);
+
+ result.simpleCmds.Add(newAssign);
+ }
+ }
+ else if (c is HavocCmd)
+ {
+ HavocCmd havoc = c as HavocCmd;
+ Debug.Assert(havoc.Vars.Length == 1);
+
+ HavocCmd newHavoc;
+
+ if (HalfDualise)
+ {
+ newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
+ (IdentifierExpr)(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr))
+ }));
+ }
+ else
+ {
+ newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
+ (IdentifierExpr)(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr)),
+ (IdentifierExpr)(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr))
+ }));
+ }
+ result.simpleCmds.Add(newHavoc);
+ }
+ else if (c is AssertCmd)
+ {
+ AssertCmd ass = c as AssertCmd;
+ if (HalfDualise || ContainsAsymmetricExpression(ass.Expr))
+ {
+ result.simpleCmds.Add(new AssertCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
+ }
+ else
+ {
+ result.simpleCmds.Add(new AssertCmd(c.tok, Expr.And(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr))));
+ }
+ }
+ else if (c is AssumeCmd)
+ {
+ AssumeCmd ass = c as AssumeCmd;
+ if (HalfDualise || ContainsAsymmetricExpression(ass.Expr))
+ {
+ result.simpleCmds.Add(new AssumeCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
+ }
+ else
+ {
+ result.simpleCmds.Add(new AssumeCmd(c.tok, Expr.And(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr))));
+ }
+ }
+ else
+ {
+ Debug.Assert(false);
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ Expr NewGuard;
+ if (verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as WhileCmd).Guard))
+ {
+ NewGuard = (bb.ec as WhileCmd).Guard;
+ }
+ else
+ {
+ NewGuard = Expr.Or(Dualise((bb.ec as WhileCmd).Guard, 1),
+ Dualise((bb.ec as WhileCmd).Guard, 2)
+ );
+ }
+ result.ec = new WhileCmd(bb.ec.tok,
+ NewGuard,
+ MakeDualInvariants((bb.ec as WhileCmd).Invariants), MakeDual((bb.ec as WhileCmd).Body, HalfDualise));
+ }
+ else if (bb.ec is IfCmd)
+ {
+ Debug.Assert(verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as IfCmd).Guard));
+ result.ec = new IfCmd(bb.ec.tok,
+ (bb.ec as IfCmd).Guard,
+ MakeDual((bb.ec as IfCmd).thn, HalfDualise),
+ null,
+ (bb.ec as IfCmd).elseBlock == null ? null : MakeDual((bb.ec as IfCmd).elseBlock, HalfDualise));
+
+ }
+
+ return result;
+
+ }
+
+ private List<PredicateCmd> MakeDualInvariants(List<PredicateCmd> originalInvariants)
+ {
+ List<PredicateCmd> result = new List<PredicateCmd>();
+ foreach (PredicateCmd p in originalInvariants)
+ {
+ result.Add(new AssertCmd(p.tok,
+ Dualise(p.Expr, 1)));
+ if ((!CommandLineOptions.Symmetry || !ContainsAsymmetricExpression(p.Expr))
+ && !verifier.uniformityAnalyser.IsUniform(procName, p.Expr))
+ {
+ result.Add(new AssertCmd(p.tok, Dualise(p.Expr, 2)));
+ }
+ }
+
+ return result;
+ }
+
+ private void MakeDualLocalVariables(Implementation impl, bool HalfDualise)
+ {
+ VariableSeq NewLocalVars = new VariableSeq();
+
+ foreach (LocalVariable v in impl.LocVars)
+ {
+ if (verifier.uniformityAnalyser.IsUniform(procName, v.Name))
+ {
+ NewLocalVars.Add (v);
+ }
+ else
+ {
+ NewLocalVars.Add(
+ new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
+ if (!HalfDualise)
+ {
+ NewLocalVars.Add(
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
+ }
+ }
+ }
+
+ impl.LocVars = NewLocalVars;
+ }
+
+ private bool ContainsAsymmetricExpression(Expr expr)
+ {
+ AsymmetricExpressionFinder finder = new AsymmetricExpressionFinder();
+ finder.VisitExpr(expr);
+ return finder.foundAsymmetricExpr();
+ }
+
+ private VariableSeq DualiseVariableSequence(VariableSeq seq, bool HalfDualise)
+ {
+ VariableSeq uniform = new VariableSeq();
+ VariableSeq nonuniform = new VariableSeq();
+
+ foreach (Variable v in seq)
+ {
+ if (verifier.uniformityAnalyser.IsUniform(procName, v.Name))
+ {
+ uniform.Add(v);
+ }
+ else
+ {
+ nonuniform.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
+ }
+ }
+
+ if (!HalfDualise)
+ {
+ foreach (Variable v in seq)
+ {
+ if (!verifier.uniformityAnalyser.IsUniform(procName, v.Name))
+ {
+ nonuniform.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
+ }
+ }
+ }
+
+ VariableSeq result = uniform;
+ result.AddRange(nonuniform);
+ return result;
+ }
+
+
+ internal void DualiseImplementation(Implementation impl)
+ {
+ procName = impl.Name;
+
+ bool HalfDualise = verifier.HalfDualisedProcedureNames.Contains(impl.Name);
+
+ impl.InParams = DualiseVariableSequence(impl.InParams, HalfDualise);
+ impl.OutParams = DualiseVariableSequence(impl.OutParams, HalfDualise);
+ MakeDualLocalVariables(impl, HalfDualise);
+ impl.StructuredStmts = MakeDual(impl.StructuredStmts, HalfDualise);
+
+ procName = null;
+ }
+
+ private Expr Dualise(Expr expr, int thread)
+ {
+ return new VariableDualiser(thread, verifier.uniformityAnalyser, procName).VisitExpr(expr.Clone() as Expr);
+ }
+
+ }
+
+
+}
diff --git a/Source/GPUVerify/LiveVariableAnalyser.cs b/Source/GPUVerify/LiveVariableAnalyser.cs
new file mode 100644
index 00000000..61ce851f
--- /dev/null
+++ b/Source/GPUVerify/LiveVariableAnalyser.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class LiveVariableAnalyser
+ {
+ private GPUVerifier verifier;
+
+ // Maps procedure -> loop -> set of variables live at the loop head
+ private Dictionary<string, Dictionary<string, HashSet<string>>> liveVariableInfo;
+
+ public LiveVariableAnalyser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ this.liveVariableInfo = new Dictionary<string, Dictionary<string, HashSet<string>>>();
+ }
+
+ internal void Analyse()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation impl = D as Implementation;
+
+ liveVariableInfo[impl.Name] = new Dictionary<string, HashSet<string>>();
+
+ LiveVariableAnalysis.ComputeLiveVariables(impl);
+
+ Analyse(impl.StructuredStmts, impl);
+
+ }
+ }
+ }
+
+ private void Analyse(StmtList stmtList, Implementation impl)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(bb, impl);
+ }
+ }
+
+ private void Analyse(BigBlock bb, Implementation impl)
+ {
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+
+ Debug.Assert(wc.Invariants.Count >= 1);
+
+ string wcLabel = wc.Invariants[0].Attributes.Key;
+
+ Debug.Assert (wcLabel.Contains("loophead_"));
+
+ liveVariableInfo[impl.Name][wcLabel] = new HashSet<string>();
+
+ Block wcStartBlock = GetBlockForWhile(wc, impl);
+
+ Debug.Assert(wcStartBlock != null);
+
+// Debug.Assert(wcStartBlock.liveVarsBefore != null);
+
+ if (wcStartBlock.liveVarsBefore == null)
+ {
+
+ }
+ else
+ {
+
+ foreach (Variable v in impl.LocVars)
+ {
+ if (wcStartBlock.IsLive(v))
+ {
+ liveVariableInfo[impl.Name][wcLabel].Add(v.Name);
+ }
+ }
+ }
+
+ Analyse(wc.Body, impl);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ Analyse((bb.ec as IfCmd).thn, impl);
+ if ((bb.ec as IfCmd).elseBlock != null)
+ {
+ Analyse((bb.ec as IfCmd).elseBlock, impl);
+ }
+ Debug.Assert((bb.ec as IfCmd).elseIf == null);
+ }
+
+ }
+
+ private Block GetBlockForWhile(WhileCmd wc, Implementation impl)
+ {
+ string whileLoopIdentifier =
+ wc.Invariants[0].Attributes.Key;
+
+ foreach (Block b in impl.Blocks)
+ {
+ if (b.Cmds.Length > 0 && b.Cmds[0] is AssertCmd)
+ {
+ AssertCmd ass = b.Cmds[0] as AssertCmd;
+ if (ass.Attributes != null)
+ {
+ if (ass.Attributes.Key.Equals(whileLoopIdentifier))
+ {
+ return b;
+ }
+ }
+ }
+ }
+
+ Debug.Assert(false);
+
+ return null;
+ }
+ }
+}
diff --git a/Source/GPUVerify/LoopInvariantGenerator.cs b/Source/GPUVerify/LoopInvariantGenerator.cs
new file mode 100644
index 00000000..38723691
--- /dev/null
+++ b/Source/GPUVerify/LoopInvariantGenerator.cs
@@ -0,0 +1,323 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+ class LoopInvariantGenerator
+ {
+ private GPUVerifier verifier;
+ private Implementation Impl;
+
+ public LoopInvariantGenerator(GPUVerifier verifier, Implementation Impl)
+ {
+ this.verifier = verifier;
+ this.Impl = Impl;
+ }
+
+ internal void instrument(List<Expr> UserSuppliedInvariants)
+ {
+ HashSet<Variable> LocalVars = new HashSet<Variable>();
+ foreach (Variable v in Impl.LocVars)
+ {
+ LocalVars.Add(v);
+ }
+ foreach (Variable v in Impl.InParams)
+ {
+ LocalVars.Add(v);
+ }
+ foreach (Variable v in Impl.OutParams)
+ {
+ LocalVars.Add(v);
+ }
+
+ AddCandidateInvariants(Impl.StructuredStmts, LocalVars, UserSuppliedInvariants, Impl);
+
+ }
+
+ private void AddEqualityCandidateInvariant(WhileCmd wc, string LoopPredicate, Variable v)
+ {
+ verifier.AddCandidateInvariant(wc,
+ Expr.Eq(
+ new IdentifierExpr(wc.tok, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(wc.tok, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
+ ));
+ }
+
+ private void AddPredicatedEqualityCandidateInvariant(WhileCmd wc, string LoopPredicate, Variable v)
+ {
+ verifier.AddCandidateInvariant(wc, Expr.Imp(
+ Expr.And(
+ new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
+ new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
+ ),
+ Expr.Eq(
+ new IdentifierExpr(wc.tok, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(wc.tok, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
+ )));
+ }
+
+
+ private void AddBarrierDivergenceCandidates(HashSet<Variable> LocalVars, Implementation Impl, WhileCmd wc)
+ {
+
+ if (CommandLineOptions.AddDivergenceCandidatesOnlyToBarrierLoops)
+ {
+ if (!verifier.ContainsBarrierCall(wc.Body))
+ {
+ return;
+ }
+ }
+
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, wc.Guard))
+ {
+ return;
+ }
+
+ Debug.Assert(wc.Guard is NAryExpr);
+ Debug.Assert((wc.Guard as NAryExpr).Args.Length == 2);
+ Debug.Assert((wc.Guard as NAryExpr).Args[0] is IdentifierExpr);
+ string LoopPredicate = ((wc.Guard as NAryExpr).Args[0] as IdentifierExpr).Name;
+
+ LoopPredicate = LoopPredicate.Substring(0, LoopPredicate.IndexOf('$'));
+
+ verifier.AddCandidateInvariant(wc, Expr.Eq(
+ // Int type used here, but it doesn't matter as we will print and then re-parse the program
+ new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
+ new IdentifierExpr(wc.tok, new LocalVariable(wc.tok, new TypedIdent(wc.tok, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
+ ));
+
+ foreach (Variable v in LocalVars)
+ {
+
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, v.Name))
+ {
+ continue;
+ }
+
+ string lv = GPUVerifier.StripThreadIdentifier(v.Name);
+
+ if (GPUVerifier.IsPredicateOrTemp(lv))
+ {
+ continue;
+ }
+
+ if (CommandLineOptions.AddDivergenceCandidatesOnlyIfModified)
+ {
+ if (!verifier.ContainsNamedVariable(GetModifiedVariables(wc.Body),
+ GPUVerifier.StripThreadIdentifier(v.Name)))
+ {
+ continue;
+ }
+ }
+
+ AddEqualityCandidateInvariant(wc, LoopPredicate, new LocalVariable(wc.tok, new TypedIdent(wc.tok, lv, Microsoft.Boogie.Type.Int)));
+
+ if (Impl != verifier.KernelImplementation)
+ {
+ AddPredicatedEqualityCandidateInvariant(wc, LoopPredicate, new LocalVariable(wc.tok, new TypedIdent(wc.tok, lv, Microsoft.Boogie.Type.Int)));
+ }
+ }
+
+ if (!CommandLineOptions.FullAbstraction && CommandLineOptions.ArrayEqualities)
+ {
+ foreach (Variable v in verifier.NonLocalState.getAllNonLocalVariables())
+ {
+ AddEqualityCandidateInvariant(wc, LoopPredicate, v);
+ }
+ }
+ }
+
+ private void AddCandidateInvariants(StmtList stmtList, HashSet<Variable> LocalVars, List<Expr> UserSuppliedInvariants, Implementation Impl)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ AddCandidateInvariants(bb, LocalVars, UserSuppliedInvariants, Impl);
+ }
+ }
+
+ private void AddCandidateInvariants(BigBlock bb, HashSet<Variable> LocalVars, List<Expr> UserSuppliedInvariants, Implementation Impl)
+ {
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+
+ AddBarrierDivergenceCandidates(LocalVars, Impl, wc);
+
+ AddLoopVariableBoundsCandidateInvariants(Impl, wc);
+
+ AddPowerOfTwoCandidateInvariants(Impl, wc);
+
+ verifier.RaceInstrumenter.AddRaceCheckingCandidateInvariants(Impl, wc);
+
+ AddUserSuppliedInvariants(wc, UserSuppliedInvariants, Impl);
+
+ AddCandidateInvariants(wc.Body, LocalVars, UserSuppliedInvariants, Impl);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ AddCandidateInvariants(ifCmd.thn, LocalVars, UserSuppliedInvariants, Impl);
+ if (ifCmd.elseBlock != null)
+ {
+ AddCandidateInvariants(ifCmd.elseBlock, LocalVars, UserSuppliedInvariants, Impl);
+ }
+
+ }
+ else
+ {
+ Debug.Assert(bb.ec == null);
+ }
+ }
+
+ private void AddPowerOfTwoCandidateInvariants(Implementation Impl, WhileCmd wc)
+ {
+ foreach (Variable v in Impl.LocVars)
+ {
+ string basicName = GPUVerifier.StripThreadIdentifier(v.Name);
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, basicName))
+ {
+ if (verifier.mayBePowerOfTwoAnalyser.MayBePowerOfTwo(Impl.Name, basicName))
+ {
+ if (verifier.ContainsNamedVariable(GetModifiedVariables(wc.Body), basicName))
+ {
+ verifier.AddCandidateInvariant(wc, MakePowerOfTwoExpr(v));
+ for (int i = (1 << 30); i > 0; i >>= 1)
+ {
+ verifier.AddCandidateInvariant(wc,
+ GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LT",
+ new IdentifierExpr(v.tok, v),
+ new LiteralExpr(v.tok, BigNum.FromInt(i), 32)));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private Expr MakePowerOfTwoExpr(Variable v)
+ {
+ Expr result = null;
+ for (int i = 1 << 30; i > 0; i >>= 1)
+ {
+ Expr eq = Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(i), 32));
+ result = (result == null ? eq : Expr.Or(eq, result));
+ }
+
+ return Expr.Or(Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(0), 32)), result);
+ }
+
+ private void AddLoopVariableBoundsCandidateInvariants(Implementation Impl, WhileCmd wc)
+ {
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, wc.Guard))
+ {
+ VariablesOccurringInExpressionVisitor visitor = new VariablesOccurringInExpressionVisitor();
+ visitor.VisitExpr(wc.Guard);
+ foreach (Variable v in visitor.GetVariables())
+ {
+ if (!verifier.ContainsNamedVariable(GetModifiedVariables(wc.Body), v.Name))
+ {
+ continue;
+ }
+
+ if (IsBVType (v.TypedIdent.Type))
+ {
+ int BVWidth = (v.TypedIdent.Type as BvType).Bits;
+
+ verifier.AddCandidateInvariant(wc,
+ GPUVerifier.MakeBitVectorBinaryBoolean("BV" + BVWidth + "_GEQ",
+ new IdentifierExpr(v.tok, v),
+ new LiteralExpr(v.tok, BigNum.FromInt(0), BVWidth)));
+ }
+ }
+ }
+ }
+
+ private bool IsBVType(Microsoft.Boogie.Type type)
+ {
+ return type.Equals(Microsoft.Boogie.Type.GetBvType(32))
+ || type.Equals(Microsoft.Boogie.Type.GetBvType(16))
+ || type.Equals(Microsoft.Boogie.Type.GetBvType(8));
+ }
+
+ private void AddUserSuppliedInvariants(WhileCmd wc, List<Expr> UserSuppliedInvariants, Implementation Impl)
+ {
+ foreach (Expr e in UserSuppliedInvariants)
+ {
+ wc.Invariants.Add(new AssertCmd(wc.tok, e));
+ bool OK = verifier.ProgramIsOK(Impl);
+ wc.Invariants.RemoveAt(wc.Invariants.Count - 1);
+ if (OK)
+ {
+ verifier.AddCandidateInvariant(wc, e);
+ }
+ }
+ }
+
+ private HashSet<Variable> GetModifiedVariables(StmtList stmtList)
+ {
+ HashSet<Variable> result = new HashSet<Variable>();
+
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ HashSet<Variable> resultForBlock = GetModifiedVariables(bb);
+ foreach (Variable v in resultForBlock)
+ {
+ result.Add(v);
+ }
+ }
+
+ return result;
+ }
+
+ private HashSet<Variable> GetModifiedVariables(BigBlock bb)
+ {
+ HashSet<Variable> result = new HashSet<Variable>();
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ VariableSeq vars = new VariableSeq();
+ c.AddAssignedVariables(vars);
+ foreach (Variable v in vars)
+ {
+ result.Add(v);
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ HashSet<Variable> modifiedByLoop = GetModifiedVariables((bb.ec as WhileCmd).Body);
+ foreach (Variable v in modifiedByLoop)
+ {
+ result.Add(v);
+ }
+ }
+ else if (bb.ec is IfCmd)
+ {
+ HashSet<Variable> modifiedByThen = GetModifiedVariables((bb.ec as IfCmd).thn);
+ foreach (Variable v in modifiedByThen)
+ {
+ result.Add(v);
+ }
+
+ if ((bb.ec as IfCmd).elseBlock != null)
+ {
+ HashSet<Variable> modifiedByElse = GetModifiedVariables((bb.ec as IfCmd).elseBlock);
+ foreach (Variable v in modifiedByElse)
+ {
+ result.Add(v);
+ }
+ }
+
+ Debug.Assert((bb.ec as IfCmd).elseIf == null);
+ }
+
+ return result;
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/Main.cs b/Source/GPUVerify/Main.cs
index cf1aaf70..b70260ce 100644
--- a/Source/GPUVerify/Main.cs
+++ b/Source/GPUVerify/Main.cs
@@ -39,11 +39,9 @@ namespace GPUVerify
{
extension = extension.ToLower();
}
- if (extension != ".bpl")
+ if (extension != ".gbpl")
{
- OnlyBoogie.ErrorWriteLine("*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file,
- extension == null ? "" : extension);
- Environment.Exit(1);
+ OnlyBoogie.AdvisoryWriteLine("Warning '{0}': Should only pass filename with extension .gbpl. Input must be GBoogie programs.", file);
}
}
diff --git a/Source/GPUVerify/MayBePowerOfTwoAnalyser.cs b/Source/GPUVerify/MayBePowerOfTwoAnalyser.cs
new file mode 100644
index 00000000..a00462c8
--- /dev/null
+++ b/Source/GPUVerify/MayBePowerOfTwoAnalyser.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+
+namespace GPUVerify
+{
+ class MayBePowerOfTwoAnalyser
+ {
+ private GPUVerifier verifier;
+
+ private Dictionary<string, Dictionary<string, bool>> mayBePowerOfTwoInfo;
+
+ public MayBePowerOfTwoAnalyser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ mayBePowerOfTwoInfo = new Dictionary<string, Dictionary<string, bool>>();
+ }
+
+ internal void Analyse()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ mayBePowerOfTwoInfo.Add(Impl.Name, new Dictionary<string, bool>());
+
+ SetNotPowerOfTwo(Impl.Name, GPUVerifier._X.Name);
+ SetNotPowerOfTwo(Impl.Name, GPUVerifier._Y.Name);
+ SetNotPowerOfTwo(Impl.Name, GPUVerifier._Z.Name);
+
+ foreach (Variable v in Impl.LocVars)
+ {
+ SetNotPowerOfTwo(Impl.Name, v.Name);
+ }
+
+ foreach (Variable v in Impl.InParams)
+ {
+ SetNotPowerOfTwo(Impl.Name, v.Name);
+ }
+
+ foreach (Variable v in Impl.OutParams)
+ {
+ SetNotPowerOfTwo(Impl.Name, v.Name);
+ }
+
+ // Fixpoint not required - this is just syntactic
+ Analyse(Impl);
+
+ }
+ }
+
+ if (CommandLineOptions.ShowMayBePowerOfTwoAnalysis)
+ {
+ dump();
+ }
+ }
+
+ private void SetNotPowerOfTwo(string p, string v)
+ {
+ mayBePowerOfTwoInfo[p][v] = false;
+ }
+
+ private void Analyse(Implementation Impl)
+ {
+ Analyse(Impl, Impl.StructuredStmts);
+ }
+
+ private void Analyse(Implementation impl, StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(impl, bb);
+ }
+ }
+
+ private void Analyse(Implementation impl, BigBlock bb)
+ {
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssignCmd)
+ {
+ AssignCmd assign = c as AssignCmd;
+ assign = c as AssignCmd;
+ Debug.Assert(assign.Lhss.Count == 1);
+ Debug.Assert(assign.Rhss.Count == 1);
+
+ if (assign.Lhss[0] is SimpleAssignLhs)
+ {
+ Variable v = (assign.Lhss[0] as SimpleAssignLhs).AssignedVariable.Decl;
+ if (mayBePowerOfTwoInfo[impl.Name].ContainsKey(v.Name))
+ {
+ if (isPowerOfTwoOperation(v, assign.Rhss[0]))
+ {
+ mayBePowerOfTwoInfo[impl.Name][v.Name] = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ Analyse(impl, wc.Body);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ Analyse(impl, ifCmd.thn);
+ if (ifCmd.elseBlock != null)
+ {
+ Analyse(impl, ifCmd.elseBlock);
+ }
+ Debug.Assert(ifCmd.elseIf == null);
+ }
+
+ }
+
+ private bool isPowerOfTwoOperation(Variable v, Expr expr)
+ {
+ if (!(
+ v.TypedIdent.Type.Equals(
+ Microsoft.Boogie.Type.GetBvType(8))
+ ||
+ v.TypedIdent.Type.Equals(
+ Microsoft.Boogie.Type.GetBvType(16))
+ ||
+ v.TypedIdent.Type.Equals(
+ Microsoft.Boogie.Type.GetBvType(32))
+ ))
+ {
+ return false;
+ }
+
+ Microsoft.Boogie.Type bvType = v.TypedIdent.Type as BvType;
+
+ if (!(expr is NAryExpr))
+ {
+ return false;
+ }
+
+ NAryExpr nary = expr as NAryExpr;
+
+ string bvPrefix = "BV" + bvType.BvBits + "_";
+
+ if (nary.Fun.FunctionName.Equals(bvPrefix + "MUL"))
+ {
+ Debug.Assert(nary.Args.Length == 2);
+ return
+ (
+ (IsVariable(nary.Args[0], v) || IsVariable(nary.Args[1], v)) &&
+ (IsConstant(nary.Args[0], 2) || IsConstant(nary.Args[1], 2))
+ );
+ }
+
+ if (nary.Fun.FunctionName.Equals(bvPrefix + "DIV"))
+ {
+ Debug.Assert(nary.Args.Length == 2);
+ return
+ (
+ IsVariable(nary.Args[0], v) && IsConstant(nary.Args[1], 2)
+ );
+ }
+
+ if (nary.Fun.FunctionName.Equals(bvPrefix + "SHL"))
+ {
+ return
+ (
+ IsVariable(nary.Args[0], v) && IsConstant(nary.Args[1], 1)
+ );
+ }
+
+ if (nary.Fun.FunctionName.Equals(bvPrefix + "ASHR"))
+ {
+ return
+ (
+ IsVariable(nary.Args[0], v) && IsConstant(nary.Args[1], 1)
+ );
+ }
+
+ return false;
+ }
+
+ private bool IsConstant(Expr expr, int x)
+ {
+ if (!(expr is LiteralExpr))
+ {
+ return false;
+ }
+
+ LiteralExpr lit = expr as LiteralExpr;
+
+ if (!(lit.Val is BvConst))
+ {
+ return false;
+ }
+
+ return (lit.Val as BvConst).Value.ToInt == x;
+ }
+
+ private bool IsVariable(Expr expr, Variable v)
+ {
+ return expr is IdentifierExpr && ((expr as IdentifierExpr).Decl.Name.Equals(v.Name));
+ }
+
+ private void dump()
+ {
+ foreach (string p in mayBePowerOfTwoInfo.Keys)
+ {
+ Console.WriteLine("Procedure " + p);
+ foreach (string v in mayBePowerOfTwoInfo[p].Keys)
+ {
+ Console.WriteLine(" " + v + ": " +
+ (mayBePowerOfTwoInfo[p][v] ? "may be power of two" : "likely not power of two"));
+ }
+ }
+
+ }
+
+
+ internal bool MayBePowerOfTwo(string p, string v)
+ {
+ if (!mayBePowerOfTwoInfo.ContainsKey(p))
+ {
+ return false;
+ }
+
+ if (!mayBePowerOfTwoInfo[p].ContainsKey(v))
+ {
+ return false;
+ }
+
+ return mayBePowerOfTwoInfo[p][v];
+ }
+ }
+}
diff --git a/Source/GPUVerify/MayBeTidAnalyser.cs b/Source/GPUVerify/MayBeTidAnalyser.cs
new file mode 100644
index 00000000..990559c2
--- /dev/null
+++ b/Source/GPUVerify/MayBeTidAnalyser.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class MayBeTidAnalyser
+ {
+
+ private GPUVerifier verifier;
+
+ private bool ProcedureChanged;
+
+ private Dictionary<string, Dictionary<string, bool>> mayBeTidInfo;
+
+ public MayBeTidAnalyser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ mayBeTidInfo = new Dictionary<string, Dictionary<string, bool>>();
+ }
+
+ internal void Analyse()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if(D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ mayBeTidInfo.Add(Impl.Name, new Dictionary<string, bool> ());
+
+ SetMayBeTid(Impl.Name, GPUVerifier._X.Name);
+ SetNotTid(Impl.Name, GPUVerifier._Y.Name);
+ SetNotTid(Impl.Name, GPUVerifier._Z.Name);
+
+ foreach (Variable v in Impl.LocVars)
+ {
+ SetMayBeTid(Impl.Name, v.Name);
+ }
+
+ foreach (Variable v in Impl.InParams)
+ {
+ SetMayBeTid(Impl.Name, v.Name);
+ }
+
+ foreach (Variable v in Impl.OutParams)
+ {
+ SetMayBeTid(Impl.Name, v.Name);
+ }
+
+ ProcedureChanged = true;
+ }
+ }
+
+ while (ProcedureChanged)
+ {
+ ProcedureChanged = false;
+
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ Analyse(Impl);
+ }
+ }
+ }
+
+ if (CommandLineOptions.ShowMayBeTidAnalysis)
+ {
+ dump();
+ }
+ }
+
+ private void Analyse(Implementation Impl)
+ {
+ Analyse(Impl, Impl.StructuredStmts);
+ }
+
+ private void Analyse(Implementation impl, StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(impl, bb);
+ }
+ }
+
+ private void Analyse(Implementation impl, BigBlock bb)
+ {
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssignCmd)
+ {
+ AssignCmd assignCmd = c as AssignCmd;
+ Debug.Assert(assignCmd.Lhss.Count == 1);
+ Debug.Assert(assignCmd.Rhss.Count == 1);
+ if (assignCmd.Lhss[0] is SimpleAssignLhs)
+ {
+ SimpleAssignLhs lhs = assignCmd.Lhss[0] as SimpleAssignLhs;
+ Expr rhs = assignCmd.Rhss[0];
+
+ if (MayBeTid (impl.Name, lhs.AssignedVariable.Name)
+ && !MayBeTid(impl.Name, rhs))
+ {
+ SetNotTid (impl.Name, lhs.AssignedVariable.Name);
+ }
+
+ }
+ }
+ else if (c is CallCmd)
+ {
+ CallCmd callCmd = c as CallCmd;
+
+ if (callCmd.callee != verifier.BarrierProcedure.Name)
+ {
+
+ Implementation CalleeImplementation = verifier.GetImplementation(callCmd.callee);
+ for (int i = 0; i < CalleeImplementation.InParams.Length; i++)
+ {
+ if (MayBeTid(callCmd.callee, CalleeImplementation.InParams[i].Name)
+ && !MayBeTid(impl.Name, callCmd.Ins[i]))
+ {
+ SetNotTid(callCmd.callee, CalleeImplementation.InParams[i].Name);
+ }
+ }
+
+ for (int i = 0; i < CalleeImplementation.OutParams.Length; i++)
+ {
+ if (MayBeTid(impl.Name, callCmd.Outs[i].Name)
+ && !MayBeTid(callCmd.callee, CalleeImplementation.OutParams[i].Name))
+ {
+ SetNotTid(impl.Name, callCmd.Outs[i].Name);
+ }
+ }
+
+ }
+ else if (c is HavocCmd)
+ {
+ HavocCmd havoc = c as HavocCmd;
+ Debug.Assert(havoc.Vars.Length == 1);
+
+ if (MayBeTid(impl.Name, havoc.Vars[0].Decl.Name))
+ {
+ SetNotTid(impl.Name, havoc.Vars[0].Decl.Name);
+ }
+ }
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ Analyse(impl, wc.Body);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ Analyse(impl, ifCmd.thn);
+ if (ifCmd.elseBlock != null)
+ {
+ Analyse(impl, ifCmd.elseBlock);
+ }
+ Debug.Assert(ifCmd.elseIf == null);
+ }
+
+ }
+
+ private void SetNotTid(string proc, string v)
+ {
+ mayBeTidInfo[proc][v] = false;
+ ProcedureChanged = true;
+ }
+
+ private void SetMayBeTid(string proc, string v)
+ {
+ mayBeTidInfo[proc][v] = true;
+ }
+
+ internal bool MayBeTid(string proc, string v)
+ {
+ if (!mayBeTidInfo.ContainsKey(proc))
+ {
+ return false;
+ }
+
+ if (!mayBeTidInfo[proc].ContainsKey(v))
+ {
+ return false;
+ }
+
+ return mayBeTidInfo[proc][v];
+ }
+
+ internal bool MayBeTid(string proc, Expr e)
+ {
+ if (e is IdentifierExpr)
+ {
+ return MayBeTid(proc, (e as IdentifierExpr).Decl.Name);
+ }
+ return false;
+ }
+
+ private void dump()
+ {
+ foreach (string p in mayBeTidInfo.Keys)
+ {
+ Console.WriteLine("Procedure " + p);
+ foreach (string v in mayBeTidInfo[p].Keys)
+ {
+ Console.WriteLine(" " + v + ": " +
+ (mayBeTidInfo[p][v] ? "may be tid" : "likely not tid"));
+ }
+ }
+
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/MayBeTidPlusConstantAnalyser.cs b/Source/GPUVerify/MayBeTidPlusConstantAnalyser.cs
new file mode 100644
index 00000000..59b62b81
--- /dev/null
+++ b/Source/GPUVerify/MayBeTidPlusConstantAnalyser.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class MayBeTidPlusConstantAnalyser
+ {
+ private GPUVerifier verifier;
+
+ // Given a p.v, says whether p.v may be assigned to a tid variable at some point
+ private Dictionary<string, Dictionary<string, bool>> mayBeAssignedTid;
+
+ // Records the constants (as strings) that p.v may be incremented by
+ private Dictionary<string, Dictionary<string, HashSet<string>>> incrementedBy;
+
+ // The final result
+ private Dictionary<string, Dictionary<string, bool>> mayBeTidPlusConstantInfo;
+
+ public MayBeTidPlusConstantAnalyser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ mayBeAssignedTid = new Dictionary<string, Dictionary<string, bool>>();
+ incrementedBy = new Dictionary<string, Dictionary<string, HashSet<string>>>();
+ mayBeTidPlusConstantInfo = new Dictionary<string, Dictionary<string, bool>>();
+ }
+
+ internal void Analyse()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ mayBeAssignedTid[Impl.Name] = new Dictionary<string, bool>();
+ incrementedBy[Impl.Name] = new Dictionary<string, HashSet<string>>();
+ mayBeTidPlusConstantInfo[Impl.Name] = new Dictionary<string, bool> ();
+
+ foreach (Variable v in Impl.LocVars)
+ {
+ mayBeAssignedTid[Impl.Name][v.Name] = false;
+ incrementedBy[Impl.Name][v.Name] = new HashSet<string>();
+ }
+
+ foreach (Variable v in Impl.InParams)
+ {
+ mayBeAssignedTid[Impl.Name][v.Name] = false;
+ incrementedBy[Impl.Name][v.Name] = new HashSet<string>();
+ }
+
+ foreach (Variable v in Impl.OutParams)
+ {
+ mayBeAssignedTid[Impl.Name][v.Name] = false;
+ incrementedBy[Impl.Name][v.Name] = new HashSet<string>();
+ }
+
+ // Fixpoint not required - this is just syntactic
+ Analyse(Impl);
+
+ foreach (string v in mayBeAssignedTid[Impl.Name].Keys)
+ {
+ mayBeTidPlusConstantInfo[Impl.Name][v] =
+ mayBeAssignedTid[Impl.Name][v] && incrementedBy[Impl.Name][v].Count == 1;
+ }
+
+ }
+ }
+
+ if (CommandLineOptions.ShowMayBeTidPlusConstantAnalysis)
+ {
+ dump();
+ }
+ }
+
+ private void Analyse(Implementation Impl)
+ {
+ Analyse(Impl, Impl.StructuredStmts);
+ }
+
+ private void Analyse(Implementation impl, StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(impl, bb);
+ }
+ }
+
+ private void Analyse(Implementation impl, BigBlock bb)
+ {
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssignCmd)
+ {
+ AssignCmd assign = c as AssignCmd;
+ assign = c as AssignCmd;
+ Debug.Assert(assign.Lhss.Count == 1);
+ Debug.Assert(assign.Rhss.Count == 1);
+
+ if (assign.Lhss[0] is SimpleAssignLhs)
+ {
+ Variable lhsV = (assign.Lhss[0] as SimpleAssignLhs).AssignedVariable.Decl;
+
+ if (mayBeAssignedTid[impl.Name].ContainsKey(lhsV.Name))
+ {
+
+ if (assign.Rhss[0] is IdentifierExpr)
+ {
+
+ Variable rhsV = (assign.Rhss[0] as IdentifierExpr).Decl;
+
+ if (verifier.mayBeTidAnalyser.MayBeTid(impl.Name, rhsV.Name))
+ {
+ mayBeAssignedTid[impl.Name][lhsV.Name] = true;
+ }
+
+ }
+ else
+ {
+
+ Expr constantIncrement = GetConstantIncrement(lhsV, assign.Rhss[0]);
+
+ if (constantIncrement != null)
+ {
+ incrementedBy[impl.Name][lhsV.Name].Add(ConvertToString(constantIncrement));
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ Analyse(impl, wc.Body);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ Analyse(impl, ifCmd.thn);
+ if (ifCmd.elseBlock != null)
+ {
+ Analyse(impl, ifCmd.elseBlock);
+ }
+ Debug.Assert(ifCmd.elseIf == null);
+ }
+
+ }
+
+ private string ConvertToString(Expr constantIncrement)
+ {
+ if (constantIncrement is IdentifierExpr)
+ {
+ return (constantIncrement as IdentifierExpr).Decl.Name;
+ }
+
+ LiteralExpr lit = constantIncrement as LiteralExpr;
+
+ return (lit.Val as BvConst).Value.ToString() + "bv32";
+
+ }
+
+ private Expr GetConstantIncrement(Variable v, Expr expr)
+ {
+
+ if (!(expr is NAryExpr))
+ {
+ return null;
+ }
+
+ NAryExpr nary = expr as NAryExpr;
+
+ if (!nary.Fun.FunctionName.Equals("BV32_ADD"))
+ {
+ return null;
+ }
+
+ if (!(nary.Args[0] is IdentifierExpr &&
+ ((nary.Args[0] as IdentifierExpr).Decl.Name.Equals(v.Name))))
+ {
+ return null;
+ }
+
+ if (!IsConstant(nary.Args[1]))
+ {
+ return null;
+ }
+
+ return nary.Args[1];
+ }
+
+ private bool IsConstant(Expr expr)
+ {
+ return expr is LiteralExpr
+ || (expr is IdentifierExpr && (expr as IdentifierExpr).Decl is Constant);
+ }
+
+ private bool IsVariable(Expr expr, Variable v)
+ {
+ return expr is IdentifierExpr && ((expr as IdentifierExpr).Decl.Name.Equals(v.Name));
+ }
+
+ private void dump()
+ {
+ foreach (string p in mayBeTidPlusConstantInfo.Keys)
+ {
+ Console.WriteLine("Procedure " + p);
+ foreach (string v in mayBeTidPlusConstantInfo[p].Keys)
+ {
+ Console.WriteLine(" " + v + ": gets assigned tid - " + mayBeAssignedTid[p][v]);
+ Console.Write(" " + v + ": incremented by -");
+ foreach(string s in incrementedBy[p][v])
+ {
+ Console.Write(" " + s);
+ }
+ Console.WriteLine("");
+
+ Console.Write(" " + v + ": ");
+
+ if(mayBeTidPlusConstantInfo[p][v])
+ {
+ Console.Write("may be tid + ");
+ foreach(string s in incrementedBy[p][v])
+ {
+ Console.WriteLine(s);
+ }
+ }
+ else
+ {
+ Console.WriteLine("likely not tid + const");
+ }
+ }
+ }
+
+ }
+
+
+ internal bool MayBeTidPlusConstant(string p, string v)
+ {
+ if (!mayBeTidPlusConstantInfo.ContainsKey(p))
+ {
+ return false;
+ }
+
+ if (!mayBeTidPlusConstantInfo[p].ContainsKey(v))
+ {
+ return false;
+ }
+
+ return mayBeTidPlusConstantInfo[p][v];
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/NullRaceInstrumenter.cs b/Source/GPUVerify/NullRaceInstrumenter.cs
index a825a2eb..b2941815 100644
--- a/Source/GPUVerify/NullRaceInstrumenter.cs
+++ b/Source/GPUVerify/NullRaceInstrumenter.cs
@@ -9,7 +9,7 @@ namespace GPUVerify
class NullRaceInstrumenter : IRaceInstrumenter
{
- public void AddRaceCheckingCandidateInvariants(Microsoft.Boogie.WhileCmd wc)
+ public void AddRaceCheckingCandidateInvariants(Implementation impl, Microsoft.Boogie.WhileCmd wc)
{
}
@@ -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 a4174cbb..4dab448b 100644
--- a/Source/GPUVerify/Predicator.cs
+++ b/Source/GPUVerify/Predicator.cs
@@ -7,23 +7,31 @@ 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;
- internal Predicator(bool AddPredicateParameter)
+ private Stack<Expr> predicate;
+ private Stack<Expr> enclosingLoopPredicate;
+
+ private Implementation impl = null;
+
+ internal Predicator(GPUVerifier verifier, bool AddPredicateParameter) : base(verifier)
{
this.AddPredicateParameter = AddPredicateParameter;
WhileLoopCounter = 0;
IfCounter = 0;
RequiredHavocVariables = new HashSet<Microsoft.Boogie.Type>();
+ predicate = new Stack<Expr>();
+ enclosingLoopPredicate = new Stack<Expr>();
}
internal void transform(Implementation impl)
{
+ this.impl = impl;
Expr Predicate;
if (AddPredicateParameter)
@@ -43,201 +51,299 @@ namespace GPUVerify
Predicate = Expr.True;
}
- impl.StructuredStmts = MakePredicated(impl.StructuredStmts, Predicate, null);
- AddPredicateLocalVariables(impl);
+ predicate.Push(Predicate);
+ enclosingLoopPredicate.Push(Expr.True);
+
+ impl.StructuredStmts = VisitStmtList(impl.StructuredStmts);
+
+ AddPredicateLocalVariables(impl);
+
+ this.impl = null;
}
+ 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>();
- foreach (BigBlock bodyBlock in sl.BigBlocks)
+ if (!verifier.uniformityAnalyser.IsUniform(Call.callee))
{
- List<BigBlock> newBigBlocks = MakePredicated(bodyBlock, predicate, EnclosingLoopPredicate);
- foreach (BigBlock newBigBlock in newBigBlocks)
- {
- result.BigBlocks.Add(newBigBlock);
- }
+ NewIns.Add(predicate.Peek());
}
- return result;
+ foreach (Expr e in Call.Ins)
+ {
+ NewIns.Add(e);
+ }
+
+ CallCmd newCallCmd = new CallCmd(Call.tok, Call.callee, NewIns, Call.Outs);
+ newCallCmd.Proc = Call.Proc;
+
+ return new CmdSeq(
+ new Cmd[] { newCallCmd });
}
- 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);
+
+ return new CmdSeq(new Cmd[] { new AssignCmd(assign.tok, assign.Lhss, newRhs) });
- foreach (Cmd c in b.simpleCmds)
+ }
+
+ public override CmdSeq VisitHavocCmd(HavocCmd havoc)
+ {
+ CmdSeq result = new CmdSeq();
+
+ Debug.Assert(havoc.Vars.Length == 1);
+
+ if (predicate.Peek().Equals(Expr.True))
{
- if (c is CallCmd)
- {
+ result.Add(havoc);
+ return result;
+ }
- CallCmd Call = c as CallCmd;
+ Microsoft.Boogie.Type type = havoc.Vars[0].Decl.TypedIdent.Type;
+ Debug.Assert(type != null);
- List<Expr> NewIns = new List<Expr>();
- NewIns.Add(IncomingPredicate);
+ IdentifierExpr HavocTempExpr = new IdentifierExpr(havoc.tok, new LocalVariable(havoc.tok, new TypedIdent(havoc.tok, "_HAVOC_" + type.ToString(), type)));
- foreach (Expr e in Call.Ins)
- {
- NewIns.Add(e);
- }
+ if (!RequiredHavocVariables.Contains(type))
+ {
+ verifier.uniformityAnalyser.AddNonUniform(impl.Name, HavocTempExpr.Decl.Name);
+ }
- CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, NewIns, Call.Outs);
+ RequiredHavocVariables.Add(type);
- 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);
+ result.Add(new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
+ HavocTempExpr
+ })));
- 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);
+ List<AssignLhs> lhss = new List<AssignLhs>();
+ lhss.Add(new SimpleAssignLhs(havoc.tok, havoc.Vars[0]));
- List<Expr> newRhs = new List<Expr>();
- newRhs.Add(ite);
+ 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] })));
- AssignCmd newAssign = new AssignCmd(assign.tok, assign.Lhss, newRhs);
+ result.Add(new AssignCmd(havoc.tok, lhss, rhss));
- firstBigBlock.simpleCmds.Add(newAssign);
- }
- else if (c is HavocCmd)
- {
- HavocCmd havoc = c as HavocCmd;
- Debug.Assert(havoc.Vars.Length == 1);
+ return result;
- Microsoft.Boogie.Type type = havoc.Vars[0].Decl.TypedIdent.Type;
- Debug.Assert(type != null);
+ }
- RequiredHavocVariables.Add(type);
+ public override CmdSeq VisitAssertCmd(AssertCmd assert)
+ {
+ return new CmdSeq(new Cmd[] {
+ new AssertCmd(assert.tok, Expr.Imp(predicate.Peek(), assert.Expr))
+ });
+ }
- 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 VisitAssumeCmd(AssumeCmd assume)
+ {
+ return new CmdSeq(new Cmd[] {
+ new AssumeCmd(assume.tok, Expr.Imp(predicate.Peek(), assume.Expr))
+ });
+ }
- List<AssignLhs> lhss = new List<AssignLhs>();
- lhss.Add(new SimpleAssignLhs(havoc.tok, havoc.Vars[0]));
+ public override List<BigBlock> VisitBigBlock(BigBlock bb)
+ {
+ BigBlock firstBigBlock = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
- 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] })));
+ List<BigBlock> result = new List<BigBlock>();
+ result.Add(firstBigBlock);
- firstBigBlock.simpleCmds.Add(new AssignCmd(havoc.tok, lhss, rhss));
+ firstBigBlock.simpleCmds = VisitCmdSeq(bb.simpleCmds);
- }
- else if (c is AssertCmd)
- {
- firstBigBlock.simpleCmds.Add(new AssertCmd(c.tok, Expr.Imp(IncomingPredicate, (c as AssertCmd).Expr)));
- }
- else
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd whileCmd = bb.ec as WhileCmd;
+
+ Expr PredicateExpr;
+ Expr NewGuard;
+ string LoopPredicate = null;
+ List<AssignLhs> WhilePredicateLhss = new List<AssignLhs>();
+
+ if (!enclosingLoopPredicate.Peek().Equals(Expr.True) || !verifier.uniformityAnalyser.IsUniform(impl.Name, whileCmd.Guard))
{
- Debug.Assert(false);
- }
- }
+ LoopPredicate = "_LC" + WhileLoopCounter;
+ WhileLoopCounter++;
- if (b.ec is WhileCmd)
- {
- string LoopPredicate = "_LC" + WhileLoopCounter;
- WhileLoopCounter++;
+ verifier.uniformityAnalyser.AddNonUniform(impl.Name, LoopPredicate);
- 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);
- List<AssignLhs> WhilePredicateLhss = new List<AssignLhs>();
- WhilePredicateLhss.Add(new SimpleAssignLhs(b.ec.tok, PredicateExpr));
+ PredicateExpr = new IdentifierExpr(whileCmd.tok, new LocalVariable(whileCmd.tok, LoopPredicateTypedIdent));
- List<Expr> WhilePredicateRhss = new List<Expr>();
- WhilePredicateRhss.Add(IncomingPredicate.Equals(Expr.True) ? GuardExpr : Expr.And(IncomingPredicate, GuardExpr));
+ WhilePredicateLhss.Add(new SimpleAssignLhs(whileCmd.tok, PredicateExpr as IdentifierExpr));
- firstBigBlock.simpleCmds.Add(new AssignCmd(b.ec.tok, WhilePredicateLhss, WhilePredicateRhss));
+ List<Expr> WhilePredicateRhss = new List<Expr>();
+ WhilePredicateRhss.Add(predicate.Peek().Equals(Expr.True) ?
+ whileCmd.Guard : Expr.And(predicate.Peek(), whileCmd.Guard));
- WhileCmd NewWhile = new WhileCmd(b.ec.tok, PredicateExpr, (b.ec as WhileCmd).Invariants, MakePredicated((b.ec as WhileCmd).Body, PredicateExpr, PredicateExpr));
+ firstBigBlock.simpleCmds.Add(new AssignCmd(whileCmd.tok, WhilePredicateLhss, WhilePredicateRhss));
- List<Expr> UpdatePredicateRhss = new List<Expr>();
- UpdatePredicateRhss.Add(Expr.And(PredicateExpr, GuardExpr));
+ NewGuard = PredicateExpr;
+ }
+ else
+ {
+ PredicateExpr = enclosingLoopPredicate.Peek();
+ NewGuard = whileCmd.Guard;
+ }
- CmdSeq updateCmd = new CmdSeq();
- updateCmd.Add(new AssignCmd(b.ec.tok, WhilePredicateLhss, UpdatePredicateRhss));
+ predicate.Push(PredicateExpr);
+ enclosingLoopPredicate.Push(PredicateExpr);
+ WhileCmd NewWhile = new WhileCmd(whileCmd.tok, NewGuard,
+ VisitWhileInvariants(whileCmd.Invariants, NewGuard),
+ VisitStmtList(whileCmd.Body));
+ enclosingLoopPredicate.Pop();
+ predicate.Pop();
- NewWhile.Body.BigBlocks.Add(new BigBlock(b.ec.tok, "update_" + LoopPredicate, updateCmd, null, null));
+ if (!enclosingLoopPredicate.Peek().Equals(Expr.True) || !verifier.uniformityAnalyser.IsUniform(impl.Name, whileCmd.Guard))
+ {
+ List<Expr> UpdatePredicateRhss = new List<Expr>();
+ UpdatePredicateRhss.Add(Expr.And(PredicateExpr, whileCmd.Guard));
+
+ CmdSeq updateCmd = new CmdSeq();
+ updateCmd.Add(new AssignCmd(whileCmd.tok, WhilePredicateLhss, UpdatePredicateRhss));
+
+ 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++;
+ if (IfCommand.elseIf != null)
+ {
+ throw new InvalidOperationException();
+ }
- IdentifierExpr PredicateExpr = new IdentifierExpr(b.ec.tok, new LocalVariable(b.ec.tok, new TypedIdent(b.ec.tok, IfPredicate, Microsoft.Boogie.Type.Bool)));
- Expr GuardExpr = IfCommand.Guard;
+ if (predicate.Peek().Equals(Expr.True) && verifier.uniformityAnalyser.IsUniform(impl.Name, IfCommand.Guard))
+ {
+ firstBigBlock.ec =
+ new IfCmd(IfCommand.tok, IfCommand.Guard, VisitStmtList(IfCommand.thn),
+ null, IfCommand.elseBlock == null ? null : VisitStmtList(IfCommand.elseBlock));
+ }
+ else
+ {
+ string IfPredicate = "_P" + IfCounter;
+ IfCounter++;
- List<AssignLhs> IfPredicateLhss = new List<AssignLhs>();
- IfPredicateLhss.Add(new SimpleAssignLhs(b.ec.tok, PredicateExpr));
+ verifier.uniformityAnalyser.AddNonUniform(impl.Name, IfPredicate);
- List<Expr> IfPredicateRhss = new List<Expr>();
- IfPredicateRhss.Add(GuardExpr);
+ IdentifierExpr PredicateExpr = new IdentifierExpr(IfCommand.tok,
+ new LocalVariable(IfCommand.tok, new TypedIdent(IfCommand.tok, IfPredicate, Microsoft.Boogie.Type.Bool)));
+ Expr GuardExpr = IfCommand.Guard;
- firstBigBlock.simpleCmds.Add(new AssignCmd(b.ec.tok, IfPredicateLhss, IfPredicateRhss));
+ List<AssignLhs> IfPredicateLhss = new List<AssignLhs>();
+ IfPredicateLhss.Add(new SimpleAssignLhs(IfCommand.tok, PredicateExpr));
- Debug.Assert(IfCommand.elseIf == null); // We need to preprocess these away
+ List<Expr> IfPredicateRhss = new List<Expr>();
+ IfPredicateRhss.Add(GuardExpr);
- StmtList PredicatedThen = MakePredicated(IfCommand.thn, Expr.And(IncomingPredicate, PredicateExpr), EnclosingLoopPredicate);
+ firstBigBlock.simpleCmds.Add(new AssignCmd(IfCommand.tok, IfPredicateLhss, IfPredicateRhss));
- foreach (BigBlock bb in PredicatedThen.BigBlocks)
- {
- result.Add(bb);
- }
+ Debug.Assert(IfCommand.elseIf == null); // We need to preprocess these away
- if (IfCommand.elseBlock != null)
- {
- StmtList PredicatedElse = MakePredicated(IfCommand.elseBlock, Expr.And(IncomingPredicate, Expr.Not(PredicateExpr)), EnclosingLoopPredicate);
+ predicate.Push(Expr.And(predicate.Peek(), PredicateExpr));
+ StmtList PredicatedThen = VisitStmtList(IfCommand.thn);
+ predicate.Pop();
+ result.AddRange(PredicatedThen.BigBlocks);
- foreach (BigBlock bb in PredicatedElse.BigBlocks)
+ if (IfCommand.elseBlock != null)
{
- 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)
+ {
+ if (enclosingLoopPredicate.Equals(Expr.True))
+ {
+ firstBigBlock.ec = bb.ec;
+ }
+ else
+ {
-
-
+ firstBigBlock.simpleCmds.Add(new AssignCmd(bb.tok,
+ new List<AssignLhs>(new AssignLhs[] {
+ new SimpleAssignLhs(bb.tok, enclosingLoopPredicate.Peek() as IdentifierExpr) }),
+ 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 (b.ec is BreakCmd)
+ else if (bb.ec != null)
{
+ throw new InvalidOperationException();
+ }
+ return result;
- 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;
+ }
- }
- else
+ public override IfCmd VisitIfCmd(IfCmd ifCmd)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public override WhileCmd VisitWhileCmd(WhileCmd whileCmd)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public override BreakCmd VisitBreakCmd(BreakCmd breakCmd)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public override List<PredicateCmd> VisitWhileInvariants(List<PredicateCmd> invariants, Expr WhileGuard)
+ {
+ 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, WhileGuard)));
}
return result;
}
+ internal static Expr ProcessEnabledIntrinsics(Expr expr, Expr 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..e3a09404 100644
--- a/Source/GPUVerify/RaceInstrumenterBase.cs
+++ b/Source/GPUVerify/RaceInstrumenterBase.cs
@@ -21,6 +21,8 @@ namespace GPUVerify
public bool addedLogWrite;
private int logAddCount;
+ private Dictionary<string, Procedure> logAccessProcedures = new Dictionary<string, Procedure>();
+
public RaceInstrumenterBase()
{
onlyLog1 = -1;
@@ -48,13 +50,29 @@ namespace GPUVerify
private void AddNoReadOrWriteCandidateInvariants(WhileCmd wc, Variable v)
{
- AddNoReadOrWriteCandidateInvariant(wc, v, "READ", "1");
- AddNoReadOrWriteCandidateInvariant(wc, v, "WRITE", "1");
- if (!CommandLineOptions.Symmetry)
- {
- AddNoReadOrWriteCandidateInvariant(wc, v, "READ", "2");
+ // Reasoning: if READ_HAS_OCCURRED_v is not in the modifies set for the
+ // loop then there is no point adding an invariant
+ //
+ // If READ_HAS_OCCURRED_v is in the modifies set, but the loop does not
+ // contain a barrier, then it is almost certain that a read CAN be
+ // pending at the loop head, so the invariant will not hold
+ //
+ // If there is a barrier in the loop body then READ_HAS_OCCURRED_v will
+ // be in the modifies set, but there may not be a live read at the loop
+ // head, so it is worth adding the loop invariant candidate.
+ //
+ // The same reasoning applies for WRITE
+
+ if (verifier.ContainsBarrierCall(wc.Body))
+ {
+ AddNoReadOrWriteCandidateInvariant(wc, v, "READ", "1");
+ AddNoReadOrWriteCandidateInvariant(wc, v, "WRITE", "1");
+ if (!CommandLineOptions.Symmetry)
+ {
+ AddNoReadOrWriteCandidateInvariant(wc, v, "READ", "2");
+ }
+ AddNoReadOrWriteCandidateInvariant(wc, v, "WRITE", "2");
}
- AddNoReadOrWriteCandidateInvariant(wc, v, "WRITE", "2");
}
private void AddNoReadOrWriteCandidateRequires(Procedure Proc, Variable v)
@@ -81,24 +99,62 @@ namespace GPUVerify
protected abstract void AddNoReadOrWriteCandidateInvariant(WhileCmd wc, Variable v, string ReadOrWrite, string OneOrTwo);
- public void AddRaceCheckingCandidateInvariants(WhileCmd wc)
+ public void AddRaceCheckingCandidateInvariants(Implementation impl, WhileCmd wc)
{
foreach (Variable v in NonLocalStateToCheck.getAllNonLocalVariables())
{
AddNoReadOrWriteCandidateInvariants(wc, v);
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(wc, v);
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(impl, wc, v);
+ AddGroupStrideAccessCandidateInvariants(wc, v);
}
}
- private void AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(WhileCmd wc, Variable v)
+ private void AddGroupStrideAccessCandidateInvariants(WhileCmd wc, Variable v)
{
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "WRITE", 1);
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "WRITE", 2);
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "READ", 1);
- if (!CommandLineOptions.Symmetry)
+ // TODO
+ }
+
+ private void AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(Implementation impl, WhileCmd wc, Variable v)
+ {
+ HashSet<Expr> OffsetsWrittenInLoop = GetOffsetsAccessed(wc.Body, v, "WRITE ");
+
+ foreach (Expr e in GetOffsetsAccessed(wc.Body, v, "READ"))
{
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "READ", 2);
+ if (e is IdentifierExpr)
+ {
+ string indexVarName =
+ GPUVerifier.StripThreadIdentifier((e as IdentifierExpr).Decl.Name);
+
+ if (verifier.mayBeTidAnalyser.MayBeTid(impl.Name, indexVarName))
+ {
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "READ", 1);
+ if (!CommandLineOptions.Symmetry)
+ {
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "READ", 2);
+ }
+ // No point adding it multiple times
+ break;
+ }
+ }
}
+
+ foreach (Expr e in GetOffsetsAccessed(wc.Body, v, "WRITE"))
+ {
+ if (e is IdentifierExpr)
+ {
+ string indexVarName =
+ GPUVerifier.StripThreadIdentifier((e as IdentifierExpr).Decl.Name);
+
+ if (verifier.mayBeTidAnalyser.MayBeTid(impl.Name, indexVarName))
+ {
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "WRITE", 1);
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariant(wc, v, "WRITE", 2);
+ // No point adding it multiple times
+ break;
+ }
+ }
+ }
+
}
private void AddReadOrWrittenOffsetIsThreadIdCandidateRequires(Procedure Proc, Variable v)
@@ -182,17 +238,6 @@ namespace GPUVerify
AddLogAccessProcedure(v, "READ");
AddLogAccessProcedure(v, "WRITE");
- HashSet<string> MayCallBarrier = verifier.GetProceduresThatIndirectlyCallProcedure(verifier.BarrierProcedure.Name);
-
- verifier.ExtendModifiesSetOfProcedures(ReadDeclsResetAtBarrier, MayCallBarrier);
- verifier.ExtendModifiesSetOfProcedures(WriteDeclsResetAtBarrier, MayCallBarrier);
-
- HashSet<string> MayCallLogRead = verifier.GetProceduresThatIndirectlyCallProcedure("_LOG_READ_" + v.Name);
- HashSet<string> MayCallLogWrite = verifier.GetProceduresThatIndirectlyCallProcedure("_LOG_WRITE_" + v.Name);
-
- verifier.ExtendModifiesSetOfProcedures(ReadDeclsModifiedAtLogRead, MayCallLogRead);
- verifier.ExtendModifiesSetOfProcedures(WriteDeclsModifiedAtLogWrite, MayCallLogWrite);
-
}
private StmtList AddRaceCheckCalls(StmtList stmtList)
@@ -277,7 +322,13 @@ namespace GPUVerify
inParams.Add(ar.IndexX);
}
- result.simpleCmds.Add(new CallCmd(c.tok, "_LOG_READ_" + ar.v.Name, inParams, new IdentifierExprSeq()));
+ Procedure logProcedure = GetLogAccessProcedure(c.tok, "_LOG_READ_" + ar.v.Name);
+
+ CallCmd logAccessCallCmd = new CallCmd(c.tok, logProcedure.Name, inParams, new IdentifierExprSeq());
+
+ logAccessCallCmd.Proc = logProcedure;
+
+ result.simpleCmds.Add(logAccessCallCmd);
}
}
@@ -305,7 +356,14 @@ namespace GPUVerify
inParams.Add(ar.IndexX);
}
- result.simpleCmds.Add(new CallCmd(c.tok, "_LOG_WRITE_" + ar.v.Name, inParams, new IdentifierExprSeq()));
+ Procedure logProcedure = GetLogAccessProcedure(c.tok, "_LOG_WRITE_" + ar.v.Name);
+
+ CallCmd logAccessCallCmd = new CallCmd(c.tok, logProcedure.Name, inParams, new IdentifierExprSeq());
+
+ logAccessCallCmd.Proc = logProcedure;
+
+ result.simpleCmds.Add(logAccessCallCmd);
+
addedLogWrite = true;
}
@@ -319,7 +377,8 @@ namespace GPUVerify
if (bb.ec is WhileCmd)
{
WhileCmd WhileCommand = bb.ec as WhileCmd;
- result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, AddRaceCheckCalls(WhileCommand.Body));
+ result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard,
+ WhileCommand.Invariants, AddRaceCheckCalls(WhileCommand.Body));
}
else if (bb.ec is IfCmd)
{
@@ -340,6 +399,17 @@ namespace GPUVerify
}
+ private Procedure GetLogAccessProcedure(IToken tok, string name)
+ {
+ if (logAccessProcedures.ContainsKey(name))
+ {
+ return logAccessProcedures[name];
+ }
+ Procedure newProcedure = new Procedure(tok, name, new TypeVariableSeq(), new VariableSeq(), new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), new EnsuresSeq());
+ logAccessProcedures[name] = newProcedure;
+ return newProcedure;
+ }
+
protected abstract void AddLogRaceDeclarations(Variable v, String ReadOrWrite, out IdentifierExprSeq ResetAtBarrier, out IdentifierExprSeq ModifiedAtLog);
@@ -353,7 +423,7 @@ namespace GPUVerify
{
foreach (Variable v in NonLocalStateToCheck.getAllNonLocalVariables())
{
- CheckForRaces(tok, checkForRaces, v, false);
+ CheckForRaces(checkForRaces, v, false);
}
}
@@ -372,7 +442,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)
{
@@ -385,7 +455,6 @@ namespace GPUVerify
{
MapType mt = v.TypedIdent.Type as MapType;
Debug.Assert(mt.Arguments.Length == 1);
- Debug.Assert(GPUVerifier.IsIntOrBv32(mt.Arguments[0]));
XParameterVariable = new LocalVariable(v.tok, new TypedIdent(v.tok, "_X_index", mt.Arguments[0]));
if (mt.Result is MapType)
@@ -420,7 +489,11 @@ namespace GPUVerify
inParams.Add(XParameterVariable);
}
- LogReadOrWriteProcedure = new Procedure(v.tok, "_LOG_" + ReadOrWrite + "_" + v.Name, new TypeVariableSeq(), inParams, new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), new EnsuresSeq());
+ string LogProcedureName = "_LOG_" + ReadOrWrite + "_" + v.Name;
+
+ LogReadOrWriteProcedure = GetLogAccessProcedure(v.tok, LogProcedureName);
+
+ LogReadOrWriteProcedure.InParams = inParams;
if (CommandLineOptions.Symmetry && ReadOrWrite.Equals("READ"))
{
@@ -462,6 +535,145 @@ 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);
+
+
+ private HashSet<Expr> GetOffsetsAccessed(StmtList stmts, Variable v, string AccessType)
+ {
+ HashSet<Expr> result = new HashSet<Expr> ();
+ foreach (BigBlock bb in stmts.BigBlocks)
+ {
+ HashSet<Expr> offsetsReadInBigBlock = GetOffsetsAccessed(bb, v, AccessType);
+ foreach (Expr e in offsetsReadInBigBlock)
+ {
+ result.Add(e);
+ }
+ }
+ return result;
+ }
+
+ private HashSet<Expr> GetOffsetsAccessed(BigBlock bb, Variable v, string AccessType)
+ {
+ HashSet<Expr> result = new HashSet<Expr>();
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is CallCmd)
+ {
+ CallCmd call = c as CallCmd;
+
+ if (call.callee == "_LOG_" + AccessType + "_" + v.Name)
+ {
+ // Ins[0] is thread 1's predicate,
+ // Ins[1] is the offset to be read
+ result.Add(call.Ins[1]);
+ }
+
+ }
+
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ HashSet<Expr> bodyResult = GetOffsetsAccessed((bb.ec as WhileCmd).Body, v, AccessType);
+ foreach (Expr e in bodyResult)
+ {
+ result.Add(e);
+ }
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+
+ HashSet<Expr> thenResult = GetOffsetsAccessed(ifCmd.thn, v, AccessType);
+ foreach (Expr e in thenResult)
+ {
+ result.Add(e);
+ }
+
+ Debug.Assert(ifCmd.elseIf == null);
+
+ if(ifCmd.elseBlock != null)
+ {
+ HashSet<Expr> elseResult = GetOffsetsAccessed(ifCmd.elseBlock, v, AccessType);
+ foreach (Expr e in elseResult)
+ {
+ result.Add(e);
+ }
+ }
+ }
+
+ return result;
+ }
}
+
+
}
diff --git a/Source/GPUVerify/SetEncodingRaceInstrumenter.cs b/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
index e7e5854e..bda8f01f 100644
--- a/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
+++ b/Source/GPUVerify/SetEncodingRaceInstrumenter.cs
@@ -190,13 +190,13 @@ namespace GPUVerify
protected override void SetNoAccessOccurred(IToken tok, BigBlock bb, Variable v, string AccessType)
{
- IdentifierExpr AccessSet1 = new IdentifierExpr(tok, new VariableDualiser(1).VisitVariable(
+ IdentifierExpr AccessSet1 = new IdentifierExpr(tok, new VariableDualiser(1, null, null).VisitVariable(
MakeAccessSetVariable(v, AccessType)));
IdentifierExprSeq VariablesToHavoc = new IdentifierExprSeq();
VariablesToHavoc.Add(AccessSet1);
if (!CommandLineOptions.Symmetry || !AccessType.Equals("READ"))
{
- IdentifierExpr AccessSet2 = new IdentifierExpr(tok, new VariableDualiser(2).VisitVariable(
+ IdentifierExpr AccessSet2 = new IdentifierExpr(tok, new VariableDualiser(2, null, null).VisitVariable(
MakeAccessSetVariable(v, AccessType)));
VariablesToHavoc.Add(AccessSet2);
}
@@ -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++)
{
@@ -277,8 +284,8 @@ namespace GPUVerify
{
VariableSeq DummyVarsAccess1;
VariableSeq DummyVarsAccess2;
- Expr IndexExpr1 = QuantifiedIndexExpr(v, new VariableDualiser(1).VisitVariable(v.Clone() as Variable), out DummyVarsAccess1);
- Expr IndexExpr2 = QuantifiedIndexExpr(v, new VariableDualiser(2).VisitVariable(v.Clone() as Variable), out DummyVarsAccess2);
+ Expr IndexExpr1 = QuantifiedIndexExpr(v, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable), out DummyVarsAccess1);
+ Expr IndexExpr2 = QuantifiedIndexExpr(v, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable), out DummyVarsAccess2);
Debug.Assert(DummyVarsAccess1.Length == DummyVarsAccess2.Length);
Debug.Assert(DummyVars1.Length == DummyVarsAccess1.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)
@@ -335,7 +341,7 @@ namespace GPUVerify
private static Expr AccessExpr(Variable v, String AccessType, int Thread, out VariableSeq DummyVars)
{
- return QuantifiedIndexExpr(v, new VariableDualiser(Thread).VisitVariable(MakeAccessSetVariable(v, AccessType)), out DummyVars);
+ return QuantifiedIndexExpr(v, new VariableDualiser(Thread, null, null).VisitVariable(MakeAccessSetVariable(v, AccessType)), out DummyVars);
}
private static Expr QuantifiedIndexExpr(Variable v, Variable AccessSetVariable, out VariableSeq DummyVars)
@@ -395,7 +401,7 @@ namespace GPUVerify
private static Expr NoAccess0DExpr(IToken tok, Variable v, String AccessType, int Thread)
{
- return Expr.Not(new IdentifierExpr(tok, new VariableDualiser(Thread).VisitVariable(MakeAccessSetVariable(v, AccessType))));
+ return Expr.Not(new IdentifierExpr(tok, new VariableDualiser(Thread, null, null).VisitVariable(MakeAccessSetVariable(v, AccessType))));
}
diff --git a/Source/GPUVerify/StructuredProgramVisitor.cs b/Source/GPUVerify/StructuredProgramVisitor.cs
new file mode 100644
index 00000000..8ed5a926
--- /dev/null
+++ b/Source/GPUVerify/StructuredProgramVisitor.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class StructuredProgramVisitor
+ {
+
+ protected GPUVerifier verifier;
+
+ public StructuredProgramVisitor(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ }
+
+ 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, whileCmd.Guard), VisitStmtList(whileCmd.Body));
+ }
+
+ public virtual BreakCmd VisitBreakCmd(BreakCmd breakCmd)
+ {
+ return breakCmd;
+ }
+
+
+ public virtual List<PredicateCmd> VisitWhileInvariants(List<PredicateCmd> invariants, Expr WhileGuard)
+ {
+ 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/UniformExpressionAnalysisVisitor.cs b/Source/GPUVerify/UniformExpressionAnalysisVisitor.cs
new file mode 100644
index 00000000..76f6b5de
--- /dev/null
+++ b/Source/GPUVerify/UniformExpressionAnalysisVisitor.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class UniformExpressionAnalysisVisitor : StandardVisitor
+ {
+
+ private bool isUniform = true;
+ private Dictionary<string, bool> uniformityInfo;
+
+ public UniformExpressionAnalysisVisitor(Dictionary<string, bool> uniformityInfo)
+ {
+ this.uniformityInfo = uniformityInfo;
+ }
+
+ public override Variable VisitVariable(Variable v)
+ {
+ if (!uniformityInfo.ContainsKey(v.Name))
+ {
+ isUniform = isUniform && (v is Constant);
+ }
+ else if (!uniformityInfo[v.Name])
+ {
+ isUniform = false;
+ }
+
+ return v;
+ }
+
+ internal bool IsUniform()
+ {
+ return isUniform;
+ }
+ }
+}
diff --git a/Source/GPUVerify/UniformityAnalyser.cs b/Source/GPUVerify/UniformityAnalyser.cs
new file mode 100644
index 00000000..072688a0
--- /dev/null
+++ b/Source/GPUVerify/UniformityAnalyser.cs
@@ -0,0 +1,332 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+
+namespace GPUVerify
+{
+
+ class UniformityAnalyser
+ {
+ private GPUVerifier verifier;
+
+ private bool ProcedureChanged;
+
+ private Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>> uniformityInfo;
+
+ private Dictionary<string, List<string>> inParameters;
+
+ private Dictionary<string, List<string>> outParameters;
+
+ public UniformityAnalyser(GPUVerifier verifier)
+ {
+ this.verifier = verifier;
+ uniformityInfo = new Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>>();
+ inParameters = new Dictionary<string, List<string>>();
+ outParameters = new Dictionary<string, List<string>>();
+ }
+
+ internal void Analyse()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if(D is Implementation)
+ {
+ bool uniformProcedure =
+ (D == verifier.KernelImplementation
+ || CommandLineOptions.DoUniformityAnalysis);
+
+ Implementation Impl = D as Implementation;
+ uniformityInfo.Add(Impl.Name, new KeyValuePair<bool, Dictionary<string, bool>>
+ (uniformProcedure, new Dictionary<string, bool> ()));
+
+ SetNonUniform(Impl.Name, GPUVerifier._X.Name);
+ SetNonUniform(Impl.Name, GPUVerifier._Y.Name);
+ SetNonUniform(Impl.Name, GPUVerifier._Z.Name);
+
+ foreach (Variable v in Impl.LocVars)
+ {
+ if (CommandLineOptions.DoUniformityAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ inParameters[Impl.Name] = new List<string>();
+
+ foreach (Variable v in Impl.InParams)
+ {
+ inParameters[Impl.Name].Add(v.Name);
+ if (CommandLineOptions.DoUniformityAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ outParameters[Impl.Name] = new List<string>();
+ foreach (Variable v in Impl.OutParams)
+ {
+ outParameters[Impl.Name].Add(v.Name);
+ if (CommandLineOptions.DoUniformityAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ ProcedureChanged = true;
+ }
+ }
+
+ if (CommandLineOptions.DoUniformityAnalysis)
+ {
+ while (ProcedureChanged)
+ {
+ ProcedureChanged = false;
+
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ Analyse(Impl, uniformityInfo[Impl.Name].Key);
+ }
+ }
+ }
+ }
+
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations)
+ {
+ if (D is Implementation)
+ {
+ Implementation Impl = D as Implementation;
+ if (!IsUniform (Impl.Name))
+ {
+ List<string> newIns = new List<String>();
+ newIns.Add("_P");
+ foreach (string s in inParameters[Impl.Name])
+ {
+ newIns.Add(s);
+ }
+ inParameters[Impl.Name] = newIns;
+ }
+ }
+ }
+
+ if (CommandLineOptions.ShowUniformityAnalysis)
+ {
+ dump();
+ }
+ }
+
+ private void Analyse(Implementation Impl, bool ControlFlowIsUniform)
+ {
+ Analyse(Impl, Impl.StructuredStmts, ControlFlowIsUniform);
+ }
+
+ private void Analyse(Implementation impl, StmtList stmtList, bool ControlFlowIsUniform)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(impl, bb, ControlFlowIsUniform);
+ }
+ }
+
+ private void Analyse(Implementation impl, BigBlock bb, bool ControlFlowIsUniform)
+ {
+ foreach (Cmd c in bb.simpleCmds)
+ {
+ if (c is AssignCmd)
+ {
+ AssignCmd assignCmd = c as AssignCmd;
+ Debug.Assert(assignCmd.Lhss.Count == 1);
+ Debug.Assert(assignCmd.Rhss.Count == 1);
+ if (assignCmd.Lhss[0] is SimpleAssignLhs)
+ {
+ SimpleAssignLhs lhs = assignCmd.Lhss[0] as SimpleAssignLhs;
+ Expr rhs = assignCmd.Rhss[0];
+
+ if (IsUniform(impl.Name, lhs.AssignedVariable.Name) &&
+ (!ControlFlowIsUniform || !IsUniform(impl.Name, rhs)))
+ {
+ SetNonUniform(impl.Name, lhs.AssignedVariable.Name);
+ }
+
+ }
+ }
+ else if (c is CallCmd)
+ {
+ CallCmd callCmd = c as CallCmd;
+
+ if (callCmd.callee != verifier.BarrierProcedure.Name)
+ {
+
+ if (!ControlFlowIsUniform)
+ {
+ if (IsUniform(callCmd.callee))
+ {
+ SetNonUniform(callCmd.callee);
+ }
+ }
+ Implementation CalleeImplementation = verifier.GetImplementation(callCmd.callee);
+ for (int i = 0; i < CalleeImplementation.InParams.Length; i++)
+ {
+ if (IsUniform(callCmd.callee, CalleeImplementation.InParams[i].Name)
+ && !IsUniform(impl.Name, callCmd.Ins[i]))
+ {
+ SetNonUniform(callCmd.callee, CalleeImplementation.InParams[i].Name);
+ }
+ }
+
+ for (int i = 0; i < CalleeImplementation.OutParams.Length; i++)
+ {
+ if (IsUniform(impl.Name, callCmd.Outs[i].Name)
+ && !IsUniform(callCmd.callee, CalleeImplementation.OutParams[i].Name))
+ {
+ SetNonUniform(impl.Name, callCmd.Outs[i].Name);
+ }
+ }
+
+ }
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ Analyse(impl, wc.Body, ControlFlowIsUniform && IsUniform(impl.Name, wc.Guard));
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ Analyse(impl, ifCmd.thn, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
+ if (ifCmd.elseBlock != null)
+ {
+ Analyse(impl, ifCmd.elseBlock, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
+ }
+ Debug.Assert(ifCmd.elseIf == null);
+ }
+
+ }
+
+ private void SetNonUniform(string procedureName)
+ {
+ uniformityInfo[procedureName] = new KeyValuePair<bool,Dictionary<string,bool>>
+ (false, uniformityInfo[procedureName].Value);
+ RecordProcedureChanged();
+ }
+
+ internal bool IsUniform(string procedureName)
+ {
+ if (!uniformityInfo.ContainsKey(procedureName))
+ {
+ return false;
+ }
+ return uniformityInfo[procedureName].Key;
+ }
+
+ internal bool IsUniform(string procedureName, Expr expr)
+ {
+ UniformExpressionAnalysisVisitor visitor = new UniformExpressionAnalysisVisitor(uniformityInfo[procedureName].Value);
+ visitor.VisitExpr(expr);
+ return visitor.IsUniform();
+ }
+
+ internal bool IsUniform(string procedureName, string v)
+ {
+ if (!uniformityInfo.ContainsKey(procedureName))
+ {
+ return false;
+ }
+
+ if (!uniformityInfo[procedureName].Value.ContainsKey(v))
+ {
+ return false;
+ }
+ return uniformityInfo[procedureName].Value[v];
+ }
+
+ private void SetUniform(string procedureName, string v)
+ {
+ uniformityInfo[procedureName].Value[v] = true;
+ RecordProcedureChanged();
+ }
+
+ private void RecordProcedureChanged()
+ {
+ ProcedureChanged = true;
+ }
+
+ private void SetNonUniform(string procedureName, string v)
+ {
+ uniformityInfo[procedureName].Value[v] = false;
+ RecordProcedureChanged();
+ }
+
+ private void dump()
+ {
+ foreach (string p in uniformityInfo.Keys)
+ {
+ Console.WriteLine("Procedure " + p + ": "
+ + (uniformityInfo[p].Key ? "uniform" : "nonuniform"));
+ foreach (string v in uniformityInfo[p].Value.Keys)
+ {
+ Console.WriteLine(" " + v + ": " +
+ (uniformityInfo[p].Value[v] ? "uniform" : "nonuniform"));
+ }
+ Console.Write("Ins [");
+ for (int i = 0; i < inParameters[p].Count; i++)
+ {
+ Console.Write((i == 0 ? "" : ", ") + inParameters[p][i]);
+ }
+ Console.WriteLine("]");
+ Console.Write("Outs [");
+ for (int i = 0; i < outParameters[p].Count; i++)
+ {
+ Console.Write((i == 0 ? "" : ", ") + outParameters[p][i]);
+ }
+ Console.WriteLine("]");
+ }
+ }
+
+
+ internal string GetInParameter(string procName, int i)
+ {
+ return inParameters[procName][i];
+ }
+
+ internal string GetOutParameter(string procName, int i)
+ {
+ return outParameters[procName][i];
+ }
+
+
+ internal bool knowsOf(string p)
+ {
+ return uniformityInfo.ContainsKey(p);
+ }
+
+ internal void AddNonUniform(string proc, string v)
+ {
+ if (uniformityInfo.ContainsKey(proc))
+ {
+ Debug.Assert(!uniformityInfo[proc].Value.ContainsKey(v));
+ uniformityInfo[proc].Value[v] = false;
+ }
+ }
+ }
+
+}
diff --git a/Source/GPUVerify/VariableDualiser.cs b/Source/GPUVerify/VariableDualiser.cs
index 5cbfed99..7f637734 100644
--- a/Source/GPUVerify/VariableDualiser.cs
+++ b/Source/GPUVerify/VariableDualiser.cs
@@ -11,10 +11,17 @@ namespace GPUVerify
class VariableDualiser : Duplicator
{
private int id;
+ private UniformityAnalyser uniformityAnalyser;
+ private string procName;
- public VariableDualiser(int id)
+ public VariableDualiser(int id, UniformityAnalyser uniformityAnalyser, string procName)
{
+ Debug.Assert((uniformityAnalyser == null && procName == null)
+ || (uniformityAnalyser != null && procName != null));
+
this.id = id;
+ this.uniformityAnalyser = uniformityAnalyser;
+ this.procName = procName;
}
public override Expr VisitIdentifierExpr(IdentifierExpr node)
@@ -34,7 +41,13 @@ namespace GPUVerify
private TypedIdent DualiseTypedIdent(Variable v)
{
- return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type);
+
+ if (uniformityAnalyser == null || !uniformityAnalyser.IsUniform(procName, v.Name))
+ {
+ return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type);
+ }
+
+ return new TypedIdent(v.tok, v.Name, v.TypedIdent.Type);
}
public override Variable VisitVariable(Variable node)
@@ -49,6 +62,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/GPUVerify/VariablesOccurringInExpressionVisitor.cs b/Source/GPUVerify/VariablesOccurringInExpressionVisitor.cs
new file mode 100644
index 00000000..9c46db38
--- /dev/null
+++ b/Source/GPUVerify/VariablesOccurringInExpressionVisitor.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class VariablesOccurringInExpressionVisitor : StandardVisitor
+ {
+ private HashSet<Variable> variables = new HashSet<Variable>();
+
+ internal IEnumerable<Microsoft.Boogie.Variable> GetVariables()
+ {
+ return variables;
+ }
+
+ public override Variable VisitVariable(Variable node)
+ {
+ variables.Add(node);
+ return base.VisitVariable(node);
+ }
+
+ }
+}
diff --git a/Source/Houdini/Checker.cs b/Source/Houdini/Checker.cs
index 08d8346a..f99c4651 100644
--- a/Source/Houdini/Checker.cs
+++ b/Source/Houdini/Checker.cs
@@ -8,9 +8,7 @@ using System.Diagnostics.Contracts;
using System.Collections.Generic;
using Microsoft.Boogie;
using Microsoft.Boogie.VCExprAST;
-using Microsoft.Boogie.Simplify;
-using Microsoft.Boogie.Z3;
-using Microsoft.Boogie.SMTLib;
+using Microsoft.Basetypes;
using System.Collections;
using System.IO;
using System.Threading;
@@ -20,7 +18,7 @@ namespace Microsoft.Boogie.Houdini {
public class HoudiniSession {
public static double proverTime = 0;
public static int numProverQueries = 0;
- private string descriptiveName;
+ public string descriptiveName;
private VCExpr conjecture;
private ProverInterface.ErrorHandler handler;
ConditionGeneration.CounterexampleCollector collector;
@@ -29,16 +27,22 @@ namespace Microsoft.Boogie.Houdini {
descriptiveName = impl.Name;
collector = new ConditionGeneration.CounterexampleCollector();
collector.OnProgress("HdnVCGen", 0, 0, 0.0);
- if (CommandLineOptions.Clo.SoundnessSmokeTest) {
- throw new Exception("HoudiniVCGen does not support Soundness smoke test.");
- }
vcgen.ConvertCFG2DAG(impl, program);
ModelViewInfo mvInfo;
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, null, out label2absy, checker);
+ conjecture = vcgen.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)));
+ conjecture = exprGen.Implies(eqExpr, conjecture);
+ }
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);
@@ -52,26 +56,21 @@ namespace Microsoft.Boogie.Houdini {
collector.examples.Clear();
VCExpr vc = checker.VCExprGen.Implies(axiom, conjecture);
+ 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 1f3909e4..f6c334e7 100644
--- a/Source/Houdini/Houdini.cs
+++ b/Source/Houdini/Houdini.cs
@@ -8,9 +8,7 @@ using System.Diagnostics.Contracts;
using System.Collections.Generic;
using Microsoft.Boogie;
using Microsoft.Boogie.VCExprAST;
-using Microsoft.Boogie.Simplify;
using VC;
-using Microsoft.Boogie.Z3;
using System.Collections;
using System.IO;
using Microsoft.AbstractInterpretationFramework;
@@ -305,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...");
@@ -513,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:
@@ -574,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) {
@@ -626,18 +557,20 @@ 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();
}
private void UpdateAssignment(HoudiniState current, RefutedAnnotation refAnnot) {
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("Removing " + refAnnot.Constant);
+ }
current.Assignment.Remove(refAnnot.Constant);
current.Assignment.Add(refAnnot.Constant, false);
this.NotifyConstant(refAnnot.Constant);
@@ -650,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)) {
@@ -704,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) {
@@ -726,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 {
@@ -809,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);
@@ -917,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;
@@ -1027,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) {
@@ -1084,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;
@@ -1097,141 +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
- 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;
}
}
@@ -1241,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)
@@ -1255,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)
@@ -1266,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/Houdini/Houdini.csproj b/Source/Houdini/Houdini.csproj
index c4d4cb8a..af1755a3 100644
--- a/Source/Houdini/Houdini.csproj
+++ b/Source/Houdini/Houdini.csproj
@@ -106,18 +106,10 @@
<Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
<Name>ParserHelper</Name>
</ProjectReference>
- <ProjectReference Include="..\Provers\Simplify\Simplify.csproj">
- <Project>{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}</Project>
- <Name>Simplify</Name>
- </ProjectReference>
<ProjectReference Include="..\Provers\SMTLib\SMTLib.csproj">
<Project>{9B163AA3-36BC-4AFB-88AB-79BC9E97E401}</Project>
<Name>SMTLib</Name>
</ProjectReference>
- <ProjectReference Include="..\Provers\Z3\Z3.csproj">
- <Project>{BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}</Project>
- <Name>Z3</Name>
- </ProjectReference>
<ProjectReference Include="..\VCExpr\VCExpr.csproj">
<Project>{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}</Project>
<Name>VCExpr</Name>
diff --git a/Source/Model/Model.cs b/Source/Model/Model.cs
index 0b20ff33..204d130e 100644
--- a/Source/Model/Model.cs
+++ b/Source/Model/Model.cs
@@ -35,6 +35,7 @@ using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
+using System.Text.RegularExpressions;
namespace Microsoft.Boogie
{
@@ -701,10 +702,13 @@ namespace Microsoft.Boogie
if (f < 0) BadModel("mismatched parentheses in datatype term");
return f;
}
+
+ static Regex bv = new Regex(@"\(_ BitVec (\d+)\)");
List<object> GetFunctionTuple(string newLine) {
if (newLine == null)
return null;
+ newLine = bv.Replace(newLine, "bv${1}");
string line = newLine;
int openParenCounter = CountOpenParentheses(newLine, 0);
if (!newLine.Contains("}")) {
@@ -850,7 +854,7 @@ namespace Microsoft.Boogie
if (fn == null)
fn = currModel.MkFunc(funName, 1);
if (tuple0 == "}") break;
- fn.Else = GetElt(tuple0);
+ fn.Else = GetElt(tuple[0]);
continue;
}
string tuplePenultimate = tuple[tuple.Count - 2] as string;
diff --git a/Source/ModelViewer/ModelViewer.csproj b/Source/ModelViewer/ModelViewer.csproj
index 383ccf43..ae46767b 100644
--- a/Source/ModelViewer/ModelViewer.csproj
+++ b/Source/ModelViewer/ModelViewer.csproj
@@ -31,7 +31,7 @@
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@@ -41,7 +41,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
@@ -63,7 +63,7 @@
<OutputPath>bin\x86\Checked\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
- <PlatformTarget>x86</PlatformTarget>
+ <PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisLogFile>..\..\Binaries\BVD.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
@@ -194,4 +194,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project> \ No newline at end of file
diff --git a/Source/ModelViewer/VccProvider.cs b/Source/ModelViewer/VccProvider.cs
index 1393b3a2..c226d646 100644
--- a/Source/ModelViewer/VccProvider.cs
+++ b/Source/ModelViewer/VccProvider.cs
@@ -37,7 +37,7 @@ namespace Microsoft.Boogie.ModelViewer.Vcc
public readonly Model.Func f_ptr_to, f_phys_ptr_cast, f_spec_ptr_cast, f_mathint, f_local_value_is, f_spec_ptr_to, f_heap, f_select_field,
f_select_value, f_field, f_field_type, f_int_to_ptr, f_ptr_to_int, f_ptr, f_map_t, f_select_ptr,
f_owners, f_closed, f_roots, f_timestamps, f_select_bool, f_select_int, f_is_null, f_good_state,
- f_int_to_version, f_int_to_ptrset, f_set_in0, f_is_ghost_field, f_is_phys_field, f_idx, f_field_plus,
+ f_int_to_version, f_int_to_ptrset, f_set_in0, f_is_ghost_field, f_is_phys_field, f_idx,
f_is_sequential_field, f_is_volatile_field, f_type_project_0, f_array, f_active_option, f_int_to_field,
f_blob_type, f_array_emb, f_addr, f_address_root, f_base, f_field_arr_size, f_field_arr_root, f_field_arr_index,
f_dot, f_prim_emb;
@@ -92,7 +92,6 @@ namespace Microsoft.Boogie.ModelViewer.Vcc
f_is_ghost_field = m.MkFunc("$is_ghost_field", 1);
f_is_phys_field = m.MkFunc("$is_phys_field", 1);
f_idx = m.MkFunc("$idx", 2);
- f_field_plus = m.MkFunc("$field_plus", 2);
f_is_sequential_field = m.MkFunc("$is_sequential_field", 1);
f_is_volatile_field = m.MkFunc("$is_volatile_field", 1);
f_type_project_0 = m.MkFunc("$type_project_0", 1);
@@ -970,33 +969,26 @@ namespace Microsoft.Boogie.ModelViewer.Vcc
}
{
- var eltBase = f_base.TryEval(elt);
- var eltField = f_field.TryEval(elt);
- if (eltBase != null && eltField != null) {
- foreach (var app in f_field_plus.AppsWithArg(0, eltField)) {
- var fieldName = app.Result;
- var addr = f_dot.TryEval(eltBase, fieldName);
- if (addr == null) continue;
-
- Model.Element val = null, atp = tp;
-
- addresses.Add(addr);
-
- foreach (var papp in f_dot.AppsWithResult(addr)) {
- var tmp = f_select_value.OptEval(f_select_field.OptEval(heap, papp.Args[1]), papp.Args[0]);
- if (tmp != null) {
- val = tmp;
- var tt = f_field_type.TryEval(papp.Args[1]);
- if (tt != null) atp = tt;
- }
+ foreach (var app in f_idx.AppsWithArg(0, elt)) {
+ var addr = app.Result;
+ Model.Element val = null, atp = tp;
+
+ addresses.Add(addr);
+
+ foreach (var papp in f_dot.AppsWithResult(addr)) {
+ var tmp = f_select_value.OptEval(f_select_field.OptEval(heap, papp.Args[1]), papp.Args[0]);
+ if (tmp != null) {
+ val = tmp;
+ var tt = f_field_type.TryEval(papp.Args[1]);
+ if (tt != null) atp = tt;
}
-
- if (val != null)
- val = WrapForUse(val, atp);
- result.Add(new MapletNode(state, new EdgeName(this, "[%0]", app.Args[1]), val, atp) { Category = NodeCategory.Maplet });
- if (addr != null)
- result.Add(new MapletNode(state, new EdgeName(this, "&[%0]", app.Args[1]), addr, GuessPtrTo(atp)) { Category = NodeCategory.Maplet });
}
+
+ if (val != null)
+ val = WrapForUse(val, atp);
+ result.Add(new MapletNode(state, new EdgeName(this, "[%0]", app.Args[1]), val, atp) { Category = NodeCategory.Maplet });
+ if (addr != null)
+ result.Add(new MapletNode(state, new EdgeName(this, "&[%0]", app.Args[1]), addr, GuessPtrTo(atp)) { Category = NodeCategory.Maplet });
}
}
diff --git a/Source/Provers/SMTLib/Inspector.cs b/Source/Provers/SMTLib/Inspector.cs
index 4126c169..362502f3 100644
--- a/Source/Provers/SMTLib/Inspector.cs
+++ b/Source/Provers/SMTLib/Inspector.cs
@@ -11,7 +11,6 @@ using System.Collections.Generic;
using System.Diagnostics.Contracts;
//using util;
using Microsoft.Boogie;
-using Microsoft.Boogie.Simplify;
using Microsoft.Basetypes;
using Microsoft.Boogie.VCExprAST;
diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs
index 40492ce4..6ef3778d 100644
--- a/Source/Provers/SMTLib/ProverInterface.cs
+++ b/Source/Provers/SMTLib/ProverInterface.cs
@@ -17,12 +17,11 @@ using Microsoft.Boogie;
using Microsoft.Boogie.VCExprAST;
using Microsoft.Boogie.Clustering;
using Microsoft.Boogie.TypeErasure;
-using Microsoft.Boogie.Simplify;
using System.Text;
namespace Microsoft.Boogie.SMTLib
{
- public class SMTLibProcessTheoremProver : ApiProverInterface
+ public class SMTLibProcessTheoremProver : ProverInterface
{
private readonly SMTLibProverContext ctx;
private readonly VCExpressionGenerator gen;
@@ -94,7 +93,6 @@ namespace Microsoft.Boogie.SMTLib
PrepareCommon();
}
prevOutcomeAvailable = false;
- pendingPop = false;
}
void SetupProcess()
@@ -187,7 +185,7 @@ namespace Microsoft.Boogie.SMTLib
if (common.Length == 0) {
SendCommon("(set-option :print-success false)");
SendCommon("(set-info :smt-lib-version 2.0)");
- if (options.ExpectingModel())
+ if (options.ProduceModel())
SendCommon("(set-option :produce-models true)");
foreach (var opt in options.SmtOptions) {
SendCommon("(set-option :" + opt.Option + " " + opt.Value + ")");
@@ -383,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;
@@ -401,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();
@@ -449,63 +466,91 @@ namespace Microsoft.Boogie.SMTLib
}
}
- private string[] GetLabelsInfo(ErrorHandler handler)
+ 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.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;
+ path.Add(v);
+ break;
+ }
+ else if (resp.ArgCount != 0)
+ break;
+ 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 {
+ HandleProverError("Unexpected prover response getting model: " + resp.ToString());
+ }
+ 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)
+ 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 new ErrorModel(theModel);
+ }
+
+ private string[] GetLabelsInfo()
{
SendThisVC("(labels)");
- if (options.ExpectingModel())
- SendThisVC("(get-model)");
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 (labelNums != null) {
- ErrorModel m = null;
- if (theModel != null)
- m = new ErrorModel(theModel);
- handler.OnModel(labelNums, m);
- }
-
return res;
}
@@ -718,7 +763,6 @@ namespace Microsoft.Boogie.SMTLib
throw new NotImplementedException();
}
- // For implementing ApiProverInterface
public override void Assert(VCExpr vc, bool polarity)
{
string a = "";
@@ -741,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)");
@@ -757,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
@@ -786,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");
@@ -796,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/SMTLib/SMTLib.csproj b/Source/Provers/SMTLib/SMTLib.csproj
index f4cdbb14..3dc042a6 100644
--- a/Source/Provers/SMTLib/SMTLib.csproj
+++ b/Source/Provers/SMTLib/SMTLib.csproj
@@ -191,10 +191,6 @@
<Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
<Name>VCGeneration</Name>
</ProjectReference>
- <ProjectReference Include="..\Simplify\Simplify.csproj">
- <Project>{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}</Project>
- <Name>Simplify</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
diff --git a/Source/Provers/SMTLib/SMTLibNamer.cs b/Source/Provers/SMTLib/SMTLibNamer.cs
index a874c6c5..5629c0d6 100644
--- a/Source/Provers/SMTLib/SMTLibNamer.cs
+++ b/Source/Provers/SMTLib/SMTLibNamer.cs
@@ -36,6 +36,12 @@ namespace Microsoft.Boogie.SMTLib
"bvsge", "bvslt", "bvugt", "bvsgt", "bvxor", "bvnand", "bvnor", "bvxnor", "sign_extend", "zero_extend",
"repeat", "bvredor", "bvredand", "bvcomp", "bvumul_noovfl", "bvsmul_noovfl", "bvsmul_noudfl", "bvashr",
"rotate_left", "rotate_right", "ext_rotate_left", "ext_rotate_right", "int2bv", "bv2int",
+ // floating point
+ "plusInfinity", "minusInfinity", "NaN",
+ "roundNearestTiesToEven", "roundNearestTiesToAway", "roundTowardPositive", "roundTowardNegative", "roundTowardZero",
+ "+", "-", "/", "*", "==", "<", ">", "<=", ">=",
+ "abs", "remainder", "fusedMA", "squareRoot", "roundToIntegral",
+ "isZero", "isNZero", "isPZero", "isSignMinus", "min", "max", "asFloat",
// SMT v1 stuff
"flet", "implies", "!=", "if_then_else",
// Z3 extensions
diff --git a/Source/Provers/SMTLib/SMTLibProverOptions.cs b/Source/Provers/SMTLib/SMTLibProverOptions.cs
index 036b1f4a..6fe025c0 100644
--- a/Source/Provers/SMTLib/SMTLibProverOptions.cs
+++ b/Source/Provers/SMTLib/SMTLibProverOptions.cs
@@ -41,12 +41,16 @@ namespace Microsoft.Boogie.SMTLib
public string Inspector = null;
public bool OptimizeForBv = false;
+ public bool ProduceModel() {
+ return !CommandLineOptions.Clo.UseLabels ||
+ ExpectingModel();
+ }
+
public bool ExpectingModel()
{
return CommandLineOptions.Clo.PrintErrorModel >= 1 ||
CommandLineOptions.Clo.EnhancedErrorMessages == 1 ||
CommandLineOptions.Clo.ModelViewFile != null ||
- CommandLineOptions.Clo.ContractInfer ||
CommandLineOptions.Clo.LazyInlining > 0 ||
(CommandLineOptions.Clo.StratifiedInlining > 0 && !CommandLineOptions.Clo.StratifiedInliningWithoutModels);
}
diff --git a/Source/Provers/SMTLib/TypeDeclCollector.cs b/Source/Provers/SMTLib/TypeDeclCollector.cs
index 40dc7cf6..05a6caf3 100644
--- a/Source/Provers/SMTLib/TypeDeclCollector.cs
+++ b/Source/Provers/SMTLib/TypeDeclCollector.cs
@@ -164,6 +164,7 @@ void ObjectInvariant()
return TypeToString(t);
}
+
public override bool Visit(VCExprNAry node, bool arg) {
Contract.Requires(node != null);
@@ -171,7 +172,9 @@ void ObjectInvariant()
else if (node.Op is VCExprSelectOp) RegisterSelect(node);
else {
VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp;
- if (op != null && !IsDatatypeFunction(op.Func) && !KnownFunctions.Contains(op.Func)) {
+ if (op != null &&
+ !(op.Func is DatatypeConstructor) && !(op.Func is DatatypeMembership) && !(op.Func is DatatypeSelector) &&
+ !KnownFunctions.Contains(op.Func)) {
Function f = op.Func;
Contract.Assert(f != null);
@@ -250,26 +253,16 @@ void ObjectInvariant()
if (type.IsBool || type.IsInt || type.IsBv)
return;
- if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.Monomorphic && !IsDatatype(type)) {
+ CtorType ctorType = type as CtorType;
+ if (ctorType != null && ctorType.IsDatatype())
+ return;
+
+ if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.Monomorphic) {
AddDeclaration("(declare-sort " + TypeToString(type) + " 0)");
KnownTypes.Add(type);
return;
}
- }
-
- public static bool IsDatatype(Type t) {
- CtorType ctorType = t.AsCtor;
- if (t == null)
- return false;
- return QKeyValue.FindBoolAttribute(ctorType.Decl.Attributes, "datatype");
- }
-
- public static bool IsDatatypeFunction(Function f) {
- return
- f is DatatypeConstructor ||
- f is DatatypeSelector ||
- f is DatatypeMembership;
- }
+ }
private void RegisterSelect(VCExprNAry node)
{
diff --git a/Source/Provers/SMTLib/Z3.cs b/Source/Provers/SMTLib/Z3.cs
index 2b426f0b..ce0265d3 100644
--- a/Source/Provers/SMTLib/Z3.cs
+++ b/Source/Provers/SMTLib/Z3.cs
@@ -43,8 +43,12 @@ namespace Microsoft.Boogie.SMTLib
_proverPath = Path.Combine(CodebaseString(), proverExe);
string firstTry = _proverPath;
- if (File.Exists(firstTry))
+ if (File.Exists(firstTry)) {
+ if (CommandLineOptions.Clo.Trace) {
+ Console.WriteLine("[TRACE] Using prover: " + _proverPath);
+ }
return;
+ }
string programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
Contract.Assert(programFiles != null);
diff --git a/Source/Provers/TPTP/TPTP.csproj b/Source/Provers/TPTP/TPTP.csproj
index 564b33f3..882d8009 100644
--- a/Source/Provers/TPTP/TPTP.csproj
+++ b/Source/Provers/TPTP/TPTP.csproj
@@ -116,10 +116,6 @@
<Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
<Name>VCGeneration</Name>
</ProjectReference>
- <ProjectReference Include="..\Simplify\Simplify.csproj">
- <Project>{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}</Project>
- <Name>Simplify</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
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/Provers/Z3api/Z3api.csproj b/Source/Provers/Z3api/Z3api.csproj
index 94184957..7c481438 100644
--- a/Source/Provers/Z3api/Z3api.csproj
+++ b/Source/Provers/Z3api/Z3api.csproj
@@ -162,14 +162,6 @@
<Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
<Name>VCGeneration</Name>
</ProjectReference>
- <ProjectReference Include="..\Simplify\Simplify.csproj">
- <Project>{FEE9F01B-9722-4A76-A24B-72A4016DFA8E}</Project>
- <Name>Simplify</Name>
- </ProjectReference>
- <ProjectReference Include="..\Z3\Z3.csproj">
- <Project>{BB49B90B-BE21-4BE8-85BA-359FDB55F4DF}</Project>
- <Name>Z3</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\version.cs">
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 b4e330ea..b9b0928c 100644
--- a/Source/VCGeneration/StratifiedVC.cs
+++ b/Source/VCGeneration/StratifiedVC.cs
@@ -29,6 +29,7 @@ namespace VC
public readonly static string recordProcName = "boogie_si_record";
private bool useSummary;
private SummaryComputation summaryComputation;
+ private HashSet<string> procsThatReachedRecBound;
[ContractInvariantMethod]
void ObjectInvariant()
@@ -50,6 +51,7 @@ namespace VC
this.GenerateVCsForStratifiedInlining(program);
PersistCallTree = false;
useSummary = false;
+ procsThatReachedRecBound = new HashSet<string>();
}
public static RECORD_TYPES getRecordType(Bpl.Type type)
@@ -85,7 +87,6 @@ namespace VC
{
Contract.Invariant(cce.NonNullElements(privateVars));
Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
}
public bool initialized;
@@ -125,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())
@@ -206,8 +204,20 @@ namespace VC
Hashtable/*<int, Absy!>*/ label2absy;
VCExpressionGenerator gen = checker.VCExprGen;
Contract.Assert(gen != null);
- VCExpr vcexpr = gen.Not(GenerateVC(impl, null, out label2absy, checker));
+
+ 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, 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;
@@ -266,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>();
@@ -550,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,
@@ -620,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;
@@ -1017,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)
@@ -1168,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) {
@@ -1215,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) {
@@ -1242,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) {
@@ -1266,7 +1164,7 @@ namespace VC
}
}
- public override void SetTimeOut(int msec)
+ public void SetTimeOut(int msec)
{
TheoremProver.SetTimeOut(msec);
}
@@ -1283,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
@@ -1297,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)
@@ -1305,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;
@@ -1363,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);
@@ -1418,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));
@@ -1460,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;
@@ -1629,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);
@@ -1700,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
@@ -1856,7 +1750,12 @@ namespace VC
}
#region expand call tree
-
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
+ {
+ Console.Write(">> SI Inlining: ");
+ reporter.candidatesToExpand.ForEach(c => Console.Write("{0} ", calls.getProc(c)));
+ Console.WriteLine();
+ }
// Expand and try again
vState.checker.LogComment(";;;;;;;;;;;; Expansion begin ;;;;;;;;;;");
DoExpansion(incrementalSearch, reporter.candidatesToExpand, vState);
@@ -1885,19 +1784,23 @@ 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();
numInlined = (calls.candidateParent.Keys.Count + 1) - (calls.currCandidates.Count);
+ var rbound = "Procs that reached bound: ";
+ foreach (var s in procsThatReachedRecBound) rbound += " " + s;
+ if(ret == Outcome.ReachedBound) Helpers.ExtraTraceInformation(rbound);
+
// Store current call tree
if (PersistCallTree && (ret == Outcome.Correct || ret == Outcome.Errors || ret == Outcome.ReachedBound))
{
@@ -1948,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;
@@ -2008,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;
@@ -2029,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;
@@ -2160,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);
@@ -2182,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)) {
@@ -2205,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;
@@ -2250,6 +2158,8 @@ namespace VC
}
}
+
+
// A step of the stratified inlining algorithm: both under-approx and over-approx queries
private Outcome stratifiedStep(int bound, VerificationState vState, HashSet<int> block)
{
@@ -2330,6 +2240,8 @@ namespace VC
bool allFalse = true;
assumptions = new List<VCExpr>();
+ procsThatReachedRecBound.Clear();
+
foreach (int id in calls.currCandidates)
{
if (calls.getRecursionBound(id) <= bound)
@@ -2349,6 +2261,7 @@ namespace VC
}
else
{
+ procsThatReachedRecBound.Add(calls.getProc(id));
//checker.AddAxiom(calls.getFalseExpr(id));
assumptions.Add(calls.getFalseExpr(id));
allTrue = false;
@@ -2440,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>();
@@ -2609,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,
@@ -3139,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
@@ -3415,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>();
@@ -3425,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);
@@ -3455,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;
@@ -3481,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);
@@ -3522,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)
{
@@ -3550,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;
}
@@ -3571,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));
}
}
@@ -3632,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));
}
@@ -3650,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));
}
@@ -3662,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 6026b862..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);
@@ -607,8 +607,19 @@ namespace VC {
Hashtable label2Absy;
Checker ch = parent.FindCheckerFor(impl, CommandLineOptions.Clo.SmokeTimeout);
Contract.Assert(ch != null);
- VCExpr vc = parent.GenerateVC(impl, null, out label2Absy, ch);
+
+ var exprGen = ch.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch);
Contract.Assert(vc != null);
+
+ 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);
+ }
+
impl.Blocks = backup;
if (CommandLineOptions.Clo.TraceVerify) {
@@ -1329,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);
}
}
}
@@ -1536,9 +1547,18 @@ namespace VC {
}
));
- VCExpr vc = parent.GenerateVCAux(impl, null, label2absy, checker);
+ var exprGen = ctx.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker);
Contract.Assert(vc != null);
+ 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);
+ }
+
if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local) {
reporter = new ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, parent.implName2LazyInliningInfo, cce.NonNull(this.Checker.TheoremProver.Context), parent.program);
} else {
@@ -1610,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);
@@ -1618,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);
@@ -1652,13 +1672,13 @@ namespace VC {
break;
case CommandLineOptions.VCVariety.Dag:
if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags) {
- vc = DagVC(cce.NonNull(impl.Blocks[0]), 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);
@@ -2050,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;
}
@@ -2701,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;
}
@@ -2839,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;
@@ -3384,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>();
@@ -3423,7 +3441,7 @@ namespace VC {
}
static VCExpr LetVC(Block startBlock,
- Variable controlFlowVariable,
+ VCExpr controlFlowVariableExpr,
Hashtable/*<int, Absy!>*/ label2absy,
ProverContext proverCtxt,
out int assertionCount) {
@@ -3434,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) {
@@ -3486,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);
@@ -3497,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;
@@ -3510,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,
@@ -3551,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);
@@ -3566,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;
@@ -3578,6 +3594,7 @@ namespace VC {
}
static VCExpr DagVC(Block block,
+ VCExpr controlFlowVariableExpr,
Hashtable/*<int, Absy!>*/ label2absy,
Hashtable/*<Block, VCExpr!>*/ blockEquations,
ProverContext proverCtxt,
@@ -3608,8 +3625,13 @@ namespace VC {
foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
Contract.Assert(successor != null);
int ac;
- VCExpr c = DagVC(successor, label2absy, blockEquations, proverCtxt, out ac);
+ VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac);
assertionCount += ac;
+ 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);
+ }
SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
}
}
@@ -3617,7 +3639,7 @@ namespace VC {
SuccCorrect = VCExpressionGenerator.True;
}
- VCContext context = new VCContext(label2absy, proverCtxt);
+ 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 b84df433..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,19 +126,17 @@ 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)));
+ VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId)));
if (ctxt.Label2absy == null) {
- return gen.AndSimp(gen.Implies(assertFailure, C), gen.Implies(C, N));
+ return gen.AndSimp(gen.Implies(assertFailure, C), N);
} else {
- return gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), gen.Implies(C, N));
+ return gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), N);
}
}
}
diff --git a/Test/alltests.txt b/Test/alltests.txt
index dced2455..7076a370 100644
--- a/Test/alltests.txt
+++ b/Test/alltests.txt
@@ -21,17 +21,17 @@ prover Use Tests checking various prover options
test17 Postponed Tests inference of parameterized contracts
z3api Postponed Test for Z3 Managed .NET API prover
houdini Use Test for Houdini decision procedure
-datatypes DisabledUntilZ3IsUpdated Test for datatypes
+datatypes SoonToBeIncluded Test for datatypes
generalizedarray Use Test for generalized array theory
+livevars Use STORM benchmarks for testing correctness of live variable analysis
+lazyinline Postponed Lazy inlining benchmarks
+stratifiedinline Use Stratified inlining benchmarks
+extractloops Use Extract loops benchmarks
+havoc0 Use HAVOC-generated bpl files
dafny0 Use Dafny functionality tests
dafny1 Use Various Dafny examples
dafny2 Use More Dafny examples
-havoc0 Use HAVOC-generated bpl files
VSI-Benchmarks Use Solutions to Verified Software Initiative verification challenges
vacid0 Use Dafny attempts to VACID Edition 0 benchmarks
vstte2012 Use Dafny solutions for the VSTTE 2012 program verification competition
-livevars Use STORM benchmarks for testing correctness of live variable analysis
-lazyinline Postponed Lazy inlining benchmarks
-stratifiedinline Use Stratified inlining benchmarks
-extractloops Use Extract loops benchmarks
VSComp2010 Use Dafny solutions to VSComp (verified software competition) problems
diff --git a/Test/dafny0/Answer b/Test/dafny0/Answer
index 6f160a66..589a43e2 100644
--- a/Test/dafny0/Answer
+++ b/Test/dafny0/Answer
@@ -247,8 +247,47 @@ SmallTests.dfy(408,10): Error BP5003: A postcondition might not hold on this ret
SmallTests.dfy(411,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
+SmallTests.dfy(561,12): Error: assertion violation
+Execution trace:
+ (0,0): anon0
+ (0,0): anon3_Then
+ (0,0): anon2
+SmallTests.dfy(575,20): Error: left-hand sides 0 and 1 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ (0,0): anon28_Then
+ (0,0): anon4
+ (0,0): anon29_Then
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Then
+ (0,0): anon32_Then
+ (0,0): anon12
+SmallTests.dfy(577,15): Error: left-hand sides 1 and 2 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ SmallTests.dfy(570,18): anon28_Else
+ (0,0): anon4
+ (0,0): anon29_Else
+ (0,0): anon7
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Else
+ (0,0): anon35_Then
+ (0,0): anon36_Then
+ (0,0): anon37_Then
+ (0,0): anon22
+ (0,0): anon38_Then
+SmallTests.dfy(584,18): Error: target object may be null
+Execution trace:
+ (0,0): anon0
+SmallTests.dfy(597,10): Error: assertion violation
+Execution trace:
+ (0,0): anon0
-Dafny program verifier finished with 58 verified, 21 errors
+Dafny program verifier finished with 68 verified, 26 errors
-------------------- Definedness.dfy --------------------
Definedness.dfy(8,7): Error: possible division by zero
@@ -498,7 +537,9 @@ ResolutionErrors.dfy(305,16): Error: arguments must have the same type (got DTD_
ResolutionErrors.dfy(306,25): Error: arguments must have the same type (got bool and int)
ResolutionErrors.dfy(309,18): Error: ghost fields are allowed only in specification contexts
ResolutionErrors.dfy(318,15): Error: ghost variables are allowed only in specification contexts
-46 resolution/type errors detected in ResolutionErrors.dfy
+ResolutionErrors.dfy(343,2): Error: incorrect type of method in-parameter 1 (expected GenericClass<int>, got GenericClass<bool>)
+ResolutionErrors.dfy(355,18): Error: incorrect type of datatype constructor argument (found GList<T$0>, expected GList<int>)
+48 resolution/type errors detected in ResolutionErrors.dfy
-------------------- ParseErrors.dfy --------------------
ParseErrors.dfy(4,19): error: a chain cannot have more than one != operator
@@ -1037,7 +1078,9 @@ ParallelResolveErrors.dfy(86,20): Error: trying to break out of more loop levels
ParallelResolveErrors.dfy(87,20): Error: break label is undefined or not in scope: OutsideLoop
ParallelResolveErrors.dfy(96,24): Error: trying to break out of more loop levels than there are enclosing loops
ParallelResolveErrors.dfy(97,24): Error: break label is undefined or not in scope: OutsideLoop
-14 resolution/type errors detected in ParallelResolveErrors.dfy
+ParallelResolveErrors.dfy(105,2): Warning: the conclusion of the body of this parallel statement will not be known outside the parallel statement; consider using an 'ensures' clause
+ParallelResolveErrors.dfy(106,9): Error: the body of the enclosing parallel statement is not allowed to update heap locations
+15 resolution/type errors detected in ParallelResolveErrors.dfy
-------------------- Parallel.dfy --------------------
Parallel.dfy(31,5): Error BP5002: A precondition for this call might not hold.
@@ -1250,6 +1293,10 @@ Execution trace:
Dafny program verifier finished with 12 verified, 3 errors
+-------------------- NoTypeArgs.dfy --------------------
+
+Dafny program verifier finished with 12 verified, 0 errors
+
-------------------- SplitExpr.dfy --------------------
Dafny program verifier finished with 5 verified, 0 errors
@@ -1353,8 +1400,24 @@ Refinement.dfy(93,3): Error BP5003: A postcondition might not hold on this retur
Refinement.dfy(74,15): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
+Refinement.dfy(179,5): Error BP5003: A postcondition might not hold on this return path.
+Refinement.dfy(112,15): Related location: This is the postcondition that might not hold.
+Refinement.dfy(176,9): Related location: Related location
+Execution trace:
+ (0,0): anon0
+Refinement.dfy(183,5): Error BP5003: A postcondition might not hold on this return path.
+Refinement.dfy(120,15): Related location: This is the postcondition that might not hold.
+Refinement.dfy(176,9): Related location: Related location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon4_Then
+ (0,0): anon3
+Refinement.dfy(189,7): Error: assertion violation
+Refinement.dfy[IncorrectConcrete](128,24): Related location: Related location
+Execution trace:
+ (0,0): anon0
-Dafny program verifier finished with 28 verified, 6 errors
+Dafny program verifier finished with 48 verified, 9 errors
-------------------- RefinementErrors.dfy --------------------
RefinementErrors.dfy(27,17): Error: a refining method is not allowed to add preconditions
@@ -1367,9 +1430,8 @@ RefinementErrors.dfy(35,11): Error: type parameters are not allowed to be rename
RefinementErrors.dfy(35,13): Error: type parameters are not allowed to be renamed from the names given in the function in the module being refined (expected 'C', found 'B')
RefinementErrors.dfy(36,23): Error: the type of parameter 'z' is different from the type of the same parameter in the corresponding function in the module it refines ('seq<C>' instead of 'set<C>')
RefinementErrors.dfy(37,9): Error: there is a difference in name of parameter 3 ('k' versus 'b') of function F compared to corresponding function in the module it refines
-RefinementErrors.dfy(46,11): Error: body of refining method is not yet supported
RefinementErrors.dfy(54,20): Error: a function can be changed into a function method in a refining module only if the function has not yet been given a body: G
-12 resolution/type errors detected in RefinementErrors.dfy
+11 resolution/type errors detected in RefinementErrors.dfy
-------------------- ReturnErrors.dfy --------------------
ReturnErrors.dfy(30,10): Error: cannot have method call in return statement.
@@ -1424,7 +1486,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.
@@ -1455,6 +1517,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:
@@ -1563,8 +1639,47 @@ SmallTests.dfy(408,10): Error BP5003: A postcondition might not hold on this ret
SmallTests.dfy(411,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
+SmallTests.dfy(561,12): Error: assertion violation
+Execution trace:
+ (0,0): anon0
+ (0,0): anon3_Then
+ (0,0): anon2
+SmallTests.dfy(575,20): Error: left-hand sides 0 and 1 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ (0,0): anon28_Then
+ (0,0): anon4
+ (0,0): anon29_Then
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Then
+ (0,0): anon32_Then
+ (0,0): anon12
+SmallTests.dfy(577,15): Error: left-hand sides 1 and 2 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ SmallTests.dfy(570,18): anon28_Else
+ (0,0): anon4
+ (0,0): anon29_Else
+ (0,0): anon7
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Else
+ (0,0): anon35_Then
+ (0,0): anon36_Then
+ (0,0): anon37_Then
+ (0,0): anon22
+ (0,0): anon38_Then
+SmallTests.dfy(584,18): Error: target object may be null
+Execution trace:
+ (0,0): anon0
+SmallTests.dfy(597,10): Error: assertion violation
+Execution trace:
+ (0,0): anon0
-Dafny program verifier finished with 58 verified, 21 errors
+Dafny program verifier finished with 68 verified, 26 errors
out.tmp.dfy(33,11): Error: index out of range
Execution trace:
(0,0): anon0
@@ -1672,8 +1787,47 @@ out.tmp.dfy(469,10): Error BP5003: A postcondition might not hold on this return
out.tmp.dfy(470,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
+out.tmp.dfy(507,12): Error: assertion violation
+Execution trace:
+ (0,0): anon0
+ (0,0): anon3_Then
+ (0,0): anon2
+out.tmp.dfy(521,20): Error: left-hand sides 0 and 1 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ (0,0): anon28_Then
+ (0,0): anon4
+ (0,0): anon29_Then
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Then
+ (0,0): anon32_Then
+ (0,0): anon12
+out.tmp.dfy(523,15): Error: left-hand sides 1 and 2 may refer to the same location
+Execution trace:
+ (0,0): anon0
+ (0,0): anon27_Then
+ out.tmp.dfy(516,18): anon28_Else
+ (0,0): anon4
+ (0,0): anon29_Else
+ (0,0): anon7
+ (0,0): anon30_Then
+ (0,0): anon9
+ (0,0): anon31_Else
+ (0,0): anon35_Then
+ (0,0): anon36_Then
+ (0,0): anon37_Then
+ (0,0): anon22
+ (0,0): anon38_Then
+out.tmp.dfy(530,18): Error: target object may be null
+Execution trace:
+ (0,0): anon0
+out.tmp.dfy(543,10): Error: assertion violation
+Execution trace:
+ (0,0): anon0
-Dafny program verifier finished with 58 verified, 21 errors
+Dafny program verifier finished with 68 verified, 26 errors
-------------------- LetExpr.dfy --------------------
LetExpr.dfy(5,12): Error: assertion violation
@@ -1684,7 +1838,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
@@ -1693,4 +1847,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/NoTypeArgs.dfy b/Test/dafny0/NoTypeArgs.dfy
new file mode 100644
index 00000000..c41c7990
--- /dev/null
+++ b/Test/dafny0/NoTypeArgs.dfy
@@ -0,0 +1,82 @@
+datatype List<T> = Nil | Cons(hd: T, tl: List);
+
+method M0() {
+ var l: List;
+ l := Cons(5, Nil);
+ assert l.hd == 5;
+
+ var k: MyClass<bool>;
+ k := new MyClass;
+ k.data := false;
+
+ var h := new MyClass;
+ h.data := false;
+
+ var y := new MyClass.Init(120);
+ var z: int := y.data;
+}
+
+method M1() { // same thing as above, but with types filled in explicitly
+ var l: List<int>;
+ l := Cons(5, Nil);
+ assert l.hd == 5;
+
+ var k: MyClass<bool>;
+ k := new MyClass<bool>;
+ k.data := false;
+
+ var h := new MyClass<bool>;
+ h.data := false;
+
+ var y := new MyClass<int>.Init(120);
+ var z: int := y.data;
+}
+
+class MyClass<G> {
+ var data: G;
+ method Init(g: G)
+ modifies this;
+ {
+ data := g;
+ }
+}
+
+// ---------------------------------------------------
+
+// The followinng functions and methods are oblivious of the fact that
+// List takes a type parameter.
+
+function concat(xs: List, ys: List): List
+{
+ match xs
+ case Nil => ys
+ case Cons(x, tail) => Cons(x, concat(tail, ys))
+}
+
+function reverse(xs: List): List
+{
+ match xs
+ case Nil => Nil
+ case Cons(t, rest) => concat(reverse(rest), Cons(t, Nil))
+}
+
+ghost method Theorem(xs: List)
+ ensures reverse(reverse(xs)) == xs;
+{
+ match (xs) {
+ case Nil =>
+ case Cons(t, rest) =>
+ Lemma(reverse(rest), Cons(t, Nil));
+ }
+}
+
+ghost method Lemma(xs: List, ys: List)
+ ensures reverse(concat(xs, ys)) == concat(reverse(ys), reverse(xs));
+{
+ match (xs) {
+ case Nil =>
+ assert forall ws :: concat(ws, Nil) == ws;
+ case Cons(t, rest) =>
+ assert forall a, b, c :: concat(a, concat(b, c)) == concat(concat(a, b), c);
+ }
+}
diff --git a/Test/dafny0/ParallelResolveErrors.dfy b/Test/dafny0/ParallelResolveErrors.dfy
index 98f1ae3a..ab711d02 100644
--- a/Test/dafny0/ParallelResolveErrors.dfy
+++ b/Test/dafny0/ParallelResolveErrors.dfy
@@ -99,3 +99,10 @@ method M1() {
}
}
}
+
+method M2() {
+ var a := new int[100];
+ parallel (x | 0 <= x < 100) {
+ a[x] :| a[x] > 0; // error: not allowed to update heap location in a parallel statement with a(n implicit) assume
+ }
+}
diff --git a/Test/dafny0/Refinement.dfy b/Test/dafny0/Refinement.dfy
index 280227f1..da7f0ac2 100644
--- a/Test/dafny0/Refinement.dfy
+++ b/Test/dafny0/Refinement.dfy
@@ -25,7 +25,7 @@ module B refines A {
}
method M(x: int) returns (y: int)
ensures y % 2 == 0; // add a postcondition
- method Q() returns (q: int, r: int, s: int)
+ method Q ...
ensures 12 <= r;
ensures 1200 <= s; // error: postcondition is not established by
// inherited method body
@@ -44,7 +44,7 @@ module A_AnonymousClass {
}
module B_AnonymousClass refines A_AnonymousClass {
- method Increment(d: int)
+ method Increment...
ensures x <= old(x) + d;
}
@@ -96,10 +96,10 @@ module FullBodied refines BodyFree {
}
// ------------------------------------------------
-/* SOON
+
module Abstract {
class MyNumber {
- var N: int;
+ ghost var N: int;
ghost var Repr: set<object>;
predicate Valid
reads this, Repr;
@@ -125,7 +125,8 @@ module Abstract {
requires Valid;
ensures n == N;
{
- n := N;
+ var k; assume k == N;
+ n := k;
}
}
}
@@ -148,7 +149,8 @@ module Concrete refines Abstract {
}
method Get() returns (n: int)
{
- n := a - b;
+ var k := a - b;
+ assert ...;
}
}
}
@@ -164,4 +166,27 @@ module Client imports Concrete {
}
}
}
-*/
+
+module IncorrectConcrete refines Abstract {
+ class MyNumber {
+ var a: int;
+ var b: int;
+ predicate Valid
+ {
+ N == 2*a - b
+ }
+ constructor Init()
+ { // error: postcondition violation
+ a := b;
+ }
+ method Inc()
+ { // error: postcondition violation
+ if (*) { a := a + 1; } else { b := b - 1; }
+ }
+ method Get() returns (n: int)
+ {
+ var k := a - b;
+ assert ...; // error: assertion violation
+ }
+ }
+}
diff --git a/Test/dafny0/RefinementErrors.dfy b/Test/dafny0/RefinementErrors.dfy
index 25ba94ad..df6f1a71 100644
--- a/Test/dafny0/RefinementErrors.dfy
+++ b/Test/dafny0/RefinementErrors.dfy
@@ -44,7 +44,7 @@ module B refines A {
{ // yes, can give it a body
}
method FullBodied(x: int) returns (y: bool, k: seq<set<object>>)
- { // error: not allowed to change body (not yet implemented)
+ {
}
}
}
diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy
index 34cfc762..274cc95a 100644
--- a/Test/dafny0/ResolutionErrors.dfy
+++ b/Test/dafny0/ResolutionErrors.dfy
@@ -317,3 +317,40 @@ method PrintOnlyNonGhosts(a: int, ghost b: int)
print "a: ", a, "\n";
print "b: ", b, "\n"; // error: print statement cannot take ghosts
}
+
+// ------------------- auto-added type arguments ------------------------------
+
+class GenericClass<T> { var data: T; }
+
+method MG0(a: GenericClass, b: GenericClass)
+ requires a != null && b != null;
+ modifies a;
+{
+ a.data := b.data; // allowed, since both a and b get the same auto type argument
+}
+
+method G_Caller()
+{
+ var x := new GenericClass;
+ MG0(x, x); // fine
+ var y := new GenericClass;
+ MG0(x, y); // also fine (and now y's type argument is constrained to be that of x's)
+ var z := new GenericClass<int>;
+ y.data := z.data; // this will have the effect of unifying all type args so far to be 'int'
+ assert x.data == 5; // this is type correct
+
+ var w := new GenericClass<bool>;
+ MG0(x, w); // error: types don't match up
+}
+
+datatype GList<T> = GNil | GCons(hd: T, tl: GList);
+
+method MG1(l: GList, n: nat)
+{
+ if (n != 0) {
+ MG1(l, n-1);
+ MG1(GCons(12, GCons(20, GNil)), n-1);
+ }
+ var t := GCons(100, GNil);
+ t := GCons(120, l); // error: types don't match up (List<T$0> versus List<int>)
+}
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/SmallTests.dfy b/Test/dafny0/SmallTests.dfy
index 914e228e..4d219cd3 100644
--- a/Test/dafny0/SmallTests.dfy
+++ b/Test/dafny0/SmallTests.dfy
@@ -535,3 +535,71 @@ static method TestNotNot()
assert true == !(!true);
}
+
+// ----------------------- Assign-such-that statements -------
+
+method AssignSuchThat0(a: int, b: int) returns (x: int, y: int)
+ ensures x == a && y == b;
+{
+ if (*) {
+ x, y :| a <= x < a + 1 && b + a <= y + a && y <= b;
+ } else {
+ var xx, yy :| a <= xx < a + 1 && b + a <= yy + a && yy <= b;
+ x, y := xx, yy;
+ }
+}
+
+method AssignSuchThat1(a: int, b: int) returns (x: int, y: int)
+{
+ var k :| 0 <= k < a - b; // this acts like an 'assume 0 < a - b;'
+ assert b < a;
+ k :| k == old(2*k); // note, the 'old' has no effect on local variables like k
+ assert k == 0;
+ var S := {2, 4, 7};
+ var T :| T <= S;
+ assert 3 !in T;
+ assert T == {}; // error: T may be larger
+}
+
+method AssignSuchThat2(i: int, j: int, ghost S: set<Node>)
+ modifies S;
+{
+ var n := new Node;
+ var a := new int[25];
+ var t;
+ if (0 <= i < j < 25) {
+ a[i], t, a[j], n.next, n :| true;
+ }
+ if (n != null && n.next != null) {
+ assume n in S && n.next in S;
+ n.next.next, n.next :| n != null && n.next != null && n.next.next == n.next; // error: n.next may equal n (thus aliasing n.next.next and n.next)
+ } else if (0 <= i < 25 && 0 <= j < 25) {
+ t, a[i], a[j] :| t < a[i] < a[j]; // error: i may equal j (thus aliasing a[i] and a[j])
+ }
+}
+
+method AssignSuchThat3()
+{
+ var n := new Node;
+ n, n.next :| n.next == n; // error: RHS is not well defined (RHS is evaluated after the havocking of the LHS)
+}
+
+method AssignSuchThat4()
+{
+ var n := new Node;
+ n, n.next :| n != null && n.next == n; // that's the ticket
+}
+
+method AssignSuchThat5()
+{
+ var n := new Node;
+ n :| fresh(n); // fine
+ assert false; // error
+}
+
+method AssignSuchThat6()
+{
+ var n: Node;
+ n :| n != null && fresh(n); // there is no non-null fresh object, so this amounts to 'assume false;'
+ assert false; // no problemo
+}
diff --git a/Test/dafny0/runtest.bat b/Test/dafny0/runtest.bat
index d09e1cc2..608b7358 100644
--- a/Test/dafny0/runtest.bat
+++ b/Test/dafny0/runtest.bat
@@ -17,11 +17,12 @@ for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
ModulesCycle.dfy Modules0.dfy Modules1.dfy BadFunction.dfy
Comprehensions.dfy Basics.dfy ControlStructures.dfy
Termination.dfy DTypes.dfy ParallelResolveErrors.dfy Parallel.dfy
- TypeParameters.dfy Datatypes.dfy TypeAntecedents.dfy SplitExpr.dfy
+ TypeParameters.dfy Datatypes.dfy TypeAntecedents.dfy NoTypeArgs.dfy
+ SplitExpr.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/dafny2/Answer b/Test/dafny2/Answer
index ea481dae..381b9cb1 100644
--- a/Test/dafny2/Answer
+++ b/Test/dafny2/Answer
@@ -30,3 +30,7 @@ Dafny program verifier finished with 23 verified, 0 errors
-------------------- Intervals.dfy --------------------
Dafny program verifier finished with 5 verified, 0 errors
+
+-------------------- StoreAndRetrieve.dfy --------------------
+
+Dafny program verifier finished with 22 verified, 0 errors
diff --git a/Test/dafny2/StoreAndRetrieve.dfy b/Test/dafny2/StoreAndRetrieve.dfy
new file mode 100644
index 00000000..ea26a234
--- /dev/null
+++ b/Test/dafny2/StoreAndRetrieve.dfy
@@ -0,0 +1,72 @@
+module A imports Library {
+ class {:autocontracts} StoreAndRetrieve<Thing> {
+ ghost var Contents: set<Thing>;
+ predicate Valid
+ {
+ true
+ }
+ constructor Init()
+ {
+ Contents := {};
+ }
+ method Store(t: Thing)
+ {
+ Contents := Contents + {t};
+ }
+ method Retrieve(matchCriterion: Function) returns (thing: Thing)
+ requires exists t :: t in Contents && Function.Apply(matchCriterion, t);
+ ensures Contents == old(Contents);
+ ensures thing in Contents && Function.Apply(matchCriterion, thing);
+ {
+ var k :| k in Contents && Function.Apply(matchCriterion, k);
+ thing := k;
+ }
+ }
+}
+
+module B refines A {
+ class StoreAndRetrieve<Thing> {
+ var arr: seq<Thing>;
+ predicate Valid
+ {
+ Contents == set x | x in arr
+ }
+ constructor Init()
+ {
+ arr := [];
+ }
+ method Store...
+ {
+ arr := arr + [t];
+ }
+ method Retrieve...
+ {
+ var i := 0;
+ while (i < |arr|)
+ invariant i < |arr|;
+ invariant forall j :: 0 <= j < i ==> !Function.Apply(matchCriterion, arr[j]);
+ {
+ if (Function.Apply(matchCriterion, arr[i])) { break; }
+ i := i + 1;
+ }
+ var k := arr[i];
+ }
+ }
+}
+
+module C refines B {
+ class StoreAndRetrieve<Thing> {
+ method Retrieve...
+ {
+ ...;
+ arr := [thing] + arr[..i] + arr[i+1..]; // LRU behavior
+ }
+ }
+}
+
+module Library {
+ // This class simulates function parameters
+ class Function {
+ static function method Apply<T>(f: Function, t: T): bool
+ }
+}
diff --git a/Test/dafny2/runtest.bat b/Test/dafny2/runtest.bat
index 79ee0f89..a4796939 100644
--- a/Test/dafny2/runtest.bat
+++ b/Test/dafny2/runtest.bat
@@ -15,6 +15,7 @@ for %%f in (
COST-verif-comp-2011-3-TwoDuplicates.dfy
COST-verif-comp-2011-4-FloydCycleDetect.dfy
Intervals.dfy
+ StoreAndRetrieve.dfy
) do (
echo.
echo -------------------- %%f --------------------
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/test0/Answer b/Test/test0/Answer
index d434a8ca..51a139b7 100644
--- a/Test/test0/Answer
+++ b/Test/test0/Answer
@@ -186,6 +186,12 @@ type any;
type name;
+procedure {:myAttribute "h\n\"ello\"", "again", "and\\" a\"gain\"", again} P();
+
+
+
+const again: int;
+
Boogie program verifier finished with 0 verified, 0 errors
AttributeResolution.bpl(1,18): Error: undeclared identifier: foo
AttributeResolution.bpl(3,18): Error: undeclared identifier: bar
diff --git a/Test/test0/AttributeParsing.bpl b/Test/test0/AttributeParsing.bpl
index a6a8418b..e2b6101c 100644
--- a/Test/test0/AttributeParsing.bpl
+++ b/Test/test0/AttributeParsing.bpl
@@ -23,3 +23,16 @@ implementation {:id 2} foo(x : int) returns(n : int)
}
type ref, any, name;
+
+
+// allow \" and other backslashes rather liberally:
+
+procedure
+ {:myAttribute
+ "h\n\"ello\"",
+ "again",
+ "and\\" a\"gain\"",
+ again}
+P();
+
+const again: int;
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 195c687b..84f7c157 100644
--- a/_admin/Boogie/aste/summary.log
+++ b/_admin/Boogie/aste/summary.log
@@ -1,30 +1,29 @@
-# Aste started: 2012-01-19 07:00:05
+# Aste started: 2012-03-12 07:00:05
# Host id: Boogiebox
# Configuration: boogie.cfg
# Task: aste.tasks.boogie.FullBuild
-# [2012-01-19 07:03:03] SpecSharp revision: ed2f65098882
-# [2012-01-19 07:03:03] SscBoogie revision: ed2f65098882
-# [2012-01-19 07:04:56] Boogie revision: 5c0c274f9b98
-[2012-01-19 07:06:25] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com SpecSharp.sln /Project "Checkin Tests" /Build
+# [2012-03-12 07:05:12] SpecSharp revision: e3878dffb70b
+# [2012-03-12 07:05:12] SscBoogie revision: e3878dffb70b
+# [2012-03-12 07:08:40] Boogie revision: b0709df982cd
+[2012-03-12 07:10:18] 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-01-19 07:07:59] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
+[2012-03-12 07:11:45] 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(116,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(121,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(124,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(1697,11): warning CS0162: Unreachable code detected
- D:\Temp\aste\Boogie\Source\VCGeneration\VC.cs(1858,11): warning CS0162: Unreachable code detected
- D:\Temp\aste\Boogie\Source\VCGeneration\StratifiedVC.cs(1093,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-01-19 08:05:27] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
-# [2012-01-19 08:06:35] Released nightly of Boogie
+[2012-03-12 08:11:41] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
+# [2012-03-12 08:12:49] Released nightly of Boogie
diff --git a/_admin/Chalice/aste/summary.log b/_admin/Chalice/aste/summary.log
index 4386927d..0376bf46 100644
--- a/_admin/Chalice/aste/summary.log
+++ b/_admin/Chalice/aste/summary.log
@@ -1,15 +1,15 @@
-# Aste started: 2011-09-28 08:49:35
+# Aste started: 2012-03-26 15:14:28
# Host id: Boogiebox
# Configuration: chalice.cfg
# Task: aste.tasks.chalice.FullBuild
-# [2011-09-28 08:51:21] Chalice revision: 7e0b55e0fb47
-[2011-09-28 08:52:44] cmd /c "(set JAVA_OPTS=-Dsbt.ivy.home=D:\temp\.ivy2\) && (sbt.bat clean compile)"
+# [2012-03-26 15:16:07] Chalice revision: beb0d999dc0f
+[2012-03-26 15:17:27] cmd /c "(set JAVA_OPTS=-Dsbt.ivy.home=D:\temp\.ivy2\) && (sbt.bat clean compile)"
[warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:77: case class `class SeqClass' has case class ancestor `class Class'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
[warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:111: case class `class TokenClass' has case class ancestor `class Class'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
[warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:121: case class `class ChannelClass' has case class ancestor `class Class'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
[warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:141: case class `class TokenType' has case class ancestor `class Type'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
[warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:168: case class `class SpecialField' has case class ancestor `class Field'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
- [warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:212: case class `class SpecialVariable' has case class ancestor `class Variable'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
-[2011-09-28 09:11:22] 0 out of 64 test(s) failed
-# [2011-09-28 09:12:30] Released nightly of Chalice
+ [warn] D:\temp\aste\Boogie\Chalice\src\main\scala\Ast.scala:227: case class `class SpecialVariable' has case class ancestor `class Variable'. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
+[2012-03-26 16:32:51] 0 out of 82 test(s) failed
+# [2012-03-26 16:33:53] Released nightly of Chalice