summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Sam Blackshear <unknown>2011-05-24 14:46:12 +0530
committerGravatar Sam Blackshear <unknown>2011-05-24 14:46:12 +0530
commit40e4151cb1072695f1a2aed297206203481cdd66 (patch)
treea89f729fd386fd1ede2421faee65c4fc69e428db
parent5cfbcc0fed2cc711ddcd6702ebd821cff95103ab (diff)
parent356651d4f4e2d9825f18858603f506332d582ad5 (diff)
merge
-rw-r--r--BCT/BytecodeTranslator/BytecodeTranslator.csproj12
-rw-r--r--BCT/BytecodeTranslator/ExpressionTraverser.cs641
-rw-r--r--BCT/BytecodeTranslator/Heap.cs71
-rw-r--r--BCT/BytecodeTranslator/HeapFactory.cs4
-rw-r--r--BCT/BytecodeTranslator/MetadataTraverser.cs50
-rw-r--r--BCT/BytecodeTranslator/Program.cs93
-rw-r--r--BCT/BytecodeTranslator/Sink.cs35
-rw-r--r--BCT/BytecodeTranslator/StatementTraverser.cs34
-rw-r--r--BCT/BytecodeTranslator/TraverserFactory.cs6
-rw-r--r--BCT/BytecodeTranslator/WholeProgram.cs88
-rw-r--r--BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt589
-rw-r--r--BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt617
-rw-r--r--Binaries/DafnyPrelude.bpl79
-rw-r--r--Binaries/DafnyRuntime.cs34
-rw-r--r--Source/BoogieDriver/BoogieDriver.cs6
-rw-r--r--Source/Core/Absy.cs26
-rw-r--r--Source/Core/BoogiePL.atg4
-rw-r--r--Source/Core/CommandLineOptions.cs15
-rw-r--r--Source/Core/Parser.cs4
-rw-r--r--Source/Core/ResolutionContext.cs144
-rw-r--r--Source/Dafny/Compiler.cs131
-rw-r--r--Source/Dafny/Dafny.atg104
-rw-r--r--Source/Dafny/DafnyAst.cs194
-rw-r--r--Source/Dafny/Parser.cs297
-rw-r--r--Source/Dafny/Printer.cs73
-rw-r--r--Source/Dafny/Resolver.cs285
-rw-r--r--Source/Dafny/Translator.cs584
-rw-r--r--Source/ModelViewer/bvdicon.designbin0 -> 7272 bytes
-rw-r--r--Test/dafny0/Answer100
-rw-r--r--Test/dafny0/Comprehensions.dfy40
-rw-r--r--Test/dafny0/ControlStructures.dfy137
-rw-r--r--Test/dafny0/Modules0.dfy15
-rw-r--r--Test/dafny0/NatTypes.dfy2
-rw-r--r--Test/dafny0/NonGhostQuantifiers.dfy17
-rw-r--r--Test/dafny0/ResolutionErrors.dfy25
-rw-r--r--Test/dafny0/SmallTests.dfy46
-rw-r--r--Test/dafny0/runtest.bat5
-rw-r--r--Test/dafny1/Answer6
-rw-r--r--Test/dafny1/FindZero.dfy30
-rw-r--r--Test/dafny1/TerminationDemos.dfy22
-rw-r--r--Test/dafny1/runtest.bat2
-rw-r--r--Test/test0/Answer13
-rw-r--r--Test/test0/SeparateVerification0.bpl21
-rw-r--r--Test/test0/SeparateVerification1.bpl19
-rw-r--r--Test/test0/runtest.bat9
-rw-r--r--_admin/Boogie/aste/summary.log22
46 files changed, 3266 insertions, 1485 deletions
diff --git a/BCT/BytecodeTranslator/BytecodeTranslator.csproj b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
index 86fc4a5d..e4575480 100644
--- a/BCT/BytecodeTranslator/BytecodeTranslator.csproj
+++ b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
@@ -32,6 +32,7 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
+ <CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -41,7 +42,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
<CodeContractsCustomRewriterAssembly>
</CodeContractsCustomRewriterAssembly>
<CodeContractsCustomRewriterClass>
@@ -67,6 +68,15 @@
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
+ <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsExtraRewriteOptions />
+ <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
diff --git a/BCT/BytecodeTranslator/ExpressionTraverser.cs b/BCT/BytecodeTranslator/ExpressionTraverser.cs
index 29c0033f..08e32248 100644
--- a/BCT/BytecodeTranslator/ExpressionTraverser.cs
+++ b/BCT/BytecodeTranslator/ExpressionTraverser.cs
@@ -138,6 +138,16 @@ namespace BytecodeTranslator
}
public override void Visit(IArrayIndexer arrayIndexer) {
+
+#if EXPERIMENTAL
+ if (!IsAtomicInstance(arrayIndexer.IndexedObject)) {
+ // Simplify the BE so that all nested dereferences and method calls are broken up into separate assignments to locals.
+ var se = ExpressionSimplifier.Simplify(this.sink, arrayIndexer);
+ this.Visit(se);
+ return;
+ }
+#endif
+
this.Visit(arrayIndexer.IndexedObject);
Bpl.Expr arrayExpr = TranslatedExpressions.Pop();
this.Visit(arrayIndexer.Indices);
@@ -155,6 +165,9 @@ namespace BytecodeTranslator
indexExpr = new Bpl.NAryExpr(arrayIndexer.Token(), new Bpl.FunctionCall(f), new Bpl.ExprSeq(indexExprs));
}
+#if EXPERIMENTAL
+ this.TranslatedExpressions.Push(arrayExpr);
+#else
Bpl.IdentifierExpr temp = Bpl.Expr.Ident(this.sink.CreateFreshLocal(arrayIndexer.Type));
Bpl.Expr selectExpr = sink.Heap.ReadHeap(arrayExpr, indexExpr, AccessType.Array, temp.Type);
this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(temp, selectExpr));
@@ -162,10 +175,22 @@ namespace BytecodeTranslator
this.arrayExpr = arrayExpr;
this.indexExpr = indexExpr;
+#endif
}
public override void Visit(ITargetExpression targetExpression)
{
+#if EXPERIMENTAL
+ Contract.Assume(false, "The expression containing this as a subexpression should never allow a call to this routine.");
+
+ if (targetExpression.Instance != null && !IsAtomicInstance(targetExpression.Instance)) {
+ //// Simplify the BE so that all nested dereferences and method calls are broken up into separate assignments to locals.
+ var se = ExpressionSimplifier.Simplify(this.sink, targetExpression);
+ this.Visit(se);
+ return;
+ }
+#endif
+
#region ArrayIndexer
IArrayIndexer/*?*/ indexer = targetExpression.Definition as IArrayIndexer;
if (indexer != null)
@@ -252,11 +277,14 @@ namespace BytecodeTranslator
public override void Visit(IBoundExpression boundExpression)
{
- //if (boundExpression.Instance != null)
- //{
- // this.Visit(boundExpression.Instance);
- // // TODO: (mschaef) look where it's bound and do something
- //}
+
+ if (boundExpression.Instance != null && !IsAtomicInstance(boundExpression.Instance)) {
+ // Simplify the BE so that all nested dereferences and method calls are broken up into separate assignments to locals.
+ var se = ExpressionSimplifier.Simplify(this.sink, boundExpression);
+ this.Visit(se);
+ return;
+ }
+
#region Local
ILocalDefinition local = boundExpression.Definition as ILocalDefinition;
if (local != null)
@@ -290,9 +318,9 @@ namespace BytecodeTranslator
}
else {
Bpl.Expr instanceExpr = TranslatedExpressions.Pop();
- Bpl.IdentifierExpr temp = Bpl.Expr.Ident(this.sink.CreateFreshLocal(field.ResolvedField.Type));
- this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(temp, this.sink.Heap.ReadHeap(instanceExpr, f, field.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, temp.Type)));
- TranslatedExpressions.Push(temp);
+ var bplType = this.sink.CciTypeToBoogie(field.Type);
+ var e = this.sink.Heap.ReadHeap(instanceExpr, f, field.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, bplType);
+ this.TranslatedExpressions.Push(e);
}
}
return;
@@ -339,6 +367,14 @@ namespace BytecodeTranslator
#endregion
}
+ internal static bool IsAtomicInstance(IExpression expression) {
+ var thisInst = expression as IThisReference;
+ if (thisInst != null) return true;
+ var be = expression as IBoundExpression;
+ if (be == null) return false;
+ return be.Instance == null;
+ }
+
public override void Visit(IPopValue popValue) {
var locExpr = this.StmtTraverser.operandStack.Pop();
this.TranslatedExpressions.Push(locExpr);
@@ -433,102 +469,26 @@ namespace BytecodeTranslator
MemberHelper.GetMethodSignature(methodCall.MethodToCall, NameFormattingOptions.None));
}
- #region Translate In and Out Parameters
- var inexpr = new List<Bpl.Expr>();
- var outvars = new List<Bpl.IdentifierExpr>();
-
- #region Create the 'this' argument for the function call
- Bpl.IdentifierExpr thisExpr = null;
- List<Bpl.Variable> locals = null;
- List<IFieldDefinition> args = null;
- Bpl.Expr arrayExpr = null;
- Bpl.Expr indexExpr = null;
- if (!methodCall.IsStaticCall) {
- this.collectStructFields = true;
- this.structFields = new List<IFieldDefinition>();
- this.arrayExpr = null;
- this.indexExpr = null;
- this.Visit(methodCall.ThisArgument);
- this.collectStructFields = false;
- args = this.structFields;
- arrayExpr = this.arrayExpr;
- indexExpr = this.indexExpr;
-
- var e = this.TranslatedExpressions.Pop();
- inexpr.Add(e);
- if (e is Bpl.NAryExpr) {
- e = ((Bpl.NAryExpr)e).Args[0];
- }
- thisExpr = e as Bpl.IdentifierExpr;
- locals = new List<Bpl.Variable>();
- Bpl.Variable x = thisExpr.Decl;
- locals.Add(x);
- for (int i = 0; i < args.Count; i++) {
- Bpl.IdentifierExpr g = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(args[i]));
- Bpl.Variable y = this.sink.CreateFreshLocal(args[i].Type);
- StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(y), this.sink.Heap.ReadHeap(Bpl.Expr.Ident(x), g, args[i].ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, y.TypedIdent.Type)));
- x = y;
- locals.Add(y);
- }
- }
- if (!methodCall.IsStaticCall && methodCall.MethodToCall.ContainingType.ResolvedType.IsStruct) {
- outvars.Add(thisExpr);
- }
- #endregion
+ Bpl.IToken cloc = methodCall.Token();
- Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed = new Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr>();
- Dictionary<IParameterDefinition, Bpl.IdentifierExpr> p2eMap = new Dictionary<IParameterDefinition, Bpl.IdentifierExpr>();
- IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator();
- penum.MoveNext();
- foreach (IExpression exp in methodCall.Arguments) {
- if (penum.Current == null) {
- throw new TranslationException("More arguments than parameters in method call");
- }
- this.Visit(exp);
- Bpl.Expr e = this.TranslatedExpressions.Pop();
- if (penum.Current.Type is IGenericTypeParameter)
- inexpr.Add(sink.Heap.Box(methodCall.Token(), this.sink.CciTypeToBoogie(exp.Type), e));
- else
- inexpr.Add(e);
- if (penum.Current.IsByReference) {
- Bpl.IdentifierExpr unboxed = e as Bpl.IdentifierExpr;
- if (unboxed == null) {
- throw new TranslationException("Trying to pass a complex expression for an out or ref parameter");
- }
- if (penum.Current.Type is IGenericTypeParameter) {
- Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(sink.CreateFreshLocal(this.sink.Heap.BoxType));
- toBoxed[unboxed] = boxed;
- outvars.Add(boxed);
- }
- else {
- outvars.Add(unboxed);
- }
- }
- penum.MoveNext();
- }
- #endregion
+ List<Bpl.Expr> inexpr;
+ List<Bpl.IdentifierExpr> outvars;
+ Bpl.IdentifierExpr thisExpr;
+ List<Bpl.Variable> locals;
+ List<IFieldDefinition> args;
+ Bpl.Expr arrayExpr;
+ Bpl.Expr indexExpr;
+ Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ var proc = TranslateArgumentsAndReturnProcedure(cloc, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out locals, out args, out arrayExpr, out indexExpr, out toBoxed);
- Bpl.IToken cloc = methodCall.Token();
- if (resolvedMethod.Type.ResolvedType.TypeCode != PrimitiveTypeCode.Void) {
- Bpl.Variable v = this.sink.CreateFreshLocal(methodCall.Type.ResolvedType);
- Bpl.IdentifierExpr unboxed = new Bpl.IdentifierExpr(cloc, v);
- if (resolvedMethod.Type is IGenericTypeParameter) {
- Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(this.sink.CreateFreshLocal(this.sink.Heap.BoxType));
- toBoxed[unboxed] = boxed;
- outvars.Add(boxed);
- }
- else {
- outvars.Add(unboxed);
- }
- TranslatedExpressions.Push(unboxed);
- }
- var proc = this.sink.FindOrCreateProcedure(resolvedMethod);
string methodname = proc.Name;
-
+ var translateAsFunctionCall = proc is Bpl.Function;
Bpl.QKeyValue attrib = null;
- foreach (var a in resolvedMethod.Attributes) {
- if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
- attrib = new Bpl.QKeyValue(cloc, "async", new List<object>(), null);
+ if (!translateAsFunctionCall) {
+ foreach (var a in resolvedMethod.Attributes) {
+ if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
+ attrib = new Bpl.QKeyValue(cloc, "async", new List<object>(), null);
+ }
}
}
@@ -563,13 +523,24 @@ namespace BytecodeTranslator
else {
this.StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(methodCall.Token(), thisExpr, Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type));
}
- }
- else {
- if (attrib != null)
- call = new Bpl.CallCmd(cloc, methodname, inexpr, outvars, attrib);
- else
- call = new Bpl.CallCmd(cloc, methodname, inexpr, outvars);
- this.StmtTraverser.StmtBuilder.Add(call);
+ } else {
+ if (translateAsFunctionCall) {
+ var func = proc as Bpl.Function;
+ var exprSeq = new Bpl.ExprSeq();
+ foreach (var e in inexpr) {
+ exprSeq.Add(e);
+ }
+ var callFunction = new Bpl.NAryExpr(cloc, new Bpl.FunctionCall(func), exprSeq);
+ this.TranslatedExpressions.Push(callFunction);
+ return;
+
+ } else {
+ if (attrib != null)
+ call = new Bpl.CallCmd(cloc, methodname, inexpr, outvars, attrib);
+ else
+ call = new Bpl.CallCmd(cloc, methodname, inexpr, outvars);
+ this.StmtTraverser.StmtBuilder.Add(call);
+ }
}
foreach (KeyValuePair<Bpl.IdentifierExpr, Bpl.IdentifierExpr> kv in toBoxed) {
@@ -596,6 +567,99 @@ namespace BytecodeTranslator
}
}
+ 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 List<Bpl.Variable> locals, out List<IFieldDefinition> args, out Bpl.Expr arrayExpr, out Bpl.Expr indexExpr, out Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed) {
+ inexpr = new List<Bpl.Expr>();
+ outvars = new List<Bpl.IdentifierExpr>();
+
+ #region Create the 'this' argument for the function call
+ thisExpr = null;
+ locals = null;
+ args = null;
+ arrayExpr = null;
+ indexExpr = null;
+ if (thisArg != null) {
+ this.collectStructFields = true;
+ this.structFields = new List<IFieldDefinition>();
+ this.arrayExpr = null;
+ this.indexExpr = null;
+ this.Visit(thisArg);
+ this.collectStructFields = false;
+ args = this.structFields;
+ arrayExpr = this.arrayExpr;
+ indexExpr = this.indexExpr;
+
+ var e = this.TranslatedExpressions.Pop();
+ inexpr.Add(e);
+ if (e is Bpl.NAryExpr) {
+ e = ((Bpl.NAryExpr)e).Args[0];
+ }
+ thisExpr = e as Bpl.IdentifierExpr;
+ locals = new List<Bpl.Variable>();
+ Bpl.Variable x = thisExpr.Decl;
+ locals.Add(x);
+ for (int i = 0; i < args.Count; i++) {
+ Bpl.IdentifierExpr g = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(args[i]));
+ Bpl.Variable y = this.sink.CreateFreshLocal(args[i].Type);
+ StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(y), this.sink.Heap.ReadHeap(Bpl.Expr.Ident(x), g, args[i].ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, y.TypedIdent.Type)));
+ x = y;
+ locals.Add(y);
+ }
+ }
+ if (thisArg != null && methodToCall.ContainingType.ResolvedType.IsStruct) {
+ outvars.Add(thisExpr);
+ }
+ #endregion
+
+ toBoxed = new Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr>();
+ IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator();
+ penum.MoveNext();
+ foreach (IExpression exp in arguments) {
+ if (penum.Current == null) {
+ throw new TranslationException("More arguments than parameters in method call");
+ }
+ this.Visit(exp);
+ Bpl.Expr e = this.TranslatedExpressions.Pop();
+ if (penum.Current.Type is IGenericTypeParameter)
+ inexpr.Add(sink.Heap.Box(token, this.sink.CciTypeToBoogie(exp.Type), e));
+ else
+ inexpr.Add(e);
+ if (penum.Current.IsByReference) {
+ Bpl.IdentifierExpr unboxed = e as Bpl.IdentifierExpr;
+ if (unboxed == null) {
+ throw new TranslationException("Trying to pass a complex expression for an out or ref parameter");
+ }
+ if (penum.Current.Type is IGenericTypeParameter) {
+ Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(sink.CreateFreshLocal(this.sink.Heap.BoxType));
+ toBoxed[unboxed] = boxed;
+ outvars.Add(boxed);
+ } else {
+ outvars.Add(unboxed);
+ }
+ }
+ penum.MoveNext();
+ }
+
+ var proc = this.sink.FindOrCreateProcedure(resolvedMethod);
+
+ var translateAsFunctionCall = proc is Bpl.Function;
+ if (!translateAsFunctionCall) {
+ if (resolvedMethod.Type.ResolvedType.TypeCode != PrimitiveTypeCode.Void) {
+ Bpl.Variable v = this.sink.CreateFreshLocal(resolvedMethod.Type.ResolvedType);
+ Bpl.IdentifierExpr unboxed = new Bpl.IdentifierExpr(token, v);
+ if (resolvedMethod.Type is IGenericTypeParameter) {
+ Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(this.sink.CreateFreshLocal(this.sink.Heap.BoxType));
+ toBoxed[unboxed] = boxed;
+ outvars.Add(boxed);
+ } else {
+ outvars.Add(unboxed);
+ }
+ TranslatedExpressions.Push(unboxed);
+ }
+ }
+
+ return proc;
+ }
+
#endregion
#region Translate Assignments
@@ -604,6 +668,7 @@ namespace BytecodeTranslator
private Bpl.Expr arrayExpr = null;
private Bpl.Expr indexExpr = null;
+#if EXPERIMENTAL
/// <summary>
///
/// </summary>
@@ -612,18 +677,119 @@ namespace BytecodeTranslator
public override void Visit(IAssignment assignment) {
Contract.Assert(TranslatedExpressions.Count == 0);
+ var tok = assignment.Token();
+
+ object container = assignment.Target.Definition;
+
+ var/*?*/ local = container as ILocalDefinition;
+ if (local != null) {
+ Contract.Assume(assignment.Target.Instance == null);
+ this.Visit(assignment.Source);
+ var e = this.TranslatedExpressions.Pop();
+ var bplLocal = Bpl.Expr.Ident(this.sink.FindOrCreateLocalVariable(local));
+ StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, bplLocal, e));
+ return;
+ }
+
+ var/*?*/ parameter = container as IParameterDefinition;
+ if (parameter != null) {
+ Contract.Assume(assignment.Target.Instance == null);
+ this.Visit(assignment.Source);
+ var e = this.TranslatedExpressions.Pop();
+ var bplParam = Bpl.Expr.Ident(this.sink.FindParameterVariable(parameter, this.contractContext));
+ StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, bplParam, e));
+ return;
+ }
+
+ var/*?*/ field = container as IFieldReference;
+ if (field != null) {
+ this.Visit(assignment.Source);
+ var e = this.TranslatedExpressions.Pop();
+ var f = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(field));
+ if (assignment.Target.Instance == null) {
+ // static fields are not kept in the heap
+ StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, f, e));
+ } else {
+ if (field.ContainingType.ResolvedType.IsStruct) {
+ //var s_prime = this.sink.CreateFreshLocal(this.sink.Heap.StructType);
+ //var s_prime_expr = Bpl.Expr.Ident(s_prime);
+ //var boogieType = sink.CciTypeToBoogie(field.Type);
+ //StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(tok, s_prime_expr, f, e,
+ // field.ResolvedField.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap,
+ // boogieType));
+ UpdateStruct(tok, assignment.Target.Instance, field, e);
+ } else {
+ this.Visit(assignment.Target.Instance);
+ var x = this.TranslatedExpressions.Pop();
+ var boogieType = sink.CciTypeToBoogie(field.Type);
+ StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(tok, x, f, e,
+ field.ResolvedField.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap,
+ boogieType));
+ }
+ }
+ return;
+ }
+
+ var/*?*/ arrayIndexer = container as IArrayIndexer;
+ if (arrayIndexer != null) {
+ this.Visit(assignment.Target.Instance);
+ var x = this.TranslatedExpressions.Pop();
+ this.Visit(arrayIndexer.Indices);
+ var indices_prime = this.TranslatedExpressions.Pop();
+ this.Visit(assignment.Source);
+ var e = this.TranslatedExpressions.Pop();
+ StmtTraverser.StmtBuilder.Add(sink.Heap.WriteHeap(Bpl.Token.NoToken, x, indices_prime, e, AccessType.Array, sink.CciTypeToBoogie(arrayIndexer.Type)));
+ return;
+ }
+
+ Contract.Assume(false);
+ }
+
+ private void UpdateStruct(Bpl.IToken tok, IExpression iExpression, IFieldReference field, Bpl.Expr e) {
+ var addrOf = iExpression as IAddressOf;
+ if (addrOf == null) return;
+ var addressableExpression = addrOf.Expression as IAddressableExpression;
+ if (addressableExpression == null) return;
+
+ var f = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(field));
+
+ if (addressableExpression.Instance == null) {
+ var boogieType = sink.CciTypeToBoogie(field.Type);
+ this.Visit(addressableExpression);
+ var def = this.TranslatedExpressions.Pop();
+ StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(tok, def, f, e,
+ AccessType.Struct,
+ boogieType));
+ } else {
+ var s_prime = this.sink.CreateFreshLocal(this.sink.Heap.StructType);
+ var s_prime_expr = Bpl.Expr.Ident(s_prime);
+ var boogieType = sink.CciTypeToBoogie(field.Type);
+ StmtTraverser.StmtBuilder.Add(this.sink.Heap.WriteHeap(tok, s_prime_expr, f, e,
+ AccessType.Struct,
+ boogieType));
+ UpdateStruct(tok, addressableExpression.Instance, addressableExpression.Definition as IFieldReference, s_prime_expr);
+ }
+ }
+
+#else
+
+ public override void Visit(IAssignment assignment) {
+ Contract.Assert(TranslatedExpressions.Count == 0);
+
#region Transform Right Hand Side ...
this.Visit(assignment.Source);
- Bpl.Expr sourceexp = this.TranslatedExpressions.Pop();
+ var sourceexp = this.TranslatedExpressions.Pop();
#endregion
// Simplify the LHS so that all nested dereferences and method calls are broken
// up into separate assignments to locals.
- var blockExpression = AssignmentSimplifier.Simplify(this.sink, assignment.Target);
- foreach (var s in blockExpression.BlockStatement.Statements) {
- this.StmtTraverser.Visit(s);
- }
- var target = blockExpression.Expression as ITargetExpression;
+ //var blockExpression = ExpressionSimplifier.Simplify(this.sink, assignment.Target) as IBlockExpression;
+ //foreach (var s in blockExpression.BlockStatement.Statements) {
+ // this.StmtTraverser.Visit(s);
+ //}
+ //var target = blockExpression.Expression as ITargetExpression;
+
+ var target = assignment.Target;
List<IFieldDefinition> args = null;
Bpl.Expr arrayExpr = null;
@@ -643,8 +809,7 @@ namespace BytecodeTranslator
Bpl.IdentifierExpr f = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(fieldReference.ResolvedField));
if (target.Instance == null) {
StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(assignment.Token(), f, sourceexp));
- }
- else {
+ } else {
Debug.Assert(args != null);
List<Bpl.Variable> locals = new List<Bpl.Variable>();
Bpl.IdentifierExpr instanceExpr = TranslatedExpressions.Pop() as Bpl.IdentifierExpr;
@@ -715,6 +880,8 @@ namespace BytecodeTranslator
return;
}
+#endif
+
#endregion
#region Translate Object Creation
@@ -725,77 +892,35 @@ namespace BytecodeTranslator
/// </summary>
public override void Visit(ICreateObjectInstance createObjectInstance)
{
- TranslateObjectCreation(createObjectInstance.MethodToCall, createObjectInstance.Arguments, createObjectInstance);
- }
-
- public override void Visit(ICreateArray createArrayInstance)
- {
- TranslateArrayCreation(createArrayInstance);
- }
-
- public override void Visit(ICreateDelegateInstance createDelegateInstance)
- {
- if (createDelegateInstance.Instance == null) {
- TranslatedExpressions.Push(Bpl.Expr.Literal(0));
- }
- else {
- this.Visit(createDelegateInstance.Instance);
- }
-
- TranslateDelegateCreation(createDelegateInstance.MethodToCallViaDelegate, createDelegateInstance.Type, createDelegateInstance);
- }
-
- private void TranslateArrayCreation(IExpression creationAST)
- {
- Bpl.IToken cloc = creationAST.Token();
-
- var a = this.sink.CreateFreshLocal(creationAST.Type);
-
- // First generate an Alloc() call
- this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(cloc, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
-
- TranslatedExpressions.Push(Bpl.Expr.Ident(a));
- }
-
- private void TranslateObjectCreation(IMethodReference ctor, IEnumerable<IExpression> arguments, IExpression creationAST)
- {
+ var ctor = createObjectInstance.MethodToCall;
var resolvedMethod = Sink.Unspecialize(ctor).ResolvedMethod;
- Bpl.IToken token = creationAST.Token();
-
- var a = this.sink.CreateFreshLocal(creationAST.Type);
+ Bpl.IToken token = createObjectInstance.Token();
+
+ var a = this.sink.CreateFreshLocal(createObjectInstance.Type);
// First generate an Alloc() call
this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(token, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
// Second, generate the call to the appropriate ctor
- var proc = this.sink.FindOrCreateProcedure(resolvedMethod);
- Bpl.ExprSeq inexpr = new Bpl.ExprSeq();
- inexpr.Add(Bpl.Expr.Ident(a));
- IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator();
- penum.MoveNext();
- foreach (IExpression exp in arguments) {
- if (penum.Current == null) {
- throw new TranslationException("More Arguments than Parameters in functioncall");
- }
- this.Visit(exp);
- Bpl.Expr e = this.TranslatedExpressions.Pop();
- if (penum.Current.Type is IGenericTypeParameter)
- inexpr.Add(sink.Heap.Box(ctor.Token(), this.sink.CciTypeToBoogie(exp.Type), e));
- else
- inexpr.Add(e);
- penum.MoveNext();
- }
- Bpl.IdentifierExprSeq outvars = new Bpl.IdentifierExprSeq();
+ List<Bpl.Expr> inexpr;
+ List<Bpl.IdentifierExpr> outvars;
+ Bpl.IdentifierExpr thisExpr;
+ List<Bpl.Variable> locals;
+ List<IFieldDefinition> args;
+ Bpl.Expr arrayExpr;
+ Bpl.Expr indexExpr;
+ Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ var proc = TranslateArgumentsAndReturnProcedure(token, ctor, resolvedMethod, null, createObjectInstance.Arguments, out inexpr, out outvars, out thisExpr, out locals, out args, out arrayExpr, out indexExpr, out toBoxed);
this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(token, proc.Name, inexpr, outvars));
// Generate assumption about the dynamic type of the just allocated object
this.StmtTraverser.StmtBuilder.Add(
- new Bpl.AssumeCmd(token,
+ new Bpl.AssumeCmd(token,
Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq,
this.sink.Heap.DynamicType(inexpr[0]),
- Bpl.Expr.Ident(this.sink.FindOrCreateType(creationAST.Type))
+ Bpl.Expr.Ident(this.sink.FindOrCreateType(createObjectInstance.Type))
)
)
);
@@ -803,6 +928,37 @@ namespace BytecodeTranslator
TranslatedExpressions.Push(Bpl.Expr.Ident(a));
}
+ public override void Visit(ICreateArray createArrayInstance)
+ {
+ Bpl.IToken cloc = createArrayInstance.Token();
+ var a = this.sink.CreateFreshLocal(createArrayInstance.Type);
+
+ Debug.Assert(createArrayInstance.Rank > 0);
+ Bpl.Expr lengthExpr = Bpl.Expr.Literal(1);
+ foreach (IExpression expr in createArrayInstance.Sizes) {
+ this.Visit(expr);
+ lengthExpr = Bpl.Expr.Mul(lengthExpr, TranslatedExpressions.Pop());
+ }
+
+ // First generate an Alloc() call
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(cloc, this.sink.AllocationMethodName, new Bpl.ExprSeq(), new Bpl.IdentifierExprSeq(Bpl.Expr.Ident(a))));
+ Bpl.Expr assumeExpr = Bpl.Expr.Eq(new Bpl.NAryExpr(cloc, new Bpl.FunctionCall(this.sink.Heap.ArrayLengthFunction), new Bpl.ExprSeq(Bpl.Expr.Ident(a))), lengthExpr);
+ this.StmtTraverser.StmtBuilder.Add(new Bpl.AssumeCmd(cloc, assumeExpr));
+ TranslatedExpressions.Push(Bpl.Expr.Ident(a));
+ }
+
+ public override void Visit(ICreateDelegateInstance createDelegateInstance)
+ {
+ if (createDelegateInstance.Instance == null) {
+ TranslatedExpressions.Push(Bpl.Expr.Literal(0));
+ }
+ else {
+ this.Visit(createDelegateInstance.Instance);
+ }
+
+ TranslateDelegateCreation(createDelegateInstance.MethodToCallViaDelegate, createDelegateInstance.Type, createDelegateInstance);
+ }
+
private void TranslateDelegateCreation(IMethodReference methodToCall, ITypeReference type, IExpression creationAST)
{
Bpl.IToken cloc = creationAST.Token();
@@ -1134,9 +1290,7 @@ namespace BytecodeTranslator
public override void Visit(IVectorLength vectorLength) {
base.Visit(vectorLength.Vector);
var e = TranslatedExpressions.Pop();
- TranslatedExpressions.Push(
- Bpl.Expr.Select(new Bpl.IdentifierExpr(vectorLength.Token(), this.sink.Heap.ArrayLengthVariable), new Bpl.Expr[] { e })
- );
+ TranslatedExpressions.Push(new Bpl.NAryExpr(vectorLength.Token(), new Bpl.FunctionCall(this.sink.Heap.ArrayLengthFunction), new Bpl.ExprSeq(e)));
}
#endregion
@@ -1161,74 +1315,125 @@ namespace BytecodeTranslator
}
#endregion
+ public override void Visit(IBlockExpression blockExpression) {
+ this.StmtTraverser.Visit(blockExpression.BlockStatement);
+ this.Visit(blockExpression.Expression);
+ }
+
/// <summary>
/// This is a rewriter so it must be used on a mutable Code Model!!!
/// </summary>
- private class AssignmentSimplifier : CodeRewriter {
+ private class ExpressionSimplifier : CodeRewriter {
Sink sink;
- private List<IStatement> localDeclarations = new List<IStatement>();
- private AssignmentSimplifier(Sink sink)
+ private ExpressionSimplifier(Sink sink)
: base(sink.host) {
this.sink = sink;
}
- public static IBlockExpression Simplify(Sink sink, ITargetExpression targetExpression) {
- var a = new AssignmentSimplifier(sink);
- var leftOverExpression = a.Rewrite(targetExpression);
- return new BlockExpression() {
- BlockStatement = new BlockStatement() { Statements = a.localDeclarations, },
- Expression = leftOverExpression,
- Type = targetExpression.Type,
- };
+ public static IExpression Simplify(Sink sink, IExpression expression) {
+ var a = new ExpressionSimplifier(sink);
+ return a.Rewrite(expression);
}
public override IExpression Rewrite(IBoundExpression boundExpression) {
- if (boundExpression.Instance == null)
- return base.Rewrite(boundExpression); // REVIEW: Maybe just stop the rewriting and return boundExpression?
- var e = base.Rewrite(boundExpression);
- boundExpression = e as IBoundExpression;
- if (boundExpression == null) return e;
+
+ if (ExpressionTraverser.IsAtomicInstance(boundExpression.Instance)) return boundExpression;
+
+ // boundExpression == BE(inst, def), i.e., inst.def
+ // return { loc := e; [assert loc != null;] | BE(BE(null,loc), def) }, i.e., "loc := e; loc.def"
+ // where e is the rewritten inst
+
+ var e = base.Rewrite(boundExpression.Instance);
+
var loc = new LocalDefinition() {
- Name = this.host.NameTable.GetNameFor("_loc" + this.sink.LocalCounter.ToString()), // TODO: should make the name unique within the method containing the assignment
+ Name = this.host.NameTable.GetNameFor("_loc" + this.sink.LocalCounter.ToString()),
Type = boundExpression.Type,
};
- this.localDeclarations.Add(
- new LocalDeclarationStatement() {
- InitialValue = boundExpression,
- LocalVariable = loc,
- }
- );
- return new BoundExpression() {
- Definition = loc,
- Instance = null,
- Type = boundExpression.Type,
+ var locDecl = new LocalDeclarationStatement() {
+ InitialValue = e,
+ LocalVariable = loc,
+ };
+ return new BlockExpression() {
+ BlockStatement = new BlockStatement() {
+ Statements = new List<IStatement> { locDecl },
+ },
+ Expression = new BoundExpression() {
+ Definition = boundExpression.Definition,
+ Instance = new BoundExpression() {
+ Definition = loc,
+ Instance = null,
+ Type = loc.Type,
+ },
+ Type = boundExpression.Type,
+ },
};
+
}
- public override IExpression Rewrite(IMethodCall methodCall) {
+ public override IExpression Rewrite(IArrayIndexer arrayIndexer) {
+ if (ExpressionTraverser.IsAtomicInstance(arrayIndexer.IndexedObject)) return arrayIndexer;
+
+ // arrayIndexer == AI(inst, [index]), i.e., inst[index0, index1,...]
+ // return { loc := e; [assert loc != null;] | AI(BE(null,loc), [index]) }
+ // where e is the rewritten array instance
- var e = base.Rewrite(methodCall); // simplify anything deeper in the tree
- methodCall = e as IMethodCall;
- if (methodCall == null) return e;
+ var e = base.Rewrite(arrayIndexer.IndexedObject);
var loc = new LocalDefinition() {
- Name = this.host.NameTable.GetNameFor("_loc"), // TODO: should make the name unique within the method containing the assignment
- Type = methodCall.Type,
+ Name = this.host.NameTable.GetNameFor("_loc" + this.sink.LocalCounter.ToString()),
+ Type = arrayIndexer.Type,
};
- this.localDeclarations.Add(
- new LocalDeclarationStatement() {
- InitialValue = methodCall,
- LocalVariable = loc,
- }
- );
- return new BoundExpression() {
- Definition = loc,
- Instance = null,
- Type = methodCall.Type,
+ var locDecl = new LocalDeclarationStatement() {
+ InitialValue = e,
+ LocalVariable = loc,
};
+ return new BlockExpression() {
+ BlockStatement = new BlockStatement() {
+ Statements = new List<IStatement> { locDecl },
+ },
+ Expression = new ArrayIndexer() {
+ IndexedObject = new BoundExpression() {
+ Definition = loc,
+ Instance = null,
+ Type = loc.Type,
+ },
+ Indices = new List<IExpression>(arrayIndexer.Indices),
+ Type = arrayIndexer.Type,
+ },
+ };
+ }
+
+#if EXPERIMENTAL
+ public override ITargetExpression Rewrite(ITargetExpression targetExpression) {
+ Contract.Assume(false, "The expression containing this as a subexpression should never allow a call to this routine.");
+ return null;
}
+#endif
+
+ //public override IExpression Rewrite(IMethodCall methodCall) {
+
+ // var e = base.Rewrite(methodCall); // simplify anything deeper in the tree
+ // methodCall = e as IMethodCall;
+ // if (methodCall == null) return e;
+
+ // var loc = new LocalDefinition() {
+ // Name = this.host.NameTable.GetNameFor("_loc"), // TODO: should make the name unique within the method containing the assignment
+ // Type = methodCall.Type,
+ // };
+ // this.localDeclarations.Add(
+ // new LocalDeclarationStatement() {
+ // InitialValue = methodCall,
+ // LocalVariable = loc,
+ // }
+ // );
+ // return new BoundExpression() {
+ // Definition = loc,
+ // Instance = null,
+ // Type = methodCall.Type,
+ // };
+ //}
}
}
diff --git a/BCT/BytecodeTranslator/Heap.cs b/BCT/BytecodeTranslator/Heap.cs
index 283a59a3..87d950c4 100644
--- a/BCT/BytecodeTranslator/Heap.cs
+++ b/BCT/BytecodeTranslator/Heap.cs
@@ -56,6 +56,35 @@ axiom (forall x: bool :: { Bool2Box(x) } Box2Bool(Bool2Box(x)) == x );
axiom (forall x: Ref :: { Ref2Box(x) } Box2Ref(Ref2Box(x)) == x );
axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
+procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref)
+{
+ $result := $TypeOf($DynamicType(this));
+}
+function $TypeOfInv(Ref): Type;
+axiom (forall t: Type :: {$TypeOf(t)} $TypeOfInv($TypeOf(t)) == t);
+
+function $ThreadDelegate(Ref) : Ref;
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref)
+{
+ call {:async} System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
+}
+procedure {:extern} System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref);
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+procedure {:inline 1} System.Threading.Thread.Start(this: Ref)
+{
+ call {:async} System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
+}
+procedure {:extern} System.Threading.ThreadStart.Invoke(this: Ref);
+
";
private Sink sink;
@@ -71,7 +100,7 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
this.TypeType = new Bpl.CtorType(this.TypeTypeDecl.tok, this.TypeTypeDecl, new Bpl.TypeSeq());
this.RefType = new Bpl.CtorType(this.RefTypeDecl.tok, this.RefTypeDecl, new Bpl.TypeSeq());
this.RealType = new Bpl.CtorType(this.RealTypeDecl.tok, this.RealTypeDecl, new Bpl.TypeSeq());
- }
+ }
return b;
}
@@ -82,6 +111,7 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
public override Bpl.Variable CreateFieldVariable(IFieldReference field) {
Bpl.Variable v;
string fieldname = TypeHelper.GetTypeName(field.ContainingType) + "." + field.Name.Value;
+ fieldname = TranslationHelper.TurnStringIntoValidIdentifier(fieldname);
Bpl.IToken tok = field.Token();
Bpl.Type t = this.sink.CciTypeToBoogie(field.Type.ResolvedType);
@@ -100,6 +130,7 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
public override Bpl.Variable CreateEventVariable(IEventDefinition e) {
Bpl.Variable v;
string eventName = TypeHelper.GetTypeName(e.ContainingType) + "." + e.Name.Value;
+ eventName = TranslationHelper.TurnStringIntoValidIdentifier(eventName);
Bpl.IToken tok = e.Token();
Bpl.Type t = this.sink.CciTypeToBoogie(e.Type.ResolvedType);
@@ -108,7 +139,7 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
v = new Bpl.GlobalVariable(tok, tident);
}
else {
- Bpl.Type mt = new Bpl.MapType(tok, new Bpl.TypeVariableSeq(), new Bpl.TypeSeq(Bpl.Type.Int), t);
+ Bpl.Type mt = new Bpl.MapType(tok, new Bpl.TypeVariableSeq(), new Bpl.TypeSeq(this.RefType), t);
Bpl.TypedIdent tident = new Bpl.TypedIdent(tok, eventName, mt);
v = new Bpl.GlobalVariable(tok, tident);
}
@@ -125,11 +156,11 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
/// </param>
public override Bpl.Expr ReadHeap(Bpl.Expr/*?*/ o, Bpl.Expr f, AccessType accessType, Bpl.Type unboxType) {
if (accessType == AccessType.Struct)
- return Bpl.Expr.Select(o, f);
+ return Unbox(f.tok, unboxType, Bpl.Expr.Select(o, f));
else if (accessType == AccessType.Heap)
return Bpl.Expr.Select(f, o);
else
- return Bpl.Expr.Select(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f);
+ return Unbox(f.tok, unboxType, Bpl.Expr.Select(Bpl.Expr.Select(Bpl.Expr.Ident(ArrayContentsVariable), o), f));
}
/// <summary>
@@ -139,11 +170,11 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
public override Bpl.Cmd WriteHeap(Bpl.IToken tok, Bpl.Expr/*?*/ o, Bpl.Expr f, Bpl.Expr value, AccessType accessType, Bpl.Type boxType) {
Debug.Assert(o != null);
if (accessType == AccessType.Struct)
- return Bpl.Cmd.MapAssign(tok, (Bpl.IdentifierExpr)o, f, value);
+ return Bpl.Cmd.MapAssign(tok, (Bpl.IdentifierExpr)o, f, Box(f.tok, boxType, value));
else if (accessType == AccessType.Heap)
return Bpl.Cmd.MapAssign(tok, (Bpl.IdentifierExpr)f, 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, 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, Box(f.tok, boxType, value))));
}
}
@@ -192,6 +223,33 @@ axiom (forall x: bool :: { Bool2Box(x) } Box2Bool(Bool2Box(x)) == x );
axiom (forall x: Ref :: { Ref2Box(x) } Box2Ref(Ref2Box(x)) == x );
axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
+procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref)
+{
+ $result := $TypeOf($DynamicType(this));
+}
+function $TypeOfInv(Ref): Type;
+axiom (forall t: Type :: {$TypeOf(t)} $TypeOfInv($TypeOf(t)) == t);
+
+function $ThreadDelegate(Ref) : Ref;
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref)
+{
+ call {:async} System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
+}
+procedure {:extern} System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref);
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+procedure {:inline 1} System.Threading.Thread.Start(this: Ref)
+{
+ call {:async} System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
+}
+procedure {:extern} System.Threading.ThreadStart.Invoke(this: Ref);
";
private Sink sink;
@@ -239,6 +297,7 @@ axiom (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x );
public override Bpl.Variable CreateEventVariable(IEventDefinition e) {
Bpl.Variable v;
string fieldname = TypeHelper.GetTypeName(e.ContainingType) + "." + e.Name.Value;
+ fieldname = TranslationHelper.TurnStringIntoValidIdentifier(fieldname);
Bpl.IToken tok = e.Token();
if (e.Adder.ResolvedMethod.IsStatic) {
diff --git a/BCT/BytecodeTranslator/HeapFactory.cs b/BCT/BytecodeTranslator/HeapFactory.cs
index 6d03ef9f..004d4224 100644
--- a/BCT/BytecodeTranslator/HeapFactory.cs
+++ b/BCT/BytecodeTranslator/HeapFactory.cs
@@ -68,8 +68,8 @@ namespace BytecodeTranslator {
{
[RepresentationFor("$ArrayContents", "var $ArrayContents: [Ref][int]Box;")]
public Bpl.Variable ArrayContentsVariable = null;
- [RepresentationFor("$ArrayLength", "var $ArrayLength: [Ref]int;")]
- public Bpl.Variable ArrayLengthVariable = null;
+ [RepresentationFor("$ArrayLength", "function $ArrayLength(Ref): int;")]
+ public Bpl.Function ArrayLengthFunction = null;
public abstract Bpl.Variable CreateFieldVariable(IFieldReference field);
diff --git a/BCT/BytecodeTranslator/MetadataTraverser.cs b/BCT/BytecodeTranslator/MetadataTraverser.cs
index 58bec27f..75601140 100644
--- a/BCT/BytecodeTranslator/MetadataTraverser.cs
+++ b/BCT/BytecodeTranslator/MetadataTraverser.cs
@@ -30,23 +30,31 @@ namespace BytecodeTranslator {
public readonly TraverserFactory factory;
- public readonly PdbReader/*?*/ PdbReader;
+ public readonly IDictionary<IUnit, PdbReader> PdbReaders;
+ public PdbReader/*?*/ PdbReader;
- public MetadataTraverser(Sink sink, PdbReader/*?*/ pdbReader)
+ public MetadataTraverser(Sink sink, IDictionary<IUnit, PdbReader> pdbReaders)
: base() {
this.sink = sink;
this.factory = sink.Factory;
- this.PdbReader = pdbReader;
+ this.PdbReaders = pdbReaders;
}
#region Overrides
public override void Visit(IModule module) {
+ this.PdbReaders.TryGetValue(module, out this.PdbReader);
base.Visit(module);
}
public override void Visit(IAssembly assembly) {
- base.Visit(assembly);
+ this.PdbReaders.TryGetValue(assembly, out this.PdbReader);
+ this.sink.BeginAssembly(assembly);
+ try {
+ base.Visit(assembly);
+ } finally {
+ this.sink.EndAssembly(assembly);
+ }
}
/// <summary>
@@ -55,6 +63,9 @@ namespace BytecodeTranslator {
///
public override void Visit(ITypeDefinition typeDefinition) {
+ var savedPrivateTypes = this.privateTypes;
+ this.privateTypes = new List<ITypeDefinition>();
+
if (typeDefinition.IsClass) {
bool savedSawCctor = this.sawCctor;
this.sawCctor = false;
@@ -80,7 +91,12 @@ namespace BytecodeTranslator {
TypeHelper.GetTypeName(typeDefinition));
throw new NotImplementedException(String.Format("Unknown kind of type definition '{0}'.", TypeHelper.GetTypeName(typeDefinition)));
}
+ this.Visit(typeDefinition.PrivateHelperMembers);
+ foreach (var t in this.privateTypes) {
+ this.Visit(t);
+ }
}
+ List<ITypeDefinition> privateTypes = new List<ITypeDefinition>();
private void CreateDefaultStructConstructor(ITypeDefinition typeDefinition) {
Contract.Requires(typeDefinition.IsStruct);
@@ -256,7 +272,11 @@ namespace BytecodeTranslator {
#endregion
#region Translate body
- method.Body.Dispatch(stmtTraverser);
+ var helperTypes = stmtTraverser.TranslateMethod(method);
+ if (helperTypes != null) {
+ this.privateTypes.AddRange(helperTypes);
+ }
+ //method.Body.Dispatch(stmtTraverser);
#endregion
#region Create Local Vars For Implementation
@@ -272,6 +292,8 @@ namespace BytecodeTranslator {
Bpl.VariableSeq vseq = new Bpl.VariableSeq(vars.ToArray());
#endregion
+ var translatedBody = stmtTraverser.StmtBuilder.Collect(Bpl.Token.NoToken);
+
#region Add implementation to Boogie program
if (proc != null) {
Bpl.Implementation impl =
@@ -281,13 +303,14 @@ namespace BytecodeTranslator {
decl.InParams,
decl.OutParams,
vseq,
- stmtTraverser.StmtBuilder.Collect(Bpl.Token.NoToken));
+ translatedBody);
impl.Proc = proc;
this.sink.TranslatedProgram.TopLevelDeclarations.Add(impl);
} else { // method is translated as a function
- //Bpl.Function func = decl as Bpl.Function;
- //func.Body = new Bpl.CodeExpr(new Bpl.VariableSeq(), new List<Bpl.Block>{ new Bpl.Block(
+ //var func = decl as Bpl.Function;
+ //Contract.Assume(func != null);
+ //func.Body = new Bpl.CodeExpr(new Bpl.VariableSeq(), translatedBody.BigBlocks);
}
#endregion
@@ -366,6 +389,15 @@ namespace BytecodeTranslator {
#endregion
+ #region Public API
+ public virtual void TranslateAssemblies(IEnumerable<IUnit> assemblies) {
+ foreach (var a in assemblies) {
+ a.Dispatch(this);
+ }
+ }
+ #endregion
+
+ #region Helpers
private class FindCtorCall : BaseCodeTraverser {
private bool isDeferringCtor = false;
public ITypeReference containingType;
@@ -387,5 +419,7 @@ namespace BytecodeTranslator {
base.Visit(methodCall);
}
}
+ #endregion
+
}
} \ No newline at end of file
diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs
index f42c34d9..50ac68cf 100644
--- a/BCT/BytecodeTranslator/Program.cs
+++ b/BCT/BytecodeTranslator/Program.cs
@@ -25,6 +25,9 @@ namespace BytecodeTranslator {
[OptionDescription("The names of the assemblies to use as input", ShortForm = "a")]
public List<string> assemblies = null;
+ [OptionDescription("Break into debugger", ShortForm = "break")]
+ public bool breakIntoDebugger = false;
+
[OptionDescription("Search paths for assembly dependencies.", ShortForm = "lib")]
public List<string> libpaths = new List<string>();
@@ -36,7 +39,7 @@ namespace BytecodeTranslator {
public bool wholeProgram = false;
[OptionDescription("Stub assembly", ShortForm = "s")]
- public List<string>/*?*/ stubAssemblies = null;
+ public List<string>/*?*/ stub = null;
}
@@ -47,14 +50,21 @@ namespace BytecodeTranslator {
static int Main(string[] args)
{
int result = 0;
+ int errorReturnValue = -1;
#region Parse options
var options = new Options();
options.Parse(args);
+ if (options.HelpRequested) {
+ options.PrintOptions("");
+ return errorReturnValue;
+ }
if (options.HasErrors) {
- if (options.HelpRequested)
- options.PrintOptions("");
- return 1;
+ options.PrintErrorsAndExit(Console.Out);
+ }
+
+ if (options.breakIntoDebugger) {
+ System.Diagnostics.Debugger.Break();
}
#endregion
@@ -81,7 +91,7 @@ namespace BytecodeTranslator {
return 1;
}
- result = TranslateAssembly(assemblyNames, heap, options.libpaths, options.wholeProgram, options.stubAssemblies);
+ result = TranslateAssembly(assemblyNames, heap, options.libpaths, options.wholeProgram, options.stub);
} catch (Exception e) { // swallow everything and just return an error code
Console.WriteLine("The byte-code translator failed: {0}", e.Message);
@@ -98,7 +108,9 @@ namespace BytecodeTranslator {
var host = new CodeContractAwareHostEnvironment(libPaths != null ? libPaths : Enumerable<string>.Empty, true, true);
Host = host;
- var modules = new List<Tuple<IModule,PdbReader/*?*/>>();
+ var modules = new List<IModule>();
+ var contractExtractors = new Dictionary<IUnit, IContractProvider>();
+ var pdbReaders = new Dictionary<IUnit, PdbReader>();
foreach (var a in assemblyNames) {
var module = host.LoadUnitFrom(a) as IModule;
if (module == null || module == Dummy.Module || module == Dummy.Assembly) {
@@ -112,7 +124,9 @@ namespace BytecodeTranslator {
pdbReader = new PdbReader(pdbStream, host);
}
module = Decompiler.GetCodeModelFromMetadataModel(host, module, pdbReader) as IModule;
- modules.Add(Tuple.Create(module, pdbReader));
+ modules.Add(module);
+ contractExtractors.Add(module, host.GetContractExtractor(module.UnitIdentity));
+ pdbReaders.Add(module, pdbReader);
}
if (stubAssemblies != null) {
foreach (var s in stubAssemblies) {
@@ -132,12 +146,21 @@ namespace BytecodeTranslator {
var copier = new CodeDeepCopier(host);
var mutableModule = copier.Copy(module);
- var mutator = new ReparentModule(host,
- TypeHelper.GetDefiningUnit(host.PlatformType.SystemObject.ResolvedType),
- mutableModule);
- module = mutator.Rewrite(mutableModule);
+ var mscorlib = TypeHelper.GetDefiningUnit(host.PlatformType.SystemObject.ResolvedType);
+
+ //var mutator = new ReparentModule(host, mscorlib, mutableModule);
+ //module = mutator.Rewrite(mutableModule);
+ //modules.Add(Tuple.Create(module, pdbReader));
+
+ RewriteUnitReferences renamer = new RewriteUnitReferences(host, mutableModule);
+ var mscorlibAssembly = (IAssembly)mscorlib;
+ renamer.targetAssembly = mscorlibAssembly;
+ renamer.originalAssemblyIdentity = mscorlibAssembly.AssemblyIdentity;
+ renamer.RewriteChildren(mutableModule);
+ modules.Add((IModule)mutableModule);
+ contractExtractors.Add(module, host.GetContractExtractor(module.UnitIdentity));
+ pdbReaders.Add(module, pdbReader);
- modules.Add(Tuple.Create(module, pdbReader));
}
}
if (modules.Count == 0) {
@@ -145,7 +168,7 @@ namespace BytecodeTranslator {
return -1;
}
- var primaryModule = modules[0].Item1;
+ var primaryModule = modules[0];
TraverserFactory traverserFactory;
if (wholeProgram)
@@ -156,20 +179,8 @@ namespace BytecodeTranslator {
var sink = new Sink(host, traverserFactory, heapFactory);
TranslationHelper.tmpVarCounter = 0;
- foreach (var tup in modules) {
-
- var module = tup.Item1;
- var pdbReader = tup.Item2;
-
- IAssembly/*?*/ assembly = null;
- MetadataTraverser translator = traverserFactory.MakeMetadataTraverser(sink, host.GetContractExtractor(module.ModuleIdentity), pdbReader);
- assembly = module as IAssembly;
- if (assembly != null)
- translator.Visit(assembly);
- else
- translator.Visit(module);
-
- }
+ MetadataTraverser translator = traverserFactory.MakeMetadataTraverser(sink, contractExtractors, pdbReaders);
+ translator.TranslateAssemblies(modules);
foreach (ITypeDefinition type in sink.delegateTypeToDelegates.Keys) {
CreateDispatchMethod(sink, type);
@@ -340,6 +351,34 @@ namespace BytecodeTranslator {
// Maybe this is a good place to add the procedure to the toplevel declarations
}
}
+
+ private class RewriteUnitReferences : MetadataRewriter {
+ private UnitIdentity sourceUnitIdentity = null;
+ internal IAssembly/*?*/ targetAssembly = null;
+ internal AssemblyIdentity/*?*/ originalAssemblyIdentity = null;
+
+ Dictionary<uint, bool> internedKeys = new Dictionary<uint, bool>();
+
+ public RewriteUnitReferences(IMetadataHost host, Module sourceUnit)
+ : base(host) {
+ this.sourceUnitIdentity = sourceUnit.UnitIdentity;
+ }
+
+ public override IModuleReference Rewrite(IModuleReference moduleReference) {
+ if (this.sourceUnitIdentity.Equals(moduleReference.UnitIdentity)) {
+ return this.targetAssembly;
+ }
+ return base.Rewrite(moduleReference);
+ }
+ public override IAssemblyReference Rewrite(IAssemblyReference assemblyReference) {
+ if (this.sourceUnitIdentity.Equals(assemblyReference.UnitIdentity)) {
+ return this.targetAssembly;
+ }
+ return base.Rewrite(assemblyReference);
+ }
+
+ }
+
}
}
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index b8d8334d..97fd4441 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -118,7 +118,7 @@ namespace BytecodeTranslator {
return heap.StructType;
else if (type.IsEnum)
return Bpl.Type.Int; // The underlying type of an enum is always some kind of integer
- else if (type is IGenericTypeParameter)
+ else if (type is IGenericTypeParameter)
return heap.BoxType;
else
return heap.RefType;
@@ -167,7 +167,9 @@ namespace BytecodeTranslator {
Bpl.IToken tok = local.Token();
Bpl.Type t = CciTypeToBoogie(local.Type.ResolvedType);
if (!localVarMap.TryGetValue(local, out v)) {
- v = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, local.Name.Value, t));
+ var name = local.Name.Value;
+ name = TranslationHelper.TurnStringIntoValidIdentifier(name);
+ v = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, name, t));
localVarMap.Add(local, v);
}
return v;
@@ -334,6 +336,7 @@ namespace BytecodeTranslator {
ProcedureInfo procAndFormalMap;
var key = method.InternedKey;
+
if (!this.declaredMethods.TryGetValue(key, out procAndFormalMap)) {
string MethodName = TranslationHelper.CreateUniqueMethodName(method);
@@ -375,7 +378,7 @@ namespace BytecodeTranslator {
Bpl.Formal selfOut = null;
#region Create 'this' parameter
if (!method.IsStatic) {
- Bpl.Type selfType = CciTypeToBoogie(method.ContainingType);
+ var selfType = CciTypeToBoogie(method.ContainingType);
if (method.ContainingType.ResolvedType.IsStruct) {
//selfType = Heap.StructType;
in_count++;
@@ -470,15 +473,16 @@ namespace BytecodeTranslator {
#endregion
+ var tok = method.Token();
Bpl.DeclWithFormals decl;
if (IsPure(method)) {
- var func = new Bpl.Function(method.Token(),
+ var func = new Bpl.Function(tok,
MethodName,
new Bpl.VariableSeq(invars),
this.RetVariable);
decl = func;
} else {
- var proc = new Bpl.Procedure(method.Token(),
+ var proc = new Bpl.Procedure(tok,
MethodName,
new Bpl.TypeVariableSeq(),
new Bpl.VariableSeq(invars),
@@ -488,7 +492,10 @@ namespace BytecodeTranslator {
boogiePostcondition);
decl = proc;
}
-
+ if (this.assemblyBeingTranslated != null && !TypeHelper.GetDefiningUnitReference(method.ContainingType).UnitIdentity.Equals(this.assemblyBeingTranslated.UnitIdentity)) {
+ var attrib = new Bpl.QKeyValue(tok, "extern", new List<object>(1), null);
+ decl.Attributes = attrib;
+ }
string newName = null;
if (IsStubMethod(method, out newName)) {
@@ -573,7 +580,8 @@ namespace BytecodeTranslator {
public ProcedureInfo FindOrCreateProcedureAndReturnProcAndFormalMap(IMethodDefinition method) {
this.FindOrCreateProcedure(method);
- return this.declaredMethods[method.InternedKey];
+ var key = method.InternedKey;
+ return this.declaredMethods[key];
}
public static IMethodReference Unspecialize(IMethodReference method) {
IMethodReference result = method;
@@ -609,6 +617,10 @@ namespace BytecodeTranslator {
t = this.Heap.CreateTypeVariable(type);
this.declaredTypes.Add(key, t);
this.TranslatedProgram.TopLevelDeclarations.Add(t);
+ if (this.assemblyBeingTranslated != null && !TypeHelper.GetDefiningUnitReference(type).UnitIdentity.Equals(this.assemblyBeingTranslated.UnitIdentity)) {
+ var attrib = new Bpl.QKeyValue(Bpl.Token.NoToken, "extern", new List<object>(1), null);
+ t.Attributes = attrib;
+ }
}
return t;
}
@@ -634,6 +646,15 @@ namespace BytecodeTranslator {
this.localCounter = 0;
}
+ public void BeginAssembly(IAssembly assembly) {
+ this.assemblyBeingTranslated = assembly;
+ }
+
+ public void EndAssembly(IAssembly assembly) {
+ this.assemblyBeingTranslated = null;
+ }
+ private IAssembly/*?*/ assemblyBeingTranslated;
+
public Dictionary<ITypeDefinition, HashSet<IMethodDefinition>> delegateTypeToDelegates = new Dictionary<ITypeDefinition, HashSet<IMethodDefinition>>();
public void AddDelegate(ITypeDefinition type, IMethodDefinition defn)
diff --git a/BCT/BytecodeTranslator/StatementTraverser.cs b/BCT/BytecodeTranslator/StatementTraverser.cs
index 24b4b2ca..d26f540d 100644
--- a/BCT/BytecodeTranslator/StatementTraverser.cs
+++ b/BCT/BytecodeTranslator/StatementTraverser.cs
@@ -50,13 +50,37 @@ namespace BytecodeTranslator
return etrav.TranslatedExpressions.Pop();
}
+ public ICollection<ITypeDefinition>/*?*/ TranslateMethod(IMethodDefinition method) {
+ var methodBody = method.Body as ISourceMethodBody;
+ if (methodBody == null) return null;
+ var block = methodBody.Block as BlockStatement;
+ // TODO: Error if cast fails?
+
+ ICollection<ITypeDefinition> newTypes = null;
+ if (block != null) {
+ var remover = new AnonymousDelegateRemover(this.sink.host, this.PdbReader);
+ newTypes = remover.RemoveAnonymousDelegates(methodBody.MethodDefinition, block);
+ }
+ this.Visit(methodBody);
+ return newTypes;
+ }
+
#endregion
- public override void Visit(IBlockStatement block) {
- Bpl.StmtListBuilder slb = new Bpl.StmtListBuilder();
+ //public override void Visit(ISourceMethodBody methodBody) {
+ // var block = methodBody.Block as BlockStatement;
+ // // TODO: Error if cast fails?
+
+ // if (block != null) {
+ // var remover = new AnonymousDelegateRemover(this.sink.host, this.PdbReader);
+ // var newTypes = remover.RemoveAnonymousDelegates(methodBody.MethodDefinition, block);
+ // }
+ // base.Visit(methodBody);
+ //}
- foreach (IStatement st in block.Statements) {
- this.Visit(st);
+ public override void Visit(IBlockStatement block) {
+ foreach (var s in block.Statements) {
+ this.Visit(s);
}
}
@@ -73,7 +97,7 @@ namespace BytecodeTranslator
if (this.PdbReader != null) {
var slocs = this.PdbReader.GetClosestPrimarySourceLocationsFor(statement.Locations);
foreach (var sloc in slocs) {
- fileName = sloc.Document.Name.Value;
+ fileName = sloc.Document.Location;
lineNumber = sloc.StartLine;
break;
}
diff --git a/BCT/BytecodeTranslator/TraverserFactory.cs b/BCT/BytecodeTranslator/TraverserFactory.cs
index cdc1c8a3..78c818bd 100644
--- a/BCT/BytecodeTranslator/TraverserFactory.cs
+++ b/BCT/BytecodeTranslator/TraverserFactory.cs
@@ -18,9 +18,11 @@ using Bpl = Microsoft.Boogie;
namespace BytecodeTranslator {
public abstract class TraverserFactory {
- public virtual MetadataTraverser MakeMetadataTraverser(Sink sink, IContractProvider contractProvider, PdbReader/*?*/ pdbReader)
+ public virtual MetadataTraverser MakeMetadataTraverser(Sink sink,
+ IDictionary<IUnit, IContractProvider> contractProviders, // TODO: remove this parameter?
+ IDictionary<IUnit, PdbReader> sourceLocationProviders)
{
- return new MetadataTraverser(sink, pdbReader);
+ return new MetadataTraverser(sink, sourceLocationProviders);
}
public virtual StatementTraverser MakeStatementTraverser(Sink sink, PdbReader/*?*/ pdbReader, bool contractContext) {
return new StatementTraverser(sink, pdbReader, contractContext);
diff --git a/BCT/BytecodeTranslator/WholeProgram.cs b/BCT/BytecodeTranslator/WholeProgram.cs
index 92154020..dd00768b 100644
--- a/BCT/BytecodeTranslator/WholeProgram.cs
+++ b/BCT/BytecodeTranslator/WholeProgram.cs
@@ -16,8 +16,7 @@ namespace BytecodeTranslator {
class WholeProgram : TraverserFactory {
/// <summary>
- /// Table to be filled by the metadata traverser when it first gets to an assembly.
- /// [TODO: It should be full set of assemblies that are being translated (CUA).]
+ /// Table to be filled by the metadata traverser before visiting any assemblies.
///
/// The table lists the direct supertypes of all type definitions that it encounters during the
/// traversal. (But the table is organized so that subTypes[T] is the list of type definitions
@@ -25,8 +24,10 @@ namespace BytecodeTranslator {
/// </summary>
readonly public Dictionary<ITypeReference, List<ITypeReference>> subTypes = new Dictionary<ITypeReference, List<ITypeReference>>();
- public override MetadataTraverser MakeMetadataTraverser(Sink sink, IContractProvider contractProvider, PdbReader pdbReader) {
- return new WholeProgramMetadataSemantics(this, sink, pdbReader);
+ public override MetadataTraverser MakeMetadataTraverser(Sink sink,
+ IDictionary<IUnit, IContractProvider> contractProviders, // TODO: remove this parameter?
+ IDictionary<IUnit, PdbReader> pdbReaders) {
+ return new WholeProgramMetadataSemantics(this, sink, pdbReaders);
}
public class WholeProgramMetadataSemantics : MetadataTraverser {
@@ -34,27 +35,23 @@ namespace BytecodeTranslator {
readonly WholeProgram parent;
readonly Sink sink;
- /// <summary>
- /// TODO: Need to have this populated before any of the assemblies in the CUA are traversed.
- /// </summary>
- readonly Dictionary<IAssembly, bool> codeUnderAnalysis = new Dictionary<IAssembly, bool>();
+ readonly Dictionary<IUnit, bool> codeUnderAnalysis = new Dictionary<IUnit, bool>();
- public WholeProgramMetadataSemantics(WholeProgram parent, Sink sink, PdbReader/*?*/ pdbReader)
- : base(sink, pdbReader) {
+ public WholeProgramMetadataSemantics(WholeProgram parent, Sink sink, IDictionary<IUnit, PdbReader> pdbReaders)
+ : base(sink, pdbReaders) {
this.parent = parent;
this.sink = sink;
}
- public override void Visit(IAssembly assembly) {
-
- #region When doing whole-program analysis, traverse the assembly gathering type information
- this.codeUnderAnalysis.Add(assembly, true);
+ public override void TranslateAssemblies(IEnumerable<IUnit> assemblies) {
+ #region traverse all of the units gathering type information
var typeRecorder = new RecordSubtypes(this.parent.subTypes);
- typeRecorder.Visit(assembly);
+ foreach (var a in assemblies) {
+ this.codeUnderAnalysis.Add(a, true);
+ typeRecorder.Visit(a);
+ }
#endregion
-
- base.Visit(assembly);
-
+ base.TranslateAssemblies(assemblies);
}
class RecordSubtypes : BaseMetadataTraverser {
@@ -120,54 +117,18 @@ namespace BytecodeTranslator {
return;
}
- #region Translate In Parameters
-
- var inexpr = new List<Bpl.Expr>();
- #region Create the 'this' argument for the function call
- this.Visit(methodCall.ThisArgument);
- inexpr.Add(this.TranslatedExpressions.Pop());
- #endregion
-
- Dictionary<IParameterDefinition, Bpl.Expr> p2eMap = new Dictionary<IParameterDefinition, Bpl.Expr>();
- IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator();
- penum.MoveNext();
- foreach (IExpression exp in methodCall.Arguments) {
- if (penum.Current == null) {
- throw new TranslationException("More Arguments than Parameters in functioncall");
- }
- this.Visit(exp);
- Bpl.Expr e = this.TranslatedExpressions.Pop();
-
- p2eMap.Add(penum.Current, e);
- if (!penum.Current.IsOut) {
- inexpr.Add(e);
- }
-
- penum.MoveNext();
- }
- #endregion
-
Bpl.IToken token = methodCall.Token();
- #region Translate Out vars
- var outvars = new List<Bpl.IdentifierExpr>();
+ List<Bpl.Expr> inexpr;
+ List<Bpl.IdentifierExpr> outvars;
+ Bpl.IdentifierExpr thisExpr;
+ List<Bpl.Variable> locals;
+ List<IFieldDefinition> args;
+ Bpl.Expr arrayExpr;
+ Bpl.Expr indexExpr;
+ Dictionary<Bpl.IdentifierExpr, Bpl.IdentifierExpr> toBoxed;
+ var proc = TranslateArgumentsAndReturnProcedure(token, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out locals, out args, out arrayExpr, out indexExpr, out toBoxed);
- foreach (KeyValuePair<IParameterDefinition, Bpl.Expr> kvp in p2eMap) {
- if (kvp.Key.IsByReference) {
- Bpl.IdentifierExpr iexp = kvp.Value as Bpl.IdentifierExpr;
- if (iexp == null) {
- throw new TranslationException("Trying to pass complex expression as out in functioncall");
- }
- outvars.Add(iexp);
- }
- }
- #endregion
-
- if (methodCall.Type.ResolvedType.TypeCode != PrimitiveTypeCode.Void) {
- Bpl.Variable v = this.sink.CreateFreshLocal(methodCall.Type.ResolvedType);
- outvars.Add(new Bpl.IdentifierExpr(token, v));
- TranslatedExpressions.Push(new Bpl.IdentifierExpr(token, v));
- }
Bpl.QKeyValue attrib = null;
foreach (var a in resolvedMethod.Attributes) {
@@ -179,7 +140,6 @@ namespace BytecodeTranslator {
var elseBranch = new Bpl.StmtListBuilder();
- var proc = this.sink.FindOrCreateProcedure(resolvedMethod);
var methodname = proc.Name;
Bpl.CallCmd call;
diff --git a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
index 98d25303..295349c9 100644
--- a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
@@ -5,19 +5,16 @@ type Struct = [Field]Box;
type HeapType = [Ref,Field]Box;
-function IsGoodHeap(HeapType) : bool;
-
var $Alloc: [Ref]bool;
procedure {:inline 1} Alloc() returns (x: Ref);
modifies $Alloc;
- free ensures x != null;
implementation Alloc() returns (x: Ref)
{
- assume $Alloc[x] == false;
+ assume $Alloc[x] == false && x != null;
$Alloc[x] := true;
}
@@ -29,10 +26,87 @@ axiom Box2Int($DefaultBox) == 0;
axiom Box2Bool($DefaultBox) == false;
+axiom Box2Ref($DefaultBox) == null;
+
+axiom Box2Struct($DefaultBox) == $DefaultStruct;
+
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 (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x);
+
+procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Object.GetType(this: Ref) returns ($result: Ref)
+{
+ $result := $TypeOf($DynamicType(this));
+}
+
+
+
+function $TypeOfInv(Ref) : Type;
+
+axiom (forall t: Type :: { $TypeOf(t) } $TypeOfInv($TypeOf(t)) == t);
+
+function $ThreadDelegate(Ref) : Ref;
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref);
+
+
+
+implementation System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+
+
+
+procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref);
+
+
+
+implementation System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref)
+{
+ call {:async} System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
+}
+
+
+
+procedure {:extern} System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref);
+
+
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref);
+
+
+
+implementation System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+
+
+
+procedure {:inline 1} System.Threading.Thread.Start(this: Ref);
+
+
+
+implementation System.Threading.Thread.Start(this: Ref)
+{
+ call {:async} System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
+}
+
+
+
+procedure {:extern} System.Threading.ThreadStart.Invoke(this: Ref);
+
+
+
procedure DelegateAdd(a: Ref, b: Ref) returns (c: Ref);
@@ -190,7 +264,7 @@ implementation DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
-var $Heap: HeapType where IsGoodHeap($Heap);
+var $Heap: HeapType;
function {:inline true} Read(H: HeapType, o: Ref, f: Field) : Box
{
@@ -204,7 +278,7 @@ function {:inline true} Write(H: HeapType, o: Ref, f: Field, v: Box) : HeapType
var $ArrayContents: [Ref][int]Box;
-var $ArrayLength: [Ref]int;
+function $ArrayLength(Ref) : int;
type Field;
@@ -220,6 +294,8 @@ type Type;
const unique $DefaultStruct: Struct;
+type Real;
+
function Box2Int(Box) : int;
function Box2Bool(Box) : bool;
@@ -228,6 +304,8 @@ function Box2Struct(Box) : Struct;
function Box2Ref(Box) : Ref;
+function Box2Real(Box) : Real;
+
function Int2Box(int) : Box;
function Bool2Box(bool) : Box;
@@ -236,12 +314,23 @@ function Struct2Box(Struct) : Box;
function Ref2Box(Ref) : Box;
+function Real2Box(Real) : Box;
+
+function {:inline true} Box2Box(b: Box) : Box
+{
+ b
+}
+
function Struct2Ref(Struct) : Ref;
function Int2Ref(int) : Ref;
function Bool2Ref(bool) : Ref;
+function Int2Real(int, Type, Type) : Real;
+
+function Real2Int(Real, Type, Type) : Real;
+
function $DynamicType(Ref) : Type;
function $TypeOf(Type) : Ref;
@@ -256,6 +345,129 @@ var $Method: [Ref][Ref]int;
var $Receiver: [Ref][Ref]Ref;
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
+
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: Field;
+
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y: Field;
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref);
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref)
+{
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 130} true;
+ $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y, Int2Box(Box2Int(Read($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x))));
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 131} true;
+ return;
+}
+
+
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref);
+
+
+
+procedure {:extern} System.Object.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref)
+{
+ $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x, Int2Box(0));
+ $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y, Int2Box(0));
+ call System.Object.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor();
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
+{
+}
+
+
+
+const unique RegressionTestInput.CreateStruct: Type;
+
+procedure RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box);
+
+
+
+const unique RegressionTestInput.S.x: Field;
+
+const unique RegressionTestInput.S.b: Field;
+
+implementation RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box)
+{
+ var local_0: [Field]Box;
+ var _loc0: int;
+ var _loc1: bool;
+
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 141} true;
+ local_0 := $DefaultStruct;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 142} true;
+ _loc0 := local_0;
+ assert Box2Int(_loc0[RegressionTestInput.S.x]) == 0;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 143} true;
+ _loc1 := local_0;
+ assert !Box2Bool(_loc1[RegressionTestInput.S.b]);
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 145} true;
+ $result := local_0;
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box);
+
+
+
+implementation RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box)
+{
+ var s: [Field]Box;
+ var _loc0: int;
+
+ s := s$in;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 147} true;
+ s := s[RegressionTestInput.S.x := Int2Box(3)];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 148} true;
+ _loc0 := s;
+ assert Box2Int(_loc0[RegressionTestInput.S.x]) == 3;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 150} true;
+ $result := s;
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.CreateStruct.#ctor(this: Ref)
+{
+ call System.Object.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.#cctor();
+
+
+
+implementation RegressionTestInput.CreateStruct.#cctor()
+{
+}
+
+
+
const unique RegressionTestInput.ClassWithArrayTypes: Type;
var RegressionTestInput.ClassWithArrayTypes.s: Ref;
@@ -278,28 +490,30 @@ implementation RegressionTestInput.ClassWithArrayTypes.Main1()
var $tmp5: int;
var $tmp6: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 86} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 86} true;
call $tmp0 := Alloc();
+ assume $ArrayLength($tmp0) == 1 * 5;
local_0 := $tmp0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 87} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 87} true;
$tmp1 := Box2Int($ArrayContents[local_0][0]);
$ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := Int2Box(2)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 88} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 88} true;
$tmp2 := Box2Int($ArrayContents[local_0][0]);
assert $tmp2 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 90} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 90} true;
call $tmp3 := Alloc();
+ assume $ArrayLength($tmp3) == 1 * 4;
local_1 := $tmp3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 91} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 91} true;
$tmp4 := Box2Int($ArrayContents[local_1][0]);
$ArrayContents := $ArrayContents[local_1 := $ArrayContents[local_1][0 := Int2Box(1)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 92} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 92} true;
$tmp5 := Box2Int($ArrayContents[local_1][0]);
assert $tmp5 == 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 94} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 94} true;
$tmp6 := Box2Int($ArrayContents[local_0][0]);
assert $tmp6 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 95} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 95} true;
return;
}
@@ -320,28 +534,30 @@ implementation RegressionTestInput.ClassWithArrayTypes.Main2()
var $tmp12: int;
var $tmp13: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 100} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 100} true;
call $tmp7 := Alloc();
+ assume $ArrayLength($tmp7) == 1 * 5;
RegressionTestInput.ClassWithArrayTypes.s := $tmp7;
- assert {:sourceFile "Class1.cs"} {:sourceLine 101} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 101} true;
$tmp8 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
$ArrayContents := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0 := Int2Box(2)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 102} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 102} true;
$tmp9 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
assert $tmp9 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 104} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 104} true;
call $tmp10 := Alloc();
+ assume $ArrayLength($tmp10) == 1 * 4;
local_0 := $tmp10;
- assert {:sourceFile "Class1.cs"} {:sourceLine 105} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 105} true;
$tmp11 := Box2Int($ArrayContents[local_0][0]);
$ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := Int2Box(1)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 106} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 106} true;
$tmp12 := Box2Int($ArrayContents[local_0][0]);
assert $tmp12 == 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 108} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 108} true;
$tmp13 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
assert $tmp13 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 109} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 109} true;
return;
}
@@ -354,35 +570,23 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main3$System.Int32(this: Ref,
implementation RegressionTestInput.ClassWithArrayTypes.Main3$System.Int32(this: Ref, x$in: int)
{
var x: int;
- var _loc0: Ref;
- var $tmp14: Ref;
+ var $tmp14: int;
var $tmp15: int;
- var _loc1: Ref;
- var $tmp16: Ref;
+ var $tmp16: int;
var $tmp17: int;
- var $tmp18: Ref;
- var $tmp19: int;
- var $tmp20: Ref;
- var $tmp21: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 114} true;
- $tmp14 := Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a));
- _loc0 := $tmp14;
- $tmp15 := Box2Int($ArrayContents[_loc0][x]);
- $ArrayContents := $ArrayContents[_loc0 := $ArrayContents[_loc0][x := Int2Box(42)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 115} true;
- $tmp16 := Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a));
- _loc1 := $tmp16;
- $tmp17 := Box2Int($ArrayContents[_loc1][x + 1]);
- $ArrayContents := $ArrayContents[_loc1 := $ArrayContents[_loc1][x + 1 := Int2Box(43)]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 116} true;
- $tmp18 := Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a));
- $tmp19 := Box2Int($ArrayContents[$tmp18][x + 1]);
- $tmp20 := Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a));
- $tmp21 := Box2Int($ArrayContents[$tmp20][x]);
- assert $tmp19 == $tmp21 + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 117} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 114} true;
+ $tmp14 := Box2Int($ArrayContents[this][x]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][x := Int2Box(42)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 115} true;
+ $tmp15 := Box2Int($ArrayContents[this][x + 1]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][x + 1 := Int2Box(43)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 116} true;
+ $tmp16 := Box2Int($ArrayContents[Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a))][x + 1]);
+ $tmp17 := Box2Int($ArrayContents[Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a))][x]);
+ assert $tmp16 == $tmp17 + 1;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 117} true;
return;
}
@@ -395,26 +599,22 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array(this:
implementation RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array(this: Ref, xs$in: Ref)
{
var xs: Ref;
- var $tmp22: int;
- var _loc0: Ref;
- var $tmp23: Ref;
- var $tmp24: int;
+ var $tmp18: int;
+ var $tmp19: int;
xs := xs$in;
- if (!(if xs != null then $ArrayLength[xs] <= 0 else true))
+ if (!(if xs != null then $ArrayLength(xs) <= 0 else true))
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 121} true;
- $tmp22 := Box2Int($ArrayContents[xs][0]);
- $tmp23 := Box2Ref(Read($Heap, this, RegressionTestInput.ClassWithArrayTypes.a));
- _loc0 := $tmp23;
- $tmp24 := Box2Int($ArrayContents[_loc0][0]);
- $ArrayContents := $ArrayContents[_loc0 := $ArrayContents[_loc0][0 := Int2Box($tmp22)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ $tmp18 := Box2Int($ArrayContents[xs][0]);
+ $tmp19 := Box2Int($ArrayContents[this][0]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][0 := Int2Box($tmp18)]];
}
else
{
}
- assert {:sourceFile "Class1.cs"} {:sourceLine 123} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 123} true;
return;
}
@@ -424,10 +624,6 @@ procedure RegressionTestInput.ClassWithArrayTypes.#ctor(this: Ref);
-procedure System.Object.#ctor(this: Ref);
-
-
-
implementation RegressionTestInput.ClassWithArrayTypes.#ctor(this: Ref)
{
$Heap := Write($Heap, this, RegressionTestInput.ClassWithArrayTypes.a, Ref2Box(null));
@@ -448,6 +644,34 @@ implementation RegressionTestInput.ClassWithArrayTypes.#cctor()
+const unique RegressionTestInput.AsyncAttribute: Type;
+
+procedure RegressionTestInput.AsyncAttribute.#ctor(this: Ref);
+
+
+
+procedure {:extern} System.Attribute.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.AsyncAttribute.#ctor(this: Ref)
+{
+ call System.Attribute.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.AsyncAttribute.#cctor();
+
+
+
+implementation RegressionTestInput.AsyncAttribute.#cctor()
+{
+}
+
+
+
const unique RegressionTestInput.RefParameters: Type;
procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int);
@@ -457,9 +681,9 @@ procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (
implementation RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int)
{
x$out := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 156} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 156} true;
x$out := x$out + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 157} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 157} true;
return;
}
@@ -487,6 +711,8 @@ implementation RegressionTestInput.RefParameters.#cctor()
+const unique RegressionTestInput.S: Type;
+
const unique RegressionTestInput.Class0: Type;
var RegressionTestInput.Class0.StaticInt: int;
@@ -500,7 +726,7 @@ implementation RegressionTestInput.Class0.StaticMethod$System.Int32(x$in: int) r
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 18} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 18} true;
$result := x + 1;
return;
}
@@ -515,22 +741,22 @@ implementation RegressionTestInput.Class0.M$System.Int32(this: Ref, x$in: int)
{
var x: int;
var __temp_1: int;
- var $tmp25: int;
+ var $tmp20: int;
var local_0: int;
x := x$in;
- $tmp25 := x;
- assert $tmp25 != 0;
- __temp_1 := 5 / $tmp25;
+ $tmp20 := x;
+ assert $tmp20 != 0;
+ __temp_1 := 5 / $tmp20;
x := 3;
local_0 := __temp_1 + 3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 22} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 22} true;
assert (if x == 3 then local_0 <= 8 else false);
- assert {:sourceFile "Class1.cs"} {:sourceLine 23} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 23} true;
RegressionTestInput.Class0.StaticInt := local_0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 24} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 24} true;
assert local_0 == RegressionTestInput.Class0.StaticInt;
- assert {:sourceFile "Class1.cs"} {:sourceLine 25} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 25} true;
return;
}
@@ -547,7 +773,7 @@ implementation RegressionTestInput.Class0.M$System.Int32$System.Int32(this: Ref,
x := x$in;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 28} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 28} true;
return;
}
@@ -562,7 +788,7 @@ implementation RegressionTestInput.Class0.M$System.Boolean(this: Ref, b$in: bool
var b: bool;
b := b$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 29} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 29} true;
return;
}
@@ -577,7 +803,7 @@ implementation RegressionTestInput.Class0.M$RegressionTestInput.Class0(this: Ref
var c: Ref;
c := c$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 30} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 30} true;
return;
}
@@ -589,25 +815,26 @@ procedure RegressionTestInput.Class0.NonVoid(this: Ref) returns ($result: int);
implementation RegressionTestInput.Class0.NonVoid(this: Ref) returns ($result: int)
{
- var $tmp26: int;
+ var $tmp21: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 34} true;
- call $tmp26 := RegressionTestInput.Class0.StaticMethod$System.Int32(3);
- $result := 3 + RegressionTestInput.Class0.StaticInt + $tmp26;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 34} true;
+ call $tmp21 := RegressionTestInput.Class0.StaticMethod$System.Int32(3);
+ $result := 3 + RegressionTestInput.Class0.StaticInt + $tmp21;
return;
}
-procedure RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref) returns (x$out: int, $result: int);
+procedure RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int);
-implementation RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref) returns (x$out: int, $result: int)
+implementation RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int)
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 37} true;
+ x$out := x$in;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 37} true;
x$out := 3 + RegressionTestInput.Class0.StaticInt;
- assert {:sourceFile "Class1.cs"} {:sourceLine 39} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 39} true;
$result := x$out;
return;
}
@@ -621,11 +848,11 @@ procedure RegressionTestInput.Class0.RefParam$System.Int32$(this: Ref, x$in: int
implementation RegressionTestInput.Class0.RefParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int)
{
x$out := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 42} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 42} true;
x$out := x$out + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 43} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 43} true;
RegressionTestInput.Class0.StaticInt := x$out;
- assert {:sourceFile "Class1.cs"} {:sourceLine 45} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 45} true;
$result := x$out;
return;
}
@@ -641,11 +868,11 @@ implementation RegressionTestInput.Class0.AssignToInParam$System.Int32(this: Ref
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 48} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 48} true;
x := x + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 49} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 49} true;
RegressionTestInput.Class0.StaticInt := x;
- assert {:sourceFile "Class1.cs"} {:sourceLine 51} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 51} true;
$result := x;
return;
}
@@ -661,7 +888,7 @@ implementation RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMetho
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 56} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 56} true;
$result := x;
return;
}
@@ -675,12 +902,12 @@ procedure RegressionTestInput.Class0.CallAsyncMethod$System.Int32(this: Ref, y$i
implementation RegressionTestInput.Class0.CallAsyncMethod$System.Int32(this: Ref, y$in: int) returns ($result: int)
{
var y: int;
- var $tmp27: int;
+ var $tmp22: int;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 60} true;
- call {:async} $tmp27 := RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMethod$System.Int32(this, y);
- $result := $tmp27;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 60} true;
+ call {:async} $tmp22 := RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMethod$System.Int32(this, y);
+ $result := $tmp22;
return;
}
@@ -709,53 +936,6 @@ implementation RegressionTestInput.Class0.#cctor()
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
-
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: Field;
-
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y: Field;
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref);
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref)
-{
- var $tmp28: int;
-
- assert {:sourceFile "Class1.cs"} {:sourceLine 130} true;
- $tmp28 := Box2Int(Read($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x));
- $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y, Int2Box($tmp28));
- assert {:sourceFile "Class1.cs"} {:sourceLine 131} true;
- return;
-}
-
-
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref)
-{
- $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x, Int2Box(0));
- $Heap := Write($Heap, this, RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y, Int2Box(0));
- call System.Object.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor();
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
-{
-}
-
-
-
const unique RegressionTestInput.ClassWithBoolTypes: Type;
var RegressionTestInput.ClassWithBoolTypes.staticB: bool;
@@ -773,7 +953,7 @@ implementation RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int3
x := x$in;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 70} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 70} true;
$result := x < y;
return;
}
@@ -790,14 +970,14 @@ implementation RegressionTestInput.ClassWithBoolTypes.#ctor$System.Boolean(this:
z := z$in;
$Heap := Write($Heap, this, RegressionTestInput.ClassWithBoolTypes.b, Bool2Box(false));
- assert {:sourceFile "Class1.cs"} {:sourceLine 72} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 72} true;
call System.Object.#ctor(this);
- assert {:sourceFile "Class1.cs"} {:sourceLine 73} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 73} true;
$Heap := Write($Heap, this, RegressionTestInput.ClassWithBoolTypes.b, Bool2Box(z));
- assert {:sourceFile "Class1.cs"} {:sourceLine 74} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 74} true;
if (z)
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 74} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 74} true;
RegressionTestInput.ClassWithBoolTypes.staticB := z;
}
else
@@ -815,11 +995,11 @@ procedure RegressionTestInput.ClassWithBoolTypes.Main();
implementation RegressionTestInput.ClassWithBoolTypes.Main()
{
- var $tmp29: bool;
+ var $tmp23: bool;
- assert {:sourceFile "Class1.cs"} {:sourceLine 78} true;
- call $tmp29 := RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int32(3, 4);
- assert {:sourceFile "Class1.cs"} {:sourceLine 79} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 78} true;
+ call $tmp23 := RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int32(3, 4);
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 79} true;
return;
}
@@ -835,108 +1015,3 @@ implementation RegressionTestInput.ClassWithBoolTypes.#cctor()
}
-
-const unique RegressionTestInput.S: Type;
-
-const unique RegressionTestInput.S.x: Field;
-
-const unique RegressionTestInput.S.b: Field;
-
-const unique RegressionTestInput.AsyncAttribute: Type;
-
-procedure RegressionTestInput.AsyncAttribute.#ctor(this: Ref);
-
-
-
-procedure System.Attribute.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.AsyncAttribute.#ctor(this: Ref)
-{
- call System.Attribute.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.AsyncAttribute.#cctor();
-
-
-
-implementation RegressionTestInput.AsyncAttribute.#cctor()
-{
-}
-
-
-
-const unique RegressionTestInput.CreateStruct: Type;
-
-procedure RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box);
-
-
-
-implementation RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box)
-{
- var local_0: [Field]Box;
- var $tmp30: int;
- var $tmp31: bool;
-
- assert {:sourceFile "Class1.cs"} {:sourceLine 141} true;
- local_0 := $DefaultStruct;
- assert {:sourceFile "Class1.cs"} {:sourceLine 142} true;
- $tmp30 := Box2Int(local_0[RegressionTestInput.S.x]);
- assert $tmp30 == 0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 143} true;
- $tmp31 := Box2Bool(local_0[RegressionTestInput.S.b]);
- assert !$tmp31;
- assert {:sourceFile "Class1.cs"} {:sourceLine 145} true;
- $result := local_0;
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box);
-
-
-
-implementation RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box)
-{
- var s: [Field]Box;
- var $tmp32: int;
-
- s := s$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 147} true;
- s := s[RegressionTestInput.S.x := Int2Box(3)];
- assert {:sourceFile "Class1.cs"} {:sourceLine 148} true;
- $tmp32 := Box2Int(s[RegressionTestInput.S.x]);
- assert $tmp32 == 3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 150} true;
- $result := s;
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.CreateStruct.#ctor(this: Ref)
-{
- call System.Object.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.#cctor();
-
-
-
-implementation RegressionTestInput.CreateStruct.#cctor()
-{
-}
-
-
diff --git a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
index 6e450f38..a0ba97d5 100644
--- a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
@@ -5,21 +5,18 @@ type Struct = [Field]Box;
type HeapType = [Ref,Field]Box;
-var $Heap: HeapType where IsGoodHeap($Heap);
-
-function IsGoodHeap(HeapType) : bool;
+var $Heap: HeapType;
var $Alloc: [Ref]bool;
procedure {:inline 1} Alloc() returns (x: Ref);
modifies $Alloc;
- free ensures x != null;
implementation Alloc() returns (x: Ref)
{
- assume $Alloc[x] == false;
+ assume $Alloc[x] == false && x != null;
$Alloc[x] := true;
}
@@ -31,10 +28,87 @@ axiom Box2Int($DefaultBox) == 0;
axiom Box2Bool($DefaultBox) == false;
+axiom Box2Ref($DefaultBox) == null;
+
+axiom Box2Struct($DefaultBox) == $DefaultStruct;
+
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 (forall x: Struct :: { Struct2Box(x) } Box2Struct(Struct2Box(x)) == x);
+
+procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref);
+
+
+
+implementation System.Object.GetType(this: Ref) returns ($result: Ref)
+{
+ $result := $TypeOf($DynamicType(this));
+}
+
+
+
+function $TypeOfInv(Ref) : Type;
+
+axiom (forall t: Type :: { $TypeOf(t) } $TypeOfInv($TypeOf(t)) == t);
+
+function $ThreadDelegate(Ref) : Ref;
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref);
+
+
+
+implementation System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+
+
+
+procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref);
+
+
+
+implementation System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref)
+{
+ call {:async} System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
+}
+
+
+
+procedure {:extern} System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref);
+
+
+
+procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref);
+
+
+
+implementation System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref)
+{
+ assume $ThreadDelegate(this) == start$in;
+}
+
+
+
+procedure {:inline 1} System.Threading.Thread.Start(this: Ref);
+
+
+
+implementation System.Threading.Thread.Start(this: Ref)
+{
+ call {:async} System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
+}
+
+
+
+procedure {:extern} System.Threading.ThreadStart.Invoke(this: Ref);
+
+
+
procedure DelegateAdd(a: Ref, b: Ref) returns (c: Ref);
@@ -194,7 +268,7 @@ implementation DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
var $ArrayContents: [Ref][int]Box;
-var $ArrayLength: [Ref]int;
+function $ArrayLength(Ref) : int;
type Field;
@@ -210,6 +284,8 @@ type Type;
const unique $DefaultStruct: Struct;
+type Real;
+
function Box2Int(Box) : int;
function Box2Bool(Box) : bool;
@@ -218,6 +294,8 @@ function Box2Struct(Box) : Struct;
function Box2Ref(Box) : Ref;
+function Box2Real(Box) : Real;
+
function Int2Box(int) : Box;
function Bool2Box(bool) : Box;
@@ -226,12 +304,23 @@ function Struct2Box(Struct) : Box;
function Ref2Box(Ref) : Box;
+function Real2Box(Real) : Box;
+
+function {:inline true} Box2Box(b: Box) : Box
+{
+ b
+}
+
function Struct2Ref(Struct) : Ref;
function Int2Ref(int) : Ref;
function Bool2Ref(bool) : Ref;
+function Int2Real(int, Type, Type) : Real;
+
+function Real2Int(Real, Type, Type) : Real;
+
function $DynamicType(Ref) : Type;
function $TypeOf(Type) : Ref;
@@ -246,6 +335,129 @@ var $Method: [Ref][Ref]int;
var $Receiver: [Ref][Ref]Ref;
+const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
+
+var RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: [Ref]int;
+
+var RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y: [Ref]int;
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref);
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref)
+{
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 130} true;
+ RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y[this] := RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x[this];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 131} true;
+ return;
+}
+
+
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref);
+
+
+
+procedure {:extern} System.Object.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref)
+{
+ RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x[this] := 0;
+ RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y[this] := 0;
+ call System.Object.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor();
+
+
+
+implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
+{
+}
+
+
+
+const unique RegressionTestInput.CreateStruct: Type;
+
+procedure RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box);
+
+
+
+var RegressionTestInput.S.x: [Ref]int;
+
+var RegressionTestInput.S.b: [Ref]bool;
+
+implementation RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box)
+{
+ var local_0: [Field]Box;
+ var _loc0: int;
+ var _loc1: bool;
+
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 141} true;
+ local_0 := $DefaultStruct;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 142} true;
+ _loc0 := local_0;
+ assert Box2Int(_loc0[RegressionTestInput.S.x]) == 0;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 143} true;
+ _loc1 := local_0;
+ assert !Box2Bool(_loc1[RegressionTestInput.S.b]);
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 145} true;
+ $result := local_0;
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box);
+
+
+
+implementation RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box)
+{
+ var s: [Field]Box;
+ var _loc0: int;
+
+ s := s$in;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 147} true;
+ s[RegressionTestInput.S.x] := Int2Box(3);
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 148} true;
+ _loc0 := s;
+ assert Box2Int(_loc0[RegressionTestInput.S.x]) == 3;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 150} true;
+ $result := s;
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.CreateStruct.#ctor(this: Ref)
+{
+ call System.Object.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.CreateStruct.#cctor();
+
+
+
+implementation RegressionTestInput.CreateStruct.#cctor()
+{
+}
+
+
+
const unique RegressionTestInput.ClassWithArrayTypes: Type;
var RegressionTestInput.ClassWithArrayTypes.s: Ref;
@@ -268,28 +480,30 @@ implementation RegressionTestInput.ClassWithArrayTypes.Main1()
var $tmp5: int;
var $tmp6: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 86} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 86} true;
call $tmp0 := Alloc();
+ assume $ArrayLength($tmp0) == 1 * 5;
local_0 := $tmp0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 87} true;
- $tmp1 := $ArrayContents[local_0][0];
- $ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := 2]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 88} true;
- $tmp2 := $ArrayContents[local_0][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 87} true;
+ $tmp1 := Box2Int($ArrayContents[local_0][0]);
+ $ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := Int2Box(2)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 88} true;
+ $tmp2 := Box2Int($ArrayContents[local_0][0]);
assert $tmp2 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 90} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 90} true;
call $tmp3 := Alloc();
+ assume $ArrayLength($tmp3) == 1 * 4;
local_1 := $tmp3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 91} true;
- $tmp4 := $ArrayContents[local_1][0];
- $ArrayContents := $ArrayContents[local_1 := $ArrayContents[local_1][0 := 1]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 92} true;
- $tmp5 := $ArrayContents[local_1][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 91} true;
+ $tmp4 := Box2Int($ArrayContents[local_1][0]);
+ $ArrayContents := $ArrayContents[local_1 := $ArrayContents[local_1][0 := Int2Box(1)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 92} true;
+ $tmp5 := Box2Int($ArrayContents[local_1][0]);
assert $tmp5 == 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 94} true;
- $tmp6 := $ArrayContents[local_0][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 94} true;
+ $tmp6 := Box2Int($ArrayContents[local_0][0]);
assert $tmp6 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 95} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 95} true;
return;
}
@@ -310,28 +524,30 @@ implementation RegressionTestInput.ClassWithArrayTypes.Main2()
var $tmp12: int;
var $tmp13: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 100} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 100} true;
call $tmp7 := Alloc();
+ assume $ArrayLength($tmp7) == 1 * 5;
RegressionTestInput.ClassWithArrayTypes.s := $tmp7;
- assert {:sourceFile "Class1.cs"} {:sourceLine 101} true;
- $tmp8 := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0];
- $ArrayContents := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0 := 2]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 102} true;
- $tmp9 := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 101} true;
+ $tmp8 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
+ $ArrayContents := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0 := Int2Box(2)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 102} true;
+ $tmp9 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
assert $tmp9 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 104} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 104} true;
call $tmp10 := Alloc();
+ assume $ArrayLength($tmp10) == 1 * 4;
local_0 := $tmp10;
- assert {:sourceFile "Class1.cs"} {:sourceLine 105} true;
- $tmp11 := $ArrayContents[local_0][0];
- $ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := 1]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 106} true;
- $tmp12 := $ArrayContents[local_0][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 105} true;
+ $tmp11 := Box2Int($ArrayContents[local_0][0]);
+ $ArrayContents := $ArrayContents[local_0 := $ArrayContents[local_0][0 := Int2Box(1)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 106} true;
+ $tmp12 := Box2Int($ArrayContents[local_0][0]);
assert $tmp12 == 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 108} true;
- $tmp13 := $ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 108} true;
+ $tmp13 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.s][0]);
assert $tmp13 == 2;
- assert {:sourceFile "Class1.cs"} {:sourceLine 109} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 109} true;
return;
}
@@ -344,35 +560,23 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main3$System.Int32(this: Ref,
implementation RegressionTestInput.ClassWithArrayTypes.Main3$System.Int32(this: Ref, x$in: int)
{
var x: int;
- var _loc0: Ref;
- var $tmp14: Ref;
+ var $tmp14: int;
var $tmp15: int;
- var _loc1: Ref;
- var $tmp16: Ref;
+ var $tmp16: int;
var $tmp17: int;
- var $tmp18: Ref;
- var $tmp19: int;
- var $tmp20: Ref;
- var $tmp21: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 114} true;
- $tmp14 := RegressionTestInput.ClassWithArrayTypes.a[this];
- _loc0 := $tmp14;
- $tmp15 := $ArrayContents[_loc0][x];
- $ArrayContents := $ArrayContents[_loc0 := $ArrayContents[_loc0][x := 42]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 115} true;
- $tmp16 := RegressionTestInput.ClassWithArrayTypes.a[this];
- _loc1 := $tmp16;
- $tmp17 := $ArrayContents[_loc1][x + 1];
- $ArrayContents := $ArrayContents[_loc1 := $ArrayContents[_loc1][x + 1 := 43]];
- assert {:sourceFile "Class1.cs"} {:sourceLine 116} true;
- $tmp18 := RegressionTestInput.ClassWithArrayTypes.a[this];
- $tmp19 := $ArrayContents[$tmp18][x + 1];
- $tmp20 := RegressionTestInput.ClassWithArrayTypes.a[this];
- $tmp21 := $ArrayContents[$tmp20][x];
- assert $tmp19 == $tmp21 + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 117} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 114} true;
+ $tmp14 := Box2Int($ArrayContents[this][x]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][x := Int2Box(42)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 115} true;
+ $tmp15 := Box2Int($ArrayContents[this][x + 1]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][x + 1 := Int2Box(43)]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 116} true;
+ $tmp16 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.a[this]][x + 1]);
+ $tmp17 := Box2Int($ArrayContents[RegressionTestInput.ClassWithArrayTypes.a[this]][x]);
+ assert $tmp16 == $tmp17 + 1;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 117} true;
return;
}
@@ -385,26 +589,22 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array(this:
implementation RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array(this: Ref, xs$in: Ref)
{
var xs: Ref;
- var $tmp22: int;
- var _loc0: Ref;
- var $tmp23: Ref;
- var $tmp24: int;
+ var $tmp18: int;
+ var $tmp19: int;
xs := xs$in;
- if (!(if xs != null then $ArrayLength[xs] <= 0 else true))
+ if (!(if xs != null then $ArrayLength(xs) <= 0 else true))
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 121} true;
- $tmp22 := $ArrayContents[xs][0];
- $tmp23 := RegressionTestInput.ClassWithArrayTypes.a[this];
- _loc0 := $tmp23;
- $tmp24 := $ArrayContents[_loc0][0];
- $ArrayContents := $ArrayContents[_loc0 := $ArrayContents[_loc0][0 := $tmp22]];
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ $tmp18 := Box2Int($ArrayContents[xs][0]);
+ $tmp19 := Box2Int($ArrayContents[this][0]);
+ $ArrayContents := $ArrayContents[this := $ArrayContents[this][0 := Int2Box($tmp18)]];
}
else
{
}
- assert {:sourceFile "Class1.cs"} {:sourceLine 123} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 123} true;
return;
}
@@ -414,10 +614,6 @@ procedure RegressionTestInput.ClassWithArrayTypes.#ctor(this: Ref);
-procedure System.Object.#ctor(this: Ref);
-
-
-
implementation RegressionTestInput.ClassWithArrayTypes.#ctor(this: Ref)
{
RegressionTestInput.ClassWithArrayTypes.a[this] := null;
@@ -438,6 +634,34 @@ implementation RegressionTestInput.ClassWithArrayTypes.#cctor()
+const unique RegressionTestInput.AsyncAttribute: Type;
+
+procedure RegressionTestInput.AsyncAttribute.#ctor(this: Ref);
+
+
+
+procedure {:extern} System.Attribute.#ctor(this: Ref);
+
+
+
+implementation RegressionTestInput.AsyncAttribute.#ctor(this: Ref)
+{
+ call System.Attribute.#ctor(this);
+ return;
+}
+
+
+
+procedure RegressionTestInput.AsyncAttribute.#cctor();
+
+
+
+implementation RegressionTestInput.AsyncAttribute.#cctor()
+{
+}
+
+
+
const unique RegressionTestInput.RefParameters: Type;
procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int);
@@ -447,9 +671,9 @@ procedure RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (
implementation RegressionTestInput.RefParameters.M$System.Int32$(x$in: int) returns (x$out: int)
{
x$out := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 156} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 156} true;
x$out := x$out + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 157} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 157} true;
return;
}
@@ -477,6 +701,8 @@ implementation RegressionTestInput.RefParameters.#cctor()
+const unique RegressionTestInput.S: Type;
+
const unique RegressionTestInput.Class0: Type;
var RegressionTestInput.Class0.StaticInt: int;
@@ -490,7 +716,7 @@ implementation RegressionTestInput.Class0.StaticMethod$System.Int32(x$in: int) r
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 18} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 18} true;
$result := x + 1;
return;
}
@@ -505,22 +731,22 @@ implementation RegressionTestInput.Class0.M$System.Int32(this: Ref, x$in: int)
{
var x: int;
var __temp_1: int;
- var $tmp25: int;
+ var $tmp20: int;
var local_0: int;
x := x$in;
- $tmp25 := x;
- assert $tmp25 != 0;
- __temp_1 := 5 / $tmp25;
+ $tmp20 := x;
+ assert $tmp20 != 0;
+ __temp_1 := 5 / $tmp20;
x := 3;
local_0 := __temp_1 + 3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 22} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 22} true;
assert (if x == 3 then local_0 <= 8 else false);
- assert {:sourceFile "Class1.cs"} {:sourceLine 23} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 23} true;
RegressionTestInput.Class0.StaticInt := local_0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 24} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 24} true;
assert local_0 == RegressionTestInput.Class0.StaticInt;
- assert {:sourceFile "Class1.cs"} {:sourceLine 25} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 25} true;
return;
}
@@ -537,7 +763,7 @@ implementation RegressionTestInput.Class0.M$System.Int32$System.Int32(this: Ref,
x := x$in;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 28} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 28} true;
return;
}
@@ -552,7 +778,7 @@ implementation RegressionTestInput.Class0.M$System.Boolean(this: Ref, b$in: bool
var b: bool;
b := b$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 29} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 29} true;
return;
}
@@ -567,7 +793,7 @@ implementation RegressionTestInput.Class0.M$RegressionTestInput.Class0(this: Ref
var c: Ref;
c := c$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 30} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 30} true;
return;
}
@@ -579,25 +805,26 @@ procedure RegressionTestInput.Class0.NonVoid(this: Ref) returns ($result: int);
implementation RegressionTestInput.Class0.NonVoid(this: Ref) returns ($result: int)
{
- var $tmp26: int;
+ var $tmp21: int;
- assert {:sourceFile "Class1.cs"} {:sourceLine 34} true;
- call $tmp26 := RegressionTestInput.Class0.StaticMethod$System.Int32(3);
- $result := 3 + RegressionTestInput.Class0.StaticInt + $tmp26;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 34} true;
+ call $tmp21 := RegressionTestInput.Class0.StaticMethod$System.Int32(3);
+ $result := 3 + RegressionTestInput.Class0.StaticInt + $tmp21;
return;
}
-procedure RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref) returns (x$out: int, $result: int);
+procedure RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int);
-implementation RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref) returns (x$out: int, $result: int)
+implementation RegressionTestInput.Class0.OutParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int)
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 37} true;
+ x$out := x$in;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 37} true;
x$out := 3 + RegressionTestInput.Class0.StaticInt;
- assert {:sourceFile "Class1.cs"} {:sourceLine 39} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 39} true;
$result := x$out;
return;
}
@@ -611,11 +838,11 @@ procedure RegressionTestInput.Class0.RefParam$System.Int32$(this: Ref, x$in: int
implementation RegressionTestInput.Class0.RefParam$System.Int32$(this: Ref, x$in: int) returns (x$out: int, $result: int)
{
x$out := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 42} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 42} true;
x$out := x$out + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 43} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 43} true;
RegressionTestInput.Class0.StaticInt := x$out;
- assert {:sourceFile "Class1.cs"} {:sourceLine 45} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 45} true;
$result := x$out;
return;
}
@@ -631,11 +858,11 @@ implementation RegressionTestInput.Class0.AssignToInParam$System.Int32(this: Ref
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 48} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 48} true;
x := x + 1;
- assert {:sourceFile "Class1.cs"} {:sourceLine 49} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 49} true;
RegressionTestInput.Class0.StaticInt := x;
- assert {:sourceFile "Class1.cs"} {:sourceLine 51} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 51} true;
$result := x;
return;
}
@@ -651,7 +878,7 @@ implementation RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMetho
var x: int;
x := x$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 56} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 56} true;
$result := x;
return;
}
@@ -665,12 +892,12 @@ procedure RegressionTestInput.Class0.CallAsyncMethod$System.Int32(this: Ref, y$i
implementation RegressionTestInput.Class0.CallAsyncMethod$System.Int32(this: Ref, y$in: int) returns ($result: int)
{
var y: int;
- var $tmp27: int;
+ var $tmp22: int;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 60} true;
- call {:async} $tmp27 := RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMethod$System.Int32(this, y);
- $result := $tmp27;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 60} true;
+ call {:async} $tmp22 := RegressionTestInput.Class0.MethodThatRepresentsAnAynchronousMethod$System.Int32(this, y);
+ $result := $tmp22;
return;
}
@@ -699,53 +926,6 @@ implementation RegressionTestInput.Class0.#cctor()
-const unique RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap: Type;
-
-var RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x: [Ref]int;
-
-var RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y: [Ref]int;
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref);
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.M(this: Ref)
-{
- var $tmp28: int;
-
- assert {:sourceFile "Class1.cs"} {:sourceLine 130} true;
- $tmp28 := RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x[this];
- RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y[this] := $tmp28;
- assert {:sourceFile "Class1.cs"} {:sourceLine 131} true;
- return;
-}
-
-
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#ctor(this: Ref)
-{
- RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.x[this] := 0;
- RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.y[this] := 0;
- call System.Object.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor();
-
-
-
-implementation RegressionTestInput.WriteToTheHeapAValueReadFromTheHeap.#cctor()
-{
-}
-
-
-
const unique RegressionTestInput.ClassWithBoolTypes: Type;
var RegressionTestInput.ClassWithBoolTypes.staticB: bool;
@@ -763,7 +943,7 @@ implementation RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int3
x := x$in;
y := y$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 70} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 70} true;
$result := x < y;
return;
}
@@ -780,14 +960,14 @@ implementation RegressionTestInput.ClassWithBoolTypes.#ctor$System.Boolean(this:
z := z$in;
RegressionTestInput.ClassWithBoolTypes.b[this] := false;
- assert {:sourceFile "Class1.cs"} {:sourceLine 72} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 72} true;
call System.Object.#ctor(this);
- assert {:sourceFile "Class1.cs"} {:sourceLine 73} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 73} true;
RegressionTestInput.ClassWithBoolTypes.b[this] := z;
- assert {:sourceFile "Class1.cs"} {:sourceLine 74} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 74} true;
if (z)
{
- assert {:sourceFile "Class1.cs"} {:sourceLine 74} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 74} true;
RegressionTestInput.ClassWithBoolTypes.staticB := z;
}
else
@@ -805,11 +985,11 @@ procedure RegressionTestInput.ClassWithBoolTypes.Main();
implementation RegressionTestInput.ClassWithBoolTypes.Main()
{
- var $tmp29: bool;
+ var $tmp23: bool;
- assert {:sourceFile "Class1.cs"} {:sourceLine 78} true;
- call $tmp29 := RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int32(3, 4);
- assert {:sourceFile "Class1.cs"} {:sourceLine 79} true;
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 78} true;
+ call $tmp23 := RegressionTestInput.ClassWithBoolTypes.M$System.Int32$System.Int32(3, 4);
+ assert {:sourceFile "C:\dev\BoogieCodePlex\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 79} true;
return;
}
@@ -825,108 +1005,3 @@ implementation RegressionTestInput.ClassWithBoolTypes.#cctor()
}
-
-const unique RegressionTestInput.S: Type;
-
-var RegressionTestInput.S.x: [Ref]int;
-
-var RegressionTestInput.S.b: [Ref]bool;
-
-const unique RegressionTestInput.AsyncAttribute: Type;
-
-procedure RegressionTestInput.AsyncAttribute.#ctor(this: Ref);
-
-
-
-procedure System.Attribute.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.AsyncAttribute.#ctor(this: Ref)
-{
- call System.Attribute.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.AsyncAttribute.#cctor();
-
-
-
-implementation RegressionTestInput.AsyncAttribute.#cctor()
-{
-}
-
-
-
-const unique RegressionTestInput.CreateStruct: Type;
-
-procedure RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box);
-
-
-
-implementation RegressionTestInput.CreateStruct.Create(this: Ref) returns ($result: [Field]Box)
-{
- var local_0: [Field]Box;
- var $tmp30: int;
- var $tmp31: bool;
-
- assert {:sourceFile "Class1.cs"} {:sourceLine 141} true;
- local_0 := $DefaultStruct;
- assert {:sourceFile "Class1.cs"} {:sourceLine 142} true;
- $tmp30 := local_0[RegressionTestInput.S.x];
- assert $tmp30 == 0;
- assert {:sourceFile "Class1.cs"} {:sourceLine 143} true;
- $tmp31 := local_0[RegressionTestInput.S.b];
- assert !$tmp31;
- assert {:sourceFile "Class1.cs"} {:sourceLine 145} true;
- $result := local_0;
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box);
-
-
-
-implementation RegressionTestInput.CreateStruct.AssignThreeToSDotX$RegressionTestInput.S(this: Ref, s$in: [Field]Box) returns ($result: [Field]Box)
-{
- var s: [Field]Box;
- var $tmp32: int;
-
- s := s$in;
- assert {:sourceFile "Class1.cs"} {:sourceLine 147} true;
- s[RegressionTestInput.S.x] := 3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 148} true;
- $tmp32 := s[RegressionTestInput.S.x];
- assert $tmp32 == 3;
- assert {:sourceFile "Class1.cs"} {:sourceLine 150} true;
- $result := s;
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.#ctor(this: Ref);
-
-
-
-implementation RegressionTestInput.CreateStruct.#ctor(this: Ref)
-{
- call System.Object.#ctor(this);
- return;
-}
-
-
-
-procedure RegressionTestInput.CreateStruct.#cctor();
-
-
-
-implementation RegressionTestInput.CreateStruct.#cctor()
-{
-}
-
-
diff --git a/Binaries/DafnyPrelude.bpl b/Binaries/DafnyPrelude.bpl
index 646b16f1..a358e3c0 100644
--- a/Binaries/DafnyPrelude.bpl
+++ b/Binaries/DafnyPrelude.bpl
@@ -20,14 +20,14 @@ const null: ref;
type Set T = [T]bool;
-function Set#Empty<T>() returns (Set T);
+function Set#Empty<T>(): Set T;
axiom (forall<T> o: T :: { Set#Empty()[o] } !Set#Empty()[o]);
-function Set#Singleton<T>(T) returns (Set T);
+function Set#Singleton<T>(T): Set T;
axiom (forall<T> r: T :: { Set#Singleton(r) } Set#Singleton(r)[r]);
axiom (forall<T> r: T, o: T :: { Set#Singleton(r)[o] } Set#Singleton(r)[o] <==> r == o);
-function Set#UnionOne<T>(Set T, T) returns (Set T);
+function Set#UnionOne<T>(Set T, T): Set T;
axiom (forall<T> a: Set T, x: T, o: T :: { Set#UnionOne(a,x)[o] }
Set#UnionOne(a,x)[o] <==> o == x || a[o]);
axiom (forall<T> a: Set T, x: T :: { Set#UnionOne(a, x) }
@@ -35,7 +35,7 @@ axiom (forall<T> a: Set T, x: T :: { Set#UnionOne(a, x) }
axiom (forall<T> a: Set T, x: T, y: T :: { Set#UnionOne(a, x), a[y] }
a[y] ==> Set#UnionOne(a, x)[y]);
-function Set#Union<T>(Set T, Set T) returns (Set T);
+function Set#Union<T>(Set T, Set T): Set T;
axiom (forall<T> a: Set T, b: Set T, o: T :: { Set#Union(a,b)[o] }
Set#Union(a,b)[o] <==> a[o] || b[o]);
axiom (forall<T> a, b: Set T, y: T :: { Set#Union(a, b), a[y] }
@@ -47,7 +47,7 @@ axiom (forall<T> a, b: Set T :: { Set#Union(a, b) }
Set#Difference(Set#Union(a, b), a) == b &&
Set#Difference(Set#Union(a, b), b) == a);
-function Set#Intersection<T>(Set T, Set T) returns (Set T);
+function Set#Intersection<T>(Set T, Set T): Set T;
axiom (forall<T> a: Set T, b: Set T, o: T :: { Set#Intersection(a,b)[o] }
Set#Intersection(a,b)[o] <==> a[o] && b[o]);
@@ -60,27 +60,27 @@ axiom (forall<T> a, b: Set T :: { Set#Intersection(Set#Intersection(a, b), b) }
axiom (forall<T> a, b: Set T :: { Set#Intersection(a, Set#Intersection(a, b)) }
Set#Intersection(a, Set#Intersection(a, b)) == Set#Intersection(a, b));
-function Set#Difference<T>(Set T, Set T) returns (Set T);
+function Set#Difference<T>(Set T, Set T): Set T;
axiom (forall<T> a: Set T, b: Set T, o: T :: { Set#Difference(a,b)[o] }
Set#Difference(a,b)[o] <==> a[o] && !b[o]);
axiom (forall<T> a, b: Set T, y: T :: { Set#Difference(a, b), b[y] }
b[y] ==> !Set#Difference(a, b)[y] );
-function Set#Subset<T>(Set T, Set T) returns (bool);
+function Set#Subset<T>(Set T, Set T): bool;
axiom(forall<T> a: Set T, b: Set T :: { Set#Subset(a,b) }
Set#Subset(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] ==> b[o]));
-function Set#Equal<T>(Set T, Set T) returns (bool);
+function Set#Equal<T>(Set T, Set T): bool;
axiom(forall<T> a: Set T, b: Set T :: { Set#Equal(a,b) }
Set#Equal(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] <==> b[o]));
axiom(forall<T> a: Set T, b: Set T :: { Set#Equal(a,b) } // extensionality axiom for sets
Set#Equal(a,b) ==> a == b);
-function Set#Disjoint<T>(Set T, Set T) returns (bool);
+function Set#Disjoint<T>(Set T, Set T): bool;
axiom (forall<T> a: Set T, b: Set T :: { Set#Disjoint(a,b) }
Set#Disjoint(a,b) <==> (forall o: T :: {a[o]} {b[o]} !a[o] || !b[o]));
-function Set#Choose<T>(Set T, TickType) returns (T);
+function Set#Choose<T>(Set T, TickType): T;
axiom (forall<T> a: Set T, tick: TickType :: { Set#Choose(a, tick) }
a != Set#Empty() ==> a[Set#Choose(a, tick)]);
@@ -90,25 +90,25 @@ axiom (forall<T> a: Set T, tick: TickType :: { Set#Choose(a, tick) }
type Seq T;
-function Seq#Length<T>(Seq T) returns (int);
+function Seq#Length<T>(Seq T): int;
axiom (forall<T> s: Seq T :: { Seq#Length(s) } 0 <= Seq#Length(s));
-function Seq#Empty<T>() returns (Seq T);
+function Seq#Empty<T>(): Seq T;
axiom (forall<T> :: Seq#Length(Seq#Empty(): Seq T) == 0);
axiom (forall<T> s: Seq T :: { Seq#Length(s) } Seq#Length(s) == 0 ==> s == Seq#Empty());
-function Seq#Singleton<T>(T) returns (Seq T);
+function Seq#Singleton<T>(T): Seq T;
axiom (forall<T> t: T :: { Seq#Length(Seq#Singleton(t)) } Seq#Length(Seq#Singleton(t)) == 1);
-function Seq#Build<T>(s: Seq T, index: int, val: T, newLength: int) returns (Seq T);
+function Seq#Build<T>(s: Seq T, index: int, val: T, newLength: int): Seq T;
axiom (forall<T> s: Seq T, i: int, v: T, len: int :: { Seq#Length(Seq#Build(s,i,v,len)) }
0 <= len ==> Seq#Length(Seq#Build(s,i,v,len)) == len);
-function Seq#Append<T>(Seq T, Seq T) returns (Seq T);
+function Seq#Append<T>(Seq T, Seq T): Seq T;
axiom (forall<T> s0: Seq T, s1: Seq T :: { Seq#Length(Seq#Append(s0,s1)) }
Seq#Length(Seq#Append(s0,s1)) == Seq#Length(s0) + Seq#Length(s1));
-function Seq#Index<T>(Seq T, int) returns (T);
+function Seq#Index<T>(Seq T, int): T;
axiom (forall<T> t: T :: { Seq#Index(Seq#Singleton(t), 0) } Seq#Index(Seq#Singleton(t), 0) == t);
axiom (forall<T> s0: Seq T, s1: Seq T, n: int :: { Seq#Index(Seq#Append(s0,s1), n) }
(n < Seq#Length(s0) ==> Seq#Index(Seq#Append(s0,s1), n) == Seq#Index(s0, n)) &&
@@ -118,7 +118,7 @@ axiom (forall<T> s: Seq T, i: int, v: T, len: int, n: int :: { Seq#Index(Seq#Bui
(i == n ==> Seq#Index(Seq#Build(s,i,v,len),n) == v) &&
(i != n ==> Seq#Index(Seq#Build(s,i,v,len),n) == Seq#Index(s,n)));
-function Seq#Update<T>(Seq T, int, T) returns (Seq T);
+function Seq#Update<T>(Seq T, int, T): Seq T;
axiom (forall<T> s: Seq T, i: int, v: T :: { Seq#Length(Seq#Update(s,i,v)) }
0 <= i && i < Seq#Length(s) ==> Seq#Length(Seq#Update(s,i,v)) == Seq#Length(s));
axiom (forall<T> s: Seq T, i: int, v: T, n: int :: { Seq#Index(Seq#Update(s,i,v),n) }
@@ -126,7 +126,7 @@ axiom (forall<T> s: Seq T, i: int, v: T, n: int :: { Seq#Index(Seq#Update(s,i,v)
(i == n ==> Seq#Index(Seq#Update(s,i,v),n) == v) &&
(i != n ==> Seq#Index(Seq#Update(s,i,v),n) == Seq#Index(s,n)));
-function Seq#Contains<T>(Seq T, T) returns (bool);
+function Seq#Contains<T>(Seq T, T): bool;
axiom (forall<T> s: Seq T, x: T :: { Seq#Contains(s,x) }
Seq#Contains(s,x) <==>
(exists i: int :: { Seq#Index(s,i) } 0 <= i && i < Seq#Length(s) && Seq#Index(s,i) == x));
@@ -153,22 +153,22 @@ axiom (forall<T> s: Seq T, n: int, x: T ::
(exists i: int :: { Seq#Index(s, i) }
0 <= n && n <= i && i < Seq#Length(s) && Seq#Index(s, i) == x));
-function Seq#Equal<T>(Seq T, Seq T) returns (bool);
+function Seq#Equal<T>(Seq T, Seq T): bool;
axiom (forall<T> s0: Seq T, s1: Seq T :: { Seq#Equal(s0,s1) }
Seq#Equal(s0,s1) <==>
Seq#Length(s0) == Seq#Length(s1) &&
(forall j: int :: { Seq#Index(s0,j) } { Seq#Index(s1,j) }
0 <= j && j < Seq#Length(s0) ==> Seq#Index(s0,j) == Seq#Index(s1,j)));
-axiom(forall<T> a: Seq T, b: Seq T :: { Seq#Equal(a,b) } // extensionality axiom for sequences
+axiom (forall<T> a: Seq T, b: Seq T :: { Seq#Equal(a,b) } // extensionality axiom for sequences
Seq#Equal(a,b) ==> a == b);
-function Seq#SameUntil<T>(Seq T, Seq T, int) returns (bool);
+function Seq#SameUntil<T>(Seq T, Seq T, int): bool;
axiom (forall<T> s0: Seq T, s1: Seq T, n: int :: { Seq#SameUntil(s0,s1,n) }
Seq#SameUntil(s0,s1,n) <==>
(forall j: int :: { Seq#Index(s0,j) } { Seq#Index(s1,j) }
0 <= j && j < n ==> Seq#Index(s0,j) == Seq#Index(s1,j)));
-function Seq#Take<T>(s: Seq T, howMany: int) returns (Seq T);
+function Seq#Take<T>(s: Seq T, howMany: int): Seq T;
axiom (forall<T> s: Seq T, n: int :: { Seq#Length(Seq#Take(s,n)) }
0 <= n ==>
(n <= Seq#Length(s) ==> Seq#Length(Seq#Take(s,n)) == n) &&
@@ -177,7 +177,7 @@ axiom (forall<T> s: Seq T, n: int, j: int :: { Seq#Index(Seq#Take(s,n), j) } {:w
0 <= j && j < n && j < Seq#Length(s) ==>
Seq#Index(Seq#Take(s,n), j) == Seq#Index(s, j));
-function Seq#Drop<T>(s: Seq T, howMany: int) returns (Seq T);
+function Seq#Drop<T>(s: Seq T, howMany: int): Seq T;
axiom (forall<T> s: Seq T, n: int :: { Seq#Length(Seq#Drop(s,n)) }
0 <= n ==>
(n <= Seq#Length(s) ==> Seq#Length(Seq#Drop(s,n)) == Seq#Length(s) - n) &&
@@ -197,8 +197,8 @@ axiom (forall<T> s, t: Seq T ::
type BoxType;
-function $Box<T>(T) returns (BoxType);
-function $Unbox<T>(BoxType) returns (T);
+function $Box<T>(T): BoxType;
+function $Unbox<T>(BoxType): T;
axiom (forall<T> x: T :: { $Box(x) } $Unbox($Box(x)) == x);
axiom (forall b: BoxType :: { $Unbox(b): int } $Box($Unbox(b): int) == b);
@@ -206,7 +206,10 @@ axiom (forall b: BoxType :: { $Unbox(b): ref } $Box($Unbox(b): ref) == b);
axiom (forall b: BoxType :: { $Unbox(b): Set BoxType } $Box($Unbox(b): Set BoxType) == b);
axiom (forall b: BoxType :: { $Unbox(b): Seq BoxType } $Box($Unbox(b): Seq BoxType) == b);
axiom (forall b: BoxType :: { $Unbox(b): DatatypeType } $Box($Unbox(b): DatatypeType) == b);
-// note: an axiom like this for bool would not be sound
+// Note: an axiom like this for bool would not be sound; instead, we do:
+function $IsCanonicalBoolBox(BoxType): bool;
+axiom $IsCanonicalBoolBox($Box(false)) && $IsCanonicalBoolBox($Box(true));
+axiom (forall b: BoxType :: { $Unbox(b): bool } $IsCanonicalBoolBox(b) ==> $Box($Unbox(b): bool) == b);
// ---------------------------------------------------------------
// -- Encoding of type names -------------------------------------
@@ -218,12 +221,12 @@ const unique class.bool: ClassName;
const unique class.set: ClassName;
const unique class.seq: ClassName;
-function /*{:never_pattern true}*/ dtype(ref) returns (ClassName);
-function /*{:never_pattern true}*/ TypeParams(ref, int) returns (ClassName);
+function /*{:never_pattern true}*/ dtype(ref): ClassName;
+function /*{:never_pattern true}*/ TypeParams(ref, int): ClassName;
-function TypeTuple(a: ClassName, b: ClassName) returns (ClassName);
-function TypeTupleCar(ClassName) returns (ClassName);
-function TypeTupleCdr(ClassName) returns (ClassName);
+function TypeTuple(a: ClassName, b: ClassName): ClassName;
+function TypeTupleCar(ClassName): ClassName;
+function TypeTupleCdr(ClassName): ClassName;
// TypeTuple is injective in both arguments:
axiom (forall a: ClassName, b: ClassName :: { TypeTuple(a,b) }
TypeTupleCar(TypeTuple(a,b)) == a &&
@@ -235,13 +238,13 @@ axiom (forall a: ClassName, b: ClassName :: { TypeTuple(a,b) }
type DatatypeType;
-function /*{:never_pattern true}*/ DtType(DatatypeType) returns (ClassName); // the analog of dtype for datatype values
-function /*{:never_pattern true}*/ DtTypeParams(DatatypeType, int) returns (ClassName); // the analog of TypeParams
+function /*{:never_pattern true}*/ DtType(DatatypeType): ClassName; // the analog of dtype for datatype values
+function /*{:never_pattern true}*/ DtTypeParams(DatatypeType, int): ClassName; // the analog of TypeParams
type DtCtorId;
-function DatatypeCtorId(DatatypeType) returns (DtCtorId);
+function DatatypeCtorId(DatatypeType): DtCtorId;
-function DtRank(DatatypeType) returns (int);
+function DtRank(DatatypeType): int;
// ---------------------------------------------------------------
// -- Axiom contexts ---------------------------------------------
@@ -274,7 +277,7 @@ axiom (forall f: Field BoxType, i: int :: { MultiIndexField(f,i) }
MultiIndexField_Inverse1(MultiIndexField(f,i)) == i);
-function DeclType<T>(Field T) returns (ClassName);
+function DeclType<T>(Field T): ClassName;
// ---------------------------------------------------------------
// -- Allocatedness ----------------------------------------------
@@ -339,10 +342,10 @@ type HeapType = <alpha>[ref,Field alpha]alpha;
function {:inline true} read<alpha>(H:HeapType, r:ref, f:Field alpha): alpha { H[r, f] }
function {:inline true} update<alpha>(H:HeapType, r:ref, f:Field alpha, v:alpha): HeapType { H[r,f := v] }
-function $IsGoodHeap(HeapType) returns (bool);
+function $IsGoodHeap(HeapType): bool;
var $Heap: HeapType where $IsGoodHeap($Heap);
-function $HeapSucc(HeapType, HeapType) returns (bool);
+function $HeapSucc(HeapType, HeapType): bool;
axiom (forall<alpha> h: HeapType, r: ref, f: Field alpha, x: alpha :: { update(h, r, f, x) }
$HeapSucc(h, update(h, r, f, x)));
axiom (forall a,b,c: HeapType :: { $HeapSucc(a,b), $HeapSucc(b,c) }
diff --git a/Binaries/DafnyRuntime.cs b/Binaries/DafnyRuntime.cs
index b10aeac9..46a3f3df 100644
--- a/Binaries/DafnyRuntime.cs
+++ b/Binaries/DafnyRuntime.cs
@@ -18,9 +18,16 @@ namespace Dafny
public static Set<T> FromElements(params T[] values) {
Dictionary<T, bool> d = new Dictionary<T, bool>(values.Length);
foreach (T t in values)
- d.Add(t, true);
+ d[t] = true;
return new Set<T>(d);
}
+ public static Set<T> FromCollection(ICollection<T> values) {
+ Dictionary<T, bool> d = new Dictionary<T, bool>();
+ foreach (T t in values)
+ d[t] = true;
+ return new Set<T>(d);
+ }
+
public IEnumerable<T> Elements {
get {
return dict.Keys;
@@ -98,7 +105,7 @@ namespace Dafny
} else {
a = other.dict; b = dict;
}
- Dictionary<T, bool> r = new Dictionary<T, bool>();
+ var r = new Dictionary<T, bool>();
foreach (T t in a.Keys) {
if (b.ContainsKey(t))
r.Add(t, true);
@@ -110,7 +117,7 @@ namespace Dafny
return this;
else if (other.dict.Count == 0)
return this;
- Dictionary<T, bool> r = new Dictionary<T, bool>();
+ var r = new Dictionary<T, bool>();
foreach (T t in dict.Keys) {
if (!other.dict.ContainsKey(t))
r.Add(t, true);
@@ -226,6 +233,7 @@ namespace Dafny
}
}
public partial class Helpers {
+ // Computing forall/exists quantifiers
public static bool QuantBool(bool frall, System.Predicate<bool> pred) {
if (frall) {
return pred(false) && pred(true);
@@ -239,17 +247,25 @@ namespace Dafny
}
return frall;
}
- public static bool QuantSet<T>(Dafny.Set<T> set, bool frall, System.Predicate<T> pred) {
- foreach (var t in set.Elements) {
- if (pred(t) != frall) { return !frall; }
+ public static bool QuantSet<U>(Dafny.Set<U> set, bool frall, System.Predicate<U> pred) {
+ foreach (var u in set.Elements) {
+ if (pred(u) != frall) { return !frall; }
}
return frall;
}
- public static bool QuantSeq<T>(Dafny.Sequence<T> seq, bool frall, System.Predicate<T> pred) {
- foreach (var t in seq.Elements) {
- if (pred(t) != frall) { return !frall; }
+ public static bool QuantSeq<U>(Dafny.Sequence<U> seq, bool frall, System.Predicate<U> pred) {
+ foreach (var u in seq.Elements) {
+ if (pred(u) != frall) { return !frall; }
}
return frall;
}
+ // Enumerating other collections
+ public delegate Dafny.Set<T> ComprehensionDelegate<T>();
+ public static IEnumerable<bool> AllBooleans {
+ get {
+ yield return false;
+ yield return true;
+ }
+ }
}
}
diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs
index 3929e237..dcc007fe 100644
--- a/Source/BoogieDriver/BoogieDriver.cs
+++ b/Source/BoogieDriver/BoogieDriver.cs
@@ -261,7 +261,8 @@ namespace Microsoft.Boogie {
//BoogiePL.Errors.count = 0;
Program program = null;
bool okay = true;
- foreach (string bplFileName in fileNames) {
+ for (int fileId = 0; fileId < fileNames.Count; fileId++) {
+ string bplFileName = fileNames[fileId];
if (!suppressTraceOutput) {
if (CommandLineOptions.Clo.XmlSink != null) {
CommandLineOptions.Clo.XmlSink.WriteFileFragment(bplFileName);
@@ -274,7 +275,8 @@ namespace Microsoft.Boogie {
Program programSnippet;
int errorCount;
try {
- errorCount = BoogiePL.Parser.Parse(bplFileName, null, out programSnippet);
+ var defines = new List<string>() { "FILE_" + fileId };
+ errorCount = BoogiePL.Parser.Parse(bplFileName, defines, out programSnippet);
if (programSnippet == null || errorCount != 0) {
Console.WriteLine("{0} parse errors detected in {1}", errorCount, bplFileName);
okay = false;
diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs
index cde8fc3f..67500c88 100644
--- a/Source/Core/Absy.cs
+++ b/Source/Core/Absy.cs
@@ -235,30 +235,26 @@ namespace Microsoft.Boogie {
ResolveTypes(rc);
- List<Declaration/*!*/> prunedTopLevelDecls = CommandLineOptions.Clo.OverlookBoogieTypeErrors ? new List<Declaration/*!*/>() : null;
-
+ var prunedTopLevelDecls = new List<Declaration/*!*/>();
foreach (Declaration d in TopLevelDeclarations) {
+ if (QKeyValue.FindBoolAttribute(d.Attributes, "ignore")) {
+ continue;
+ }
// resolve all the non-type-declarations
if (d is TypeCtorDecl || d is TypeSynonymDecl) {
- if (prunedTopLevelDecls != null)
- prunedTopLevelDecls.Add(d);
} else {
int e = rc.ErrorCount;
d.Resolve(rc);
- if (prunedTopLevelDecls != null) {
- if (rc.ErrorCount != e && d is Implementation) {
- // ignore this implementation
- System.Console.WriteLine("Warning: Ignoring implementation {0} because of translation resolution errors", ((Implementation)d).Name);
- rc.ErrorCount = e;
- } else {
- prunedTopLevelDecls.Add(d);
- }
+ if (CommandLineOptions.Clo.OverlookBoogieTypeErrors && rc.ErrorCount != e && d is Implementation) {
+ // ignore this implementation
+ System.Console.WriteLine("Warning: Ignoring implementation {0} because of translation resolution errors", ((Implementation)d).Name);
+ rc.ErrorCount = e;
+ continue;
}
}
+ prunedTopLevelDecls.Add(d);
}
- if (prunedTopLevelDecls != null) {
- TopLevelDeclarations = prunedTopLevelDecls;
- }
+ TopLevelDeclarations = prunedTopLevelDecls;
foreach (Declaration d in TopLevelDeclarations) {
Variable v = d as Variable;
diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg
index b7743983..ec27422e 100644
--- a/Source/Core/BoogiePL.atg
+++ b/Source/Core/BoogiePL.atg
@@ -40,7 +40,9 @@ Contract.Requires(cce.NonNullElements(defines,true));
FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
- return Parse(stream, filename, defines, out program);
+ var ret = Parse(stream, filename, defines, out program);
+ stream.Close();
+ return ret;
}
diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs
index 5094fb9e..84ecce6d 100644
--- a/Source/Core/CommandLineOptions.cs
+++ b/Source/Core/CommandLineOptions.cs
@@ -1875,6 +1875,21 @@ namespace Microsoft.Boogie {
Console.WriteLine(
@"Boogie: The following attributes are supported by this implementation.
+ ---- On top-level declarations ---------------------------------------------
+
+ {:ignore}
+ Ignore the declaration (after checking for duplicate names).
+ See also below for more options when :ignore is used with axioms.
+
+ {:extern}
+ If two top-level declarations introduce the same name (for example, two
+ constants with the same name or two procedures with the same name), then
+ Boogie usually produces an error message. However, if at least one of
+ the declarations is declared with :extern, one of the declarations is
+ ignored. If both declarations are :extern, Boogie arbitrarily chooses
+ one of them to keep; otherwise, Boogie ignore the :extern declaration
+ and keeps the other.
+
---- On axioms -------------------------------------------------------------
{:inline true}
diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs
index 71804945..5e5dd178 100644
--- a/Source/Core/Parser.cs
+++ b/Source/Core/Parser.cs
@@ -59,7 +59,9 @@ Contract.Requires(cce.NonNullElements(defines,true));
FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
- return Parse(stream, filename, defines, out program);
+ var ret = Parse(stream, filename, defines, out program);
+ stream.Close();
+ return ret;
}
diff --git a/Source/Core/ResolutionContext.cs b/Source/Core/ResolutionContext.cs
index d4b353ef..251ca1db 100644
--- a/Source/Core/ResolutionContext.cs
+++ b/Source/Core/ResolutionContext.cs
@@ -169,16 +169,23 @@ namespace Microsoft.Boogie {
public void AddType(NamedDeclaration td) {
Contract.Requires(td != null);
- Contract.Assert((td is TypeCtorDecl) || (td is TypeSynonymDecl));
+ Contract.Requires((td is TypeCtorDecl) || (td is TypeSynonymDecl));
+ Contract.Requires(td.Name != null);
- string name = cce.NonNull(td.Name);
+ string name = td.Name;
if (CheckBvNameClashes(td, name))
return; // error has already been reported
- if (types[name] != null) {
- Error(td, "more than one declaration of type name: {0}", name);
- } else {
+ var previous = (NamedDeclaration)types[name];
+ if (previous == null) {
types.Add(name, td);
+ } else {
+ var r = (NamedDeclaration)SelectNonExtern(td, previous);
+ if (r == null) {
+ Error(td, "more than one declaration of type name: {0}", name);
+ } else {
+ types[name] = r;
+ }
}
}
@@ -247,79 +254,6 @@ namespace Microsoft.Boogie {
return null; // not present
}
- // ------------------------------ Types ------------------------------
-
- // user-defined types
- // Hashtable /*string->TypeDecl*/! types = new Hashtable /*string->TypeDecl*/ ();
- /*
- public void AddType(TypeDecl td){
- Contract.Requires(td != null);
- string! name = (!)td.Name;
-
- if (name.StartsWith("bv") && name.Length > 2) {
- bool isBv = true;
- for (int i = 2; i < name.Length; ++i)
- if (!char.IsDigit(name[i])) isBv = false;
- if (isBv)
- Error(td, "type name: {0} is registered for bitvectors", name);
- }
-
- if (types[name] != null)
- {
- Error(td, "more than one declaration of type name: {0}", name);
- }
- else
- {
- types.Add(name, td);
- }
- }
- */
- /// <summary>
- /// Returns the declaration of the named type, or null if
- /// no such type is declared.
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- /* public TypeDecl LookUpType(string name){
-Contract.Requires(name != null);
- return (TypeDecl)types[name];
- }
- */
- // ------------------------------ Type Binders ------------------------------
- /*
- List<TypeBinderDecl!>! typeBinders = new List<TypeBinderDecl!>(5);
-
- public void AddTypeBinder(TypeBinderDecl td){
- Contract.Requires(td != null);
- for (int i = 0; i < typeBinders.Count; i++) {
- if (typeBinders[i].Name == td.Name) {
- Error(td, "more than one declaration of type binder name: {0}", td.Name);
- return;
- }
- }
- typeBinders.Add(td);
- }
-
- public int TypeBinderState {
- get { return typeBinders.Count; }
- set { typeBinders.RemoveRange(value, typeBinders.Count - value); }
- }
-
- /// <summary>
- /// Returns the declaration of the named type binder, or null if
- /// no such binder is declared.
- /// </summary>
- public TypeDecl LookUpTypeBinder(string name){
- Contract.Requires(name != null);
- for (int i = typeBinders.Count; 0 <= --i; ) {
- TypeBinderDecl td = typeBinders[i];
- if (td.Name == name) {
- return td;
- }
- }
- return null; // not present
- }
- */
// ------------------------------ Variables ------------------------------
class VarContextNode {
@@ -365,10 +299,16 @@ Contract.Requires(name != null);
public void AddVariable(Variable var, bool global) {
Contract.Requires(var != null);
- if (FindVariable(cce.NonNull(var.Name), !global) != null) {
- Error(var, "more than one declaration of variable name: {0}", var.Name);
- } else {
+ var previous = FindVariable(cce.NonNull(var.Name), !global);
+ if (previous == null) {
varContext.VarSymbols.Add(var.Name, var);
+ } else {
+ var r = (Variable)SelectNonExtern(var, previous);
+ if (r == null) {
+ Error(var, "more than one declaration of variable name: {0}", var.Name);
+ } else {
+ varContext.VarSymbols[var.Name] = r;
+ }
}
}
@@ -417,11 +357,47 @@ Contract.Requires(name != null);
public void AddProcedure(DeclWithFormals proc) {
Contract.Requires(proc != null);
- if (funcdures[cce.NonNull(proc.Name)] != null) {
- Error(proc, "more than one declaration of function/procedure name: {0}", proc.Name);
+ Contract.Requires(proc.Name != null);
+
+ string name = proc.Name;
+ var previous = (DeclWithFormals)funcdures[name];
+ if (previous == null) {
+ funcdures.Add(name, proc);
+ } else {
+ var r = (DeclWithFormals)SelectNonExtern(proc, previous);
+ if (r == null) {
+ Error(proc, "more than one declaration of function/procedure name: {0}", name);
+ } else {
+ funcdures[name] = r;
+ }
+ }
+ }
+
+ /// <summary>
+ /// If both "a" and "b" have an ":extern" attribute, returns either one.
+ /// If one of "a" and "b" has an ":extern" attribute, returns that one.
+ /// If neither of "a" and "b" has an ":extern" attribute, returns null.
+ /// If a non-value value is returned, this method also adds the ":ignore"
+ /// attribute to the declaration NOT returned.
+ /// </summary>
+ Declaration SelectNonExtern(Declaration a, Declaration b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Declaration>() == null || Contract.Result<Declaration>() == a || Contract.Result<Declaration>() == b);
+
+ Declaration ignore, keep;
+ if (QKeyValue.FindBoolAttribute(a.Attributes, "extern")) {
+ ignore = a;
+ keep = b;
+ } else if (QKeyValue.FindBoolAttribute(b.Attributes, "extern")) {
+ ignore = b;
+ keep = a;
} else {
- funcdures.Add(proc.Name, proc);
+ return null;
}
+ // prepend :ignore attribute
+ ignore.Attributes = new QKeyValue(ignore.tok, "ignore", new List<object/*!*/>(), ignore.Attributes);
+ return keep;
}
/// <summary>
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index 9495d64e..6dabace1 100644
--- a/Source/Dafny/Compiler.cs
+++ b/Source/Dafny/Compiler.cs
@@ -716,7 +716,20 @@ namespace Microsoft.Dafny {
Indent(indent); wr.WriteLine("else");
TrStmt(s.Els, indent);
}
-
+
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ Indent(indent);
+ foreach (var alternative in s.Alternatives) {
+ wr.Write("if (");
+ TrExpr(alternative.Guard);
+ wr.WriteLine(") {");
+ TrStmtList(alternative.Body, indent);
+ Indent(indent);
+ wr.Write("} else ");
+ }
+ wr.WriteLine("{ /*unreachable alternative*/ }");
+
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
if (s.Guard == null) {
@@ -730,6 +743,26 @@ namespace Microsoft.Dafny {
TrStmt(s.Body, indent);
}
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ if (s.Alternatives.Count != 0) {
+ Indent(indent);
+ wr.WriteLine("while (true) {");
+ int ind = indent + IndentAmount;
+ Indent(ind);
+ foreach (var alternative in s.Alternatives) {
+ wr.Write("if (");
+ TrExpr(alternative.Guard);
+ wr.WriteLine(") {");
+ TrStmtList(alternative.Body, ind);
+ Indent(ind);
+ wr.Write("} else ");
+ }
+ wr.WriteLine("{ break; }");
+ Indent(indent);
+ wr.WriteLine("}");
+ }
+
} else if (stmt is ForeachStmt) {
ForeachStmt s = (ForeachStmt)stmt;
// List<Pair<TType,RhsType>> pendingUpdates = new List<Pair<TType,RhsType>>();
@@ -795,21 +828,22 @@ namespace Microsoft.Dafny {
// } else if (true) {
// ...
// }
+ if (s.Cases.Count != 0) {
+ string source = "_source" + tmpVarCount;
+ tmpVarCount++;
+ Indent(indent);
+ wr.Write("{0} {1} = ", TypeName(cce.NonNull(s.Source.Type)), source);
+ TrExpr(s.Source);
+ wr.WriteLine(";");
- string source = "_source" + tmpVarCount;
- tmpVarCount++;
- Indent(indent);
- wr.Write("{0} {1} = ", TypeName(cce.NonNull(s.Source.Type)), source);
- TrExpr(s.Source);
- wr.WriteLine(";");
-
- int i = 0;
- foreach (MatchCaseStmt mc in s.Cases) {
- MatchCasePrelude(source, cce.NonNull(mc.Ctor), mc.Arguments, i, s.Cases.Count, indent);
- TrStmtList(mc.Body, indent);
- i++;
+ int i = 0;
+ foreach (MatchCaseStmt mc in s.Cases) {
+ MatchCasePrelude(source, cce.NonNull(mc.Ctor), mc.Arguments, i, s.Cases.Count, indent);
+ TrStmtList(mc.Body, indent);
+ i++;
+ }
+ Indent(indent); wr.WriteLine("}");
}
- Indent(indent); wr.WriteLine("}");
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
@@ -1126,7 +1160,7 @@ 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 {0}", dtv.DatatypeName, DtCtorName(dtv.Ctor));
+ wr.Write("new {0}(new {1}", dtv.DatatypeName, DtCtorName(dtv.Ctor));
if (dtv.InferredTypeArgs.Count != 0) {
wr.Write("<{0}>", TypeNames(dtv.InferredTypeArgs));
}
@@ -1306,7 +1340,7 @@ namespace Microsoft.Dafny {
Contract.Assert(e.Bounds != null); // for non-ghost quantifiers, the resolver would have insisted on finding bounds
var n = e.BoundVars.Count;
Contract.Assert(e.Bounds.Count == n);
- for (int i = n; 0 <= --i; ) {
+ for (int i = 0; i < n; i++) {
var bound = e.Bounds[i];
var bv = e.BoundVars[i];
// emit: Dafny.Helpers.QuantX(boundsInformation, isForall, bv => body)
@@ -1335,11 +1369,72 @@ namespace Microsoft.Dafny {
wr.Write("{0}, ", expr is ForallExpr ? "true" : "false");
wr.Write("@{0} => ", bv.Name);
}
- TrExpr(e.Body);
+ TrExpr(e.LogicalBody());
for (int i = 0; i < n; i++) {
wr.Write(")");
}
-
+
+ } else if (expr is SetComprehension) {
+ var e = (SetComprehension)expr;
+ // For "set i,j,k,l | R(i,j,k,l) :: Term(i,j,k,l)" where the term has type "G", emit something like:
+ // ((ComprehensionDelegate<G>)delegate() {
+ // var _coll = new List<G>();
+ // foreach (L l in sq.Elements) {
+ // foreach (K k in st.Elements) {
+ // for (BigInteger j = Lo; j < Hi; j++) {
+ // for (bool i in Helper.AllBooleans) {
+ // if (R(i,j,k,l)) {
+ // _coll.Add(Term(i,j,k,l));
+ // }
+ // }
+ // }
+ // }
+ // }
+ // return Dafny.Set<G>.FromCollection(_coll);
+ // })()
+ Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds
+ var typeName = TypeName(((SetType)e.Type).Arg);
+ wr.Write("((Dafny.Helpers.ComprehensionDelegate<{0}>)delegate() {{ ", typeName);
+ wr.Write("var _coll = new System.Collections.Generic.List<{0}>(); ", typeName);
+ var n = e.BoundVars.Count;
+ Contract.Assert(e.Bounds.Count == n);
+ for (int i = 0; i < n; i++) {
+ var bound = e.Bounds[i];
+ var bv = e.BoundVars[i];
+ if (bound is QuantifierExpr.BoolBoundedPool) {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.Name);
+ } else if (bound is QuantifierExpr.IntBoundedPool) {
+ var b = (QuantifierExpr.IntBoundedPool)bound;
+ wr.Write("for (var @{0} = ", bv.Name);
+ TrExpr(b.LowerBound);
+ wr.Write("; @{0} < ", bv.Name);
+ TrExpr(b.UpperBound);
+ wr.Write("; @{0}++) {{ ", bv.Name);
+ } else if (bound is QuantifierExpr.SetBoundedPool) {
+ var b = (QuantifierExpr.SetBoundedPool)bound;
+ wr.Write("foreach (var @{0} in (", bv.Name);
+ TrExpr(b.Set);
+ wr.Write(").Elements) { ");
+ } else if (bound is QuantifierExpr.SeqBoundedPool) {
+ var b = (QuantifierExpr.SeqBoundedPool)bound;
+ wr.Write("foreach (var @{0} in (", bv.Name);
+ TrExpr(b.Seq);
+ wr.Write(").Elements) { ");
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
+ }
+ }
+ wr.Write("if (");
+ TrExpr(e.Range);
+ wr.Write(") { _coll.Add(");
+ TrExpr(e.Term);
+ wr.Write("); }");
+ for (int i = 0; i < n; i++) {
+ wr.Write("}");
+ }
+ wr.Write("return Dafny.Set<{0}>.FromCollection(_coll); ", typeName);
+ wr.Write("})()");
+
} else if (expr is ITEExpr) {
ITEExpr e = (ITEExpr)expr;
wr.Write("(");
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index 23582495..388ae8cd 100644
--- a/Source/Dafny/Dafny.atg
+++ b/Source/Dafny/Dafny.atg
@@ -555,7 +555,7 @@ ReferenceType<out IToken/*!*/ tok, out Type/*!*/ ty>
if (tok.val.Length != 5) {
dims = int.Parse(tok.val.Substring(5));
}
- ty = theBuiltIns.ArrayType(dims, gt[0], true);
+ ty = theBuiltIns.ArrayType(tok, dims, gt[0], true);
.)
| Ident<out tok> (. gt = new List<Type/*!*/>(); .)
[ GenericInstantiation<gt> ] (. ty = new UserDefinedType(tok, tok.val, gt); .)
@@ -808,7 +808,7 @@ AssignRhs<.out List<Expression> ee, out Type ty, out CallStmt initCall, Expressi
[ "[" (. ee = new List<Expression>(); .)
Expressions<ee>
"]" (. // make sure an array class with this dimensionality exists
- UserDefinedType tmp = theBuiltIns.ArrayType(ee.Count, new IntType(), true);
+ UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true);
.)
| "." Ident<out x>
"(" (. args = new List<Expression/*!*/>(); .)
@@ -881,29 +881,72 @@ IfStmt<out Statement/*!*/ ifStmt>
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
+ List<GuardedAlternative> alternatives;
+ ifStmt = dummyStmt; // to please the compiler
.)
"if" (. x = t; .)
- Guard<out guard>
- BlockStmt<out thn, out bodyStart, out bodyEnd>
- [ "else"
- ( IfStmt<out s> (. els = s; .)
- | BlockStmt<out s, out bodyStart, out bodyEnd> (. els = s; .)
- )
- ]
- (. ifStmt = new IfStmt(x, guard, thn, els); .)
+ (
+ Guard<out guard>
+ BlockStmt<out thn, out bodyStart, out bodyEnd>
+ [ "else"
+ ( IfStmt<out s> (. els = s; .)
+ | BlockStmt<out s, out bodyStart, out bodyEnd> (. els = s; .)
+ )
+ ]
+ (. ifStmt = new IfStmt(x, guard, thn, els); .)
+ |
+ AlternativeBlock<out alternatives>
+ (. ifStmt = new AlternativeStmt(x, alternatives); .)
+ )
+ .
+
+AlternativeBlock<.out List<GuardedAlternative> alternatives.>
+= (. alternatives = new List<GuardedAlternative>();
+ IToken x;
+ Expression e;
+ List<Statement> body;
+ .)
+ "{"
+ { "case" (. x = t; .)
+ Expression<out e>
+ "=>"
+ (. body = new List<Statement>(); .)
+ (. parseVarScope.PushMarker(); .)
+ { Stmt<body> }
+ (. parseVarScope.PopMarker(); .)
+ (. alternatives.Add(new GuardedAlternative(x, e, body)); .)
+ }
+ "}"
.
WhileStmt<out Statement/*!*/ stmt>
= (. Contract.Ensures(Contract.ValueAtReturn(out stmt) != null); IToken/*!*/ x;
Expression guard;
- bool isFree; Expression/*!*/ e;
List<MaybeFreeExpression/*!*/> invariants = new List<MaybeFreeExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
Statement/*!*/ body;
IToken bodyStart, bodyEnd;
+ 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)); .)
+ LoopSpec<out invariants, out decreases>
+ BlockStmt<out body, out bodyStart, out bodyEnd>
+ (. stmt = new WhileStmt(x, guard, invariants, decreases, body); .)
+ |
+ LoopSpec<out invariants, out decreases>
+ AlternativeBlock<out alternatives>
+ (. stmt = new AlternativeLoopStmt(x, invariants, decreases, alternatives); .)
+ )
+ .
+
+LoopSpec<.out List<MaybeFreeExpression/*!*/> invariants, out List<Expression/*!*/> decreases.>
+= (. bool isFree; Expression/*!*/ e;
+ invariants = new List<MaybeFreeExpression/*!*/>();
+ decreases = new List<Expression/*!*/>();
+ .)
{ (. isFree = false; .)
[ "free" (. isFree = true; .)
]
@@ -916,7 +959,6 @@ WhileStmt<out Statement/*!*/ stmt>
}
";"
}
- BlockStmt<out body, out bodyStart, out bodyEnd> (. stmt = new WhileStmt(x, guard, invariants, decreases, body); .)
.
Guard<out Expression e> /* null represents demonic-choice */
@@ -1237,6 +1279,7 @@ ConstAtomExpression<out Expression/*!*/ e>
"then" Expression<out e0>
"else" Expression<out e1> (. e = new ITEExpr(x, e, e0, e1); .)
| QuantifierGuts<out e>
+ | ComprehensionExpr<out e>
)
.
@@ -1312,6 +1355,8 @@ SelectOrCallSuffix<ref Expression/*!*/ e>
)
(. 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 */
@@ -1359,6 +1404,7 @@ QuantifierGuts<out Expression/*!*/ q>
List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
Attributes attrs = null;
Triggers trigs = null;
+ Expression range = null;
Expression/*!*/ body;
.)
( Forall (. x = t; univ = true; .)
@@ -1370,12 +1416,15 @@ QuantifierGuts<out Expression/*!*/ q>
IdentTypeOptional<out bv> (. bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); .)
}
{ AttributeOrTrigger<ref attrs, ref trigs> }
+ [ "|"
+ Expression<out range>
+ ]
QSep
Expression<out body>
(. if (univ) {
- q = new ForallExpr(x, bvars, body, trigs, attrs);
+ q = new ForallExpr(x, bvars, range, body, trigs, attrs);
} else {
- q = new ExistsExpr(x, bvars, body, trigs, attrs);
+ q = new ExistsExpr(x, bvars, range, body, trigs, attrs);
}
parseVarScope.PopMarker();
.)
@@ -1385,6 +1434,31 @@ Forall = "forall" | '\u2200'.
Exists = "exists" | '\u2203'.
QSep = "::" | '\u2022'.
+ComprehensionExpr<out Expression/*!*/ q>
+= (. Contract.Ensures(Contract.ValueAtReturn(out q) != null);
+ IToken/*!*/ x = Token.NoToken;
+ BoundVar/*!*/ bv;
+ List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
+ Expression/*!*/ range;
+ Expression body = null;
+ .)
+ "set" (. x = t; .)
+ (. parseVarScope.PushMarker(); .)
+ IdentTypeOptional<out bv> (. bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); .)
+ { ","
+ IdentTypeOptional<out bv> (. bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); .)
+ }
+ "|" Expression<out range>
+ [
+ QSep
+ Expression<out body>
+ ]
+ (. if (body == null && bvars.Count != 1) { SemErr(t, "a set comprehension with more than one bound variable must have a term expression"); }
+ q = new SetComprehension(x, bvars, range, body);
+ parseVarScope.PopMarker();
+ .)
+ .
+
Expressions<.List<Expression/*!*/>/*!*/ args.>
= (. Contract.Requires(cce.NonNullElements(args)); Expression/*!*/ e; .)
Expression<out e> (. args.Add(e); .)
diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs
index d923e5dc..f0a58293 100644
--- a/Source/Dafny/DafnyAst.cs
+++ b/Source/Dafny/DafnyAst.cs
@@ -40,20 +40,21 @@ namespace Microsoft.Dafny {
ClassDecl obj = new ClassDecl(Token.NoToken, "object", SystemModule, new List<TypeParameter>(), new List<MemberDecl>(), null);
SystemModule.TopLevelDecls.Add(obj);
// add one-dimensional arrays, since they may arise during type checking
- UserDefinedType tmp = ArrayType(1, Type.Int, true);
+ UserDefinedType tmp = ArrayType(Token.NoToken, 1, Type.Int, true);
}
public UserDefinedType ArrayType(int dims, Type arg) {
- return ArrayType(dims, arg, false);
+ return ArrayType(Token.NoToken, dims, arg, false);
}
- public UserDefinedType ArrayType(int dims, Type arg, bool allowCreationOfNewClass) {
+ public UserDefinedType ArrayType(IToken tok, int dims, Type arg, bool allowCreationOfNewClass) {
+ Contract.Requires(tok != null);
Contract.Requires(1 <= dims);
Contract.Requires(arg != null);
Contract.Ensures(Contract.Result<UserDefinedType>() != null);
List<Type/*!*/> typeArgs = new List<Type/*!*/>();
typeArgs.Add(arg);
- UserDefinedType udt = new UserDefinedType(Token.NoToken, ArrayClassName(dims), typeArgs);
+ UserDefinedType udt = new UserDefinedType(tok, ArrayClassName(dims), typeArgs);
if (allowCreationOfNewClass && !arrayTypeDecls.ContainsKey(dims)) {
ArrayClassDecl arrayClass = new ArrayClassDecl(dims, SystemModule);
for (int d = 0; d < dims; d++) {
@@ -1556,8 +1557,6 @@ namespace Microsoft.Dafny {
[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)
@@ -1573,36 +1572,103 @@ namespace Microsoft.Dafny {
}
}
- public class WhileStmt : Statement {
+ public class GuardedAlternative
+ {
+ public readonly IToken Tok;
public readonly Expression Guard;
+ public readonly List<Statement> Body;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Tok != null);
+ Contract.Invariant(Guard != null);
+ Contract.Invariant(Body != null);
+ }
+ public GuardedAlternative(IToken tok, Expression guard, List<Statement> body)
+ {
+ Contract.Requires(tok != null);
+ Contract.Requires(guard != null);
+ Contract.Requires(body != null);
+ this.Tok = tok;
+ this.Guard = guard;
+ this.Body = body;
+ }
+ }
+
+ public class AlternativeStmt : Statement
+ {
+ public readonly List<GuardedAlternative> Alternatives;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Alternatives != null);
+ }
+ public AlternativeStmt(IToken tok, List<GuardedAlternative> alternatives)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(alternatives != null);
+ this.Alternatives = alternatives;
+ }
+ }
+
+ public abstract class LoopStmt : Statement
+ {
public readonly List<MaybeFreeExpression/*!*/>/*!*/ Invariants;
public readonly List<Expression/*!*/>/*!*/ Decreases;
- public readonly Statement/*!*/ Body;
[ContractInvariantMethod]
void ObjectInvariant() {
- Contract.Invariant(Body != null);
Contract.Invariant(cce.NonNullElements(Invariants));
Contract.Invariant(cce.NonNullElements(Decreases));
}
+ public LoopStmt(IToken tok, List<MaybeFreeExpression/*!*/>/*!*/ invariants, List<Expression/*!*/>/*!*/ decreases)
+ : base(tok)
+ {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(invariants));
+ Contract.Requires(cce.NonNullElements(decreases));
+
+ this.Invariants = invariants;
+ this.Decreases = decreases;
+ }
+ }
+ public class WhileStmt : LoopStmt
+ {
+ public readonly Expression Guard;
+ public readonly Statement/*!*/ Body;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Body != null);
+ }
public WhileStmt(IToken tok, Expression guard,
List<MaybeFreeExpression/*!*/>/*!*/ invariants, List<Expression/*!*/>/*!*/ decreases,
Statement/*!*/ body)
- : base(tok) {
+ : base(tok, invariants, decreases) {
Contract.Requires(tok != null);
Contract.Requires(body != null);
- Contract.Requires(cce.NonNullElements(invariants));
- Contract.Requires(cce.NonNullElements(decreases));
this.Guard = guard;
- this.Invariants = invariants;
- this.Decreases = decreases;
this.Body = body;
+ }
+ }
+ public class AlternativeLoopStmt : LoopStmt
+ {
+ public readonly List<GuardedAlternative> Alternatives;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Alternatives != null);
+ }
+ public AlternativeLoopStmt(IToken tok,
+ List<MaybeFreeExpression/*!*/>/*!*/ invariants, List<Expression/*!*/>/*!*/ decreases,
+ List<GuardedAlternative> alternatives)
+ : base(tok, invariants, decreases) {
+ Contract.Requires(tok != null);
+ Contract.Requires(alternatives != null);
+ this.Alternatives = alternatives;
}
}
- public class ForeachStmt : Statement {
+ public class ForeachStmt : Statement
+ {
public readonly BoundVar/*!*/ BoundVar;
public readonly Expression/*!*/ Collection;
public readonly Expression/*!*/ Range;
@@ -1641,10 +1707,12 @@ namespace Microsoft.Dafny {
void ObjectInvariant() {
Contract.Invariant(Source != null);
Contract.Invariant(cce.NonNullElements(Cases));
+ Contract.Invariant(cce.NonNullElements(MissingCases));
}
public readonly Expression Source;
public readonly List<MatchCaseStmt/*!*/>/*!*/ Cases;
+ public readonly List<DatatypeCtor/*!*/> MissingCases = new List<DatatypeCtor>(); // filled in during resolution
public MatchStmt(IToken tok, Expression source, [Captured] List<MatchCaseStmt/*!*/>/*!*/ cases)
: base(tok) {
@@ -2299,17 +2367,25 @@ namespace Microsoft.Dafny {
}
}
- public abstract class QuantifierExpr : Expression {
+ /// <summary>
+ /// A ComprehensionExpr has the form:
+ /// BINDER x Attributes | Range(x) :: Term(x)
+ /// When BINDER is "forall" or "exists", the range may be "null" (which stands for the logical value "true").
+ /// For other BINDERs (currently, "set"), the range is non-null.
+ /// where "Attributes" is optional, and "| Range(x)" is optional and defaults to "true".
+ /// Currently, BINDER is one of the logical quantifiers "exists" or "forall".
+ /// </summary>
+ public abstract class ComprehensionExpr : Expression {
public readonly List<BoundVar/*!*/>/*!*/ BoundVars;
- public readonly Expression/*!*/ Body;
+ public readonly Expression Range;
+ public readonly Expression/*!*/ Term;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(BoundVars != null);
- Contract.Invariant(Body != null);
+ Contract.Invariant(Term != null);
}
- public readonly Triggers Trigs;
public readonly Attributes Attributes;
public abstract class BoundedPool { }
@@ -2337,23 +2413,40 @@ namespace Microsoft.Dafny {
}
public List<BoundedPool> Bounds; // initialized and filled in by resolver
- // invariant bounds == null || bounds.Count == BoundVars.Count;
+ // invariant Bounds == null || Bounds.Count == BoundVars.Count;
- public QuantifierExpr(IToken/*!*/ tok, List<BoundVar/*!*/>/*!*/ bvars, Expression/*!*/ body, Triggers trigs, Attributes attrs)
+ public ComprehensionExpr(IToken/*!*/ tok, List<BoundVar/*!*/>/*!*/ bvars, Expression range, Expression/*!*/ term, Attributes attrs)
: base(tok) {
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(bvars));
- Contract.Requires(body != null);
+ Contract.Requires(term != null);
this.BoundVars = bvars;
- this.Body = body;
- this.Trigs = trigs;
+ this.Range = range;
+ this.Term = term;
this.Attributes = attrs;
}
public override IEnumerable<Expression> SubExpressions {
- get { yield return Body; }
+ get {
+ if (Range != null) { yield return Range; }
+ yield return Term;
+ }
+ }
+ }
+
+ public abstract class QuantifierExpr : ComprehensionExpr {
+ public readonly Triggers Trigs;
+
+ public QuantifierExpr(IToken/*!*/ tok, List<BoundVar/*!*/>/*!*/ bvars, Expression range, Expression/*!*/ term, Triggers trigs, Attributes attrs)
+ : base(tok, bvars, range, term, attrs) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(bvars));
+ Contract.Requires(term != null);
+
+ this.Trigs = trigs;
}
+ public abstract Expression/*!*/ LogicalBody();
}
public class Triggers {
@@ -2372,24 +2465,58 @@ namespace Microsoft.Dafny {
}
public class ForallExpr : QuantifierExpr {
- public ForallExpr(IToken tok, List<BoundVar/*!*/>/*!*/ bvars, Expression body, Triggers trig, Attributes attrs)
- : base(tok, bvars, body, trig, attrs) {
+ public ForallExpr(IToken tok, List<BoundVar/*!*/>/*!*/ bvars, Expression range, Expression term, Triggers trig, Attributes attrs)
+ : base(tok, bvars, range, term, trig, attrs) {
Contract.Requires(cce.NonNullElements(bvars));
Contract.Requires(tok != null);
- Contract.Requires(body != null);
+ Contract.Requires(term != null);
+ }
+ public override Expression/*!*/ LogicalBody() {
+ if (Range == null) {
+ return Term;
+ }
+ var body = new BinaryExpr(Term.tok, BinaryExpr.Opcode.Imp, Range, Term);
+ body.ResolvedOp = BinaryExpr.ResolvedOpcode.Imp;
+ body.Type = Term.Type;
+ return body;
}
}
public class ExistsExpr : QuantifierExpr {
- public ExistsExpr(IToken tok, List<BoundVar/*!*/>/*!*/ bvars, Expression body, Triggers trig, Attributes attrs)
- : base(tok, bvars, body, trig, attrs) {
+ public ExistsExpr(IToken tok, List<BoundVar/*!*/>/*!*/ bvars, Expression range, Expression term, Triggers trig, Attributes attrs)
+ : base(tok, bvars, range, term, trig, attrs) {
Contract.Requires(cce.NonNullElements(bvars));
Contract.Requires(tok != null);
- Contract.Requires(body != null);
+ Contract.Requires(term != null);
+ }
+ public override Expression/*!*/ LogicalBody() {
+ if (Range == null) {
+ return Term;
+ }
+ var body = new BinaryExpr(Term.tok, BinaryExpr.Opcode.And, Range, Term);
+ body.ResolvedOp = BinaryExpr.ResolvedOpcode.And;
+ body.Type = Term.Type;
+ return body;
+ }
+ }
+
+ public class SetComprehension : ComprehensionExpr
+ {
+ public readonly bool TermIsImplicit;
+
+ public SetComprehension(IToken/*!*/ tok, List<BoundVar/*!*/>/*!*/ bvars, Expression/*!*/ range, Expression term)
+ : base(tok, bvars, range, term ?? new IdentifierExpr(tok, bvars[0].Name), null) {
+ Contract.Requires(tok != null);
+ Contract.Requires(cce.NonNullElements(bvars));
+ Contract.Requires(1 <= bvars.Count);
+ Contract.Requires(range != null);
+
+ TermIsImplicit = term == null;
}
}
- public class WildcardExpr : Expression { // a WildcardExpr can occur only in reads clauses and a loop's decreases clauses (with different meanings)
+ public class WildcardExpr : Expression
+ { // a WildcardExpr can occur only in reads clauses and a loop's decreases clauses (with different meanings)
public WildcardExpr(IToken tok)
: base(tok) {
Contract.Requires(tok != null);
@@ -2430,10 +2557,13 @@ namespace Microsoft.Dafny {
public class MatchExpr : Expression { // a MatchExpr is an "extended expression" and is only allowed in certain places
public readonly Expression Source;
public readonly List<MatchCaseExpr/*!*/>/*!*/ Cases;
+ public readonly List<DatatypeCtor/*!*/> MissingCases = new List<DatatypeCtor>(); // filled in during resolution
+
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Source != null);
Contract.Invariant(cce.NonNullElements(Cases));
+ Contract.Invariant(cce.NonNullElements(MissingCases));
}
public MatchExpr(IToken tok, Expression source, [Captured] List<MatchCaseExpr/*!*/>/*!*/ cases)
diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs
index 180f15ab..aa02c796 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -877,7 +877,7 @@ List<Expression/*!*/>/*!*/ decreases) {
if (tok.val.Length != 5) {
dims = int.Parse(tok.val.Substring(5));
}
- ty = theBuiltIns.ArrayType(dims, gt[0], true);
+ ty = theBuiltIns.ArrayType(tok, dims, gt[0], true);
} else if (la.kind == 1) {
Ident(out tok);
@@ -1267,62 +1267,54 @@ List<Expression/*!*/>/*!*/ decreases) {
Statement/*!*/ s;
Statement els = null;
IToken bodyStart, bodyEnd;
+ List<GuardedAlternative> alternatives;
+ ifStmt = dummyStmt; // to please the compiler
Expect(57);
x = t;
- Guard(out guard);
- BlockStmt(out thn, out bodyStart, out bodyEnd);
- if (la.kind == 58) {
- Get();
- if (la.kind == 57) {
- IfStmt(out s);
- els = s;
- } else if (la.kind == 7) {
- BlockStmt(out s, out bodyStart, out bodyEnd);
- els = s;
- } else SynErr(124);
- }
- ifStmt = new IfStmt(x, guard, thn, els);
+ if (la.kind == 32) {
+ Guard(out guard);
+ BlockStmt(out thn, out bodyStart, out bodyEnd);
+ if (la.kind == 58) {
+ Get();
+ if (la.kind == 57) {
+ IfStmt(out s);
+ els = s;
+ } else if (la.kind == 7) {
+ BlockStmt(out s, out bodyStart, out bodyEnd);
+ els = s;
+ } else SynErr(124);
+ }
+ ifStmt = new IfStmt(x, guard, thn, els);
+ } else if (la.kind == 7) {
+ AlternativeBlock(out alternatives);
+ ifStmt = new AlternativeStmt(x, alternatives);
+ } else SynErr(125);
}
void WhileStmt(out Statement/*!*/ stmt) {
Contract.Ensures(Contract.ValueAtReturn(out stmt) != null); IToken/*!*/ x;
Expression guard;
- bool isFree; Expression/*!*/ e;
List<MaybeFreeExpression/*!*/> invariants = new List<MaybeFreeExpression/*!*/>();
List<Expression/*!*/> decreases = new List<Expression/*!*/>();
Statement/*!*/ body;
IToken bodyStart, bodyEnd;
+ List<GuardedAlternative> alternatives;
+ stmt = dummyStmt; // to please the compiler
Expect(59);
x = t;
- Guard(out guard);
- Contract.Assume(guard == null || cce.Owner.None(guard));
- while (la.kind == 28 || la.kind == 31 || la.kind == 60) {
- if (la.kind == 28 || la.kind == 60) {
- isFree = false;
- if (la.kind == 28) {
- Get();
- isFree = true;
- }
- Expect(60);
- Expression(out e);
- invariants.Add(new MaybeFreeExpression(e, isFree));
- Expect(15);
- } else {
- Get();
- PossiblyWildExpression(out e);
- decreases.Add(e);
- while (la.kind == 19) {
- Get();
- PossiblyWildExpression(out e);
- decreases.Add(e);
- }
- Expect(15);
- }
- }
- BlockStmt(out body, out bodyStart, out bodyEnd);
- stmt = new WhileStmt(x, guard, invariants, decreases, body);
+ if (la.kind == 32) {
+ Guard(out guard);
+ Contract.Assume(guard == null || cce.Owner.None(guard));
+ LoopSpec(out invariants, out decreases);
+ BlockStmt(out body, out bodyStart, out bodyEnd);
+ stmt = new WhileStmt(x, guard, invariants, decreases, body);
+ } else if (StartOf(12)) {
+ LoopSpec(out invariants, out decreases);
+ AlternativeBlock(out alternatives);
+ stmt = new AlternativeLoopStmt(x, invariants, decreases, alternatives);
+ } else SynErr(126);
}
void MatchStmt(out Statement/*!*/ s) {
@@ -1382,13 +1374,13 @@ List<Expression/*!*/>/*!*/ decreases) {
if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); }
}
}
- if (StartOf(12)) {
+ if (StartOf(13)) {
AssignStmt(out s, false);
if (s is AssignStmt) { bodyAssign = (AssignStmt)s; }
} else if (la.kind == 56) {
HavocStmt(out s);
if (s is AssignStmt) { bodyAssign = (AssignStmt)s; }
- } else SynErr(125);
+ } else SynErr(127);
Expect(8);
if (bodyAssign != null) {
s = new ForeachStmt(x, new BoundVar(boundVar, boundVar.val, ty), collection, range, bodyPrefix, bodyAssign);
@@ -1419,7 +1411,7 @@ List<Expression/*!*/>/*!*/ decreases) {
ee = new List<Expression>();
Expressions(ee);
Expect(53);
- UserDefinedType tmp = theBuiltIns.ArrayType(ee.Count, new IntType(), true);
+ UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true);
} else {
Get();
@@ -1444,7 +1436,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (StartOf(8)) {
Expression(out e);
ee = new List<Expression>() { e };
- } else SynErr(126);
+ } else SynErr(128);
if (ee == null && ty == null) { ee = new List<Expression>() { dummyExpr}; }
}
@@ -1454,7 +1446,7 @@ List<Expression/*!*/>/*!*/ decreases) {
IdentOrFuncExpression(out e);
} else if (la.kind == 32 || la.kind == 99 || la.kind == 100) {
ObjectExpression(out e);
- } else SynErr(127);
+ } else SynErr(129);
while (la.kind == 52 || la.kind == 54) {
SelectOrCallSuffix(ref e);
}
@@ -1501,10 +1493,63 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (StartOf(8)) {
Expression(out ee);
e = ee;
- } else SynErr(128);
+ } else SynErr(130);
Expect(33);
}
+ void AlternativeBlock(out List<GuardedAlternative> alternatives) {
+ alternatives = new List<GuardedAlternative>();
+ IToken x;
+ Expression e;
+ List<Statement> body;
+
+ Expect(7);
+ while (la.kind == 45) {
+ Get();
+ x = t;
+ Expression(out e);
+ Expect(46);
+ body = new List<Statement>();
+ parseVarScope.PushMarker();
+ while (StartOf(9)) {
+ Stmt(body);
+ }
+ parseVarScope.PopMarker();
+ alternatives.Add(new GuardedAlternative(x, e, body));
+ }
+ Expect(8);
+ }
+
+ void LoopSpec(out List<MaybeFreeExpression/*!*/> invariants, out List<Expression/*!*/> decreases) {
+ bool isFree; Expression/*!*/ e;
+ invariants = new List<MaybeFreeExpression/*!*/>();
+ decreases = new List<Expression/*!*/>();
+
+ while (la.kind == 28 || la.kind == 31 || la.kind == 60) {
+ if (la.kind == 28 || la.kind == 60) {
+ isFree = false;
+ if (la.kind == 28) {
+ Get();
+ isFree = true;
+ }
+ Expect(60);
+ Expression(out e);
+ invariants.Add(new MaybeFreeExpression(e, isFree));
+ Expect(15);
+ } else {
+ Get();
+ PossiblyWildExpression(out e);
+ decreases.Add(e);
+ while (la.kind == 19) {
+ Get();
+ PossiblyWildExpression(out e);
+ decreases.Add(e);
+ }
+ Expect(15);
+ }
+ }
+ }
+
void CaseStatement(out MatchCaseStmt/*!*/ c) {
Contract.Ensures(Contract.ValueAtReturn(out c) != null);
IToken/*!*/ x, id, arg;
@@ -1544,7 +1589,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (la.kind == 32 || la.kind == 99 || la.kind == 100) {
ObjectExpression(out e);
SelectOrCallSuffix(ref e);
- } else SynErr(129);
+ } else SynErr(131);
while (la.kind == 52 || la.kind == 54) {
SelectOrCallSuffix(ref e);
}
@@ -1558,7 +1603,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (StartOf(8)) {
Expression(out e);
arg = new Attributes.Argument(e);
- } else SynErr(130);
+ } else SynErr(132);
}
void EquivExpression(out Expression/*!*/ e0) {
@@ -1588,13 +1633,13 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 69) {
Get();
- } else SynErr(131);
+ } else SynErr(133);
}
void LogicalExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
RelationalExpression(out e0);
- if (StartOf(13)) {
+ if (StartOf(14)) {
if (la.kind == 72 || la.kind == 73) {
AndOp();
x = t;
@@ -1626,13 +1671,13 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 71) {
Get();
- } else SynErr(132);
+ } else SynErr(134);
}
void RelationalExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
Term(out e0);
- if (StartOf(14)) {
+ if (StartOf(15)) {
RelOp(out x, out op);
Term(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -1644,7 +1689,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 73) {
Get();
- } else SynErr(133);
+ } else SynErr(135);
}
void OrOp() {
@@ -1652,7 +1697,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 75) {
Get();
- } else SynErr(134);
+ } else SynErr(136);
}
void Term(out Expression/*!*/ e0) {
@@ -1728,7 +1773,7 @@ List<Expression/*!*/>/*!*/ decreases) {
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- default: SynErr(135); break;
+ default: SynErr(137); break;
}
}
@@ -1750,7 +1795,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (la.kind == 86) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(136);
+ } else SynErr(138);
}
void UnaryExpression(out Expression/*!*/ e) {
@@ -1765,11 +1810,11 @@ List<Expression/*!*/>/*!*/ decreases) {
x = t;
UnaryExpression(out e);
e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e);
- } else if (StartOf(12)) {
+ } else if (StartOf(13)) {
SelectExpression(out e);
- } else if (StartOf(15)) {
+ } else if (StartOf(16)) {
ConstAtomExpression(out e);
- } else SynErr(137);
+ } else SynErr(139);
}
void MulOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
@@ -1783,7 +1828,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (la.kind == 88) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(138);
+ } else SynErr(140);
}
void NegOp() {
@@ -1791,7 +1836,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 90) {
Get();
- } else SynErr(139);
+ } else SynErr(141);
}
void ConstAtomExpression(out Expression/*!*/ e) {
@@ -1898,7 +1943,11 @@ List<Expression/*!*/>/*!*/ decreases) {
QuantifierGuts(out e);
break;
}
- default: SynErr(140); break;
+ case 37: {
+ ComprehensionExpr(out e);
+ break;
+ }
+ default: SynErr(142); break;
}
}
@@ -1920,6 +1969,7 @@ List<Expression/*!*/>/*!*/ decreases) {
List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
Attributes attrs = null;
Triggers trigs = null;
+ Expression range = null;
Expression/*!*/ body;
if (la.kind == 101 || la.kind == 102) {
@@ -1928,7 +1978,7 @@ List<Expression/*!*/>/*!*/ decreases) {
} else if (la.kind == 103 || la.kind == 104) {
Exists();
x = t;
- } else SynErr(141);
+ } else SynErr(143);
parseVarScope.PushMarker();
IdentTypeOptional(out bv);
bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name);
@@ -1940,17 +1990,51 @@ List<Expression/*!*/>/*!*/ decreases) {
while (la.kind == 7) {
AttributeOrTrigger(ref attrs, ref trigs);
}
+ if (la.kind == 17) {
+ Get();
+ Expression(out range);
+ }
QSep();
Expression(out body);
if (univ) {
- q = new ForallExpr(x, bvars, body, trigs, attrs);
+ q = new ForallExpr(x, bvars, range, body, trigs, attrs);
} else {
- q = new ExistsExpr(x, bvars, body, trigs, attrs);
+ q = new ExistsExpr(x, bvars, range, body, trigs, attrs);
}
parseVarScope.PopMarker();
}
+ void ComprehensionExpr(out Expression/*!*/ q) {
+ Contract.Ensures(Contract.ValueAtReturn(out q) != null);
+ IToken/*!*/ x = Token.NoToken;
+ BoundVar/*!*/ bv;
+ List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
+ Expression/*!*/ range;
+ Expression body = null;
+
+ Expect(37);
+ x = t;
+ parseVarScope.PushMarker();
+ IdentTypeOptional(out bv);
+ bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name);
+ while (la.kind == 19) {
+ Get();
+ IdentTypeOptional(out bv);
+ bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name);
+ }
+ Expect(17);
+ Expression(out range);
+ if (la.kind == 105 || la.kind == 106) {
+ QSep();
+ Expression(out body);
+ }
+ if (body == null && bvars.Count != 1) { SemErr(t, "a set comprehension with more than one bound variable must have a term expression"); }
+ q = new SetComprehension(x, bvars, range, body);
+ parseVarScope.PopMarker();
+
+ }
+
void IdentOrFuncExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ id; e = dummyExpr; List<Expression/*!*/>/*!*/ args;
Ident(out id);
@@ -1989,7 +2073,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
Expression(out e);
Expect(33);
- } else SynErr(142);
+ } else SynErr(144);
}
void SelectOrCallSuffix(ref Expression/*!*/ e) {
@@ -2039,14 +2123,16 @@ List<Expression/*!*/>/*!*/ decreases) {
multipleIndices.Add(ee);
}
- } else SynErr(143);
+ } else SynErr(145);
} else if (la.kind == 98) {
Get();
Expression(out ee);
anyDots = true; e1 = ee;
- } else SynErr(144);
+ } else SynErr(146);
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 */
@@ -2066,7 +2152,7 @@ List<Expression/*!*/>/*!*/ decreases) {
}
Expect(53);
- } else SynErr(145);
+ } else SynErr(147);
}
void Forall() {
@@ -2074,7 +2160,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 102) {
Get();
- } else SynErr(146);
+ } else SynErr(148);
}
void Exists() {
@@ -2082,7 +2168,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 104) {
Get();
- } else SynErr(147);
+ } else SynErr(149);
}
void AttributeOrTrigger(ref Attributes attrs, ref Triggers trigs) {
@@ -2095,7 +2181,7 @@ List<Expression/*!*/>/*!*/ decreases) {
es = new List<Expression/*!*/>();
Expressions(es);
trigs = new Triggers(es, trigs);
- } else SynErr(148);
+ } else SynErr(150);
Expect(8);
}
@@ -2104,7 +2190,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Get();
} else if (la.kind == 106) {
Get();
- } else SynErr(149);
+ } else SynErr(151);
}
void AttributeBody(ref Attributes attrs) {
@@ -2115,7 +2201,7 @@ List<Expression/*!*/>/*!*/ decreases) {
Expect(22);
Expect(1);
aName = t.val;
- if (StartOf(16)) {
+ if (StartOf(17)) {
AttributeArg(out aArg);
aArgs.Add(aArg);
while (la.kind == 19) {
@@ -2147,15 +2233,16 @@ List<Expression/*!*/>/*!*/ decreases) {
{x,x,x,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, 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,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, x},
{x,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,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,T, 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, 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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,x,x,x, x},
+ {x,T,T,x, x,x,x,T, 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,T,x,x, x,x,x,x, x,x,x,x, x,x,x,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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,x,x,x, x},
{x,T,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,x,T,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, T,x,x,T, T,T,x,x, x,x,x,x, T,T,x,T, x,T,T,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,T, T,x,x,x, x,x,x,x, x},
- {x,T,T,x, x,x,x,T, 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,T,x, x,x,x,x, x,x,x,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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,x,x,x, x},
+ {x,T,T,x, x,x,x,T, 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,T,x,x, x,x,T,x, x,x,x,x, x,x,x,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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,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, T,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,x,x, x,x,x,x, T,T,x,T, x,T,T,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,T, 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, 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,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, 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, 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, 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,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, x,x,x,x, x,x,x,x, x,x,x,x, 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,T,x, x,x,x,T, 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, 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, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,T,T,T, T,x,x,x, x},
- {x,T,T,x, T,x,x,T, 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, 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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,x,x,x, x}
+ {x,x,T,x, x,x,x,T, 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,T,x,x, x,x,x,x, x,x,x,x, x,x,x,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, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,T,T,T, T,x,x,x, x},
+ {x,T,T,x, T,x,x,T, 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,T,x,x, x,x,x,x, x,x,x,x, x,x,x,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, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,x,x,x, x}
};
} // end Parser
@@ -2305,31 +2392,33 @@ public class Errors {
case 122: s = "invalid Stmt"; break;
case 123: s = "invalid OneStmt"; break;
case 124: s = "invalid IfStmt"; break;
- case 125: s = "invalid ForeachStmt"; break;
- case 126: s = "invalid AssignRhs"; break;
- case 127: s = "invalid SelectExpression"; break;
- case 128: s = "invalid Guard"; break;
- case 129: s = "invalid CallStmtSubExpr"; break;
- case 130: s = "invalid AttributeArg"; break;
- case 131: s = "invalid EquivOp"; break;
- case 132: s = "invalid ImpliesOp"; break;
- case 133: s = "invalid AndOp"; break;
- case 134: s = "invalid OrOp"; break;
- case 135: s = "invalid RelOp"; break;
- case 136: s = "invalid AddOp"; break;
- case 137: s = "invalid UnaryExpression"; break;
- case 138: s = "invalid MulOp"; break;
- case 139: s = "invalid NegOp"; break;
- case 140: s = "invalid ConstAtomExpression"; break;
- case 141: s = "invalid QuantifierGuts"; break;
- case 142: s = "invalid ObjectExpression"; break;
- case 143: s = "invalid SelectOrCallSuffix"; break;
- case 144: s = "invalid SelectOrCallSuffix"; break;
+ case 125: s = "invalid IfStmt"; break;
+ case 126: s = "invalid WhileStmt"; break;
+ case 127: s = "invalid ForeachStmt"; break;
+ case 128: s = "invalid AssignRhs"; break;
+ case 129: s = "invalid SelectExpression"; break;
+ case 130: s = "invalid Guard"; break;
+ case 131: s = "invalid CallStmtSubExpr"; break;
+ case 132: s = "invalid AttributeArg"; break;
+ case 133: s = "invalid EquivOp"; break;
+ case 134: s = "invalid ImpliesOp"; break;
+ case 135: s = "invalid AndOp"; break;
+ case 136: s = "invalid OrOp"; break;
+ case 137: s = "invalid RelOp"; break;
+ case 138: s = "invalid AddOp"; break;
+ case 139: s = "invalid UnaryExpression"; break;
+ case 140: s = "invalid MulOp"; break;
+ case 141: s = "invalid NegOp"; break;
+ case 142: s = "invalid ConstAtomExpression"; break;
+ case 143: s = "invalid QuantifierGuts"; break;
+ case 144: s = "invalid ObjectExpression"; break;
case 145: s = "invalid SelectOrCallSuffix"; break;
- case 146: s = "invalid Forall"; break;
- case 147: s = "invalid Exists"; break;
- case 148: s = "invalid AttributeOrTrigger"; break;
- case 149: s = "invalid QSep"; break;
+ case 146: s = "invalid SelectOrCallSuffix"; break;
+ case 147: s = "invalid SelectOrCallSuffix"; break;
+ case 148: s = "invalid Forall"; break;
+ case 149: s = "invalid Exists"; break;
+ case 150: s = "invalid AttributeOrTrigger"; break;
+ case 151: s = "invalid QSep"; break;
default: s = "error " + n; break;
}
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index 003a977c..2dd2724f 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -507,6 +507,13 @@ namespace Microsoft.Dafny {
break;
}
}
+
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ wr.WriteLine("if {");
+ PrintAlternatives(indent, s.Alternatives);
+ Indent(indent);
+ wr.Write("}");
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
@@ -514,12 +521,23 @@ namespace Microsoft.Dafny {
PrintGuard(s.Guard);
wr.WriteLine(")");
- int ind = indent + IndentAmount;
- PrintSpec("invariant", s.Invariants, ind);
- PrintSpecLine("decreases", s.Decreases, indent);
+ PrintSpec("invariant", s.Invariants, indent + IndentAmount);
+ PrintSpecLine("decreases", s.Decreases, indent + IndentAmount);
Indent(indent);
PrintStatement(s.Body, indent);
-
+
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ wr.WriteLine("while");
+ PrintSpec("invariant", s.Invariants, indent + IndentAmount);
+ PrintSpecLine("decreases", s.Decreases, indent + IndentAmount);
+
+ Indent(indent);
+ wr.WriteLine("{");
+ PrintAlternatives(indent, s.Alternatives);
+ Indent(indent);
+ wr.Write("}");
+
} else if (stmt is ForeachStmt) {
ForeachStmt s = (ForeachStmt)stmt;
wr.Write("foreach ({0} in ", s.BoundVar.Name);
@@ -572,6 +590,21 @@ namespace Microsoft.Dafny {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
}
}
+
+ void PrintAlternatives(int indent, List<GuardedAlternative> alternatives) {
+ int caseInd = indent + IndentAmount;
+ foreach (var alternative in alternatives) {
+ Indent(caseInd);
+ wr.Write("case ");
+ PrintExpression(alternative.Guard);
+ wr.WriteLine(" =>");
+ foreach (Statement s in alternative.Body) {
+ Indent(caseInd + IndentAmount);
+ PrintStatement(s, caseInd + IndentAmount);
+ wr.WriteLine();
+ }
+ }
+ }
void PrintDeterminedRhs(DeterminedAssignmentRhs rhs) {
Contract.Requires(rhs != null);
@@ -931,17 +964,43 @@ namespace Microsoft.Dafny {
wr.Write(" ");
PrintAttributes(e.Attributes);
PrintTriggers(e.Trigs);
+ if (e.Range != null) {
+ wr.Write("| ");
+ PrintExpression(e.Range);
+ wr.Write(" ");
+ }
wr.Write(":: ");
if (0 <= indent) {
int ind = indent + IndentAmount;
wr.WriteLine();
Indent(ind);
- PrintExpression(e.Body, ind);
+ PrintExpression(e.Term, ind);
} else {
- PrintExpression(e.Body);
+ PrintExpression(e.Term);
}
if (parensNeeded) { wr.Write(")"); }
-
+
+ } else if (expr is SetComprehension) {
+ var e = (SetComprehension)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("set ");
+ string sep = "";
+ foreach (BoundVar bv in e.BoundVars) {
+ wr.Write("{0}{1}", sep, bv.Name);
+ sep = ", ";
+ PrintType(": ", bv.Type);
+ }
+ wr.Write(" ");
+ PrintAttributes(e.Attributes);
+ wr.Write("| ");
+ PrintExpression(e.Range);
+ if (!e.TermIsImplicit) {
+ wr.Write(" :: ");
+ PrintExpression(e.Term);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
} else if (expr is WildcardExpr) {
wr.Write("*");
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index 22a58a39..3549d0db 100644
--- a/Source/Dafny/Resolver.cs
+++ b/Source/Dafny/Resolver.cs
@@ -837,7 +837,11 @@ namespace Microsoft.Dafny {
#if !NO_CHEAP_OBJECT_WORKAROUND
if (a is ObjectType || b is ObjectType) { // TODO: remove this temporary hack
- // allow anything with object; this is BOGUS
+ var other = a is ObjectType ? b : a;
+ if (other is BoolType || other is IntType || other is SetType || other is SeqType || other.IsDatatype) {
+ return false;
+ }
+ // allow anything else with object; this is BOGUS
return true;
}
#endif
@@ -960,7 +964,7 @@ namespace Microsoft.Dafny {
if (!UnifyTypes(iProxy.Arg, ((SeqType)t).Arg)) {
return false;
}
- } else if (t.IsArrayType) {
+ } else if (t.IsArrayType && (t.AsArrayType).Dims == 1) {
Type elType = UserDefinedType.ArrayElementType(t);
if (!UnifyTypes(iProxy.Arg, elType)) {
return false;
@@ -1313,10 +1317,14 @@ namespace Microsoft.Dafny {
if (s.Els != null) {
ResolveStatement(s.Els, branchesAreSpecOnly, method);
}
-
+
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ s.IsGhost = ResolveAlternatives(s.Alternatives, specContextOnly, method);
+
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
- bool bodyIsSpecOnly = specContextOnly;
+ bool bodyMustBeSpecOnly = specContextOnly;
if (s.Guard != null) {
int prevErrorCount = ErrorCount;
ResolveExpression(s.Guard, true, true);
@@ -1326,7 +1334,7 @@ namespace Microsoft.Dafny {
Error(s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type);
}
if (!specContextOnly && successfullyResolved) {
- bodyIsSpecOnly = UsesSpecFeatures(s.Guard);
+ bodyMustBeSpecOnly = UsesSpecFeatures(s.Guard);
}
}
foreach (MaybeFreeExpression inv in s.Invariants) {
@@ -1338,11 +1346,32 @@ namespace Microsoft.Dafny {
}
foreach (Expression e in s.Decreases) {
ResolveExpression(e, true, true);
+ if (bodyMustBeSpecOnly && e is WildcardExpr) {
+ Error(e, "'decreases *' is not allowed on ghost loops");
+ }
// any type is fine
}
- s.IsGhost = bodyIsSpecOnly;
- ResolveStatement(s.Body, bodyIsSpecOnly, method);
-
+ s.IsGhost = bodyMustBeSpecOnly;
+ ResolveStatement(s.Body, bodyMustBeSpecOnly, method);
+
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ s.IsGhost = ResolveAlternatives(s.Alternatives, specContextOnly, method);
+ foreach (MaybeFreeExpression inv in s.Invariants) {
+ ResolveExpression(inv.E, true, true);
+ Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(inv.E.Type, Type.Bool)) {
+ Error(inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type);
+ }
+ }
+ foreach (Expression e in s.Decreases) {
+ ResolveExpression(e, true, true);
+ if (s.IsGhost && e is WildcardExpr) {
+ Error(e, "'decreases *' is not allowed on ghost loops");
+ }
+ // any type is fine
+ }
+
} else if (stmt is ForeachStmt) {
ForeachStmt s = (ForeachStmt)stmt;
@@ -1466,7 +1495,16 @@ namespace Microsoft.Dafny {
scope.PopMarker();
}
if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
- Error(stmt, "match expression does not cover all constructors");
+ // We could complain about the syntactic omission of constructors:
+ // Error(stmt, "match statement does not cover all constructors");
+ // but instead we let the verifier do a semantic check.
+ // So, for now, record the missing constructors:
+ foreach (var ctr in dtd.Ctors) {
+ if (!memberNamesUsed.ContainsKey(ctr.Name)) {
+ s.MissingCases.Add(ctr);
+ }
+ }
+ Contract.Assert(memberNamesUsed.Count + s.MissingCases.Count == dtd.Ctors.Count);
}
@@ -1475,6 +1513,34 @@ namespace Microsoft.Dafny {
}
}
+ bool ResolveAlternatives(List<GuardedAlternative> alternatives, bool specContextOnly, Method method) {
+ Contract.Requires(alternatives != null);
+ Contract.Requires(method != null);
+
+ bool isGhost = specContextOnly;
+ // first, resolve the guards, which tells us whether or not the entire statement is a ghost statement
+ foreach (var alternative in alternatives) {
+ int prevErrorCount = ErrorCount;
+ ResolveExpression(alternative.Guard, true, true);
+ Contract.Assert(alternative.Guard.Type != null); // follows from postcondition of ResolveExpression
+ bool successfullyResolved = ErrorCount == prevErrorCount;
+ if (!UnifyTypes(alternative.Guard.Type, Type.Bool)) {
+ Error(alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type);
+ }
+ if (!specContextOnly && successfullyResolved) {
+ isGhost = isGhost || UsesSpecFeatures(alternative.Guard);
+ }
+ }
+ foreach (var alternative in alternatives) {
+ scope.PushMarker();
+ foreach (Statement ss in alternative.Body) {
+ ResolveStatement(ss, isGhost, method);
+ }
+ scope.PopMarker();
+ }
+ return isGhost;
+ }
+
void ResolveCallStmt(CallStmt s, bool specContextOnly, Method method, Type receiverType) {
Contract.Requires(s != null);
Contract.Requires(method != null);
@@ -1906,7 +1972,7 @@ namespace Microsoft.Dafny {
Contract.Assert(e.Array.Type != null); // follows from postcondition of ResolveExpression
Type elementType = new InferredTypeProxy();
if (!UnifyTypes(e.Array.Type, builtIns.ArrayType(e.Indices.Count, elementType))) {
- Error(e.Array, "array selection requires an array (got {0})", e.Array.Type);
+ Error(e.Array, "array selection requires an array{0} (got {1})", e.Indices.Count, e.Array.Type);
}
int i = 0;
foreach (Expression idx in e.Indices) {
@@ -2019,6 +2085,8 @@ namespace Microsoft.Dafny {
OldExpr e = (OldExpr)expr;
if (!twoState) {
Error(expr, "old expressions are not allowed in this context");
+ } else if (!specContext) {
+ Error(expr, "old expressions are allowed only in specification and ghost contexts");
}
ResolveExpression(e.E, twoState, specContext);
expr.Type = e.E.Type;
@@ -2027,6 +2095,8 @@ namespace Microsoft.Dafny {
FreshExpr e = (FreshExpr)expr;
if (!twoState) {
Error(expr, "fresh expressions are not allowed in this context");
+ } else if (!specContext) {
+ Error(expr, "fresh expressions are allowed only in specification and ghost contexts");
}
ResolveExpression(e.E, twoState, specContext);
// the type of e.E must be either an object or a collection of objects
@@ -2047,6 +2117,9 @@ namespace Microsoft.Dafny {
} else if (expr is AllocatedExpr) {
AllocatedExpr e = (AllocatedExpr)expr;
ResolveExpression(e.E, twoState, specContext);
+ if (!specContext) {
+ Error(expr, "allocated expressions are allowed only in specification and ghost contexts");
+ }
// e.E can be of any type
expr.Type = Type.Bool;
@@ -2213,10 +2286,17 @@ namespace Microsoft.Dafny {
}
ResolveType(v.tok, v.Type);
}
- ResolveExpression(e.Body, twoState, specContext);
- Contract.Assert(e.Body.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Body.Type, Type.Bool)) {
- Error(expr, "body of quantifier must be of type bool (instead got {0})", e.Body.Type);
+ if (e.Range != null) {
+ ResolveExpression(e.Range, twoState, specContext);
+ Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(e.Range.Type, Type.Bool)) {
+ Error(expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type);
+ }
+ }
+ ResolveExpression(e.Term, twoState, specContext);
+ Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(e.Term.Type, Type.Bool)) {
+ Error(expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type);
}
// Since the body is more likely to infer the types of the bound variables, resolve it
// first (above) and only then resolve the attributes and triggers (below).
@@ -2226,9 +2306,35 @@ namespace Microsoft.Dafny {
expr.Type = Type.Bool;
if (prevErrorCount == ErrorCount) {
- e.Bounds = DiscoverBounds(e, specContext);
+ e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, specContext ? null : "quantifiers in non-ghost contexts must be compilable");
}
-
+
+ } else if (expr is SetComprehension) {
+ var e = (SetComprehension)expr;
+ int prevErrorCount = ErrorCount;
+ scope.PushMarker();
+ foreach (BoundVar v in e.BoundVars) {
+ if (!scope.Push(v.Name, v)) {
+ Error(v, "Duplicate bound-variable name: {0}", v.Name);
+ }
+ ResolveType(v.tok, v.Type);
+ }
+ ResolveExpression(e.Range, twoState, specContext);
+ Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(e.Range.Type, Type.Bool)) {
+ Error(expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type);
+ }
+ ResolveExpression(e.Term, twoState, specContext);
+ Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression
+
+ ResolveAttributes(e.Attributes, twoState);
+ scope.PopMarker();
+ expr.Type = new SetType(e.Term.Type);
+
+ if (prevErrorCount == ErrorCount) {
+ e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, "a set comprehension must produce a finite set");
+ }
+
} else if (expr is WildcardExpr) {
expr.Type = new SetType(new ObjectType());
@@ -2343,7 +2449,16 @@ namespace Microsoft.Dafny {
scope.PopMarker();
}
if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
- Error(expr, "match expression does not cover all constructors");
+ // We could complain about the syntactic omission of constructors:
+ // Error(expr, "match expression does not cover all constructors");
+ // but instead we let the verifier do a semantic check.
+ // So, for now, record the missing constructors:
+ foreach (var ctr in dtd.Ctors) {
+ if (!memberNamesUsed.ContainsKey(ctr.Name)) {
+ me.MissingCases.Add(ctr);
+ }
+ }
+ Contract.Assert(memberNamesUsed.Count + me.MissingCases.Count == dtd.Ctors.Count);
}
} else {
@@ -2357,39 +2472,40 @@ namespace Microsoft.Dafny {
}
/// <summary>
- /// Tries to find a bounded pool for each of the bound variables of "e". If this process fails, appropriate
- /// error messages are reported and "null" is returned, unless "friendlyTry" is "true", in which case no
- /// error messages are reported.
+ /// Tries to find a bounded pool for each of the bound variables "bvars" of "expr". If this process
+ /// fails, then "null" is returned and:
+ /// if "errorMessage" is non-null, then appropriate error messages are reported and "null" is returned;
+ /// if "errorMessage" is null, no error messages are reported.
/// Requires "e" to be successfully resolved.
/// </summary>
- List<QuantifierExpr.BoundedPool> DiscoverBounds(QuantifierExpr e, bool friendlyTry) {
- Contract.Requires(e != null);
- Contract.Requires(e.Type != null); // a sanity check (but not a complete proof) that "e" has been resolved
- Contract.Ensures(Contract.Result<List<QuantifierExpr.BoundedPool>>().Count == e.BoundVars.Count);
+ List<QuantifierExpr.BoundedPool> DiscoverBounds(IToken tok, List<BoundVar> bvars, Expression expr, bool polarity, string errorMessage) {
+ Contract.Requires(tok != null);
+ Contract.Requires(bvars != null);
+ Contract.Requires(expr.Type != null); // a sanity check (but not a complete proof) that "e" has been resolved
+ Contract.Ensures(Contract.Result<List<QuantifierExpr.BoundedPool>>().Count == bvars.Count);
var bounds = new List<QuantifierExpr.BoundedPool>();
- for (int j = 0; j < e.BoundVars.Count; j++) {
- var bv = e.BoundVars[j];
- if (bv.Type == Type.Bool) {
+ for (int j = 0; j < bvars.Count; j++) {
+ var bv = bvars[j];
+ if (bv.Type is BoolType) {
// easy
bounds.Add(new QuantifierExpr.BoolBoundedPool());
} else {
// Go through the conjuncts of the range expression look for bounds.
Expression lowerBound = bv.Type is NatType ? new LiteralExpr(bv.tok, new BigInteger(0)) : null;
Expression upperBound = null;
- foreach (var conjunct in NormalizedConjuncts(e.Body, e is ExistsExpr)) {
+ foreach (var conjunct in NormalizedConjuncts(expr, polarity)) {
var c = conjunct as BinaryExpr;
if (c == null) {
goto CHECK_NEXT_CONJUNCT;
}
var e0 = c.E0;
var e1 = c.E1;
- var op = c.ResolvedOp;
- int whereIsBv = SanitizeForBoundDiscovery(e.BoundVars, j, ref op, ref e0, ref e1);
+ int whereIsBv = SanitizeForBoundDiscovery(bvars, j, c.ResolvedOp, ref e0, ref e1);
if (whereIsBv < 0) {
goto CHECK_NEXT_CONJUNCT;
}
- switch (op) {
+ switch (c.ResolvedOp) {
case BinaryExpr.ResolvedOpcode.InSet:
if (whereIsBv == 0) {
bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
@@ -2398,7 +2514,7 @@ namespace Microsoft.Dafny {
break;
case BinaryExpr.ResolvedOpcode.InSeq:
if (whereIsBv == 0) {
- bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
+ bounds.Add(new QuantifierExpr.SeqBoundedPool(e1));
goto CHECK_NEXT_BOUND_VARIABLE;
}
break;
@@ -2411,7 +2527,7 @@ namespace Microsoft.Dafny {
break;
case BinaryExpr.ResolvedOpcode.Gt:
case BinaryExpr.ResolvedOpcode.Ge:
- Contract.Assert(false); throw new cce.UnreachableException(); // promised by postconditions of NormalizedConjunct and SanitizeForBoundDiscovery
+ Contract.Assert(false); throw new cce.UnreachableException(); // promised by postconditions of NormalizedConjunct
case BinaryExpr.ResolvedOpcode.Lt:
if (whereIsBv == 0 && upperBound == null) {
upperBound = e1; // bv < E
@@ -2437,8 +2553,8 @@ namespace Microsoft.Dafny {
CHECK_NEXT_CONJUNCT: ;
}
// we have checked every conjunct in the range expression and still have not discovered good bounds
- if (!friendlyTry) {
- Error(e, "quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
+ if (errorMessage != null) {
+ Error(tok, "{0}, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{1}'", errorMessage, bv.Name);
}
return null;
}
@@ -2448,14 +2564,13 @@ namespace Microsoft.Dafny {
}
/// <summary>
- /// If the return value is negative, the resulting "op", "e0", and "e1" should not be used.
+ /// If the return value is negative, the resulting "e0" and "e1" should not be used.
/// Otherwise, the following is true on return:
/// The new "e0 op e1" is equivalent to the old "e0 op e1".
/// One of "e0" and "e1" is the identifier "boundVars[bvi]"; the return value is either 0 or 1, and indicates which.
/// The other of "e0" and "e1" is an expression whose free variables are not among "boundVars[bvi..]".
- /// Requires the initial value of "op" not to be Gt or Ge, and ensures the same about the final value of "op".
/// </summary>
- int SanitizeForBoundDiscovery(List<BoundVar> boundVars, int bvi, ref BinaryExpr.ResolvedOpcode op, ref Expression e0, ref Expression e1)
+ int SanitizeForBoundDiscovery(List<BoundVar> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, ref Expression e0, ref Expression e1)
{
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
@@ -2485,54 +2600,57 @@ namespace Microsoft.Dafny {
}
// Next, clean up the side where bv is by adjusting both sides of the expression
- while (true) {
- switch (op) {
- case BinaryExpr.ResolvedOpcode.EqCommon:
- case BinaryExpr.ResolvedOpcode.NeqCommon:
- case BinaryExpr.ResolvedOpcode.Gt:
- case BinaryExpr.ResolvedOpcode.Ge:
- case BinaryExpr.ResolvedOpcode.Le:
- case BinaryExpr.ResolvedOpcode.Lt:
+ switch (op) {
+ case BinaryExpr.ResolvedOpcode.EqCommon:
+ case BinaryExpr.ResolvedOpcode.NeqCommon:
+ case BinaryExpr.ResolvedOpcode.Gt:
+ case BinaryExpr.ResolvedOpcode.Ge:
+ case BinaryExpr.ResolvedOpcode.Le:
+ case BinaryExpr.ResolvedOpcode.Lt:
+ // Repeatedly move additive or subtractive terms from thisSide to thatSide
+ while (true) {
var bin = thisSide as BinaryExpr;
- if (bin != null) {
- if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add) {
- // Change "A+B op C" into either "A op C-B" or "B op C-A", depending on where we find bv among A and B.
- if (!FreeVariables(bin.E1).Contains(bv)) {
- thisSide = bin.E0;
- thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E1);
- } else {
- thisSide = bin.E1;
- thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E0);
- }
+ if (bin == null) {
+ break; // done simplifying
+
+ } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add) {
+ // Change "A+B op C" into either "A op C-B" or "B op C-A", depending on where we find bv among A and B.
+ if (!FreeVariables(bin.E1).Contains(bv)) {
+ thisSide = bin.E0;
+ thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E1);
+ } else {
+ thisSide = bin.E1;
+ thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E0);
+ }
+ ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;
+ thatSide.Type = bin.Type;
+
+ } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub) {
+ // Change "A-B op C" in a similar way.
+ if (!FreeVariables(bin.E1).Contains(bv)) {
+ // change to "A op C+B"
+ thisSide = bin.E0;
+ thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Add, thatSide, bin.E1);
+ ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Add;
+ } else {
+ // In principle, change to "-B op C-A" and then to "B dualOp A-C". But since we don't want
+ // to change "op", we instead end with "A-C op B" and switch the mapping of thisSide/thatSide
+ // to e0/e1 (by inverting "whereIsBv").
+ thisSide = bin.E1;
+ thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, bin.E0, thatSide);
((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;
- thatSide.Type = bin.Type;
- continue; // continue simplifying
-
- } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub) {
- // Change "A-B op C" in a similar way.
- if (!FreeVariables(bin.E1).Contains(bv)) {
- // change to "A op C+B"
- thisSide = bin.E0;
- thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Add, thatSide, bin.E1);
- ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Add;
- } else {
- // In principle, change to "-B op C-A" and then to "B dualOp A-C". But since we don't want
- // to return with the operator being > or >=, we instead end with "A-C op B" and switch the
- // mapping of thisSide/thatSide to e0/e1 (by inverting "whereIsBv").
- thisSide = bin.E1;
- thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, bin.E0, thatSide);
- ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;
- whereIsBv = 1 - whereIsBv;
- }
- thatSide.Type = bin.Type;
- continue; // continue simplifying
+ whereIsBv = 1 - whereIsBv;
}
+ thatSide.Type = bin.Type;
+
+ } else {
+ break; // done simplifying
}
- break; // done simplifying
- default:
- break; // done simplifying
- }
- break; // done simplifying
+ }
+ break;
+
+ default:
+ break;
}
// Now, see if the interesting side is simply bv itself
@@ -2661,6 +2779,7 @@ namespace Microsoft.Dafny {
b.ResolvedOp = newROp;
b.Type = Type.Bool;
yield return b;
+ yield break;
}
}
JUST_RETURN_IT: ;
@@ -2699,7 +2818,7 @@ namespace Microsoft.Dafny {
} else if (expr is QuantifierExpr) {
var e = (QuantifierExpr)expr;
- var s = FreeVariables(e.Body);
+ var s = FreeVariables(e.LogicalBody());
foreach (var bv in e.BoundVars) {
s.Remove(bv);
}
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index 2bb5a51e..e338c0ca 100644
--- a/Source/Dafny/Translator.cs
+++ b/Source/Dafny/Translator.cs
@@ -1371,8 +1371,26 @@ namespace Microsoft.Dafny {
Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(mc.tok, mc.Ctor.FullName, predef.DatatypeType);
return new Bpl.NAryExpr(mc.tok, new Bpl.FunctionCall(id), args);
}
-
- Bpl.Expr IsTotal(Expression expr, ExpressionTranslator etran){
+
+ Bpl.Expr CtorInvocation(IToken tok, DatatypeCtor ctor, ExpressionTranslator etran, Bpl.VariableSeq locals, StmtListBuilder localTypeAssumptions) {
+ Contract.Requires(tok != null);
+ Contract.Requires(ctor != null);
+ Contract.Requires(etran != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(localTypeAssumptions != null);
+ Contract.Requires(predef != null);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+
+ VariableSeq bvars;
+ List<Bpl.Expr> args;
+ CreateBoundVariables(ctor.Formals, out bvars, out args);
+ locals.AddRange(bvars);
+
+ Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(tok, ctor.FullName, predef.DatatypeType);
+ return new Bpl.NAryExpr(tok, new Bpl.FunctionCall(id), new ExprSeq(args.ToArray()));
+ }
+
+ Bpl.Expr IsTotal(Expression expr, ExpressionTranslator etran) {
Contract.Requires(expr != null);Contract.Requires(etran != null);
Contract.Requires(predef != null);
Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
@@ -1509,9 +1527,12 @@ namespace Microsoft.Dafny {
}
Bpl.Expr r = BplAnd(t0, t1);
return z == null ? r : BplAnd(r, z);
- } else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
- Bpl.Expr total = IsTotal(e.Body, etran);
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ var total = IsTotal(e.Term, etran);
+ if (e.Range != null) {
+ total = BplAnd(IsTotal(e.Range, etran), BplImp(etran.TrExpr(e.Range), total));
+ }
if (total != Bpl.Expr.True) {
Bpl.VariableSeq bvars = new Bpl.VariableSeq();
Bpl.Expr typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars);
@@ -1636,9 +1657,12 @@ namespace Microsoft.Dafny {
break;
}
return BplAnd(t0, t1);
- } else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
- Bpl.Expr total = CanCallAssumption(e.Body, etran);
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ var total = CanCallAssumption(e.Term, etran);
+ if (e.Range != null) {
+ total = BplAnd(CanCallAssumption(e.Range, etran), BplImp(etran.TrExpr(e.Range), total));
+ }
if (total != Bpl.Expr.True) {
Bpl.VariableSeq bvars = new Bpl.VariableSeq();
Bpl.Expr typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars);
@@ -1684,6 +1708,18 @@ namespace Microsoft.Dafny {
}
}
+ Bpl.Expr BplImp(Bpl.Expr a, Bpl.Expr b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+
+ if (a == Bpl.Expr.True || b == Bpl.Expr.True) {
+ return b;
+ } else {
+ return Bpl.Expr.Imp(a, b);
+ }
+ }
+
void CheckNonNull(IToken tok, Expression e, Bpl.StmtListBuilder builder, ExpressionTranslator etran, Bpl.QKeyValue kv) {
Contract.Requires(tok != null);
Contract.Requires(e != null);
@@ -1785,6 +1821,9 @@ namespace Microsoft.Dafny {
bool isSequence = e.Seq.Type is SeqType;
CheckWellformed(e.Seq, options, locals, builder, etran);
Bpl.Expr seq = etran.TrExpr(e.Seq);
+ if (e.Seq.Type.IsArrayType) {
+ builder.Add(Assert(e.Seq.tok, Bpl.Expr.Neq(seq, predef.Null), "array may be null"));
+ }
Bpl.Expr e0 = null;
if (e.E0 != null) {
e0 = etran.TrExpr(e.E0);
@@ -1967,8 +2006,8 @@ namespace Microsoft.Dafny {
break;
}
- } else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
Dictionary<IVariable,Expression> substMap = new Dictionary<IVariable,Expression>();
foreach (BoundVar bv in e.BoundVars) {
VarDecl local = new VarDecl(bv.tok, bv.Name, bv.Type, bv.IsGhost, null);
@@ -1983,8 +2022,18 @@ namespace Microsoft.Dafny {
builder.Add(new Bpl.AssumeCmd(bv.tok, wh));
}
}
- Expression body = Substitute(e.Body, null, substMap);
- CheckWellformed(body, options, locals, builder, etran);
+
+ Expression body = Substitute(e.Term, null, substMap);
+ if (e.Range == null) {
+ CheckWellformed(body, options, locals, builder, etran);
+ } else {
+ Expression range = Substitute(e.Range, null, substMap);
+ CheckWellformed(range, options, locals, builder, etran);
+
+ Bpl.StmtListBuilder b = new Bpl.StmtListBuilder();
+ CheckWellformed(body, options, locals, b, etran);
+ builder.Add(new Bpl.IfCmd(expr.tok, etran.TrExpr(range), b.Collect(expr.tok), null, null));
+ }
} else if (expr is ITEExpr) {
ITEExpr e = (ITEExpr)expr;
@@ -1999,20 +2048,40 @@ namespace Microsoft.Dafny {
MatchExpr me = (MatchExpr)expr;
CheckWellformed(me.Source, options, locals, builder, etran);
Bpl.Expr src = etran.TrExpr(me.Source);
- Bpl.IfCmd ifcmd = null;
+ Bpl.IfCmd ifCmd = null;
StmtListBuilder elsBldr = new StmtListBuilder();
elsBldr.Add(new Bpl.AssumeCmd(expr.tok, Bpl.Expr.False));
StmtList els = elsBldr.Collect(expr.tok);
+ foreach (var missingCtor in me.MissingCases) {
+ // havoc all bound variables
+ var b = new Bpl.StmtListBuilder();
+ VariableSeq newLocals = new VariableSeq();
+ Bpl.Expr r = CtorInvocation(me.tok, missingCtor, etran, newLocals, b);
+ locals.AddRange(newLocals);
+
+ if (newLocals.Length != 0) {
+ Bpl.IdentifierExprSeq havocIds = new Bpl.IdentifierExprSeq();
+ foreach (Variable local in newLocals) {
+ havocIds.Add(new Bpl.IdentifierExpr(local.tok, local));
+ }
+ builder.Add(new Bpl.HavocCmd(me.tok, havocIds));
+ }
+ b.Add(Assert(me.tok, Bpl.Expr.False, "missing case in case statement: " + missingCtor.Name));
+
+ Bpl.Expr guard = Bpl.Expr.Eq(src, r);
+ ifCmd = new Bpl.IfCmd(me.tok, guard, b.Collect(me.tok), ifCmd, els);
+ els = null;
+ }
for (int i = me.Cases.Count; 0 <= --i; ) {
MatchCaseExpr mc = me.Cases[i];
Bpl.StmtListBuilder b = new Bpl.StmtListBuilder();
Bpl.Expr ct = CtorInvocation(mc, etran, locals, b);
// generate: if (src == ctor(args)) { assume args-is-well-typed; mc.Body is well-formed; assume Result == TrExpr(case); } else ...
CheckWellformedWithResult(mc.Body, options, result, resultType, locals, b, etran);
- ifcmd = new Bpl.IfCmd(mc.tok, Bpl.Expr.Eq(src, ct), b.Collect(mc.tok), ifcmd, els);
+ ifCmd = new Bpl.IfCmd(mc.tok, Bpl.Expr.Eq(src, ct), b.Collect(mc.tok), ifCmd, els);
els = null;
}
- builder.Add(ifcmd);
+ builder.Add(ifCmd);
result = null;
} else {
@@ -2070,15 +2139,16 @@ namespace Microsoft.Dafny {
return decr;
}
- List<Expression> LoopDecreasesWithDefault(WhileStmt s, out bool inferredDecreases) {
- Contract.Requires(s != null);
+ List<Expression> LoopDecreasesWithDefault(IToken tok, Expression Guard, List<Expression> Decreases, out bool inferredDecreases) {
+ Contract.Requires(tok != null);
+ Contract.Requires(Decreases != null);
- List<Expression> theDecreases = s.Decreases;
+ List<Expression> theDecreases = Decreases;
inferredDecreases = false;
- if (theDecreases.Count == 0 && s.Guard != null) {
+ if (theDecreases.Count == 0 && Guard != null) {
theDecreases = new List<Expression>();
Expression prefix = null;
- foreach (Expression guardConjunct in Conjuncts(s.Guard)) {
+ foreach (Expression guardConjunct in Conjuncts(Guard)) {
Expression guess = null;
BinaryExpr bin = guardConjunct as BinaryExpr;
if (bin != null) {
@@ -2086,23 +2156,23 @@ namespace Microsoft.Dafny {
case BinaryExpr.ResolvedOpcode.Lt:
case BinaryExpr.ResolvedOpcode.Le:
// for A < B and A <= B, use the decreases B - A
- guess = CreateIntSub(s.Tok, bin.E1, bin.E0);
+ guess = CreateIntSub(tok, bin.E1, bin.E0);
break;
case BinaryExpr.ResolvedOpcode.Ge:
case BinaryExpr.ResolvedOpcode.Gt:
// for A >= B and A > B, use the decreases A - B
- guess = CreateIntSub(s.Tok, bin.E0, bin.E1);
+ guess = CreateIntSub(tok, bin.E0, bin.E1);
break;
case BinaryExpr.ResolvedOpcode.NeqCommon:
if (bin.E0.Type is IntType) {
// for A != B where A and B are integers, use the absolute difference between A and B (that is: if 0 <= A-B then A-B else B-A)
- Expression AminusB = CreateIntSub(s.Tok, bin.E0, bin.E1);
- Expression BminusA = CreateIntSub(s.Tok, bin.E1, bin.E0);
- Expression zero = CreateIntLiteral(s.Tok, 0);
- BinaryExpr test = new BinaryExpr(s.Tok, BinaryExpr.Opcode.Le, zero, AminusB);
+ Expression AminusB = CreateIntSub(tok, bin.E0, bin.E1);
+ Expression BminusA = CreateIntSub(tok, bin.E1, bin.E0);
+ Expression zero = CreateIntLiteral(tok, 0);
+ BinaryExpr test = new BinaryExpr(tok, BinaryExpr.Opcode.Le, zero, AminusB);
test.ResolvedOp = BinaryExpr.ResolvedOpcode.Le; // resolve here
test.Type = Type.Bool; // resolve here
- guess = CreateIntITE(s.Tok, test, AminusB, BminusA);
+ guess = CreateIntITE(tok, test, AminusB, BminusA);
}
break;
default:
@@ -2112,8 +2182,8 @@ namespace Microsoft.Dafny {
if (guess != null) {
if (prefix != null) {
// Make the following guess: if prefix then guess else -1
- Expression negativeOne = CreateIntLiteral(s.Tok, -1);
- guess = CreateIntITE(s.Tok, prefix, guess, negativeOne);
+ Expression negativeOne = CreateIntLiteral(tok, -1);
+ guess = CreateIntITE(tok, prefix, guess, negativeOne);
}
theDecreases.Add(guess);
inferredDecreases = true;
@@ -2122,7 +2192,7 @@ namespace Microsoft.Dafny {
if (prefix == null) {
prefix = guardConjunct;
} else {
- BinaryExpr and = new BinaryExpr(s.Tok, BinaryExpr.Opcode.And, prefix, guardConjunct);
+ BinaryExpr and = new BinaryExpr(tok, BinaryExpr.Opcode.And, prefix, guardConjunct);
and.ResolvedOp = BinaryExpr.ResolvedOpcode.And; // resolve here
and.Type = Type.Bool; // resolve here
prefix = and;
@@ -2944,134 +3014,28 @@ namespace Microsoft.Dafny {
}
}
builder.Add(new Bpl.IfCmd(stmt.Tok, guard, thn, elsIf, els));
-
+
+ } else if (stmt is AlternativeStmt) {
+ AddComment(builder, stmt, "alternative statement");
+ var s = (AlternativeStmt)stmt;
+ var elseCase = Assert(s.Tok, Bpl.Expr.False, "alternative cases fail to cover all possibilties");
+ TrAlternatives(s.Alternatives, elseCase, null, builder, locals, etran);
+
} else if (stmt is WhileStmt) {
AddComment(builder, stmt, "while statement");
- WhileStmt s = (WhileStmt)stmt;
- int loopId = loopHeapVarCount;
- loopHeapVarCount++;
-
- // use simple heuristics to create a default decreases clause, if none is given
- bool inferredDecreases;
- List<Expression> theDecreases = LoopDecreasesWithDefault(s, out inferredDecreases);
-
- Bpl.LocalVariable preLoopHeapVar = new Bpl.LocalVariable(stmt.Tok, new Bpl.TypedIdent(stmt.Tok, "$PreLoopHeap" + loopId, predef.HeapType));
- locals.Add(preLoopHeapVar);
- Bpl.IdentifierExpr preLoopHeap = new Bpl.IdentifierExpr(stmt.Tok, preLoopHeapVar);
- ExpressionTranslator etranPreLoop = new ExpressionTranslator(this, predef, preLoopHeap);
- builder.Add(Bpl.Cmd.SimpleAssign(stmt.Tok, preLoopHeap, etran.HeapExpr)); // TODO: does this screw up labeled breaks for this loop?
-
- List<Bpl.Expr> initDecr = null;
- if (!Contract.Exists(theDecreases, e => e is WildcardExpr)) {
- initDecr = RecordDecreasesValue(theDecreases, builder, locals, etran, "$decr" + loopId + "$init$");
- }
-
- // the variable w is used to coordinate the definedness checking of the loop invariant
- Bpl.LocalVariable wVar = new Bpl.LocalVariable(stmt.Tok, new Bpl.TypedIdent(stmt.Tok, "$w" + loopId, Bpl.Type.Bool));
- Bpl.IdentifierExpr w = new Bpl.IdentifierExpr(stmt.Tok, wVar);
- locals.Add(wVar);
- // havoc w;
- builder.Add(new Bpl.HavocCmd(stmt.Tok, new Bpl.IdentifierExprSeq(w)));
-
- List<Bpl.PredicateCmd> invariants = new List<Bpl.PredicateCmd>();
- Bpl.StmtListBuilder invDefinednessBuilder = new Bpl.StmtListBuilder();
- foreach (MaybeFreeExpression loopInv in s.Invariants) {
- TrStmt_CheckWellformed(loopInv.E, invDefinednessBuilder, locals, etran, false);
- invDefinednessBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, etran.TrExpr(loopInv.E)));
-
- invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, CanCallAssumption(loopInv.E, etran))));
- if (loopInv.IsFree) {
- invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E))));
- } else {
- bool splitHappened;
- var ss = TrSplitExpr(loopInv.E, etran, out splitHappened);
- if (!splitHappened) {
- var wInv = Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E));
- invariants.Add(Assert(loopInv.E.tok, wInv, "loop invariant violation"));
- } else {
- foreach (var split in ss) {
- var wInv = Bpl.Expr.Binary(split.E.tok, BinaryOperator.Opcode.Imp, w, split.E);
- if (split.IsFree) {
- invariants.Add(new Bpl.AssumeCmd(split.E.tok, wInv));
- } else {
- invariants.Add(Assert(split.E.tok, wInv, "loop invariant violation")); // TODO: it would be fine to have this use {:subsumption 0}
- }
- }
- }
- }
- }
- // check definedness of decreases clause
- // TODO: can this check be omitted if the decreases clause is inferred?
- foreach (Expression e in theDecreases) {
- TrStmt_CheckWellformed(e, invDefinednessBuilder, locals, etran, true);
- }
- // include boilerplate invariants
- foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(stmt.Tok, currentMethod, etranPreLoop, etran)) {
- if (tri.IsFree) {
- invariants.Add(new Bpl.AssumeCmd(stmt.Tok, tri.Expr));
- } else {
- Contract.Assert(tri.ErrorMessage != null); // follows from BoilerplateTriple invariant
- invariants.Add(Assert(stmt.Tok, tri.Expr, tri.ErrorMessage));
- }
- }
- // include a free invariant that says that all completed iterations so far have only decreased the termination metric
- if (initDecr != null) {
- List<IToken> toks = new List<IToken>();
- List<Type> types = new List<Type>();
- List<Bpl.Expr> decrs = new List<Bpl.Expr>();
- foreach (Expression e in theDecreases) {
- toks.Add(e.tok);
- types.Add(cce.NonNull(e.Type));
- decrs.Add(etran.TrExpr(e));
- }
- Bpl.Expr decrCheck = DecreasesCheck(toks, types, decrs, initDecr, etran, null, null, true, false);
- invariants.Add(new Bpl.AssumeCmd(stmt.Tok, decrCheck));
- }
-
- Bpl.StmtListBuilder loopBodyBuilder = new Bpl.StmtListBuilder();
- // as the first thing inside the loop, generate: if (!w) { assert IsTotal(inv); assume false; }
- invDefinednessBuilder.Add(new Bpl.AssumeCmd(stmt.Tok, Bpl.Expr.False));
- loopBodyBuilder.Add(new Bpl.IfCmd(stmt.Tok, Bpl.Expr.Not(w), invDefinednessBuilder.Collect(stmt.Tok), null, null));
- // generate: assert IsTotal(guard); if (!guard) { break; }
- Bpl.Expr guard = null;
- if (s.Guard != null) {
- TrStmt_CheckWellformed(s.Guard, loopBodyBuilder, locals, etran, true);
- guard = Bpl.Expr.Not(etran.TrExpr(s.Guard));
- }
- Bpl.StmtListBuilder guardBreak = new Bpl.StmtListBuilder();
- guardBreak.Add(new Bpl.BreakCmd(s.Tok, null));
- loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, guard, guardBreak.Collect(s.Tok), null, null));
-
- loopBodyBuilder.Add(CaptureState(stmt.Tok, "loop entered"));
- // termination checking
- if (Contract.Exists(theDecreases, e => e is WildcardExpr)) {
- // omit termination checking for this loop
- TrStmt(s.Body, loopBodyBuilder, locals, etran);
- } else {
- List<Bpl.Expr> oldBfs = RecordDecreasesValue(theDecreases, loopBodyBuilder, locals, etran, "$decr" + loopId + "$");
- // time for the actual loop body
- TrStmt(s.Body, loopBodyBuilder, locals, etran);
- // check definedness of decreases expressions
- List<IToken> toks = new List<IToken>();
- List<Type> types = new List<Type>();
- List<Bpl.Expr> decrs = new List<Bpl.Expr>();
- foreach (Expression e in theDecreases) {
- toks.Add(e.tok);
- types.Add(cce.NonNull(e.Type));
- decrs.Add(etran.TrExpr(e));
- }
- Bpl.Expr decrCheck = DecreasesCheck(toks, types, decrs, oldBfs, etran, loopBodyBuilder, " at end of loop iteration", false, false);
- loopBodyBuilder.Add(Assert(stmt.Tok, decrCheck, inferredDecreases ? "cannot prove termination; try supplying a decreases clause for the loop" : "decreases expression might not decrease"));
- }
- // Finally, assume the well-formedness of the invariant (which has been checked once and for all above), so that the check
- // of invariant-maintenance can use the appropriate canCall predicates.
- foreach (MaybeFreeExpression loopInv in s.Invariants) {
- loopBodyBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, CanCallAssumption(loopInv.E, etran)));
- }
- Bpl.StmtList body = loopBodyBuilder.Collect(stmt.Tok);
-
- builder.Add(new Bpl.WhileCmd(stmt.Tok, Bpl.Expr.True, invariants, body));
- builder.Add(CaptureState(stmt.Tok, "loop exit"));
+ var s = (WhileStmt)stmt;
+ TrLoop(s, s.Guard,
+ delegate(Bpl.StmtListBuilder bld) { TrStmt(s.Body, bld, locals, etran); },
+ builder, locals, etran);
+
+ } else if (stmt is AlternativeLoopStmt) {
+ AddComment(builder, stmt, "alternative loop statement");
+ var s = (AlternativeLoopStmt)stmt;
+ var tru = new LiteralExpr(s.Tok, true);
+ tru.Type = Type.Bool; // resolve here
+ TrLoop(s, tru,
+ delegate(Bpl.StmtListBuilder bld) { TrAlternatives(s.Alternatives, null, new Bpl.BreakCmd(s.Tok, null), bld, locals, etran); },
+ builder, locals, etran);
} else if (stmt is ForeachStmt) {
AddComment(builder, stmt, "foreach statement");
@@ -3202,16 +3166,36 @@ namespace Microsoft.Dafny {
builder.Add(CaptureState(stmt.Tok));
} else if (stmt is MatchStmt) {
- MatchStmt s = (MatchStmt)stmt;
+ var s = (MatchStmt)stmt;
TrStmt_CheckWellformed(s.Source, builder, locals, etran, true);
Bpl.Expr source = etran.TrExpr(s.Source);
- Bpl.StmtListBuilder b = new Bpl.StmtListBuilder();
+ var b = new Bpl.StmtListBuilder();
b.Add(new Bpl.AssumeCmd(stmt.Tok, Bpl.Expr.False));
Bpl.StmtList els = b.Collect(stmt.Tok);
Bpl.IfCmd ifCmd = null;
+ foreach (var missingCtor in s.MissingCases) {
+ // havoc all bound variables
+ b = new Bpl.StmtListBuilder();
+ VariableSeq newLocals = new VariableSeq();
+ Bpl.Expr r = CtorInvocation(s.Tok, missingCtor, etran, newLocals, b);
+ locals.AddRange(newLocals);
+
+ if (newLocals.Length != 0) {
+ Bpl.IdentifierExprSeq havocIds = new Bpl.IdentifierExprSeq();
+ foreach (Variable local in newLocals) {
+ havocIds.Add(new Bpl.IdentifierExpr(local.tok, local));
+ }
+ builder.Add(new Bpl.HavocCmd(s.Tok, havocIds));
+ }
+ b.Add(Assert(s.Tok, Bpl.Expr.False, "missing case in case statement: " + missingCtor.Name));
+
+ Bpl.Expr guard = Bpl.Expr.Eq(source, r);
+ ifCmd = new Bpl.IfCmd(s.Tok, guard, b.Collect(s.Tok), ifCmd, els);
+ els = null;
+ }
for (int i = s.Cases.Count; 0 <= --i; ) {
- MatchCaseStmt mc = (MatchCaseStmt)s.Cases[i];
+ var mc = (MatchCaseStmt)s.Cases[i];
// havoc all bound variables
b = new Bpl.StmtListBuilder();
VariableSeq newLocals = new VariableSeq();
@@ -3235,7 +3219,7 @@ namespace Microsoft.Dafny {
ifCmd = new Bpl.IfCmd(mc.tok, guard, b.Collect(mc.tok), ifCmd, els);
els = null;
}
- Contract.Assert(ifCmd != null); // follows from the fact that s.Cases.Count != 0.
+ Contract.Assert(ifCmd != null); // follows from the fact that s.Cases.Count + s.MissingCases.Count != 0.
builder.Add(ifCmd);
} else {
@@ -3243,6 +3227,193 @@ namespace Microsoft.Dafny {
}
}
+ delegate void BodyTranslator(Bpl.StmtListBuilder builder);
+
+ void TrLoop(LoopStmt s, Expression Guard, BodyTranslator bodyTr,
+ Bpl.StmtListBuilder builder, Bpl.VariableSeq locals, ExpressionTranslator etran) {
+ Contract.Requires(s != null);
+ Contract.Requires(bodyTr != null);
+ Contract.Requires(builder != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(etran != null);
+
+ int loopId = loopHeapVarCount;
+ loopHeapVarCount++;
+
+ // use simple heuristics to create a default decreases clause, if none is given
+ bool inferredDecreases;
+ List<Expression> theDecreases = LoopDecreasesWithDefault(s.Tok, Guard, s.Decreases, out inferredDecreases);
+
+ Bpl.LocalVariable preLoopHeapVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, "$PreLoopHeap" + loopId, predef.HeapType));
+ locals.Add(preLoopHeapVar);
+ Bpl.IdentifierExpr preLoopHeap = new Bpl.IdentifierExpr(s.Tok, preLoopHeapVar);
+ ExpressionTranslator etranPreLoop = new ExpressionTranslator(this, predef, preLoopHeap);
+ builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, preLoopHeap, etran.HeapExpr)); // TODO: does this screw up labeled breaks for this loop?
+
+ List<Bpl.Expr> initDecr = null;
+ if (!Contract.Exists(theDecreases, e => e is WildcardExpr)) {
+ initDecr = RecordDecreasesValue(theDecreases, builder, locals, etran, "$decr" + loopId + "$init$");
+ }
+
+ // the variable w is used to coordinate the definedness checking of the loop invariant
+ Bpl.LocalVariable wVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, "$w" + loopId, Bpl.Type.Bool));
+ Bpl.IdentifierExpr w = new Bpl.IdentifierExpr(s.Tok, wVar);
+ locals.Add(wVar);
+ // havoc w;
+ builder.Add(new Bpl.HavocCmd(s.Tok, new Bpl.IdentifierExprSeq(w)));
+
+ List<Bpl.PredicateCmd> invariants = new List<Bpl.PredicateCmd>();
+ Bpl.StmtListBuilder invDefinednessBuilder = new Bpl.StmtListBuilder();
+ foreach (MaybeFreeExpression loopInv in s.Invariants) {
+ TrStmt_CheckWellformed(loopInv.E, invDefinednessBuilder, locals, etran, false);
+ invDefinednessBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, etran.TrExpr(loopInv.E)));
+
+ invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, CanCallAssumption(loopInv.E, etran))));
+ if (loopInv.IsFree) {
+ invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E))));
+ } else {
+ bool splitHappened;
+ var ss = TrSplitExpr(loopInv.E, etran, out splitHappened);
+ if (!splitHappened) {
+ var wInv = Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E));
+ invariants.Add(Assert(loopInv.E.tok, wInv, "loop invariant violation"));
+ } else {
+ foreach (var split in ss) {
+ var wInv = Bpl.Expr.Binary(split.E.tok, BinaryOperator.Opcode.Imp, w, split.E);
+ if (split.IsFree) {
+ invariants.Add(new Bpl.AssumeCmd(split.E.tok, wInv));
+ } else {
+ invariants.Add(Assert(split.E.tok, wInv, "loop invariant violation")); // TODO: it would be fine to have this use {:subsumption 0}
+ }
+ }
+ }
+ }
+ }
+ // check definedness of decreases clause
+ // TODO: can this check be omitted if the decreases clause is inferred?
+ foreach (Expression e in theDecreases) {
+ TrStmt_CheckWellformed(e, invDefinednessBuilder, locals, etran, true);
+ }
+ // include boilerplate invariants
+ foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(s.Tok, currentMethod, etranPreLoop, etran)) {
+ if (tri.IsFree) {
+ invariants.Add(new Bpl.AssumeCmd(s.Tok, tri.Expr));
+ } else {
+ Contract.Assert(tri.ErrorMessage != null); // follows from BoilerplateTriple invariant
+ invariants.Add(Assert(s.Tok, tri.Expr, tri.ErrorMessage));
+ }
+ }
+ // include a free invariant that says that all completed iterations so far have only decreased the termination metric
+ if (initDecr != null) {
+ List<IToken> toks = new List<IToken>();
+ List<Type> types = new List<Type>();
+ List<Bpl.Expr> decrs = new List<Bpl.Expr>();
+ foreach (Expression e in theDecreases) {
+ toks.Add(e.tok);
+ types.Add(cce.NonNull(e.Type));
+ decrs.Add(etran.TrExpr(e));
+ }
+ Bpl.Expr decrCheck = DecreasesCheck(toks, types, decrs, initDecr, etran, null, null, true, false);
+ invariants.Add(new Bpl.AssumeCmd(s.Tok, decrCheck));
+ }
+
+ Bpl.StmtListBuilder loopBodyBuilder = new Bpl.StmtListBuilder();
+ // as the first thing inside the loop, generate: if (!w) { assert IsTotal(inv); assume false; }
+ invDefinednessBuilder.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, Bpl.Expr.Not(w), invDefinednessBuilder.Collect(s.Tok), null, null));
+ // generate: assert IsTotal(guard); if (!guard) { break; }
+ Bpl.Expr guard = null;
+ if (Guard != null) {
+ TrStmt_CheckWellformed(Guard, loopBodyBuilder, locals, etran, true);
+ guard = Bpl.Expr.Not(etran.TrExpr(Guard));
+ }
+ Bpl.StmtListBuilder guardBreak = new Bpl.StmtListBuilder();
+ guardBreak.Add(new Bpl.BreakCmd(s.Tok, null));
+ loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, guard, guardBreak.Collect(s.Tok), null, null));
+
+ loopBodyBuilder.Add(CaptureState(s.Tok, "loop entered"));
+ // termination checking
+ if (Contract.Exists(theDecreases, e => e is WildcardExpr)) {
+ // omit termination checking for this loop
+ bodyTr(loopBodyBuilder);
+ } else {
+ List<Bpl.Expr> oldBfs = RecordDecreasesValue(theDecreases, loopBodyBuilder, locals, etran, "$decr" + loopId + "$");
+ // time for the actual loop body
+ bodyTr(loopBodyBuilder);
+ // check definedness of decreases expressions
+ List<IToken> toks = new List<IToken>();
+ List<Type> types = new List<Type>();
+ List<Bpl.Expr> decrs = new List<Bpl.Expr>();
+ foreach (Expression e in theDecreases) {
+ toks.Add(e.tok);
+ types.Add(cce.NonNull(e.Type));
+ decrs.Add(etran.TrExpr(e));
+ }
+ Bpl.Expr decrCheck = DecreasesCheck(toks, types, decrs, oldBfs, etran, loopBodyBuilder, " at end of loop iteration", false, false);
+ loopBodyBuilder.Add(Assert(s.Tok, decrCheck, inferredDecreases ? "cannot prove termination; try supplying a decreases clause for the loop" : "decreases expression might not decrease"));
+ }
+ // Finally, assume the well-formedness of the invariant (which has been checked once and for all above), so that the check
+ // of invariant-maintenance can use the appropriate canCall predicates.
+ foreach (MaybeFreeExpression loopInv in s.Invariants) {
+ loopBodyBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, CanCallAssumption(loopInv.E, etran)));
+ }
+ Bpl.StmtList body = loopBodyBuilder.Collect(s.Tok);
+
+ builder.Add(new Bpl.WhileCmd(s.Tok, Bpl.Expr.True, invariants, body));
+ builder.Add(CaptureState(s.Tok, "loop exit"));
+ }
+
+ void TrAlternatives(List<GuardedAlternative> alternatives, Bpl.Cmd elseCase0, Bpl.StructuredCmd elseCase1,
+ Bpl.StmtListBuilder builder, VariableSeq locals, ExpressionTranslator etran) {
+ Contract.Requires(alternatives != null);
+ Contract.Requires((elseCase0 == null) == (elseCase1 == null)); // ugly way of doing a type union
+ Contract.Requires(builder != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(etran != null);
+
+ if (alternatives.Count == 0) {
+ if (elseCase0 != null) {
+ builder.Add(elseCase0);
+ } else {
+ builder.Add(elseCase1);
+ }
+ return;
+ }
+
+ // build the negation of the disjunction of all guards (that is, the conjunction of their negations)
+ Bpl.Expr noGuard = Bpl.Expr.True;
+ foreach (var alternative in alternatives) {
+ noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(alternative.Guard)));
+ }
+
+ var b = new Bpl.StmtListBuilder();
+ var elseTok = elseCase0 != null ? elseCase0.tok : elseCase1.tok;
+ b.Add(new Bpl.AssumeCmd(elseTok, noGuard));
+ if (elseCase0 != null) {
+ b.Add(elseCase0);
+ } else {
+ b.Add(elseCase1);
+ }
+ Bpl.StmtList els = b.Collect(elseTok);
+
+ Bpl.IfCmd elsIf = null;
+ for (int i = alternatives.Count; 0 <= --i; ) {
+ Contract.Assert(elsIf == null || els == null); // loop invariant
+ var alternative = alternatives[i];
+ b = new Bpl.StmtListBuilder();
+ TrStmt_CheckWellformed(alternative.Guard, b, locals, etran, true);
+ b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard)));
+ foreach (var s in alternative.Body) {
+ TrStmt(s, b, locals, etran);
+ }
+ Bpl.StmtList thn = b.Collect(alternative.Tok);
+ elsIf = new Bpl.IfCmd(alternative.Tok, null, thn, elsIf, els);
+ els = null;
+ }
+ Contract.Assert(elsIf != null && els == null); // follows from loop invariant and the fact that there's more than one alternative
+ builder.Add(elsIf);
+ }
+
void TrCallStmt(CallStmt s, Bpl.StmtListBuilder builder, Bpl.VariableSeq locals, ExpressionTranslator etran, Bpl.Expr actualReceiver) {
Contract.Requires(s != null);
Contract.Requires(builder != null);
@@ -3673,11 +3844,15 @@ namespace Microsoft.Dafny {
Bpl.Expr xSubI = FunctionCall(tok, BuiltinFunction.SeqIndex, predef.BoxType, x, i);
Bpl.Expr unbox = ExpressionTranslator.ModeledAsBoxType(st.Arg) ? xSubI : FunctionCall(tok, BuiltinFunction.Unbox, TrType(st.Arg), xSubI);
+ Bpl.Expr c = GetBoolBoxCondition(xSubI, st.Arg);
Bpl.Expr wh = GetWhereClause(tok, unbox, st.Arg, etran);
if (wh != null) {
+ c = BplAnd(c, wh);
+ }
+ if (c != Bpl.Expr.True) {
Bpl.Expr range = InSeqRange(tok, i, x, true, null, false);
Bpl.Trigger tr = new Bpl.Trigger(tok, true, new Bpl.ExprSeq(xSubI));
- return new Bpl.ForallExpr(tok, new Bpl.VariableSeq(iVar), tr, Bpl.Expr.Imp(range, wh));
+ return new Bpl.ForallExpr(tok, new Bpl.VariableSeq(iVar), tr, Bpl.Expr.Imp(range, c));
}
} else if (type.IsRefType) {
@@ -3703,6 +3878,18 @@ namespace Microsoft.Dafny {
return null;
}
+ Bpl.Expr GetBoolBoxCondition(Expr box, Type type) {
+ Contract.Requires(box != null);
+ Contract.Requires(type != null);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+
+ if (type is BoolType) {
+ return FunctionCall(box.tok, BuiltinFunction.IsCanonicalBoolBox, null, box);
+ } else {
+ return Bpl.Expr.True;
+ }
+ }
+
void TrAssignment(IToken tok, Expression lhs, AssignmentRhs rhs, Bpl.StmtListBuilder builder, Bpl.VariableSeq locals,
ExpressionTranslator etran)
{
@@ -4412,15 +4599,36 @@ namespace Microsoft.Dafny {
}
tr = new Bpl.Trigger(expr.tok, true, tt, tr);
}
- Bpl.Expr body = TrExpr(e.Body);
+ var antecedent = typeAntecedent;
+ if (e.Range != null) {
+ antecedent = Bpl.Expr.And(antecedent, TrExpr(e.Range));
+ }
+ Bpl.Expr body = TrExpr(e.Term);
if (e is ForallExpr) {
- return new Bpl.ForallExpr(expr.tok, new Bpl.TypeVariableSeq(), bvars, kv, tr, Bpl.Expr.Imp(typeAntecedent, body));
+ return new Bpl.ForallExpr(expr.tok, new Bpl.TypeVariableSeq(), bvars, kv, tr, Bpl.Expr.Imp(antecedent, body));
} else {
Contract.Assert(e is ExistsExpr);
- return new Bpl.ExistsExpr(expr.tok, new Bpl.TypeVariableSeq(), bvars, kv, tr, Bpl.Expr.And(typeAntecedent, body));
+ return new Bpl.ExistsExpr(expr.tok, new Bpl.TypeVariableSeq(), bvars, kv, tr, Bpl.Expr.And(antecedent, body));
}
-
+
+ } else if (expr is SetComprehension) {
+ var e = (SetComprehension)expr;
+ // Translate "set xs | R :: T" into "lambda y: BoxType :: (exists xs :: CorrectType(xs) && R && y==Box(T))".
+ Bpl.VariableSeq bvars = new Bpl.VariableSeq();
+ Bpl.Expr typeAntecedent = TrBoundVariables(e.BoundVars, bvars);
+ Bpl.QKeyValue kv = TrAttributes(e.Attributes);
+
+ var yVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, "$y#" + translator.otherTmpVarCount, predef.BoxType));
+ translator.otherTmpVarCount++;
+ Bpl.Expr y = new Bpl.IdentifierExpr(expr.tok, yVar);
+
+ var eq = Bpl.Expr.Eq(y, BoxIfNecessary(expr.tok, TrExpr(e.Term), e.Term.Type));
+ var ebody = Bpl.Expr.And(translator.BplAnd(typeAntecedent, TrExpr(e.Range)), eq);
+ var exst = new Bpl.ExistsExpr(expr.tok, bvars, ebody);
+
+ return new Bpl.LambdaExpr(expr.tok, new Bpl.TypeVariableSeq(), new VariableSeq(yVar), kv, exst);
+
} else if (expr is ITEExpr) {
ITEExpr e = (ITEExpr)expr;
Bpl.Expr g = TrExpr(e.Test);
@@ -4819,6 +5027,7 @@ namespace Microsoft.Dafny {
Box,
Unbox,
+ IsCanonicalBoolBox,
IsGoodHeap,
HeapSucc,
@@ -4950,6 +5159,10 @@ namespace Microsoft.Dafny {
Contract.Assert(args.Length == 1);
Contract.Assert(typeInstantiation != null);
return Bpl.Expr.CoerceType(tok, FunctionCall(tok, "$Unbox", typeInstantiation, args), typeInstantiation);
+ case BuiltinFunction.IsCanonicalBoolBox:
+ Contract.Assert(args.Length == 1);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "$IsCanonicalBoolBox", Bpl.Type.Bool, args);
case BuiltinFunction.IsGoodHeap:
Contract.Assert(args.Length == 1);
@@ -5217,7 +5430,7 @@ namespace Microsoft.Dafny {
substMap.Add(n, ieK);
}
- Expression bodyK = Substitute(e.Body, null, substMap);
+ Expression bodyK = Substitute(e.LogicalBody(), null, substMap);
Bpl.Expr less = DecreasesCheck(toks, types, kk, nn, etran, null, null, false, true);
@@ -5249,7 +5462,7 @@ namespace Microsoft.Dafny {
typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars);
foreach (var kase in caseProduct) {
var ante = BplAnd(BplAnd(typeAntecedent, ih), kase);
- var bdy = etran.LayerOffset(1).TrExpr(e.Body);
+ var bdy = etran.LayerOffset(1).TrExpr(e.LogicalBody());
Bpl.Expr q = new Bpl.ForallExpr(kase.tok, bvars, Bpl.Expr.Imp(ante, bdy));
splits.Add(new SplitExprInfo(false, q));
}
@@ -5341,7 +5554,7 @@ namespace Microsoft.Dafny {
// consider automatically applying induction
var inductionVariables = new List<BoundVar>();
foreach (var n in e.BoundVars) {
- if (VarOccursInArgumentToRecursiveFunction(e.Body, n, null)) {
+ if (VarOccursInArgumentToRecursiveFunction(e.LogicalBody(), n, null)) {
if (CommandLineOptions.Clo.Trace) {
Console.Write("Applying automatic induction on variable '{0}' of: ", n.Name);
new Printer(Console.Out).PrintExpression(e);
@@ -5442,9 +5655,10 @@ namespace Microsoft.Dafny {
}
return VarOccursInArgumentToRecursiveFunction(e.E0, n, p) ||
VarOccursInArgumentToRecursiveFunction(e.E1, n, p);
- } else if (expr is QuantifierExpr) {
- var e = (QuantifierExpr)expr;
- return VarOccursInArgumentToRecursiveFunction(e.Body, n, null);
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ return (e.Range != null && VarOccursInArgumentToRecursiveFunction(e.Range, n, null)) ||
+ VarOccursInArgumentToRecursiveFunction(e.Term, n, null);
} else if (expr is ITEExpr) {
var e = (ITEExpr)expr;
return VarOccursInArgumentToRecursiveFunction(e.Test, n, null) || // test is not "elevated"
@@ -5612,17 +5826,27 @@ namespace Microsoft.Dafny {
newExpr = newBin;
}
- } else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
- Expression newBody = Substitute(e.Body, receiverReplacement, substMap);
- Triggers newTrigs = SubstTriggers(e.Trigs, receiverReplacement, substMap);
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ Expression newRange = e.Range == null ? null : Substitute(e.Range, receiverReplacement, substMap);
+ Expression newTerm = Substitute(e.Term, receiverReplacement, substMap);
Attributes newAttrs = SubstAttributes(e.Attributes, receiverReplacement, substMap);
- if (newBody != e.Body || newTrigs != e.Trigs || newAttrs != e.Attributes) {
- if (expr is ForallExpr) {
- newExpr = new ForallExpr(expr.tok, e.BoundVars, newBody, newTrigs, newAttrs);
- } else {
- newExpr = new ExistsExpr(expr.tok, e.BoundVars, newBody, newTrigs, newAttrs);
+ if (e is SetComprehension) {
+ if (newRange != e.Range || newTerm != e.Term || newAttrs != e.Attributes) {
+ newExpr = new SetComprehension(expr.tok, e.BoundVars, newRange, newTerm);
}
+ } else if (e is QuantifierExpr) {
+ var q = (QuantifierExpr)e;
+ Triggers newTrigs = SubstTriggers(q.Trigs, receiverReplacement, substMap);
+ if (newRange != e.Range || newTerm != e.Term || newAttrs != e.Attributes || newTrigs != q.Trigs) {
+ if (expr is ForallExpr) {
+ newExpr = new ForallExpr(expr.tok, e.BoundVars, newRange, newTerm, newTrigs, newAttrs);
+ } else {
+ newExpr = new ExistsExpr(expr.tok, e.BoundVars, newRange, newTerm, newTrigs, newAttrs);
+ }
+ }
+ } else {
+ Contract.Assume(false); // unexpected ComprehensionExpr
}
} else if (expr is ITEExpr) {
diff --git a/Source/ModelViewer/bvdicon.design b/Source/ModelViewer/bvdicon.design
new file mode 100644
index 00000000..c71ca9a6
--- /dev/null
+++ b/Source/ModelViewer/bvdicon.design
Binary files differ
diff --git a/Test/dafny0/Answer b/Test/dafny0/Answer
index 1ac8fc1c..e0874a66 100644
--- a/Test/dafny0/Answer
+++ b/Test/dafny0/Answer
@@ -198,8 +198,18 @@ Execution trace:
(0,0): anon0
SmallTests.dfy(267,19): anon3_Else
(0,0): anon2
+SmallTests.dfy(307,3): Error BP5003: A postcondition might not hold on this return path.
+SmallTests.dfy(301,11): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon0
+ (0,0): anon18_Else
+ (0,0): anon11
+ (0,0): anon23_Then
+ (0,0): anon24_Then
+ (0,0): anon15
+ (0,0): anon25_Else
-Dafny program verifier finished with 34 verified, 13 errors
+Dafny program verifier finished with 41 verified, 14 errors
-------------------- Definedness.dfy --------------------
Definedness.dfy(8,7): Error: possible division by zero
@@ -391,6 +401,13 @@ Execution trace:
Dafny program verifier finished with 3 verified, 3 errors
+-------------------- ResolutionErrors.dfy --------------------
+ResolutionErrors.dfy(10,16): Error: 'decreases *' is not allowed on ghost loops
+ResolutionErrors.dfy(22,11): Error: array selection requires an array2 (got array3<T>)
+ResolutionErrors.dfy(23,12): Error: sequence/array selection requires a sequence or array (got array3<T>)
+ResolutionErrors.dfy(24,11): Error: array selection requires an array4 (got array<T>)
+4 resolution/type errors detected in ResolutionErrors.dfy
+
-------------------- Array.dfy --------------------
Array.dfy(10,12): Error: assignment may update an array element not in the enclosing method's modifies clause
Execution trace:
@@ -457,14 +474,17 @@ Dafny program verifier finished with 8 verified, 2 errors
-------------------- NonGhostQuantifiers.dfy --------------------
NonGhostQuantifiers.dfy(13,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'n'
-NonGhostQuantifiers.dfy(57,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'i'
-NonGhostQuantifiers.dfy(61,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
-NonGhostQuantifiers.dfy(71,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
-NonGhostQuantifiers.dfy(86,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
-NonGhostQuantifiers.dfy(94,10): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'y'
-NonGhostQuantifiers.dfy(103,8): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'x'
-NonGhostQuantifiers.dfy(120,8): Error: Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)
-8 resolution/type errors detected in NonGhostQuantifiers.dfy
+NonGhostQuantifiers.dfy(42,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'n'
+NonGhostQuantifiers.dfy(46,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'd'
+NonGhostQuantifiers.dfy(50,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'n'
+NonGhostQuantifiers.dfy(74,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'i'
+NonGhostQuantifiers.dfy(78,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
+NonGhostQuantifiers.dfy(88,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
+NonGhostQuantifiers.dfy(103,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'j'
+NonGhostQuantifiers.dfy(111,10): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'y'
+NonGhostQuantifiers.dfy(120,8): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'x'
+NonGhostQuantifiers.dfy(137,8): Error: Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)
+11 resolution/type errors detected in NonGhostQuantifiers.dfy
-------------------- AdvancedLHS.dfy --------------------
AdvancedLHS.dfy(32,23): Error: target object may be null
@@ -483,9 +503,12 @@ Modules0.dfy(62,6): Error: inter-module calls must follow the module import rela
Modules0.dfy(72,6): Error: inter-module calls must follow the module import relation (so module X0 must transitively import X1)
Modules0.dfy(91,4): Error: inter-module calls must follow the module import relation (so module _default must transitively import YY)
Modules0.dfy(116,16): Error: ghost variables are allowed only in specification contexts
-Modules0.dfy(133,10): Error: match source expression 'tree' has already been used as a match source expression in this context
-Modules0.dfy(172,12): Error: match source expression 'l' has already been used as a match source expression in this context
-10 resolution/type errors detected in Modules0.dfy
+Modules0.dfy(130,11): Error: old expressions are allowed only in specification and ghost contexts
+Modules0.dfy(131,11): Error: fresh expressions are allowed only in specification and ghost contexts
+Modules0.dfy(132,11): Error: allocated expressions are allowed only in specification and ghost contexts
+Modules0.dfy(148,10): Error: match source expression 'tree' has already been used as a match source expression in this context
+Modules0.dfy(187,12): Error: match source expression 'l' has already been used as a match source expression in this context
+13 resolution/type errors detected in Modules0.dfy
-------------------- Modules1.dfy --------------------
Modules1.dfy(55,3): Error: decreases expression must be bounded below by 0
@@ -504,6 +527,59 @@ Execution trace:
Dafny program verifier finished with 2 verified, 1 error
+-------------------- Comprehensions.dfy --------------------
+Comprehensions.dfy(9,14): Error: assertion violation
+Execution trace:
+ (0,0): anon0
+ (0,0): anon9_Then
+ (0,0): anon10_Then
+ (0,0): anon4
+ (0,0): anon11_Then
+ (0,0): anon12_Then
+ (0,0): anon8
+
+Dafny program verifier finished with 6 verified, 1 error
+
+-------------------- ControlStructures.dfy --------------------
+ControlStructures.dfy(5,3): Error: missing case in case statement: Blue
+Execution trace:
+ (0,0): anon0
+ (0,0): anon6_Else
+ (0,0): anon7_Else
+ (0,0): anon8_Else
+ (0,0): anon9_Then
+ControlStructures.dfy(5,3): Error: missing case in case statement: Purple
+Execution trace:
+ (0,0): anon0
+ (0,0): anon6_Else
+ (0,0): anon7_Else
+ (0,0): anon8_Then
+ControlStructures.dfy(14,3): Error: missing case in case statement: Purple
+Execution trace:
+ (0,0): anon0
+ (0,0): anon6_Else
+ (0,0): anon7_Else
+ (0,0): anon8_Then
+ControlStructures.dfy(43,5): Error: missing case in case statement: Red
+Execution trace:
+ (0,0): anon0
+ (0,0): anon8_Then
+ (0,0): anon9_Else
+ (0,0): anon10_Then
+ControlStructures.dfy(51,3): Error: missing case in case statement: Red
+Execution trace:
+ (0,0): anon8_Else
+ (0,0): anon9_Else
+ (0,0): anon10_Else
+ (0,0): anon11_Else
+ (0,0): anon12_Then
+ControlStructures.dfy(72,3): Error: alternative cases fail to cover all possibilties
+Execution trace:
+ (0,0): anon0
+ (0,0): anon5_Else
+
+Dafny program verifier finished with 15 verified, 6 errors
+
-------------------- Termination.dfy --------------------
Termination.dfy(102,3): Error: cannot prove termination; try supplying a decreases clause for the loop
Execution trace:
diff --git a/Test/dafny0/Comprehensions.dfy b/Test/dafny0/Comprehensions.dfy
new file mode 100644
index 00000000..8629a418
--- /dev/null
+++ b/Test/dafny0/Comprehensions.dfy
@@ -0,0 +1,40 @@
+method M()
+{
+ var numbers := set i | 0 <= i && i < 100;
+ var squares := set i | 0 <= i && i < 100 :: Id(i)*i; // verifying properties about set comprehensions with a term expression is hard
+
+ assert 12 in numbers;
+ assert Id(5) == 5;
+ assert 25 in squares;
+ assert 200 in numbers; // error
+}
+
+function method Id(x: int): int { x } // for triggering
+
+// The following mainly test that set comprehensions can be compiled, but one would
+// have to run the resulting program to check that the compiler is doing the right thing.
+method Main()
+{
+ var q := set i,j | 0 <= i && i < 10 && 0 <= j && j < 3 :: i+j;
+ call PrintSet(q);
+ q := set b: bool | true :: if b then 3 else 7;
+ call PrintSet(q);
+ var m := set k | k in q :: 2*k;
+ call PrintSet(m);
+ call PrintSet(set k | k in q && k % 2 == 0);
+ var sq := [30, 40, 20];
+ call PrintSet(set k, i | k in sq && 0 <= i && i < k && i % 7 == 0 :: k + i);
+ var bb := forall k, i | k in sq && 0 <= i && i < k && i % 7 == 0 :: k + i == 17;
+}
+
+method PrintSet<T>(s: set<T>) {
+ var q := s;
+ while (q != {})
+ decreases q;
+ {
+ var x := choose q;
+ print x, " ";
+ q := q - {x};
+ }
+ print "\n";
+}
diff --git a/Test/dafny0/ControlStructures.dfy b/Test/dafny0/ControlStructures.dfy
new file mode 100644
index 00000000..35d939d3
--- /dev/null
+++ b/Test/dafny0/ControlStructures.dfy
@@ -0,0 +1,137 @@
+datatype D = Green | Blue | Red | Purple;
+
+method M0(d: D)
+{
+ match (d) { // error: two missing cases: Blue and Purple
+ case Green =>
+ case Red =>
+ }
+}
+
+method M1(d: D)
+ requires d != #D.Blue;
+{
+ match (d) { // error: missing case: Purple
+ case Green =>
+ case Red =>
+ }
+}
+
+method M2(d: D)
+ requires d != #D.Blue && d != #D.Purple;
+{
+ match (d) {
+ case Green =>
+ case Red =>
+ }
+}
+
+method M3(d: D)
+ requires d == #D.Green;
+{
+ if (d != #D.Green) {
+ match (d) {
+ // nothing here
+ }
+ }
+}
+
+method M4(d: D)
+ requires d == #D.Green || d == #D.Red;
+{
+ if (d != #D.Green) {
+ match (d) { // error: missing case Red
+ // nothing here
+ }
+ }
+}
+
+function F0(d: D): int
+{
+ match (d) // error: missing cases Red
+ case Purple => 80
+ case Green => 0
+ case Blue => 2
+}
+
+function F1(d: D, x: int): int
+ requires x < 100;
+ requires d == #D.Red ==> x == 200; // (an impossibility, given the first precondition, so d != Red)
+{
+ match (d)
+ case Purple => 80
+ case Green => 0
+ case Blue => 2
+}
+
+// --------------- alternative statements ---------------------
+
+method A0(x: int) returns (r: int)
+ ensures 0 <= r;
+{
+ if { // error: missing case (x == 0)
+ case x < 0 => r := 12;
+ case 0 < x => r := 13;
+ }
+}
+
+method A1(x: int) returns (r: int)
+ ensures 0 <= r;
+{
+ if {
+ case x <= 0 => r := 12;
+ case 0 <= x => r := 13;
+ }
+}
+
+method DutchFlag(A: array<int>, N: int, l: int, r: int) returns (result: int)
+ requires A != null && N == A.Length;
+ requires 0 <= l && l+2 <= r && r <= N;
+ modifies A;
+ ensures l <= result && result < r;
+ ensures forall k, j :: l <= k && k < result && result <= j && j < r ==> A[k] <= A[j];
+ ensures forall k :: l <= k && k < result ==> A[k] <= old(A[l]);
+ ensures forall k :: result <= k && k < r ==> old(A[l]) <= A[k];
+{
+ var pv := A[l];
+ var i := l;
+ var j := r-1;
+ // swap A[l] and A[j]
+ var tmp := A[l]; A[l] := A[j]; A[j] := tmp;
+
+ while (i < j)
+ invariant l <= i && i <= j && j < r;
+ invariant forall k :: l <= k && k < i ==> A[k] <= pv;
+ invariant forall k :: j <= k && k < r ==> pv <= A[k];
+ {
+ if {
+ case A[i] <= pv =>
+ i := i + 1;
+ case pv <= A[j-1] =>
+ j := j - 1;
+ case A[j-1] < pv && pv < A[i] =>
+ // swap A[j-1] and A[i]
+ tmp := A[i]; A[i] := A[j-1]; A[j-1] := tmp;
+ assert A[i] < pv && pv < A[j-1];
+ i := i + 1;
+ j := j - 1;
+ }
+ }
+ result := i;
+}
+
+// --------------- alternative loop statements ---------------
+
+method B(x: int) returns (r: int)
+ ensures r == 0;
+{
+ r := x;
+ while
+ decreases if 0 <= r then r else -r;
+ {
+ case r < 0 =>
+ r := r + 1;
+ case 0 < r =>
+ r := r - 1;
+ }
+}
diff --git a/Test/dafny0/Modules0.dfy b/Test/dafny0/Modules0.dfy
index adce71a8..59052ac2 100644
--- a/Test/dafny0/Modules0.dfy
+++ b/Test/dafny0/Modules0.dfy
@@ -121,6 +121,21 @@ class Ghosty {
ghost method Theorem(a: int) { }
}
+var SomeField: int;
+
+method SpecialFunctions()
+ modifies this;
+{
+ SomeField := SomeField + 4;
+ var a := old(SomeField); // error: old can only be used in ghost contexts
+ var b := fresh(this); // error: fresh can only be used in ghost contexts
+ var c := allocated(this); // error: allocated can only be used in ghost contexts
+ if (fresh(this)) { // this guard makes the if statement a ghost statement
+ ghost var x := old(SomeField); // this is a ghost context, so it's okay
+ ghost var y := allocated(this); // this is a ghost context, so it's okay
+ }
+}
+
// ---------------------- illegal match expressions ---------------
datatype Tree { Nil; Cons(int, Tree, Tree); }
diff --git a/Test/dafny0/NatTypes.dfy b/Test/dafny0/NatTypes.dfy
index 93bd4b65..6b7ce9b9 100644
--- a/Test/dafny0/NatTypes.dfy
+++ b/Test/dafny0/NatTypes.dfy
@@ -60,7 +60,7 @@ datatype List<T> {
Cons(nat, T, List<T>);
}
-method MatchIt(list: List<bool>) returns (k: nat)
+method MatchIt(list: List<object>) returns (k: nat)
{
match (list) {
case Nil =>
diff --git a/Test/dafny0/NonGhostQuantifiers.dfy b/Test/dafny0/NonGhostQuantifiers.dfy
index ea256a58..58e64827 100644
--- a/Test/dafny0/NonGhostQuantifiers.dfy
+++ b/Test/dafny0/NonGhostQuantifiers.dfy
@@ -33,6 +33,23 @@ class MyClass<T> {
(forall n :: 2 <= n ==> 1000 <= n || (exists d :: n < d && d < 2*n))
}
+ function method GoodRange(): bool
+ {
+ (forall n | 2 <= n :: 1000 <= n || (exists d | n < d :: d < 2*n)) && (exists K: nat | K < 100 :: true)
+ }
+ function method BadRangeForall(): bool
+ {
+ forall n | n <= 2 :: 1000 <= n || n % 2 == 0 // error: cannot bound range for n
+ }
+ function method BadRangeExists(): bool
+ {
+ exists d | d < 1000 :: d < 2000 // error: cannot bound range for d
+ }
+ function method WhatAboutThis(): bool
+ {
+ forall n :: 2 <= n && (forall M | M == 1000 :: n < M) ==> n % 2 == 0 // error: heuristics don't get this one for n
+ }
+
// Here are more tests
function method F(a: array<T>): bool
diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy
new file mode 100644
index 00000000..5ec0cc4c
--- /dev/null
+++ b/Test/dafny0/ResolutionErrors.dfy
@@ -0,0 +1,25 @@
+
+//Should not verify, as ghost loops should not be allowed to diverge.
+method GhostDivergentLoop()
+{
+ var a := new int [2];
+ a[0] := 1;
+ a[1] := -1;
+ ghost var i := 0;
+ while (i < 2)
+ decreases *; // error: not allowed on a ghost loop
+ invariant i <= 2;
+ invariant (forall j :: 0 <= j && j < i ==> a[j] > 0);
+ {
+ i := 0;
+ }
+ assert a[1] != a[1]; // ...for then this would incorrectly verify
+}
+
+method M<T>(a: array3<T>, b: array<T>, m: int, n: int)
+{
+ // the following invalid expressions were once incorrectly resolved:
+ var x := a[m, n]; // error
+ var y := a[m]; // error
+ var z := b[m, n, m, n]; // error
+}
diff --git a/Test/dafny0/SmallTests.dfy b/Test/dafny0/SmallTests.dfy
index a839d5a9..a5f02dc6 100644
--- a/Test/dafny0/SmallTests.dfy
+++ b/Test/dafny0/SmallTests.dfy
@@ -272,3 +272,49 @@ class InitCalls {
r := new InitCalls.InitFromReference(r); // error, since r.z is unknown
}
}
+
+// --------------- some tests with quantifiers and ranges ----------------------
+
+method QuantifierRange0<T>(a: seq<T>, x: T, y: T, N: int)
+ requires 0 <= N && N <= |a|;
+ requires forall k | 0 <= k && k < N :: a[k] != x;
+ requires exists k | 0 <= k && k < N :: a[k] == y;
+ ensures forall k :: 0 <= k && k < N ==> a[k] != x; // same as the precondition, but using ==> instead of |
+ ensures exists k :: 0 <= k && k < N && a[k] == y; // same as the precondition, but using && instead of |
+{
+ assert x != y;
+}
+
+method QuantifierRange1<T>(a: seq<T>, x: T, y: T, N: int)
+ requires 0 <= N && N <= |a|;
+ requires forall k :: 0 <= k && k < N ==> a[k] != x;
+ requires exists k :: 0 <= k && k < N && a[k] == y;
+ ensures forall k | 0 <= k && k < N :: a[k] != x; // same as the precondition, but using | instead of ==>
+ ensures exists k | 0 <= k && k < N :: a[k] == y; // same as the precondition, but using | instead of &&
+{
+ assert x != y;
+}
+
+method QuantifierRange2<T>(a: seq<T>, x: T, y: T, N: int)
+ requires 0 <= N && N <= |a|;
+ requires exists k | 0 <= k && k < N :: a[k] == y;
+ ensures forall k | 0 <= k && k < N :: a[k] == y; // error
+{
+ assert N != 0;
+ if (N == 1) {
+ assert forall k | a[if 0 <= k && k < N then k else 0] != y :: k < 0 || N <= k; // in this case, the precondition holds trivially
+ }
+ if (forall k | 0 <= k && k < N :: a[k] == x) {
+ assert x == y;
+ }
+}
+
+// ----------------------- tests that involve sequences of boxed booleans --------
+
+ghost method M(zeros: seq<bool>, Z: bool)
+ requires 1 <= |zeros| && Z == false;
+ requires forall k :: 0 <= k && k < |zeros| ==> zeros[k] == Z;
+{
+ var x := [Z];
+ assert zeros[0..1] == [Z];
+}
diff --git a/Test/dafny0/runtest.bat b/Test/dafny0/runtest.bat
index 491b7b75..16bc0e2b 100644
--- a/Test/dafny0/runtest.bat
+++ b/Test/dafny0/runtest.bat
@@ -11,10 +11,11 @@ for %%f in (Simple.dfy) do (
%DAFNY_EXE% %* /dprint:- /env:0 /noVerify %%f
)
-for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
- FunctionSpecifications.dfy
+for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
+ FunctionSpecifications.dfy ResolutionErrors.dfy
Array.dfy MultiDimArray.dfy NonGhostQuantifiers.dfy AdvancedLHS.dfy
Modules0.dfy Modules1.dfy BadFunction.dfy
+ Comprehensions.dfy ControlStructures.dfy
Termination.dfy Use.dfy DTypes.dfy
TypeParameters.dfy Datatypes.dfy TypeAntecedents.dfy SplitExpr.dfy
Refinement.dfy RefinementErrors.dfy) do (
diff --git a/Test/dafny1/Answer b/Test/dafny1/Answer
index d96e12a5..0111f9af 100644
--- a/Test/dafny1/Answer
+++ b/Test/dafny1/Answer
@@ -59,9 +59,13 @@ Dafny program verifier finished with 2 verified, 0 errors
Dafny program verifier finished with 17 verified, 0 errors
+-------------------- FindZero.dfy --------------------
+
+Dafny program verifier finished with 4 verified, 0 errors
+
-------------------- TerminationDemos.dfy --------------------
-Dafny program verifier finished with 11 verified, 0 errors
+Dafny program verifier finished with 14 verified, 0 errors
-------------------- Substitution.dfy --------------------
diff --git a/Test/dafny1/FindZero.dfy b/Test/dafny1/FindZero.dfy
new file mode 100644
index 00000000..cff8b934
--- /dev/null
+++ b/Test/dafny1/FindZero.dfy
@@ -0,0 +1,30 @@
+method FindZero(a: array<int>) returns (r: int)
+ requires a != null && forall i :: 0 <= i && i < a.Length ==> 0 <= a[i];
+ requires forall i :: 0 <= i && i+1 < a.Length ==> a[i]-1 <= a[i+1];
+ ensures 0 <= r ==> r < a.Length && a[r] == 0;
+ ensures r < 0 ==> forall i :: 0 <= i && i < a.Length ==> a[i] != 0;
+{
+ var n := 0;
+ while (n < a.Length)
+ invariant forall i :: 0 <= i && i < n && i < a.Length ==> a[i] != 0;
+ {
+ if (a[n] == 0) { r := n; return; }
+ call Lemma(a, n, a[n]);
+ n := n + a[n];
+ }
+ r := -1;
+}
+
+ghost method Lemma(a: array<int>, k: int, m: int)
+ requires a != null && forall i :: 0 <= i && i < a.Length ==> 0 <= a[i];
+ requires forall i :: 0 <= i && i+1 < a.Length ==> a[i]-1 <= a[i+1];
+ requires 0 <= k;
+ requires k < a.Length ==> m <= a[k];
+ ensures forall i :: k <= i && i < k+m && i < a.Length ==> a[i] != 0;
+ decreases m;
+{
+ if (0 < m && k < a.Length) {
+ assert a[k] != 0;
+ call Lemma(a, k+1, m-1);
+ }
+}
diff --git a/Test/dafny1/TerminationDemos.dfy b/Test/dafny1/TerminationDemos.dfy
index 01a7c7bd..49f5a075 100644
--- a/Test/dafny1/TerminationDemos.dfy
+++ b/Test/dafny1/TerminationDemos.dfy
@@ -42,6 +42,28 @@ class Ackermann {
else
G(m - 1, G(m, n - 1))
}
+
+ function H(m: nat, n: nat): nat
+ {
+ if m == 0 then
+ n + 1
+ else if n == 0 then
+ H(m - 1, 1)
+ else
+ H(m - 1, H(m, n - 1))
+ }
+
+ method ComputeAck(m: nat, n: nat) returns (r: nat)
+ {
+ if (m == 0) {
+ r := n + 1;
+ } else if (n == 0) {
+ call r := ComputeAck(m - 1, 1);
+ } else {
+ call s := ComputeAck(m, n - 1);
+ call r := ComputeAck(m - 1, s);
+ }
+ }
}
// -----------------------------------
diff --git a/Test/dafny1/runtest.bat b/Test/dafny1/runtest.bat
index 36b93883..57ac97e3 100644
--- a/Test/dafny1/runtest.bat
+++ b/Test/dafny1/runtest.bat
@@ -19,7 +19,7 @@ for %%f in (Queue.dfy PriorityQueue.dfy ExtensibleArray.dfy
ListCopy.dfy ListReverse.dfy ListContents.dfy
MatrixFun.dfy pow2.dfy
SchorrWaite.dfy
- Cubes.dfy SumOfCubes.dfy
+ Cubes.dfy SumOfCubes.dfy FindZero.dfy
TerminationDemos.dfy Substitution.dfy TreeDatatype.dfy KatzManna.dfy
Induction.dfy Rippling.dfy
Celebrity.dfy
diff --git a/Test/test0/Answer b/Test/test0/Answer
index 0441b69b..d434a8ca 100644
--- a/Test/test0/Answer
+++ b/Test/test0/Answer
@@ -247,3 +247,16 @@ BadQuantifier.bpl(3,15): error: invalid QuantifierBody
EmptyCallArgs.bpl(31,2): Error: type variable must occur in types of given arguments: a
EmptyCallArgs.bpl(32,2): Error: type variable must occur in types of given arguments: a
2 name resolution errors detected in EmptyCallArgs.bpl
+----- SeparateVerification0.bpl
+SeparateVerification0.bpl(13,6): Error: undeclared identifier: y
+1 name resolution errors detected in SeparateVerification0.bpl
+----- SeparateVerification1.bpl SeparateVerification0.bpl
+SeparateVerification1.bpl(4,6): Error: undeclared identifier: x
+SeparateVerification0.bpl(10,6): Error: undeclared identifier: x
+2 name resolution errors detected in SeparateVerification0.bpl
+----- SeparateVerification0.bpl SeparateVerification0.bpl
+
+Boogie program verifier finished with 0 verified, 0 errors
+----- SeparateVerification0.bpl SeparateVerification0.bpl SeparateVerification1.bpl
+
+Boogie program verifier finished with 0 verified, 0 errors
diff --git a/Test/test0/SeparateVerification0.bpl b/Test/test0/SeparateVerification0.bpl
new file mode 100644
index 00000000..5a8ef283
--- /dev/null
+++ b/Test/test0/SeparateVerification0.bpl
@@ -0,0 +1,21 @@
+// need to include this file twice for it to include all necessary declarations
+
+#if FILE_0
+const x: int;
+#else
+const y: int;
+#endif
+
+#if FILE_1
+axiom x == 12;
+procedure Q();
+#else
+axiom y == 7;
+#endif
+
+// duplicates of :extern's are fine (Boogie keeps the non-:extern or chooses arbitrarily among the :extern's)
+type {:extern} T;
+const {:extern} C: int;
+function {:extern} F(): int;
+var {:extern} n: int;
+procedure {:extern} P(inconsistentParameterButThatIsOkayBecauseTheExternIsIgnored: int);
diff --git a/Test/test0/SeparateVerification1.bpl b/Test/test0/SeparateVerification1.bpl
new file mode 100644
index 00000000..0e3e7926
--- /dev/null
+++ b/Test/test0/SeparateVerification1.bpl
@@ -0,0 +1,19 @@
+// to be used with SeparateVerification0.bpl
+
+// x and y are declared in SeparateVerification0.bpl
+axiom x + y <= 100;
+
+// these are declared as :extern as SeparateVerification0.bpl
+type T;
+const C: int;
+function F(): int;
+var n: int;
+procedure P();
+procedure {:extern} Q(x: int);
+
+procedure Main() {
+ call P(); // note, calling the parameter-less non-extern P (an extern and a non-extern
+ // declaration of the same name are usually mostly identical declarations,
+ // but Boogie allows them to be different, because it ignores the extern ones)
+ call Q(); // ditto
+}
diff --git a/Test/test0/runtest.bat b/Test/test0/runtest.bat
index c7c6ee3d..5ecc22dc 100644
--- a/Test/test0/runtest.bat
+++ b/Test/test0/runtest.bat
@@ -31,3 +31,12 @@ rem set BGEXE=mono ..\..\Binaries\Boogie.exe
%BGEXE% %* /noVerify Orderings.bpl
%BGEXE% %* /noVerify BadQuantifier.bpl
%BGEXE% %* /noVerify EmptyCallArgs.bpl
+
+echo ----- SeparateVerification0.bpl
+%BGEXE% %* /noVerify SeparateVerification0.bpl
+echo ----- SeparateVerification1.bpl SeparateVerification0.bpl
+%BGEXE% %* /noVerify SeparateVerification1.bpl SeparateVerification0.bpl
+echo ----- SeparateVerification0.bpl SeparateVerification0.bpl
+%BGEXE% %* /noVerify SeparateVerification0.bpl SeparateVerification0.bpl
+echo ----- SeparateVerification0.bpl SeparateVerification0.bpl SeparateVerification1.bpl
+%BGEXE% %* /noVerify SeparateVerification0.bpl SeparateVerification0.bpl SeparateVerification1.bpl
diff --git a/_admin/Boogie/aste/summary.log b/_admin/Boogie/aste/summary.log
index d5fb6585..d974d514 100644
--- a/_admin/Boogie/aste/summary.log
+++ b/_admin/Boogie/aste/summary.log
@@ -1,17 +1,17 @@
-# Aste started: 2011-05-04 07:00:19
+# Aste started: 2011-05-20 07:00:17
# Host id: Boogiebox
-# [2011-05-04 07:02:49] SpecSharp revision: 6e9f7e851bd3
-# [2011-05-04 07:02:49] SscBoogie revision: 6e9f7e851bd3
-# [2011-05-04 07:04:02] Boogie revision: e7280be476fa
-[2011-05-04 07:06:38] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
+# [2011-05-20 07:03:02] SpecSharp revision: 590155e890f6
+# [2011-05-20 07:03:02] SscBoogie revision: 590155e890f6
+# [2011-05-20 07:04:18] Boogie revision: c2e1892f0445
+[2011-05-20 07:06:48] 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(686,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)'.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(109,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(114,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(117,65): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.Set)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.Set)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Absy.cs(682,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)'.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(111,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(116,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(119,65): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.Set)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.Set)', thus cannot add Requires.
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(111,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(290,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(309,7): warning CS0162: Unreachable code detected
@@ -31,5 +31,5 @@
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.
-[2011-05-04 07:48:22] 0 out of 30 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
-# [2011-05-04 07:49:23] Released nightly of Boogie
+[2011-05-20 07:54:44] 0 out of 30 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
+# [2011-05-20 07:55:49] Released nightly of Boogie